public
Last active

WordPress Menu & Walker for ZURB's Foundation 4 Top Bar

  • Download Gist
foundation4-topbar-menu.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
<?php
add_theme_support('menus');
 
/**
* Register Menus
* http://codex.wordpress.org/Function_Reference/register_nav_menus#Examples
*/
register_nav_menus(array(
'top-bar-l' => 'Left Top Bar', // registers the menu in the WordPress admin menu editor
'top-bar-r' => 'Right Top Bar'
));
 
 
/**
* Left top bar
* http://codex.wordpress.org/Function_Reference/wp_nav_menu
*/
function foundation_top_bar_l() {
wp_nav_menu(array(
'container' => false, // remove nav container
'container_class' => '', // class of container
'menu' => '', // menu name
'menu_class' => 'top-bar-menu left', // adding custom nav class
'theme_location' => 'top-bar-l', // where it's located in the theme
'before' => '', // before each link <a>
'after' => '', // after each link </a>
'link_before' => '', // before each link text
'link_after' => '', // after each link text
'depth' => 5, // limit the depth of the nav
'fallback_cb' => false, // fallback function (see below)
'walker' => new top_bar_walker()
));
}
 
/**
* Right top bar
*/
function foundation_top_bar_r() {
wp_nav_menu(array(
'container' => false, // remove nav container
'container_class' => '', // class of container
'menu' => '', // menu name
'menu_class' => 'top-bar-menu right', // adding custom nav class
'theme_location' => 'top-bar-r', // where it's located in the theme
'before' => '', // before each link <a>
'after' => '', // after each link </a>
'link_before' => '', // before each link text
'link_after' => '', // after each link text
'depth' => 5, // limit the depth of the nav
'fallback_cb' => false, // fallback function (see below)
'walker' => new top_bar_walker()
));
}
?>
foundation4-topbar-walker.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
<?php
/**
* Customize the output of menus for Foundation top bar
*/
 
class top_bar_walker extends Walker_Nav_Menu {
 
function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
$element->has_children = !empty( $children_elements[$element->ID] );
$element->classes[] = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';
$element->classes[] = ( $element->has_children ) ? 'has-dropdown' : '';
parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}
function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
$item_html = '';
parent::start_el( $item_html, $object, $depth, $args );
$output .= ( $depth == 0 ) ? '<li class="divider"></li>' : '';
$classes = empty( $object->classes ) ? array() : (array) $object->classes;
if( in_array('label', $classes) ) {
$output .= '<li class="divider"></li>';
$item_html = preg_replace( '/<a[^>]*>(.*)<\/a>/iU', '<label>$1</label>', $item_html );
}
if ( in_array('divider', $classes) ) {
$item_html = preg_replace( '/<a[^>]*>( .* )<\/a>/iU', '', $item_html );
}
$output .= $item_html;
}
function start_lvl( &$output, $depth = 0, $args = array() ) {
$output .= "\n<ul class=\"sub-menu dropdown\">\n";
}
}
?>
foundation4-topbar.php
PHP
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
<div class="top-bar-container fixed contain-to-grid">
<nav class="top-bar">
<ul class="title-area">
<li class="name">
<h1><a href="<?php echo home_url(); ?>"><?php bloginfo('name'); ?></a></h1>
</li>
<li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
</ul>
<section class="top-bar-section">
<?php foundation_top_bar_l(); ?>
 
<?php foundation_top_bar_r(); ?>
</section>
</nav>
</div>
readme.md
Markdown

Adding a Foundation Top Bar to WordPress

foundation-topbar-menu.php and foundation-topbar-walker.php should be required in the WordPress functions.php file.

The code in foundation-topbar.php should be added below the body tag in header.php

Setup a menu in WordPress admin under Appearance > Menus

Use the 'label' class on a menu item to create a menu section title

Foundation Top Bar Doc: http://foundation.zurb.com/docs/components/top-bar.html

Great - you're my hero! Thank you very much!

GitHub should really notify me of comments on gists! That's not nice of them.

You're welcome! I'm glad this has been helpful to others.

"As of PHP 5.3.0, you will get a warning saying that "call-time pass-by-reference" is deprecated when you use & in foo(&$a);. And as of PHP 5.4.0, call-time pass-by-reference was removed, so using it will raise a fatal error. "
Quote form from http://php.net/manual/en/language.references.pass.php

in "foundation-topbar-walker.php" on line 13, it should probably be changed from:

parent::display_element($element, &$children_elements, $max_depth, $depth, $args, &$output);

to

parent::display_element($element, $children_elements, $max_depth, $depth, $args, $output);

By doing that I could get rid of the fatal error as I'm using PHP 5.4.4
Does that sound correct?

Thanks for the Snippet awshout!

You're absolutely right. Thanks for catching that!

Great. You helped me a lot. Now, I just have to get a search form into the right menu by default :)

Glad to help.

For the search form... It will take a bit more work, but to get you started you could use the following in the <section> tag:

<ul class="right"><li><?php get_search_form(); ?></li></ul>

I just spent a day hacking around with Reverie to get this to work. Then I find this :-(

Great work though, thanks.

Thanks, just found this and put it to use straight away !!!

You're welcome. I'm happy to see so many using it.

Thanks awshout, its work well in my theme.

but I dont know why, when i see in responsive layout using web developer, the toggle menu did not work :-)

can you tell me any possibility why this is not work. also what css should i use for content bellow top-bar not-covered by top-bar ?

thanks for your help

Hi @amrinz, it's possible that there is a jQuery conflict.

I'm not sure what you're asking for about the CSS. Follow the grid outline provided by ZURB for any content below the top bar.

Nice one updating this to work with foundation 4, cheers.

Was it updated to work with foundation 4?

The last two revisions should have updated it to F4. Let me know if I missed anything though.

Hey Awshout,
I would like to thank you for this, very awesome that you shared it! Great work, keep it up!

Thank you very much!

Thank you sir, you rock!

Thanks for this! But how to incluce the menu item description into the mix?

@iggmack the top bar isn't really setup to hold the description without some CSS work. To add it into the Walker you'd do something like this in start_el:

if ( !empty( $item->description ) ) {
    $item_html .= '<span class="description">' . esc_attr( $item->description ) . '</span>';
}

Thank you. You saved my day. Bookmarking it!

Just updated to WordPress 3.6 and got a Strict error regarding start_el: the fix I made is:

function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {

    $item_html = '';
    parent::start_el($item_html, $object, $depth, $args);

    $output .= ($depth == 0) ? '<li class="divider"></li>' : '';

    $classes = empty($object->classes) ? array() : (array) $object->classes;

    if(in_array('label', $classes)) {
        $output .= '<li class="divider"></li>';
        $item_html = preg_replace('/<a[^>]*>(.*)<\/a>/iU', '<label>$1</label>', $item_html);
    }

if ( in_array('divider', $classes) ) {
    $item_html = preg_replace( '/<a[^>]*>( .* )<\/a>/iU', '', $item_html );
}

    $output .= $item_html;
}

To get a search form into the right menu by default:


// the right top bar
function foundation_top_bar_r() {
    $menu = wp_nav_menu(array( 
        'echo' => false,
        'container' => false,                           // remove nav container
        'container_class' => '',                // class of container
        'menu' => '',                               // menu name
        'menu_class' => 'top-bar-menu right',           // adding custom nav class
        'theme_location' => 'top-bar-r',                // where it's located in the theme
        'before' => '',                                 // before each link <a> 
        'after' => '',                                  // after each link </a>
        'link_before' => '',                            // before each link text
        'link_after' => '',                             // after each link text
        'depth' => 5,                                   // limit the depth of the nav
        'fallback_cb' => false,                         // fallback function (see below)
        'walker' => new top_bar_walker()
    ));    
     add_search_form($menu); //new function (bellow)
} // end right top bar


function add_search_form($topBar){
    //get the menu and create a php DOMDocument
    $dom = new DOMDocument();
    $dom->loadXML($topBar);
    $xpath = new DOMXPath($dom);
    //get the ul
    $res = $xpath->query("/ul")->item(0);
    //call your search form (notice the false arg)
    $form = get_search_form(false);
    //create a new li tag
    $li_search = $dom->createElement("li");
    //append the search form to a new dom fragment
    $form_html = $dom->createDocumentFragment();    
    $form_html->appendXML($form);    
    $li_search->appendChild($form_html);
    //create de F4 has-form css class and add it to our $li_search
    $class = $dom->createAttribute("class");
    $class->value = "has-form";    
    $li_search->appendChild($class);
    //create a divider li
    $li_divider = $dom->createElement("li");
    $li_divider_class = $dom->createAttribute("class");
    $li_divider_class->value = "divider hide-for-large hide-for-medium";
    $li_divider->appendChild($li_divider_class);
    //more appends
    $res->appendChild($li_divider);
    $res->appendChild($li_search);
    //return our topbar with a search form
    echo $dom->saveXML($res);
}

Thanks for the update @MIKendall

@juliosampaio That's some nice work there. However, I would probably just create a function to output the form for a search input.

function top_bar_search() {

    $output  = '<ul class="right"><li class="has-form">';
    $output .= '<form role="search" method="get" id="searchform" action="' . home_url() . '"><div class="row collapse">';
    $output .= '<div class="large-8 small-8 columns">';
    $output .= '<input type="text" value="' . get_search_query() . '" name="s" id="s" placeholder="' . esc_attr__('Search', 'reactor') . '" />';
    $output .= '</div>';
    $output .= '<div class="large-4 small-4 end columns">';
    $output .= '<input class="button prefix" type="submit" id="searchsubmit" value="' . esc_attr__('Search', 'reactor') . '" />';
    $output .= '</div>';
    $output .= '</div></form>'; 
    $output .= '</li></ul>';

    return $output;
}

Would you have any clue why the walker does not get any sub categories? I'm looking at

element->has_children = !empty( $children_elements[$element->ID] );

and it is always empty, although the category clearly has sub categories.

What is going on?

Thanks!

You just saved my sanity. Thanks!

Was about to write a walker class for this and then voila! Thanks!

no dropdown in foundation 4.3.1

Dropdowns aren't working for me either. :(

To fix the drop down issue, add "not-click" class to the "has-dropdown" line.

class top_bar_walker extends Walker_Nav_Menu {

function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
    $element->has_children = !empty( $children_elements[$element->ID] );
    $element->classes[] = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';
    $element->classes[] = ( $element->has_children ) ? 'has-dropdown not-click' : '';

    parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
}

....

This is the WALKER code with all fix


class top_bar_walker extends Walker_Nav_Menu {
    function display_element( $element, &$children_elements, $max_depth, $depth=0, $args, &$output ) {
        $element->has_children = !empty( $children_elements[$element->ID] );
        $element->classes[] = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';
        $element->classes[] = ( $element->has_children ) ? 'has-dropdown not-click' : '';
    
        parent::display_element( $element, $children_elements, $max_depth, $depth, $args, $output );
    }

    function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {
    
        $item_html = '';
        parent::start_el($item_html, $object, $depth, $args);
    
        $output .= ($depth == 0) ? '' : '';
    
        $classes = empty($object->classes) ? array() : (array) $object->classes;
    
        if(in_array('label', $classes)) {
            $output .= '';
            $item_html = preg_replace('/]*>(.*)/iU', '$1', $item_html);
        }
    
    if ( in_array('divider', $classes) ) {
        $item_html = preg_replace( '/]*>( .* )/iU', '', $item_html );
    }
    
        $output .= $item_html;
    }
    
    function start_lvl( &$output, $depth = 0, $args = array() ) {
        $output .= "\n
    \n"; } }

"Notice: Indirect modification of overloaded property WP_Post::$classes has no effect in ../functions.php on line 566"
"Notice: Trying to get property of non-object in .../wp-includes/nav-menu-template.php on line 88"

Any guesses? WordPress 3.5.2

This hack fixed the above problem for me, though for some reason, I still can't get the menus to display correctly:

$element->has_children = !empty($children_elements[$element->ID]);
$classes = $element->classes;
$classes[] = ($element->current || $element->current_item_ancestor) ? 'active' : '';
$classes[] = ($element->has_children) ? 'has-dropdown' : '';
$element->classes = $classes;

The "not-click" class is added by foundation.topbar.js on-the-fly when the menu is in "hover" mode. If you're not seeing the "not-click" class applied to your parent li's at runtime, then maybe check for jQuery conflict like the author said or any other errors in your console. Might save more aggravation later..

Thanks a lot for this, exactly what I was looking for. Saved me loads of time!

Just as I thought! I was trying to make it work and I thought "someone in the world must have solved this already".
Put this star at your code.

Thanks a lot for sharing this. But...I just can't get this to work. Granted, I don't know a lot about these things. I have done as you advised, included the files, added the script as advised at http://foundation.zurb.com/docs/components/top-bar.html, added the CSS and the menu bar does indeed appear.
It also turns into the mobile menu when I decrease the browser width (Chrome).

But upon clicking on the menu, it does not drop down (I did use the code with the fixes by . How can I troubleshoot this?

I am using this for a Wordpress installtion with a Twenty Twelve Child Theme.

is there any update for foundation 5? it's not working with foundation 5 now.
Thanks :)

oops just found data-topbar .. it works great

Not working with Foundation 5? hicc :?

Works for me with foundation 5 and Wordpress 3.7.1.
For drop down I added "not-click" like 808chris suggested. Works fine. Thank you

Ah this is awesome. I'm so close. Nothing showing up though. Using F5 but so far no luck. What am I missing?
1. Both .php files are in a inc folder.
2. Markup in header
3. Calling both php from functions file.

Did I miss something?

Ah! I got it working. Awesome.

I'm using F5 also. I have the navigation working but when it gets to a smart phone screen it doesn't work for some reason. Any ideas why?

** I FOUND THE FIX. If you downloaded Foundation 5.0.0 then you will have issues. If you download 5.0.1 or 5.0.2 it will fix it for you.

Thank you so much for this code. I've got Foundation 5.0.2. working with normal nav and mobile. I'm wondering if anyone also had a problem with the dropdown menu's. I can't get them to work. I can click on the parent, and darkens it's color, but no dropdown appears. I've already tried z-index.

Sending positive vibes - because you deserve them. Thanks for taking the time to put this together - hugely useful. @awshout

Thank you so much for this code

I'm not sure if anyone commented on this so I'm just going to throw this out there. When the menu goes below 767px a parent tab that has a page attached to it and children becomes a non usable tab. You click on it and it just slides the menu over to the children rather than actually going to that page. Has anyone else experienced that and if so what was the fix to this? Thanks.

@StefsterNYC I have this issue too, but on every size. Do you have any news about this issue already?

@aweshout I used the function you wrote to add a search input to the right menu, and it is not showing up in the top bar menu. I added the function inside foundation-topbar-menu.php. Was that the wrong place to add it?

<div class="top-bar-container fixed contain-to-grid">
            <nav class="top-bar" data-topbar>
                <ul class="title-area">
                    <li class="name">
                        <h1><a href="<?php echo home_url(); ?>"><?php bloginfo('name'); ?></a></h1>
                    </li>          
                    <li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
                </ul>
                <section class="top-bar-section">
                    <?php foundation_top_bar_l(); ?>
                    <?php foundation_top_bar_r(); ?>
                    <ul class="right"><li><?php top_bar_search(); ?></li>


                </section>
            </nav>
        </div>
{
    // code
}

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.