I’ve had a need to attach some data to WordPress menu items and have modified the ajaxnav\WalkerAjaxNavMenu
class I’m using in a block plugin to do the job.
Since the theme I’m developing makes heavy use of JavaScript attaching a data
attribute to each menu element made sense.
I’m defining a custom Walker here and since I’m working on the single element level the start_el
method is the entry point, $this->settings
will store previously fetched settings.
public function start_el(&$output, $item, $depth = 0, $args = array(), $id = 0)
{
$jsonItemAttribute = '';
// if the developer so wishes a JSON version of the item can be
// attached to the menu item itself
if ($this->settings->attachJsonItem) {
$postType = $item->type;
// posts and pages will require more fetching
$toFetch = array('post_type');
if (in_array($postType, $toFetch)) {
$postItem = get_post($item->object_id);
} else {
$postItem = $item;
}
$values = array();
// no values but wants to attach json data then return all
if (!$this->settings->jsonItemKeys) {
// return all values
$values = (array)$item;
} else {
// there are some keys: return those only
// from a comma separated list to an array
$jsonItemKeys = explode(',', $this->settings->jsonItemKeys);
// iterate over the array and store matching values
foreach ($item as $key => $value) {
if (in_array($key, $jsonItemKeys)) {
$values[$key] = $value;
}
}
}
// create a json value object
$encoded = json_encode($values);
// create the complete `data-item` attribute
$jsonItemAttribute = sprintf('data-item=\'%s\'', $encoded);
}
$indent = str_repeat("\t", $depth);
// append the element to the output
$output .= sprintf('%s<div class="menu-item" %s><a href="%s">%s</a>', $jsonItemAttribute, $item->url, $item->title);
}
}
and this will produce markup like
<div class="menu-item" data-item='{"ID":1765,"post_excerpt":","type":"taxonomy","description":"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua."}'>
<a href="http://testing.dev/category/markup/">
Markup
</a>
</div>
where I’ve chosen to print the post ID, excerpt, type and description in the attribute. Later in the script I will use
$('.menu-item').each(function(){
var data = $(this).data('item');
// do something with the data...
});