Fixing the menu :
WordPress menu Tricks part 1

banniere-converse-wp-color

The best part with a brand new blog is the ability to add new categories everyday if you like !
So welcome to this brand new “wordpress tricks” section where I will put pieces of code which saved me a lot of time.

One of the great feature of WP 3, as far as I’m concerned, is the new menu option.
As I told in the RIP Sparkling Bombs post, building a menu with the wp_list_posts or wp_list_pages was really tricky sometimes.
This great feature, based on the WooNav, excellent piece of code can be enhanced very simply.

I will do a little serie about these enhancements starting today with the “unpublish page” issue.


1. Houston what could be the problem ?!?

As I worked on a personnal project I noticed an annoying thing about the menu.
If you put an item matching a page link and then unpublished this page, the menu still appears in the menu bar and fataly leads to a 404 error.
You can avoid this by deleting this specific menu and recreate it later, but you can’t do that if you want to keep your settings (like title attribute and menu label).
One other way would be to create a second menu without the item you don’t want and display this one instead but it could be tricky if you already got plenty of menus and not very clean.


2. The solution : extending the menu walker !

Fortunately, all menu items are build with a Walker class.
If you don’t know what a Walker is, you can find a good definition on Shane’s blog :

“A walker class allows you to manipulate how data is displaied on your blog without having to modify the core files. What ever methods you do not override use the default method in the Walker class that you Extend.”

If you look in the nav-menu-template.php library you’ll see the declaration of the Walker Class Menu (starting line 17)
You can extends it and make a Menu walker of your own that you can fully customize afterwards :

class myCustom_Walker_Nav_Menu extends Walker_Nav_Menu
{
/* some code here... */
}

As you can see in the class definition, the start_el method applies to all the menu items, if you override this method, you can modify the menu item behavior, you can try this as an exemple which will simply add “my-custom-menu-class” css  class on each menu item.
You can add this piece of code in your functions.php

function start_el(&$output, $item, $depth, $args) {
    global $wp_query;
    $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

    $class_names = $value = '';
    $classes = empty( $item->classes ) ? array() : (array) $item->classes;
    $classes[] = 'menu-item-' . $item->ID;
    // --> Add custom Class
    $classes[] = 'my-custom-menu-class';

    $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item ) );
    $class_names = '';

    $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
    $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

    $output .= $indent . '<li' . $id . $value . $class_names .'>';

    $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
    $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
    $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
    $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

    $item_output = $args->before;
    $item_output .= '<a'. $attributes .'>';
    $item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
    $item_output .= '</a>';
    $item_output .= $args->after;

    $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
}

3. Make it works !

Now that we declared the new walker, the next step is to enable our menu to use it.
In your function.php just create an instance of your new class by adding this line :

$myCustom_menu_walker = new myCustom_Walker_Nav_Menu();

The last thing to do is to configure the menu function to use this new object.
If you look in the twentyten theme’s header.php you’ll find the menu builder function call around line 85 (wp_nav_menu).
One argument of this function is ‘walker’ where you can specify the object you want to use.
Modify the line to look like this :

<?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'walker' => $myCustom_menu_walker ) ); ?>

If you now reload your page, you’ll see that all the menu items have your new CSS class ‘my-custom-menu-class’

4. get rid of the unpublished page… finally !!!!!!

To get rid of the page, you’ll have to execute this code before creating the HTML output :

$item_to_display = true;
$item_data = get_post($item->object_id);

if ( !empty($item_data) && ($item->object == "page") )
{
    $item_to_display = ( $item_data->post_status == "publish" ) ? true : false;
    $item_output = "";
}

What we do here is to declare a new flag set on true to display the item (line 1).
Each menu element is linked to an object, with the magic of the wp_post table which contains all wp elements we can gather all the element data using the get_post function and passing the item object ID variable (which store the ID of the item linked line 2)
If I have a positive response and the object is a page (line 4) then I look at the page status and act one the flag to display it or not (line 6).
Note : I set an empty item_output string to avoid a PHP Notice that you can see only in debug mode but your code is better if you can avoid them (line 7).

The last thing to do is to put a new condition just before the final HTML render :

if ( $item_to_display )
{
$item_output = $args->before;
$item_output .= '';
$item_output .= $args->link_before . apply_filters( 'the_title', $item->title, $item->ID ) . $args->link_after;
$item_output .= '';
$item_output .= $args->after;
}

DONE !

So this is it, we set up a new Walker and modify the menu behavior with this little trick.
As it is my first tutorial, it would be great to have your feelings about it in terms of content, interest and clarity.
As you probably noticed, english is not my mother tongue ;)
You’ll find below the fully commented source code to download.

Hope this might ve useful to you,
have fun with WP !
Cheers,
jeFFF

DOWNLOAD : fixing-the-menu-1
credits – picture of WordPress Converse © realgeek.com

2 comments
  1. dance routine songs says: January 28, 201111:13 am

    Really compeling post, thanks!

  2. tejas says: May 12, 20118:17 pm

    This is really helpful. Headed to read part 2, as that is actually something what I need more, but this was a good preamble to pt. II.

    Thanks,
    -tejas

Submit comment