Menu Search
Jump to the content X X
Smashing Conf Barcelona 2016

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf Barcelona, dedicated to smart front-end techniques and design patterns.

Customizing Tree-Like Data Structures In WordPress With The Walker Class

In WordPress, a navigation menu, a list of categories or pages, and a list of comments all share one common characteristic: They are the visual representation of tree-like data structures. This means that a relationship of superordination and subordination exists among the elements of each data tree.

There will be elements that are parents of other elements and, conversely, elements that are children of other elements. A reply to a comment depends logically on its parent, in the same way that a submenu item depends logically on the root element of the tree (or subtree).

Starting with version 2.1, WordPress provides the Walker abstract class1, with the specific function of traversing these tree-like data structures. But an abstract class does not produce any output by itself. It has to be extended with a concrete child class that builds the HTML bricks for specific lists of items. With this precise function, WordPress provides the Walker_Category class to produce a nested list of categories, the Walker_Page class2, which builds a list of pages, and several other Walker concrete child classes.

But when we build a WordPress theme, we might need to customize the HTML list’s default structure to fit our particular needs. We may want to add a description to a menu item, add custom class names or perhaps redefine the HTML structure of a list of categories or comments.

Before we begin, let’s look at the most important concept in this article.

Tree-Like Data Structures Link

Wikipedia defines a tree3 as a hierarchical organization of data:

“A tree data structure can be defined recursively (locally) as a collection of nodes (starting at a root node), where each node is a data structure consisting of a value, together with a list of references to nodes (the ‘children’), with the constraints that no reference is duplicated, and none points to the root.”

So, the structure is characterized by a root element (at the first level), parent elements (which are directly referenced to subordered elements, named children), siblings (which are elements placed at the same hierarchical level) and descendant and ancestor elements (which are connected by more than one parent-child relation).

The wp_comments table structure4
Each element in the wp_comments is referenced to its parent by the value of the comment_parent field. (View large version5)

As an example of this kind of structure, let’s take the wp_comments table from the WordPress database. The comment_parent field stores the parent ID of each element in the structure, making it possible to create the reference from the child node to its parent.

What We’ll Be Doing Link

Before moving forward, I’ll show you a simple example of a concrete child class producing the HTML markup of a category list.

The category list in WordPress is printed out by the wp_list_categories template tag. When we call this function, it executes the Walker_Category class, which actually builds the HTML structure, producing something like the following code:

<li class="categories">Categories
   <ul>  
      <li class="cat-item cat-item-10">
         <a href="http://example.com/wordpress/category/coding/">Coding</a>
         <ul class="children">
            <li class="cat-item cat-item-39">
               <a href="http://example.com/wordpress/category/coding/php/">PHP</a>
            </li>
         </ul>
      </li>
      <li class="cat-item cat-item-11">
         <a href="http://example.com/wordpress/category/design/">Design</a>
      </li>
   </ul>
</li>

wp_list_categories will print the output produced by the Walker_Category concrete class. It will be a wrapper list item holding a nested list of categories.

Now, suppose you don’t like this kind of list, and you want to print custom HTML code. You can do this trick by defining your own Walker extention. In your theme’s functions.php file, add the following code:

class My_Custom_Walker extends Walker
{
   public $tree_type = 'category';

   public $db_fields = array ('parent' => 'parent', 'id' => 'term_id');

   public function start_lvl( &$output, $depth = 0, $args = array() ) {
      $output .= "<ul class='children'>\n";
   }

   public function end_lvl( &$output, $depth = 0, $args = array() ) {
      $output .= "</ul>\n";
   }

   public function start_el( &$output, $category, $depth = 0, $args = array(), $current_object_id = 0 ) {
      $output .= "<li>" . $category->name . "\n";
   }

   public function end_el( &$output, $category, $depth = 0, $args = array() ) {
      $output .= "</li>\n";
   }
}

Even if you don’t know a lot about PHP classes6, the code is quite descriptive. The start_lvl() method prints the start tag for each level of the tree (usually a <ul> tag), while end_lvl() prints the end of each level. In the same way, the start_el and end_el methods open and close each item in the list.

This is just a basic example, and we won’t dive deep into the Walker properties and methods for now. I’ll just say that the concrete child class My_Custom_Walker extends the abstract class Walker, redefining some of its properties and methods.

As I wrote above, the category list is printed out by the wp_list_categories template tag, but the HTML structure is built by the Walker_Category class. WordPress allows us to pass a custom walker class to the template tag. The new walker will build a custom HTML structure that will be printed on the screen by wp_list_categories.

As a first example, let’s create a shortcode that will print new markup for the lists of categories. In your functions.php file, add the following code:

function my_init() {
   add_shortcode( 'list', 'my_list' );
}
add_action('init', 'my_init');

function my_list( $atts ){
   $list = wp_list_categories( array( 'echo' => 0, 'walker' => new My_Custom_Walker() ) );
   return $list;
}

We are passing the function an array of two arguments: echo keeps the result in a variable, and walker sets a custom Walker (or Walker_Category) child class.

Finally, the shortcode [list] will print the resulting HTML code:

<ul>
   <li class="categories">Categories
      <ul>
         <li>Coding
            <ul class="children">
            <li>PHP</li>
            </ul>
         </li>
         <li>Design</li>
      </ul>
   </li>
</ul>

As you can see, the example is very basic but should give you an idea of our goals.

The Walker Class And Its Extensions Link

The Walker class7 is defined in wp-includes/class-wp-walker.php198 as “a class for displaying various tree-like structures.”

As I mentioned before, it’s an abstract class9 and does not produce any output by itself; rather, it has to be extended by defining one or more concrete child classes. Only these concrete child classes will produce the HTML markup. WordPress provides several extensions of the Walker class, each one producing a hierarchical HTML structure.

Look at the table below:

Class name Defined in Extends
Walker_Page post-template.php10 Walker
Walker_PageDropdown post-template.php11 Walker
Walker_Category category-template.php12 Walker
Walker_CategoryDropdown category-template.php13 Walker
Walker_Category_Checklist template.php14 Walker
Walker_Comment comment-template.php15 Walker
Walker_Nav_Menu nav-menu-template.php16 Walker
Walker_Nav_Menu_Checklist nav-menu.php17 Walker_Nav_Menu
Walker_Nav_Menu_Edit nav-menu.php18 Walker_Nav_Menu

This table shows the built-in Walker child classes, the template files they are defined in, and the corresponding parent class.

The goal of this article is to put the Walker class to work, so we need to dive into its structure.

The Walker Class’ Structure Link

Walker is defined in wp-includes/class-wp-walker.php198. It declares four properties and six main methods, most of which are left empty and should be redefined by the concrete child classes.

The properties are:

  • $tree_type
  • $db_fields
  • $max_pages
  • $has_children

$tree_type Link

This is a string or an array of the data handled by the Walker class and its extentions.

public $tree_type;

The Walker class declares the property but does not set its value. To be used, it has to be redeclared by the concrete child class. For example, the Walker_Page class declares the following $tree_type property:

public $tree_type = 'page';

Whereas Walker_Nav_menu declares the following $tree_type:

public $tree_type = array( 'post_type', 'taxonomy', 'custom' );

$db_fields Link

Just like $tree_type, $db_fields is declared with no value assigned. In the Walker class’ documentation, it just says that its value is an array:

public $db_fields;

The elements of the array should set the database fields providing the ID and the parent ID for each item of the traversed data set.

The Walker_Nav_Menu class redeclares $db_fields as follows:

public $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

$db_fields['parent'] and $db_fields['id'] will be used by the display_element method.

$max_pages Link

This keeps in memory the maximum number of pages traversed by the paged_walker method. Its initial value is set to 1.

public $max_pages = 1;

$has_children Link

This boolean is set to true if the current element has children.

public $has_children;

After the properties, the methods are:

  • start_lvl
  • end_lvl
  • start_el
  • end_el
  • display_element
  • walk

start_lvl Link

This method is executed when the Walker class reaches the root level of a new subtree. Usually, it is the container for subtree elements.

public function start_lvl( &$output, $depth = 0, $args = array() ) {}

start_lvl() takes three arguments:

Argument Type Description
$output string passed by reference; used to append additional content
$depth int depth of the item
$args array an array of additional arguments

Because it produces HTML output, start_lvl should be redefined when extending the Walker class. For instance, the start_lvl method of the Walker_Nav_Menu class will output a ul element and is defined as follows:

public function start_lvl( &$output, $depth = 0, $args = array() ) {
   $indent = str_repeat("\t", $depth);
   $output .= "\n$indent<ul class=\"sub-menu\">\n";
}

end_lvl Link

The second method of the Walker class closes the tag previously opened by start_lvl.

public function end_lvl( &$output, $depth = 0, $args = array() ) {}

The end_lvl method of Walker_Nav_Menu closes the unordered list:

public function end_lvl( &$output, $depth = 0, $args = array() ) {
   $indent = str_repeat("\t", $depth);
   $output .= "$indent</ul>\n";
}

start_el Link

This method opens the tag corresponding to each element of the tree. Obviously, if start_lvl opens a ul element, then start_el must open an li element. The Walker class defines start_el as follows:

public function start_el( &$output, $object, $depth = 0, $args = array(), $id = 0 ) {}
Argument Type Description
$output string passed by reference; used to append additional content
$object object the data object
$depth int depth of the item
$args array an array of additional arguments
$id int current item ID

end_el Link

It closes the tag opened by start_el.

public function end_el( &$output, $object, $depth = 0, $args = array() ) {}

Finally, we’ve reached the core of the Walker class. The following two methods are used to iterare over the elements of the arrays of objects retrieved from the database.

display_element Link

I won’t show the full code here, because you can find it in the WordPress Trac20. I’ll just say that this method displays the elements of the tree.

public function display_element( $element, &$children_elements, $max_depth, $depth, $args, &$output ) {}

display_element takes the following arguments:

Argument Type Description
$element object the data object
$children_elements array list of elements to continue traversing
$max_depth int maximum depth to traverse
$depth int depth of current element
$args array an array of arguments
$output string passed by reference; used to append additional content

This method does not output HTML on its own. The markup will be built by a call to each of the previously described methods: start_lvl, end_lvl, start_el and end_el.

walk Link

walk is the core of the Walker class. It iterates over the elements of the tree depending on the value of $max_depth argument (see the Trac for the full code21).

public function walk( $elements, $max_depth ) {}

walk takes two arguments.

Argument Type Description
$elements array an array of elements
$max_depth int maximum depth to traverse

Other methods are used for more specific pourposes.

paged_walk Link

This builds a page of nested elements. The method establishes which elements of the data tree should belong to a page, and then it builds the markup by calling display_element and outputs the result.

public function paged_walk( $elements, $max_depth, $page_num, $per_page ) {}

get_number_of_root_elements Link

This gets the number of first-level elements.

public function get_number_of_root_elements( $elements ){}

unset_children Link

This last method unsets the array of child elements for a given root element.

public function unset_children( $e, &$children_elements ){}

Now that we’ve introduced the Walker properties and methods, we can explore one of its possible applications: changing the HTML structure of the navigation menu. The default markup for navigation menus is produced by the Walker_Nav_Menu concrete class. For this reason, we’ll create a new concrete Walker child class based on Walker_Nav_Menu, and we’ll pass it to wp_nav_menu to replace the output.

But is extending the Walker_Nav_Menu class always necessary when rebuilding a menu? Of course not!

Most of the time, a call to the wp_nav_menu template tag will suffice.

Menus admin page
In the “Menus” editing page, setting theme locations for each custom menu is possible.

Basic Customization Of The Navigation Menu: The wp_nav_menu Template Tag Link

The navigation menu can be included in the theme’s template files with a call to the wp_nav_menu() template tag. This function takes just one argument, an array of parameters that is well described in the Codex22.

wp_nav_menu() can be included in your templates as follows:

$defaults = array(
   'theme_location'     => '',
   'menu'            => '',
   'container'       => 'div',
   'container_class' => '',
   'container_id'    => '',
   'menu_class'         => 'menu',
   'menu_id'         => '',
   'echo'            => true,
   'fallback_cb'     => 'wp_page_menu',
   'before'          => '',
   'after'           => '',
   'link_before'     => '',
   'link_after'         => '',
   'items_wrap'         => '<ul id="%1$s" class="%2$s">%3$s</ul>',
   'depth'           => 0,
   'walker'          => ''
);

wp_nav_menu( $defaults );

WordPress provides many parameters to configure the navigation menu. We can change the menu’s container (it defaults to a div), the container’s CSS class and ID, as well as the text strings and markup to be included before and after the anchor element and before and after the item’s title. Furthermore, we can change the root element’s structure (items_wrap) and the depht of the tree.

So, we don’t need to extend the Walker (or the Walker_Nav_Menu) class each time we want to make changes to the menu’s structure — only when we have to produce more advanced structural customizations. This happens when we have to assign CSS classes to the menu elements when a specific condition occurs, or when we have to add data or HTML code to the menu items.

This can be done by setting a value for the walker parameter, which will be nothing but an instance of a custom concrete class. So, from now on, we’ll dive more and more deeply into WordPress menus, from changing the menu structure to adding custom fields to the menu items’ editing boxes. As I said, we’ll do this job by extending the Walker_Nav_Menu, so it’s time to get acquainted with it.

The Walker_Nav_Menu Class Link

The Walker_Nav_Menu class is defined in wp-includes/nav-menu-template.php23. This is the class used by WordPress to build the navigation menu’s structure. Each time you want to make relevant changes to the menu’s default structure, you can extend Walker_Nav_Menu.

The concrete class redeclares the $tree_type and $db_fields properties and the start_lvl, end_lvl, start_el and end_el methods.

class Walker_Nav_Menu extends Walker {

   public $tree_type = array( 'post_type', 'taxonomy', 'custom' );

   public $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

   public function start_lvl( &$output, $depth = 0, $args = array() ) {
      $indent = str_repeat("\t", $depth);
      $output .= "\n$indent<ul class=\"sub-menu\">\n";
   }

   public function end_lvl( &$output, $depth = 0, $args = array() ) {
      $indent = str_repeat("\t", $depth);
      $output .= "$indent</ul>\n";
   }

   public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
      // code below
   }

   public function end_el( &$output, $item, $depth = 0, $args = array() ) {
      $output .= "</li>\n";
   }

} // Walker_Nav_Menu

The start_el public method builds the HTML markup of the opening li tag for each menu item. It is defined as follows:

public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
   $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

   $classes = empty( $item->classes ) ? array() : (array) $item->classes;
   $classes[] = 'menu-item-' . $item->ID;

   $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args, $depth ) );
   $class_names = $class_names ? ' class="' . esc_attr( $class_names ) . '"' : '';

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

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

   $atts = array();
   $atts['title']  = ! empty( $item->attr_title ) ? $item->attr_title : '';
   $atts['target'] = ! empty( $item->target )     ? $item->target     : '';
   $atts['rel']    = ! empty( $item->xfn )        ? $item->xfn        : '';
   $atts['href']   = ! empty( $item->url )        ? $item->url        : '';

   $atts = apply_filters( 'nav_menu_link_attributes', $atts, $item, $args, $depth );

   $attributes = '';
   foreach ( $atts as $attr => $value ) {
      if ( ! empty( $value ) ) {
         $value = ( 'href' === $attr ) ? esc_url( $value ) : esc_attr( $value );
         $attributes .= ' ' . $attr . '="' . $value . '"';
      }
   }

   $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 );
}

The code is quite self-explanatory:

  • $indent stores a number of '/t' strings corresponding to $depth’s value;
  • $classes is an array of the CSS classes assigned to the list item;
  • $id records the element’s ID, composed by the prefix 'menu-item-' and the item’s ID retrieved from the database;
  • $atts is an array of the element’s attributes;
  • $item_output keeps track of the HTML code before it is assigned to $output;
  • $output stores the HTML markup.

Extending The Walker_Nav_Menu Class Link

When building your custom navigation menu markup, you might decide to extend the Walker class itself or its concrete child class Walker_Nav_Menu. If you opt to extend the Walker class, you’ll need to define all necessary properties and methods. Otherwise, if you choose to extend the concrete child class, you’ll just need to define those methods whose output has to be changed.

The following example describes a real-life situation in which the default menu’s structure has to be changed in order to integrate a WordPress theme with the Foundation 5 framework.

Foundation 5 home page
Foundation 5’s home page.

A Working Example: The Foundation Top Bar As WordPress Navigation Menu Link

Foundation 524 comes with a flexible grid system and with plugins and components that make it easy to develop solid and responsive websites. So, chances are that you’ll decide to enrich your theme with all of this great stuff.

First, you need to include all necessary scripts and style sheets in your theme. This isn’t our topic, so we won’t dive deep into the configuration, but you can pull out all necessary information directly from Foundation’s documentation25 and the WordPress Codex26.

Here, we’ll see how to force WordPress to display Foundation Top Bar27 as a navigation menu.

WordPress should print something like the following HTML:

<nav class="top-bar" data-topbar role="navigation">
   <ul class="title-area">
   <li class="name">
      <h1><a href="#">My Site</a></h1>
   </li>
   <!-- Remove the class "menu-icon" to get rid of menu icon. Take out "Menu" to just have icon alone -->
   <li class="toggle-topbar menu-icon"><a href="#"><span>Menu</span></a></li>
   </ul>

   <div class="top-bar-section">
      <!-- Left Nav Section -->
      <ul class="left">
         <li class="active"><a href="#">Right Button Active</a></li>
         <li class="has-dropdown">
            <a href="#">Left Button Dropdown</a>
            <ul class="dropdown">
               <li><a href="#">First link in dropdown</a></li>
               <li class="active"><a href="#">Active link in dropdown</a></li>
            </ul>
         </li>
      </ul>
   </div>
</nav>

To achieve our goal, add the following code to your header.php file or to whichever template file contains the navigation menu:

<nav class="top-bar" data-topbar role="navigation">
   <ul class="title-area">
      <li class="name">
         <h1><a href="#"><?php echo get_bloginfo(); ?></a></h1>
      </li>
      <li class="toggle-topbar menu-icon"><a href="#"><span><!--<?php echo get_bloginfo(); ?>--></span></a></li>
   </ul>
   <?php wp_nav_menu( array(
      'theme_location'     => 'primary',
      'container_class'    => 'top-bar-section',
      'menu_class'         => 'left',
      'walker'             => new Custom_Foundation_Nav_Menu()) ); ?>
</nav>

We have set the Foundation CSS class top-bar-section, along with a custom Walker class, on the navigation menu’s container, location and alignment. Now, we can define Custom_Foundation_Nav_Menu:

class Custom_Foundation_Nav_Menu extends Walker_Nav_Menu {
   public function start_lvl( &$output, $depth = 0, $args = array() ) {
      $indent = str_repeat("\t", $depth);
      
      // add the dropdown CSS class
      $output .= "\n$indent<ul class=\"sub-menu dropdown\">\n";
   }
   public function display_element( $element, &$children_elements, $max_depth, $depth = 0, $args, &$output ) {
      
      // add 'not-click' class to the list item
      $element->classes[] = 'not-click';

      // if element is current or is an ancestor of the current element, add 'active' class to the list item
      $element->classes[] = ( $element->current || $element->current_item_ancestor ) ? 'active' : '';

      // if it is a root element and the menu is not flat, add 'has-dropdown' class 
      // from https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php#L140
      $element->has_children = ! empty( $children_elements[ $element->ID ] );
      $element->classes[] = ( $element->has_children && 1 !== $max_depth ) ? 'has-dropdown' : '';

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

As you can see, we’ve redefined the start_lvl and display_element methods. The first one generates the markup of the opening ul tag and assigns the dropdown CSS class.

The second method, display_element, is described in the Trac28: It’s a method to “traverse elements to create a list from elements,” so it is a good place to make changes to the menu items.

Here we’ve accessed the has_children, classes, current and current_item_ancestor properties and passed the updated $element object to the parent display_element method. That’s enough to achieve our goal, but we could do much more on the menu items. If you call var_dump on the $element object, you’ll see all of the available properties at your disposal to build more advanced navigation menus.

And, as we’ll see in a moment, we can add new properties to the object.

The Foundation Top Bar on a WordPress website
The Foundation Top Bar on a WordPress website.

The menu is up and running, but we may want deeper customization. In the next example, we’ll get more from our navigation menu, allowing the website administrator to prepend icons to the items’s titles the easy way: directly from the administration panel. In our example, we’ll use Foundation Icon Fonts 329.

Adding Fields To The WordPress Menu Items’ Editing Box Link

Before we start coding, let’s open the menu editing page and make sure that all of the advanced menu properties in the “Screen Options” tab are checked.

Screen Options Tab
WordPress’ “Screen Options” tab on the administration page for menus.

Each checkbox enables or disables certain fields in the menu item’s editing box:

Menu item edit box
The menu items’ editing box.

But we can do more than add or change field values. The menu items are considered specific post types, and the values of the menu items’ fields are stored in the database as hidden custom fields. So we can add a new menu item’s field exactly as we do with regular posts’ custom fields.

Any kind of form field is allowed: inputs, checkboxes, textboxes and so on.

In the following example, I will show you how to add a simple text field that enables the website administrator to add a new property to the $item object. It will be stored as a custom field and will be used to show data in the website’s front end.

To do that, we will:

  1. register a custom field for the navigation menu item,
  2. save the new custom field’s value,
  3. set up a new Walker class for the edit menu tree.

Step 1: Register A Custom Field For The Nav Menu Item Link

First, we’ll have to register a new custom field for the navigation menu item in the functions.php file:

/**
 * Add a property to a menu item
 *
 * @param object $item The menu item object.
 */
function custom_nav_menu_item( $item ) {
   $item->icon = get_post_meta( $item->ID, '_menu_item_icon', true );
   return $item;
}
add_filter( 'wp_setup_nav_menu_item', 'custom_nav_menu_item' );

wp_setup_nav_menu_item filters the navigation menu’s $item object, allowing us to add the icon property.

Step 2: Save The User’s Input Link

When the user submits the form from the menu’s administration page, the following callback will store the fields’ values in the database:

/**
 * Save menu item custom fields' values
 * 
 * @link https://codex.wordpress.org/Function_Reference/sanitize_html_class
 */
function custom_update_nav_menu_item( $menu_id, $menu_item_db_id, $menu_item_args ){
   if ( is_array( $_POST['menu-item-icon'] ) ) {
      $menu_item_args['menu-item-icon'] = $_POST['menu-item-icon'][$menu_item_db_id];
      update_post_meta( $menu_item_db_id, '_menu_item_icon', sanitize_html_class( $menu_item_args['menu-item-icon'] ) );
   }
}
add_action( 'wp_update_nav_menu_item', 'custom_update_nav_menu_item', 10, 3 );

When updating the menu items, this action calls custom_update_nav_menu_item(), which will sanitize and update the value of the _menu_item_icon meta field.

Now we have to print the custom field’s markup.

Step 3: Set Up A New Walker For The Edit Menu Tree Link

The structure of the menu’s administration page is built by the Walker_Nav_Menu_Edit class, which is an extension of Walker_Nav_Menu. To customize the menu items’ editing boxes, we’ll need a new custom Walker_Nav_Menu child class based on the Walker_Nav_Menu_Edit class.

To set a custom Walker, this time we’ll need the following filter:

add_filter( 'wp_edit_nav_menu_walker', function( $class ){ return 'Custom_Walker_Nav_Menu_Edit'; } );

When fired, this filter executes an anonymous function30 that sets a custom class that will build the list of menu items.

Finally, the new Walker can be declared. We won’t reproduce the full code here. Just copy and paste the full Walker_Nav_Menu_Edit code from the Trac31 into your custom class and add the custom field markup as shown below:

class Custom_Walker_Nav_Menu_Edit extends Walker_Nav_Menu {
   public function start_lvl( &$output, $depth = 0, $args = array() ) {}
   public function end_lvl( &$output, $depth = 0, $args = array() ) {}
   public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {
   ...
   
      <p class="field-xfn description description-thin">
         <label for="edit-menu-item-xfn-<?php echo $item_id; ?>">
            <?php _e( 'Link Relationship (XFN)' ); ?><br />
            <input type="text" id="edit-menu-item-xfn-<?php echo $item_id; ?>" class="widefat code edit-menu-item-xfn" name="menu-item-xfn[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->xfn ); ?>" />
         </label>
      </p>
      <p class="field-custom description description-thin">
         <label for="edit-menu-item-icon-<?php echo $item_id; ?>">
            <?php _e( 'Foundation Icon' ); ?><br />
            <input type="text" id="edit-menu-item-icon-<?php echo $item_id; ?>" class="widefat code edit-menu-item-icon" name="menu-item-icon[<?php echo $item_id; ?>]" value="<?php echo esc_attr( $item->icon ); ?>" />
         </label>
      </p>
   ...
   }
}

Now, with the new input field in place, the website administrator will be able to add the new icon property to the menu $item object.

Custom menu item edit box
A customized version of the menu items’ editing box.

At this time, the Walker_Nav_Menu class won’t be able to access the new property value; so, the value of $item->icon would not be available to build the menu structure. To make it accessible, in the Custom_Foundation_Nav_Menu class of our previous example, we will redefine the start_el method. The easiest way to proceed is to copy the code from the Walker_Nav_Menu class32 and paste it in our custom class, editing it where necessary.

So, paste the code and jump to the bottom of the new start_el method and make the following edits:

public function start_el( &$output, $item, $depth = 0, $args = array(), $id = 0 ) {

   ...

   $item_output = $args->before;
   $item_output .= '<a'. $attributes .'>';

   if( !empty( $item->icon ) )
      $item_output .= '<i class="fi-' . $item->icon . '" style="margin-right: .4em"></i>';

   $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 );
}

No other changes are being done here except the condition that checks the value of the $item->icon property. If a value has been set, a new i element is attached to $item_output and assigned to the proper CSS class.

Finally, the following markup shows the new HTML menu structure.

<div class="top-bar-section">
   <ul id="menu-nav-menu" class="left">
      <li id="menu-item-46" class="menu-item menu-item-type-custom menu-item-object-custom current-menu-item current_page_item menu-item-home not-click active menu-item-46">
         <a href="http://localhost:8888/wordpress/">
            <i class="fi-social-smashing-mag"></i>
            <span>Home</span>
         </a>
      </li>
   </ul>
</div>

The image below shows the final result on the desktop.

Foundation 5 Topbar in WordPress
The custom Foundation 5 Top Bar integrated in a WordPress theme, enriched with icon fonts from Foundation Icon Font 3.

Final Notes Link

In this article, we’ve explored some of the most common uses of the Walker class. Note, however, that our examples do not cover all possible applications and alternative ways to take advantage of the class. But you’ll discover more just by making use of your imagination and your skills as a programmer.

And never lose sight of the official documentation:

(ml, dp, jb, al, jb)

Footnotes Link

  1. 1 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php
  2. 2 https://codex.wordpress.org/Class_Reference/Walker_Page
  3. 3 https://en.wikipedia.org/wiki/Tree_(data_structure)
  4. 4 https://www.smashingmagazine.com/wp-content/uploads/2015/09/01-wpcommentsstructure-opt.png
  5. 5 https://www.smashingmagazine.com/wp-content/uploads/2015/09/01-wpcommentsstructure-opt.png
  6. 6 http://php.net/manual/en/language.oop5.basic.php
  7. 7 https://codex.wordpress.org/Class_Reference/Walker
  8. 8 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php
  9. 9 http://php.net/manual/en/language.oop5.abstract.php
  10. 10 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/post-template.php#L1325
  11. 11 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/post-template.php#L1471
  12. 12 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/category-template.php#L962
  13. 13 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/category-template.php#L1163
  14. 14 https://core.trac.wordpress.org/browser/tags/4.2.2/src/wp-admin/includes/template.php#L24
  15. 15 http://core.trac.wordpress.org/browser/tags/4.2.2/src/wp-includes/comment-template.php#L1662
  16. 16 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/nav-menu-template.php#L16
  17. 17 https://core.trac.wordpress.org/browser/tags/4.2.2/src/wp-admin/includes/nav-menu.php#L237
  18. 18 https://core.trac.wordpress.org/browser/tags/4.2.2/src/wp-admin/includes/nav-menu.php#L10
  19. 19 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php
  20. 20 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php#L112
  21. 21 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php#L175
  22. 22 https://codex.wordpress.org/Function_Reference/wp_nav_menu
  23. 23 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/nav-menu-template.php
  24. 24 http://foundation.zurb.com/
  25. 25 http://foundation.zurb.com/docs/javascript.html
  26. 26 https://codex.wordpress.org/Function_Reference/wp_enqueue_script
  27. 27 http://foundation.zurb.com/docs/components/topbar.html
  28. 28 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/class-wp-walker.php#L112
  29. 29 http://zurb.com/playground/foundation-icon-fonts-3
  30. 30 http://php.net/manual/en/functions.anonymous.php
  31. 31 https://core.trac.wordpress.org/browser/tags/4.2.4/src/wp-admin/includes/nav-menu.php
  32. 32 https://core.trac.wordpress.org/browser/trunk/src/wp-includes/nav-menu-template.php
  33. 33 https://codex.wordpress.org/Class_Reference/Walker
  34. 34 https://codex.wordpress.org/Function_Reference/wp_nav_menu
SmashingConf Barcelona 2016

Hold on, Tiger! Thank you for reading the article. Did you know that we also publish printed books and run friendly conferences – crafted for pros like you? Like SmashingConf Barcelona, on October 25–26, with smart design patterns and front-end techniques.

↑ Back to top Tweet itShare on Facebook

Advertisement

Carlo is a freelance front-end designer and developer. In the last years he's been writing for ioProgrammo, an Italian printed computer magazine, and HTML.it, a popular design and development Italian website.

When he writes articles and tutorials, Carlo mainly deals with web standards, but when he plays with websites his best workmate is WordPress.

You can follow him on Twitter @carlodaniele.

  1. 1

    Pieter Verhoeven

    October 15, 2015 3:07 pm

    Oh wow, I was just struggling with this yesterday, it’s like you read my mind. Thumbs up from me!

    2
  2. 4

    Great article, especially the Foundation menu stuff, very useful (for Foundation 5). I hear that in F6 the whole nav-menu structure will get an overhaul…

    Anyways, many thanks for posting such an in-depth article! Always happy to learn something new!

    1
  3. 5

    Hemang Rindani

    November 16, 2015 4:55 pm

    Great article.

    WordPress provides features that enable a developer to manage the pages using a tree like data structures where each page is categorized under a specific heading or subheading. However, it is important to understand the method to use this. While editing, make sure that the other pages of site map is not disturbed. Assigning user permissions for certain pages is tricky. Using Walker class makes it possible for the developer to access only the required page through the data tree without effecting other pages. It can be implemented using easy codes that even a person with basic programming knowledge can handle. Walker class also helps to identify the loopholes in page structure for a website.

    Thanks for sharing the article.

    0
  4. 6

    SHWAN NAMIQ SALEEM

    December 9, 2015 6:18 am

    Thank you Carlo Daniele it is the only more detailed post over the world about the walker tree like structure. I’m before some days decide to learn how i can create custom walker class for my wordpress menu but i can’t find the perfect post for learning or get information about all variable and functions of walker class.

    0
  5. 7

    SHWAN NAMIQ SALEEM

    December 12, 2015 6:36 am

    Please for register custom filed use or use

    -1
  6. 8

    21st Century and you still dont post a download link – you know, it’s hard to follow a foreign language, especially if you do stupid stuff like “copy something to somewhere” without a “final view”. Your tut would be great, if done completly.
    sorry.

    1

↑ Back to top