That would be great! I just created a repo on Github using the Walker I’d found but yours is probably better since it implements Soil’s walker. Please feel free to fork/PR/whatever.
I’m interested in seeing your implementation if you don’t mind.
I don’t know how my NavWalkers stack up against what’s already out there. I wrote these for my specific needs in two different projects, and they worked for me. Neither were intended for wider distribution, but here you go anyway. One is for Bootstrap and the other is for Foundation.
Maybe it will help someone.
I have situation like this in sage9-beta3.
I created new class file in new folder called Classes inside sage/app/lib/Sage/. I’ve created MainWalker.php file that looks like this:
MainWalker.php
namespace Roots\Sage\Classes;
use Roots\Soil\Nav\NavWalker as NavWalker;
/*
* @author brunekninja
*/
class MainWalker extends NavWalker
{
}
After that I just use that class as walker in my new nav menu inside header.blade.php
header.blade.php
<header class="page-header" data-method="stickyHeader">
<div class="container">
<nav class="site-navigation">
@if (has_nav_menu('primary_navigation'))
{!! wp_nav_menu([
'theme_location' => 'primary_navigation',
'menu_class' => 'site-navigation__main-nav',
'container_class' => 'site-navigation__main-nav',
'walker' => new Roots\Sage\Classes\MainWalker()
]) !!}
@endif
That’s it, now you can create your custom nav walker in sage 9.
Hope it helps someone.
Hi bruno. I tried this approach as it seemed very clean but I’m getting Fatal error: Class ‘Roots\Soil\Nav\NavWalker’ not found.
Used your code verbatim but am on Sage 9 beta 4 so i created the MainWalker class under /app and included it in functions.php as a required Sage include. Seen a lot of talk of namespace issues
yep. i have installed and activated. Can see the clean soil nav structure.
Update, i resolved this with the help of smutek’s gist… FTW!
Hey,
yes beta 4 has different structure, and also it is true that this approach requires Soil to be activated. But eventually you can just extend main navwalker class from WP and it has to work.
I checked the new structure, and there is small difference. I just putted navigation folder inside app.
Only thing that has to be changed is namespace, and call of nav walker.
So you have situation like this.
namespace App\Navigation;
this is namespace inside MainWalker file.
@if (has_nav_menu('primary_navigation'))
{!! wp_nav_menu([
'theme_location' => 'primary_navigation',
'menu_class' => 'site-navigation__main-nav',
'walker' => new \App\Navigation\MainWalker()
]) !!}
@endif
And it works!
I followed the instructions of @brunekninja, but have the same problem as @thewhipster: Fatal error: Class ‘Roots\Soil\Nav\NavWalker’ not found.
I’m using Trellis/Bedrock/Sage 9 beta 4, with Soil installed and activated.
The same question was asked here, but never resolved.
Any other thoughts on why the class can’t be found, even though Soil is installed and activated?
Hi, I had that problem on linux server in production, before that everything worked fine in docker etc.
Eventually I’ve added this in composer.json file.
"autoload": {
"psr-4": {
"App\\": "web/app/themes/sage/app/",
"App\\Widgets\\": "web/app/themes/sage/app/widgets/"
}
}
After I registered classes this way, error have disappeared
You can try this, this is the only solution that I can think of.
I tried brunekninja’s suggestion and several other autoload options in composer.json files for Bedrock, Sage, and Soil without success. I finally got this to work by loading the Foundation walker file on its own after Soil modules are loaded (and not including the Foundation walker in the Sage required files array). At the bottom of soil.php the modules are loaded with after_setup_theme, priority 100. So my Sage functions.php file now has this:
/**
* Sage required files
*
* The mapped array determines the code library included in your theme.
* Add or remove files to the array as needed. Supports child theme overrides.
*/
array_map(function ($file) use ($sage_error) {
$file = "../app/{$file}.php";
if (!locate_template($file, true, true)) {
$sage_error(sprintf(__('Error locating <code>%s</code> for inclusion.', 'sage'), $file), 'File not found');
}
}, ['helpers', 'setup', 'filters', 'admin']);
/**
* Foundation Nav Walker
*
* Load the Foundation nav walker after Soil plugin modules are loaded so that Soil's NavWalker class is available.
*/
add_action( 'after_setup_theme', 'add_foundation_nav_walker', 101 );
function add_foundation_nav_walker() {
if ( class_exists('\Roots\Soil\Nav\NavWalker') ) {
require get_template_directory() . '/../app/nav-foundation-walker.php';
}
}
I’m new to psr-4 and namespaces in php, but I gather that the reason for autoloading with psr-4 is to allow classes to be available independently of how they might otherwise be loaded via require, etc. Soil’s compser.json file currently doesn’t autoload anything. Should it include the following?
"autoload": {
"psr-4": { "Roots\\Soil\\Nav": "modules" }
},
When I try that and run composer update in Soil, the generated autoload file at soil/vendor/composer/autoload_psr4.php file correctly shows:
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Roots\\Soil\\Nav\\' => array($baseDir . '/modules'),
'Composer\\Installers\\' => array($vendorDir . '/composer/installers/src/Composer/Installers'),
);
But if I then load nav_foundation_walker.php via the Sage required array I still get “Fatal error: Class ‘Roots\Soil\Nav\NavWalker’ not found” when loading the site in my browser. I assume the correct way to do this is with autoloading, but I’m not sure how to make that work.
I’m having a somewhat similar problem. I have my Walkers working on development with no problems, but when I upload the theme to the prod server, I get the same “Walker not found error”. Weird.
You need to run composer install
in the theme directory when you deploy a Sage 9 theme:
That was in reply to Right Way to Add New Walker to Sage 9, right? Running composer install
in the theme doesn’t solve my problem.
Hard to help without anything to go off.
Please provide the exact code that you are using/changes that you have made to Sage.
Hi Ben! Thanks - will try.
I’m running Windows 10 with Trellis/Bedrock/Sage 9-beta.4, and Soil installed via composer and activated.
In sage/app/
I’ve added a file nav-foundation-walker.php
with QWp6t’s Foundation.php walker. So the file looks like this:
<?php
namespace App;
use Roots\Soil\Nav\NavWalker as SoilNavWalker;
/**
* Foundation 6 Navigation Walker
*
* @author QWp6t
* @license OSL-3.0
* @see https://gist.github.com/QWp6t/8f94b7096bb0d3a72fedba68f73033a5
*/
class FoundationWalker extends SoilNavWalker
{
public function __construct()
{
parent::__construct();
remove_filter('nav_menu_css_class', [$this, 'cssClasses'], 10);
add_filter('nav_menu_css_class', [$this, 'itemClasses'], 10, 4);
}
/**
* @param string $output
* @param int $depth
* @param array $args
* @SuppressWarnings(PHPMD.CamelCaseMethodName) This method overrides its parent
* @SuppressWarnings(PHPMD.UnusedFormalParameter) This method overrides its parent
*/
// @codingStandardsIgnoreLine
public function start_lvl(&$output, $depth = 0, $args = [])
{
$output .= '<ul class="submenu menu" data-submenu>';
}
/**
* @param $classes
* @param $item
* @param $args
* @param $depth
* @return array
* @SuppressWarnings(PHPMD.UnusedFormalParameter) This method overrides its parent
*/
public function itemClasses($classes, $item, /** @noinspection PhpUnusedParameterInspection */ $args, $depth)
{
return array_filter(array_map(function ($class) use ($depth) {
switch ($class) {
case 'menu-item-has-children':
return 'has-submenu';
default:
return $class;
}
}, parent::cssClasses($classes, $item)));
}
}
Then in sage/resources/functions.php
I added nav-foundation-walker
to the Sage required files:
/**
* Sage required files
*
* The mapped array determines the code library included in your theme.
* Add or remove files to the array as needed. Supports child theme overrides.
*/
array_map(function ($file) use ($sage_error) {
$file = "../app/{$file}.php";
if (!locate_template($file, true, true)) {
$sage_error(sprintf(__('Error locating <code>%s</code> for inclusion.', 'sage'), $file), 'File not found');
}
}, ['helpers', 'setup', 'filters', 'admin', 'nav-foundation-walker']);
When I load the site in a browser I get the error:
Fatal error: Class 'Roots\Soil\Nav\NavWalker' not found in /srv/www/test.com/current/web/app/themes/sage/app/nav-foundation-walker.php
How do I use Composer and autoloading so that Roots\Soil\Nav\Navwalker
is available in nav-foundation.php
?
I’ve tried modifying Soil’s composer.json
file by adding:
"autoload": {
"psr-4": {
"Roots\\Soil\\Nav\\": "modules/"
}
},
And I’ve tried modifying Sage’s composer.json
file by adding:
"autoload": {
"psr-4": {
"App\\": "app/",
"Roots\\Soil\\Nav\\": "../../plugins/Soil/modules/"
}
},
Each time I ran composer update
to create a new vendor/autoload_psr4.php
file. I also tried something similar in Bedrock’s composer.json
file. None of these worked. What am missing here?
Any update on this? I’ve just updated from Sage 9 beta 3 (worked fine) to beta 4 and this kind of problems are popping up all over the place.
@krishaamer No fixes yet on my end. I assume I just need a better understanding of autoloading, but I haven’t had a chance to dig in to it. I did start reading a tutorial on autoloading by Alan Storm that could be helpful.
I now have QWp6t’s Foundation.php walker working using psr-4 autloading, instead of by requiring the foundation walker file after the Soil plugin has loaded using after_setup_theme()
.
The problem is that Soil’s NavWalker
class is in a file named nav-walker.php
. According to the psr-4 spec #3.3 listed here:
“When loading a file that corresponds to a fully qualified class name, the terminating class name corresponds to a file name ending in .php. The file name MUST match the case of the terminating class name.”
So the nav-walker.php
file name and NavWalker
class name need to match.
I did the following:
-
Changed the file name from
nav-walker.php
toNavWalker.php
. -
Soil’s modules are loaded based on file name, so in Sage’s setup.php file I changed line 28 to
add_theme_support('soil-NavWalker')
. -
Added the following to Bedrock’s
composer.json
file (multi-line code formatting isn’t working in ordered lists):“autoload”: {
“psr-4”: {
“Roots\Soil\Nav\”: “web/app/plugins/soil/modules/”
}
} -
Ran
composer update
and confirmed the mapping had been added to Bedrock’s/vendor/composer/autoload_psr4.php
. -
Finally, in Sage’s
functions.php
file I removed theafter_setup_theme()
hook I had previously used to load the foundation walker file and instead added the file to Sage’s required files array:
['helpers', 'setup', 'filters', 'admin', 'theme-options', 'nav-foundation-walker']
And voila, it works!
It would be great if the Soil changes could be merged so that it can work with autoloading.
Merry Christmas! (if that’s your thing)