WP Smith

Creating WordPress & Genesis Websites Since 2010

  • Home
  • About
  • Services
  • Blog
  • Contact

Dec 06 2011

How to Automatically Add a Class (like 'first' or 'last') to a WordPress Menu

So recently, I needed a way to dynamically add a 'first' class to all the first child nav menu items of a particular parent nav menu item item. On a simple Google, one tutorial by @WPBeginner suggests that we use a filter.
[php]
//Filtering a Class in Navigation Menu Item
add_filter( 'nav_menu_css_class' , 'special_nav_class' , 10 , 2 );
function special_nav_class( $classes, $item ){
if( is_single() && $item->title == 'Blog' ){
$classes[] = 'current-menu-item';
}
return $classes;
}
[/php]
However great this filter is, this approach won't and cannot be very dynamic.

So I wrote a function (and generalized it) that would accomplish this easily and nicely. This uses a function that I wrote about previously called get_nav_menu_item_children() in a post called How to Get All the Children of a Specific Nav Menu Item that I have modified (12/6).

Given a menu id and a parent item id and the optional class name, the function will automatically add that class to the first child nav menu item. So here is the new function:
[php]
/*
* Adds a class to the first menu item.
*
* Uses update_post_meta() to update a nav menu item.
*
* @param int $menu_id Menu ID, defaults to 0.
* @param int $parent_id Menu item ID, defaults to 0.
* @param string $newclass Class to add, defaults to 'first'.
* @param boolean $remove Remove class from other children, defaults to true.
* @return boolean, false: if no $menu_id or $parent_id, else true.
*/
function wps_update_classes( $menu_id = 0 , $parent_id = 0 , $newclass = 'first' , $remove = true ) {

// Validate inputs
$menu_id = intval ( $menu_id );
$parent_id = intval ( $parent_id );

if ( ( $menu_id == 0 ) || ( $parent_id == 0 ) || ( !is_bool ( $remove ) ) || ( !is_string ( $newclass ) ) )
return false;

// Get & filter nav menu items
$nav_menu_items = wp_get_nav_menu_items( $menu_id , array( 'post_status' => 'publish,draft' ) );
$children = get_nav_menu_item_children( $parent_id , $nav_menu_items );
$first_item = true;

// Cycle through child nav menu items
foreach ( $children as $child ) {
if ( $first_item ) {
//found first item
$first_item = false;
$match = false;

// Cycle through to check for first
foreach ( $child->classes as $class ) {
// Match found
if ( $class == $newclass ) {
$match = true;
break;
}
}

// Update Post if match found
if ( ! $match ) {
if ( $child->classes[0] == '' )
$child->classes[0] = $newclass;
else
$child->classes[] = $newclass;

$menu_item_data = array(
'menu-item-classes' => $child->classes,
);
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
continue;
}

// Cycle through and remove $newclass from other children
if ( $remove ) {
foreach ( $child->classes as $key => $class ) {

// If match, remove $newclass from other children
if ( $class == $newclass ) {
$child->classes[$key] = '';
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
}
}
}

return true;
}
[/php]

So to call this function, you can use something like this:
[php]
add_action( 'init' , 'wps_update_menus' );
function wps_update_menus() {
wps_update_classes( 3 , 277 );
wps_update_classes( 3 , 7 , 'test-class' );
}
[/php]
This bit of code adds 'first' to the first child of menu item 277 on menu 3 and 'test-class' to the first child of menu item 7 on menu 3.

If you want to add the ability to add a 'last' class, you can use this:
[php]
/*
* Sorts a multidimensional array of nav menu items.
*
* @link http://php.net/manual/en/function.sort.php
* @param array $array Multidimensional array to be sorted.
* @param string $index Index to determine the sort.
* @param string $order Must be either asc or desc.
* @param boolean $natsort Sort an array using a "natural order" algorithm.
* @param boolean $case_sensitive Sort via case sensitivity.
* @return boolean, false: if no $menu_id or $parent_id, else true.
*/
function wps_sort_nav_menu_items ( $array, $index, $order, $natsort = FALSE, $case_sensitive = FALSE ) {
if( is_array ( $array ) && count( $array ) > 0 ) {
foreach ( array_keys ( $array ) as $key )
$temp[$key] = $array[$key]->$index;
if( ! $natsort ) {
if ( strtolower( $order ) == 'asc' )
asort( $temp );
else
arsort( $temp );
}
else
{
if ( $case_sensitive === true )
natsort( $temp );
else
natcasesort( $temp );
if( strtolower( $order ) != 'asc' )
$temp = array_reverse ( $temp , TRUE );
}
foreach( array_keys ( $temp ) as $key )
if ( is_numeric ( $key ) )
$sorted[] = $array[$key];
else
$sorted[$key] = $array[$key];
return $sorted;
}
return $sorted;
}

/*
* Adds a class to first/last menu item.
*
* Uses update_post_meta() to update a nav menu item.
*
* @param int $menu_id Menu ID, defaults to 0.
* @param int $parent_id Menu item ID, defaults to 0.
* @param string $newclass Class to add, defaults to 'first'.
* @param boolean $remove Remove class from other children, defaults to true.
* @return boolean, false: if no $menu_id or $parent_id, else true.
*/
function wps_update_classes( $menu_id = 0 , $parent_id = 0 , $newclass = 'first' , $firstlast = 'first' , $remove = true ) {

// Validate inputs
$menu_id = intval ( $menu_id );
$parent_id = intval ( $parent_id );

if ( ( $menu_id == 0 ) || ( $parent_id == 0 ) || ( !is_bool ( $remove ) ) || ( !is_string ( $newclass ) ) || ( !is_string ( $firstlast ) ) )
return false;

// Get & filter nav menu items
$nav_menu_items = wp_get_nav_menu_items( $menu_id , array( 'post_status' => 'publish,draft' ) );
$children = get_nav_menu_item_children( $parent_id , $nav_menu_items );
if ( strtolower( $firstlast ) == 'last' )
$children = wps_sort_nav_menu_items( $children , 'menu_order' , 'desc' );
$first_item = true;

// Cycle through child nav menu items
foreach ( $children as $child ) {
if ( $first_item ) {
//found first item
$first_item = false;
$match = false;

// Cycle through to check for first
foreach ( $child->classes as $class ) {
// Match found
if ( $class == $newclass ) {
$match = true;
break;
}
}

// Update Post if match found
if ( ! $match ) {
if ( $child->classes[0] == '' )
$child->classes[0] = $newclass;
else
$child->classes[] = $newclass;

$menu_item_data = array(
'menu-item-classes' => $child->classes,
);
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
continue;
}

// Cycle through and remove $newclass from other children
if ( $remove ) {
foreach ( $child->classes as $key => $class ) {

// If match, remove $newclass from other children
if ( $class == $newclass ) {
$child->classes[$key] = '';
update_post_meta( $child->ID, '_menu_item_classes', $child->classes );
}
}
}
}

return true;
}
[/php]

So to call this function, you can use something like this:
[php]
add_action( 'init' , 'wps_update_menus' );
function wps_update_menus() {
wps_update_classes( 3 , 277 );
wps_update_classes( 3 , 7 , 'last' , 'last' );
}
[/php]
This bit of code adds 'first' to the first child of menu item 277 on menu 3 and 'last' to the last child of menu item 7 on menu 3.

Written by Travis Smith · Categorized: Tutorials, WordPress

StudioPress Premium WordPress Themes     WP Engine Managed WordPress Hosting

What can I do for you!?

Custom Development

We develop plugins by determining both business/functional and technical requirements, following WordPress development best practices, and using agile methodology to ensure you get the best solution.

Consulting

Have questions? Need a reliable developer to consult? Please contact us today!

Customized Theme

We can customize your theme or child theme, or create a child theme for you based on your needs while enhancing the performance of every individual attribute.

Customized Plugin

We can customize your plugins, extend plugins (e.g., Gravity Forms, Jetpack, Soliloquy) based on your needs ensuring security, performance, and positive business impact.

Contact Us

About Travis Smith

As a WordPress enthusiast, developer, and speaker, Travis writes about what he learns in WordPress trying to help other WordPress travelers, beginners and enthusiasts with tutorials, explanations, & demonstrations.

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

  • Twitter
  • Facebook
  • LinkedIn
  • Google+
  • RSS

Copyright © 2025 � WP Smith on Genesis on Genesis Framework � WordPress � Log in