The nav_menu_link_attributes
filter can be used to accomplish this, so a walker is not necessary. Here’s an example with comments along the way to explain what’s happening.
add_filter( 'nav_menu_link_attributes', 'wpse_nav_menu_link_attributes', 10, 4 );
/**
* Filters the HTML attributes applied to a menu item's anchor element.
*
* Adds data-modified attribute to links.
* - For single post types, the data-modified attribute's value stores the
* modified date for that post.
*
* - For post type archives, the data-modified attribute's value stores the
* modified date for the most recently published post in the archive.
*
* - For taxonomies, the data-modified attribute's value stores the
* modified date for the most recently published post assigned to the taxonomy term.
*
* ----
*
* Docs below via WordPress core.
*
* @param array $atts {
* The HTML attributes applied to the menu item's `<a>` element, empty strings are ignored.
*
* @type string $title Title attribute.
* @type string $target Target attribute.
* @type string $rel The rel attribute.
* @type string $href The href attribute.
* }
* @param WP_Post $item The current menu item.
* @param stdClass $args An object of wp_nav_menu() arguments.
* @param int $depth Depth of menu item. Used for padding.
*/
function wpse_nav_menu_link_attributes( $atts, $item, $args, $depth ) {
// Get all post meta for this menu item. Post, Page, and other info is
// stored in the menu item post's meta data.
$item_meta = get_post_meta( $item->ID );
// Modify date format to suit your preferneces.
// http://php.net/manual/en/function.date.php
$date_format="l F j, Y";
// Bail if there is no meta.
if ( ! $item_meta ) {
return $atts;
}
$menu_item_type = false;
// Bail if _menu_item_type is unavailable.
if ( ! isset( $item_meta['_menu_item_type'][0] ) ) {
return $atts;
} else {
$menu_item_type = $item_meta['_menu_item_type'][0]; // For readability.
}
// Handle post types and post type archives accordingly.
switch ( $menu_item_type ) {
/**
* Handle single post type menu item type. E.g.: posts/pages/etc.
*/
case 'post_type' :
// Bail if _menu_item_object_id is unavailable.
if ( ! isset( $item_meta['_menu_item_object_id'][0] ) ) {
return $atts;
} else {
$menu_item_object_id = $item_meta['_menu_item_object_id'][0]; // For readability.
}
// Handle special case when this is the page for posts.
$show_on_front = get_option( 'show_on_front' ); // 'page' for static front page, 'posts' for latest posts.
$page_for_posts = get_option( 'page_for_posts' );
if ( 'page' === $show_on_front && $page_for_posts === $menu_item_object_id ) {
// Get the most recent post of the post post type. ...Buffalo buffalo Buffalo buffalo buffalo buffalo Buffalo buffalo.
$recent_post = get_posts( [
'posts_per_page' => 1,
'post_type' => 'post',
'orderby' => 'date',
'order' => 'DESC',
'post_status' => 'publish',
] );
// Add the data-modified attribute and set the date via the most recent post.
if ( is_array( $recent_post ) ) {
$atts['data-modified'] = esc_attr( get_the_modified_date(
$date_format,
$recent_post[0]
) );
}
// Handle typical case for single post/page/custom post type.
} else {
// Add the data-modified attribute and set the value to post's modified date.
$atts['data-modified'] = esc_attr( get_the_modified_date(
$date_format,
get_post( $menu_item_object_id )
) );
}
break;
/**
* Handle post type archive menu item type.
*/
case 'post_type_archive' :
// Bail if _menu_item_object is unavailable.
if ( ! isset( $item_meta['_menu_item_object'][0] ) ) {
return $atts;
} else {
$menu_item_object = $item_meta['_menu_item_object'][0]; // For readability.
}
// Get the most recent post of this archive's type.
$recent_post = get_posts( [
'posts_per_page' => 1,
'post_type' => $menu_item_object,
'orderby' => 'date',
'order' => 'DESC',
'post_status' => 'publish',
] );
// Add the data-modified attribute and set the date via the most recent post.
if ( is_array( $recent_post ) ) {
$atts['data-modified'] = esc_attr( get_the_modified_date(
$date_format,
$recent_post[0]
) );
}
break;
/**
* Handle taxonomy menu item type.
*/
case 'taxonomy' :
// Bail if _menu_item_object is unavailable.
if ( ! isset( $item_meta['_menu_item_object'][0] ) ) {
return $atts;
} else {
$menu_item_object = $item_meta['_menu_item_object'][0];
}
// Bail if _menu_item_object_id is unavailable.
if ( ! isset( $item_meta['_menu_item_object_id'][0] ) ) {
return $atts;
} else {
$menu_item_object_id = $item_meta['_menu_item_object_id'][0];
}
// Get the most recent post using this taxonomy and term.
$recent_post = get_posts( [
'posts_per_page' => 1,
'post_type' => 'any',
'orderby' => 'date',
'order' => 'DESC',
'post_status' => 'publish',
'tax_query' => array (
[
'taxonomy' => $menu_item_object,
'terms' => $menu_item_object_id,
'field' => 'id',
],
)
] );
// Add the data-modified attribute and set the date via the most recent post using this taxonomy and term.
if ( is_array( $recent_post ) ) {
$atts['data-modified'] = esc_attr( get_the_modified_date(
$date_format,
$recent_post[0]
) );
}
break;
} // end switch
return $atts;
}
Note: Each link in a menu is stored as a custom post type named nav_menu_item
. The additional information (such as the post ID that the menu item post points to) is stored in post meta. The post_id
field of the meta will point back to the nav_menu_item
‘s post id.