bootstrap-genesis
bootstrap-genesis copied to clipboard
Cleanup Nav Filters
This gives us a lot more freedom to edit/remove the menus individually.
Any thought on this?
Here's an even more advanced example... I can honestly say that this has made things so much easier when editing the menu as each menu is completely customizable individually?
/**
* Bootstrap Nav Markup
*/
add_filter('genesis_do_nav', 'genesis_child_nav', 10, 3);
add_filter('genesis_do_subnav', 'genesis_child_nav', 10, 3);
function genesis_child_nav($nav_output, $nav, $args)
{
$args['depth'] = 2;
$args['menu_class'] = 'nav navbar-nav';
$args['fallback_cb'] = 'wp_bootstrap_navwalker::fallback';
$args['walker'] = new wp_bootstrap_navwalker();
$nav = wp_nav_menu($args);
$sanitized_location = sanitize_key($args['theme_location']);
$data_target = 'nav-collapse-' . $sanitized_location;
$nav_markup = <<<EOT
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#{$data_target}">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
EOT;
$nav_markup.= apply_filters("bsg_navbar_brand_{$sanitized_location}", $navbar_brand);
$nav_markup.= '</div>'; // .navbar-header
$nav_markup.= '<div class="collapse navbar-collapse" id="' . $data_target . '">';
ob_start();
do_action('before_nav_' . $sanitized_location);
$before_nav = ob_get_clean();
ob_start();
do_action('after_nav_' . $sanitized_location);
$after_nav = ob_get_clean();
$nav_markup.= $before_nav . $nav . $after_nav;
$nav_markup.= '</div>'; // .collapse .navbar-collapse
$nav_markup_open = sprintf('<nav %s>', genesis_attr('nav-' . $sanitized_location));
$nav_markup_open.= genesis_structural_wrap('menu-' . $sanitized_location, 'open', 0);
$nav_markup_close = genesis_structural_wrap('menu-' . $sanitized_location, 'close', 0) . '</nav>';
$nav_output = $nav_markup_open . $nav_markup . $nav_markup_close;
return $nav_output;
}
Then I also have these helper functions:
/**
* Filter genesis_attr_structural-wrap to use BS .container-fluid classes
*/
add_filter( 'genesis_attr_structural-wrap', 'bsg_attributes_structural_wrap' );
function bsg_attributes_structural_wrap( $attributes ) {
$attributes['class'] = 'container';
return $attributes;
}
/**
* Add structural-wrap replacement utility function to use
* Bootstrap responsive .container class
*
* Useage: add_filter( 'genesis_structural_wrap-{$context}', 'bsg_wrap_container_fluid');
*/
function bsg_wrap_container_fluid( $output, $original_output ) {
if ( $original_output == 'open' ) {
$output = sprintf( '<div %s>', genesis_attr( 'container-fluid' ) );
}
return $output;
}
/**
* Helper function to easily change the nav menu location
*/
function child_bsg_navbar_right( $nav_output, $nav ) {
$nav_output = str_replace( 'nav navbar-nav', 'nav navbar-nav navbar-right', $nav_output );
return $nav_output;
}
Here's some examples possible with all this:
Change primary menu container to container-fluid:
add_filter( 'genesis_structural_wrap-menu-primary', 'tbg3_wrap_container_fluid', 99, 2);
Move submenu to the right side:
add_filter( 'genesis_do_subnav', 'child_bsg_navbar_right', 10, 2 );
Add the search form after the primary menu:
add_action('after_nav_menu-primary', function() { get_search_form(); });
Add to secondary brand area
add_filter('bsg_navbar_brand_menu-secondary', function() {
}
I'm still wrapping my head around this code but a couple of quick notes so I don't need to remember them for later.
PHP Warning
I'm getting the warning
call_user_func_array() expects parameter 1 to be a valid callback, function 'bsg_nav_menu' not found or invalid function name
Menus are Disappearing
When I switch to this branch, my menus disappear.
Looking at the Genesis code in lib/functions/menu.php
, it looks like the filters genesis_do_nav
and genesis_do_subnav
are still in place for backwards compatibility. So instead it looks like we should be using the filter hooks that come from 'genesis_' . $sanitized_location . '_nav'
.
I believe the Bootstrap nav only supports a depth of 2.
So, I think we should change this value from 3 to 2.
$args['depth'] = 3;
Sorry about that Sal. I added a third level to my menus a while back, but didn't include that code since it wasn't part of bootstrap core and I forgot to change it back when I proposed that change.
Anyway, for reference and for anyone who would like to use three level menus with this all you need to do is change the 2 to 3 and then drop this in your functions.php (technically these should be included using wp_enqueue_scripts
so compiling within theme scripts/styles is preferred since the code is dependent on bs nav javascript and jquery).
add_action('wp_head', 'bsg_multilevel_dropdown_menu_css', 999);
function bsg_multilevel_dropdown_menu_css() {
echo '<style>ul.dropdown-menu .caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-left:4px solid;border-right:4px solid transparent;border-top:4px solid transparent;border-bottom:4px solid transparent}@media (max-width:767px){ul.dropdown-menu .caret{display:inline-block;width:0;height:0;margin-left:2px;vertical-align:middle;border-top:4px solid;border-right:4px solid transparent;border-left:4px solid transparent}}ul.dropdown-menu ul.dropdown-menu{top:0;left:100%}</style>';
}
add_action('wp_footer', 'bsg_multilevel_dropdown_menu_js', 999);
function bsg_multilevel_dropdown_menu(){
echo '<script>!function(n){"use strict";n(function(){n("ul.dropdown-menu .dropdown>a").on("click",function(o){o.preventDefault(),o.stopPropagation();var t=n(this).parent();t.parent().find("li.dropdown").not(n(this).parent()).removeClass("open"),t.toggleClass("open")}),n("ul.navbar-nav a.dropdown-toggle").on("click",function(o){var t=n(this).parent();t.parent().find("li.dropdown").not(n(this).parent()).removeClass("open")})})}(jQuery);</script>';
}
And here's link to uncompressed js/css for those who want to include it other ways. https://gist.github.com/bryanwillis/f4b5c25c4be8bd78d742
@bryanwillis
Cool, thanks for sharing this.
With this code change I am seeing some differences in the output nav code.
For Example
Old Output
<ul id="menu-testing-menu" class="nav navbar-nav"><li id="menu-item-1355" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1355"><a title="About" href="http://genesis.dev/about/" itemprop="url"><span itemprop="name">About</span></a></li>
New Output
<ul id="menu-testing-menu-1" class="nav navbar-nav"><li class="menu-item menu-item-type-post_type menu-item-object-page menu-item-1355"><a title="About" href="http://genesis.dev/about/" itemprop="url"><span itemprop="name">About</span></a></li>
Is this a problem?
I don't think these changes are a problem but I wanted to make note and look at them more deeply before merging. You can see the work I'm doing with this PR on the branch https://github.com/salcode/bootstrap-genesis/tree/nav-filters-to-genesis-hooks-137