Let us first look at this part:
I don’t exactly understand what object
$item
is and this is probably
the problem. When I callget_class()
on$item
I getWP_Post
, but
WP_Post
does not have a classes property. So how is$item->classes
returning an array of classes?
Few notes regarding the structure of menus in WordPress:
-
Each navigational menu is registered as a term in the
nav_menu
taxonomy. -
Then when we add items to that menu, we are creating new post objects of the type
nav_menu_item
. -
The tree structure for each menu is not the stored in the
post_parent
field of thenav_menu_item
posts, as expected. We actually find it in the post meta table where it’s stored under the_menu_item_menu_item_parent
meta key, for eachnav_menu_item
post. -
The
$item
menu item data object is a decoratedWP_Post
object, i.e. with extra attributes added with thewp_setup_nav_menu_item()
function:/** * Decorates a menu item object with the shared navigation menu item properties. * * Properties: * - ID: The term_id if the menu item represents a taxonomy term. * - attr_title: The title attribute of the link element for this menu item. * - classes: The array of class attribute values for the link element of this menu item. * - db_id: The DB ID of this item as a nav_menu_item object, if it exists (0 if it doesn't exist). * - description: The description of this menu item. * - menu_item_parent: The DB ID of the nav_menu_item that is this item's menu parent, if any. 0 otherwise. * - object: The type of object originally represented, such as "category," "post", or "attachment." * - object_id: The DB ID of the original object this menu item represents, e.g. ID for posts and term_id for categories. * - post_parent: The DB ID of the original object's parent object, if any (0 otherwise). * - post_title: A "no title" label if menu item represents a post that lacks a title. * - target: The target attribute of the link element for this menu item. * - title: The title of this menu item. * - type: The family of objects originally represented, such as "post_type" or "taxonomy." * - type_label: The singular label used to describe this type of menu item. * - url: The URL to which this menu item points. * - xfn: The XFN relationship expressed in the link of this menu item. * - _invalid: Whether the menu item represents an object that no longer exists.
Then let’s look at this part:
After using the class
search-class
to locate the item, I would like to
remove it from the item. However, my call to
unset($item->classes[$class_key]);
doesn’t work.
It’s too late to remove classes from the $item
object, within the nav_menu_link_attributes
filter, in order to remove classes from the menu items (li tags).
We can e.g. use the nav_menu_css_class
filter to modify these classes.
It’s also probably a better approach in general to use such a filter rather than modifying the data object directly, because other plugins might depend on the raw data object.
Here’s an example how to remove the search-class
class:
add_filter( 'nav_menu_css_class', function( $classes, $item, $args, $depth )
{
return array_filter(
(array) $classes,
function( $val ) { return 'search-class' !== $val; }
);
}, 10, 4 );
Then we can use the nav_menu_link_attributes
filter to add a data attribute and append a class to the anchor tag:
add_filter( 'nav_menu_link_attributes', function( $atts, $item, $args )
{
// Nothing to do
if(
! isset( $item->classes )
|| ! in_array( 'klasi1', $item->classes, true )
|| ! isset( $atts['class'] )
)
return $atts;
// Add data attribute to anchor tag
$atts['data-something'] = 'something';
// Append an anchor class
$classes = explode( ' ', $atts['class'] );
$classes[] = 'something-class';
$atts['class'] = join( ' ', array_filter( $classes ) );
return $atts;
}, 10, 3 );
We might also want to restrict the above filters to a given menu, by checking if $args->theme_location
is 'primary'
or $args->menu->slug
is 'somemenuslug'
.