Skip to content

Commit ed28a3a

Browse files
authored
v3.1.0 (#85)
2 parents d84b4ce + 25d8931 commit ed28a3a

File tree

11 files changed

+257
-68
lines changed

11 files changed

+257
-68
lines changed

README.md

+56-34
Original file line numberDiff line numberDiff line change
@@ -28,59 +28,67 @@ Download the [latest release](https://github.com/Log1x/navi/releases/latest) `.z
2828

2929
## Usage
3030

31-
Check out the [**examples**](examples) folder to see how to use Navi in your project.
32-
33-
### Basic Usage
31+
Building your menu can be done by passing your menu location to `Navi::make()->build()`:
3432

3533
```php
36-
<?php
37-
3834
use Log1x\Navi\Navi;
3935

40-
$navigation = Navi::make()->build('primary_navigation');
36+
$menu = Navi::make()->build('primary_navigation');
37+
```
4138

42-
if ($navigation->isEmpty()) {
43-
return;
44-
}
39+
By default, `build()` uses `primary_navigation` if no menu location is specified.
40+
41+
Retrieving an array of menu items can be done using `all()`:
4542

46-
return $navigation->toArray();
43+
```php
44+
if ($menu->isNotEmpty()) {
45+
return $menu->all();
46+
}
4747
```
4848

49-
When building the navigation menu, Navi retains the menu object and makes it available using the `get()` method.
49+
> [!NOTE]
50+
> Check out the [**examples**](examples) folder to see how to use Navi in your project.
5051
51-
By default, `get()` returns the raw[`wp_get_nav_menu_object()`](https://codex.wordpress.org/Function_Reference/wp_get_nav_menu_object) allowing you to access it directly.
52+
### Menu Item Classes
5253

53-
Optionally, you may pass a `key` and `default` to call a specific object key with a fallback have it be null, empty, or not set.
54+
By default, Navi removes the default WordPress classes from menu items such as `menu-item` and `current-menu-item` giving you full control over your menu markup while still passing through custom classes.
55+
56+
If you would like these classes to be included on your menu items, you may call `withDefaultClasses()` before building your menu:
5457

5558
```php
56-
$navigation->get()->name;
57-
$navigation->get('name', 'My menu title');
59+
$menu = Navi::make()->withDefaultClasses()->build();
5860
```
5961

60-
### Acorn Usage
62+
In some situations, plugins may add their own classes to menu items. If you would like to prevent these classes from being added, you may pass an array of partial strings to `withoutClasses()` match against when building.
6163

62-
If you are using Navi alongside [Acorn](https://roots.io/acorn/) (e.g. Sage), you may generate a usable view component using Acorn's CLI:
64+
```php
65+
$menu = Navi::make()->withoutClasses(['shop-'])->build();
66+
```
6367

64-
```sh
65-
$ acorn make:navi
68+
### Accessing Menu Object
69+
70+
When building the navigation menu, Navi retains the menu object and makes it available using the `get()` method.
71+
72+
By default, `get()` returns the raw [`wp_get_nav_menu_object()`](https://codex.wordpress.org/Function_Reference/wp_get_nav_menu_object) allowing you to access it directly.
73+
74+
```php
75+
$menu->get()->name;
6676
```
6777

68-
Once generated, you may use the [view component](https://laravel.com/docs/11.x/blade#components) in an existing view like so:
78+
Optionally, you may pass a `key` and `default` to call a specific object key with a fallback when the value is blank:
6979

7080
```php
71-
<x-navigation />
81+
$menu->get('name', 'My menu title');
7282
```
7383

7484
### Accessing Page Objects
7585

7686
If your menu item is linked to a page object (e.g. not a custom link) – you can retrieve the ID of the page using the `objectId` attribute.
7787

78-
```php
79-
# Blade
80-
{{ get_post_type($item->objectId) }}
88+
Below is an example of getting the post type of the current menu item:
8189

82-
# PHP
83-
<?php echo get_post_type($item->objectId); ?>
90+
```php
91+
$type = get_post_type($item->objectId)
8492
```
8593

8694
### Accessing Custom Fields
@@ -90,18 +98,34 @@ In a scenario where you need to access a custom field attached directly to your
9098
Below we'll get a label override field attached to our menu [using ACF](https://www.advancedcustomfields.com/resources/adding-fields-menus/) – falling back to the default menu label if the field is empty.
9199

92100
```php
93-
# Blade
94-
{{ get_field('custom_nav_label', $item->id) ?: $item->label }}
101+
$label = get_field('custom_menu_label', $item->id) ?: $item->label;
102+
```
103+
104+
### Acorn Usage
105+
106+
If you are using Navi alongside [Acorn](https://roots.io/acorn/) (e.g. Sage), you may generate a usable view component using Acorn's CLI:
95107

96-
# PHP
97-
<?php echo get_field('custom_nav_label', $item->id) ?: $item->label; ?>
108+
```sh
109+
$ wp acorn navi:make Menu
110+
```
111+
112+
Once generated, you may use the [view component](https://laravel.com/docs/11.x/blade#components) in an existing view like so:
113+
114+
```php
115+
<x-menu name="footer_navigation" />
116+
```
117+
118+
To list all registered locations and their assigned menus, you can use the list command:
119+
120+
```sh
121+
$ wp acorn navi:list
98122
```
99123

100124
## Example Output
101125

102-
When calling `build()`, Navi will parse the passed navigation menu and return a fluent container containing your menu items. To return an array of objects, simply call `->toArray()`.
126+
When calling `build()`, Navi will retrieve the WordPress navigation menu assigned to the passed location and build out an array containing the menu items.
103127

104-
By default, `build()` calls `primary_navigation` which is the default menu theme location on Sage.
128+
An example of the menu output can be seen below:
105129

106130
```php
107131
array [
@@ -177,8 +201,6 @@ array [
177201
]
178202
```
179203

180-
That being said, depending on how deep your menu is– you can ultimately just keep looping over `->children` indefinitely.
181-
182204
## Bug Reports
183205

184206
If you discover a bug in Navi, please [open an issue](https://github.com/Log1x/navi/issues).

composer.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@
2626
"php": "^8.0"
2727
},
2828
"require-dev": {
29-
"laravel/pint": "^1.14"
29+
"laravel/pint": "^1.14",
30+
"roots/acorn": "^4.3"
3031
},
3132
"extra": {
3233
"acorn": {

examples/vanilla/template-parts/site-nav.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<?php if ( $navigation->isNotEmpty() ) : ?>
1212
<nav id="site-navigation" class="main-navigation">
1313
<ul id="primary-menu">
14-
<?php foreach ( $navigation->toArray() as $item ) : ?>
14+
<?php foreach ( $navigation->all() as $item ) : ?>
1515
<li class="<?php echo $item->classes; ?> <?php echo $item->active ? 'current-item' : ''; ?>">
1616
<a href="<?php echo $item->url; ?>">
1717
<?php echo $item->label; ?>

plugin.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Plugin Name: Navi
55
* Plugin URI: https://github.com/log1x/navi
66
* Description: A developer-friendly alternative to the WordPress NavWalker.
7-
* Version: 3.0.3
7+
* Version: 3.1.0
88
* Author: Brandon Nifong
99
* Author URI: https://github.com/log1x
1010
*/

src/Console/NaviListCommand.php

+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
3+
namespace Log1x\Navi\Console;
4+
5+
use Illuminate\Console\Command;
6+
7+
class NaviListCommand extends Command
8+
{
9+
/**
10+
* The name and signature of the console command.
11+
*
12+
* @var string
13+
*/
14+
protected $signature = 'navi:list';
15+
16+
/**
17+
* The console command description.
18+
*
19+
* @var string
20+
*/
21+
protected $description = 'List registered navigation menus';
22+
23+
/**
24+
* Execute the console command.
25+
*
26+
* @return void
27+
*/
28+
public function handle()
29+
{
30+
$registered = collect(get_registered_nav_menus());
31+
$locations = collect(get_nav_menu_locations());
32+
$menus = collect(wp_get_nav_menus());
33+
34+
$rows = $registered
35+
->map(fn ($label, $value) => $menus->firstWhere('term_id', $locations->get($value)))
36+
->map(fn ($menu, $location) => collect([
37+
$location,
38+
$menu?->name ?? 'Unassigned',
39+
$menu?->count ?? 0,
40+
])->map(fn ($value) => $menu?->name ? $value : "<fg=red>{$value}</>"));
41+
42+
$this->table([
43+
'<fg=blue>Location</>',
44+
'<fg=blue>Assigned Menu</>',
45+
'<fg=blue>Menu Items</>',
46+
], $rows, tableStyle: 'box');
47+
}
48+
}

src/Console/NaviMakeCommand.php

+21-2
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,28 @@ public function handle()
4141
return false;
4242
}
4343

44-
$name = strtolower(trim($this->argument('name')));
44+
$component = Str::of($this->argument('name'))
45+
->lower()
46+
->trim();
4547

46-
$this->components->info("Navi component <fg=blue><x-{$name} /></> is ready for use.");
48+
$default = $this->option('default') ?? 'primary_navigation';
49+
50+
$locations = collect(get_registered_nav_menus())
51+
->take(5)
52+
->map(fn ($name, $slug) => $slug === $default
53+
? "{$name}: <fg=blue><x-{$component} /></>"
54+
: "{$name}: <fg=blue><x-{$component} name=\"{$slug}\" /></>"
55+
);
56+
57+
$this->components->info("Navi component <fg=blue><x-{$component} /></> is ready for use.");
58+
59+
if ($locations->isEmpty()) {
60+
$this->components->warn('Your theme does not appear to have any registered navigation menu locations.');
61+
62+
return;
63+
}
64+
65+
$this->components->bulletList($locations->all());
4766
}
4867

4968
/**
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
namespace Log1x\Navi\Exceptions;
4+
5+
use Exception;
6+
7+
class MenuLifecycleException extends Exception
8+
{
9+
//
10+
}

src/Facades/Navi.php

+7-1
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,16 @@
55
use Illuminate\Support\Facades\Facade;
66

77
/**
8-
* @method static \Log1x\Navi\Navi build(string $menu = 'primary_navigation')
8+
* @method static \Log1x\Navi\Navi build(mixed $menu = null)
9+
* @method static \Log1x\Navi\Navi withClasses(string|array $classes)
10+
* @method static \Log1x\Navi\Navi withoutClasses(string|array $classes)
11+
* @method static \Log1x\Navi\Navi withDefaultClasses()
912
* @method static mixed get(string $key = null, mixed $default = null)
1013
* @method static bool isEmpty()
1114
* @method static bool isNotEmpty()
15+
* @method static array all()
16+
* @method static array toArray()
17+
* @method static string toJson(int $options = 0)
1218
*
1319
* @see \Log1x\Navi\Navi
1420
*/

src/MenuBuilder.php

+22-18
Original file line numberDiff line numberDiff line change
@@ -23,32 +23,20 @@ class MenuBuilder
2323
'label' => 'title',
2424
'object' => 'object',
2525
'objectId' => 'object_id',
26+
'order' => 'menu_order',
2627
'parent' => 'menu_item_parent',
2728
'slug' => 'post_name',
2829
'target' => 'target',
2930
'title' => 'attr_title',
3031
'type' => 'type',
3132
'url' => 'url',
3233
'xfn' => 'xfn',
33-
'order' => 'menu_order',
3434
];
3535

3636
/**
37-
* The disallowed menu classes.
37+
* The classes to remove from menu items.
3838
*/
39-
protected array $disallowedClasses = [
40-
'current-menu',
41-
'current_page',
42-
'sub-menu',
43-
'menu-item',
44-
'menu-item-type-post_type',
45-
'menu-item-object-page',
46-
'menu-item-type-custom',
47-
'menu-item-object-custom',
48-
'menu_item',
49-
'page-item',
50-
'page_item',
51-
];
39+
protected array $withoutClasses = [];
5240

5341
/**
5442
* Make a new Menu Builder instance.
@@ -93,7 +81,15 @@ protected function filter(array $menu = []): array
9381
_wp_menu_item_classes_by_context($menu);
9482

9583
return array_map(function ($item) {
96-
$classes = array_filter($item->classes, fn ($class) => ! in_array($class, $this->disallowedClasses));
84+
$classes = array_filter($item->classes, function ($class) {
85+
foreach ($this->withoutClasses as $value) {
86+
if (str_starts_with($class, $value)) {
87+
return false;
88+
}
89+
}
90+
91+
return true;
92+
});
9793

9894
$item->classes = is_array($classes) ? implode(' ', $classes) : $classes;
9995

@@ -142,10 +138,18 @@ protected function handle(array $items, string|int $parent = 0): array
142138
$item->children = $this->handle($items, $item->id);
143139

144140
$menu[$item->id] = $item;
145-
146-
unset($item);
147141
}
148142

149143
return $menu;
150144
}
145+
146+
/**
147+
* Remove classes from menu items.
148+
*/
149+
public function withoutClasses(array $classes = []): self
150+
{
151+
$this->withoutClasses = $classes;
152+
153+
return $this;
154+
}
151155
}

0 commit comments

Comments
 (0)