Get current post menu

For one of my projects I needed to get the menu name of the current post. After searching the WordPress database structure for almost 1 day I found out that WordPress menus are basically just terms from the taxonomy ‘nav_menu’. So made it simple for me. I just needed to get the term by the get_the_terms() function like:

global $post;
$terms = get_the_terms( $post->ID, 'nav_menu' );
return array_shift( $terms );

But unfortunately it isn’t that simple. When you create a menu in WordPress and insert a page in it, WordPress creates a copy of that page to the post type ‘nav_menu_item’. This post holds a custom field called ‘_menu_item_object_id’ with as value; the post id of the original page.

So I have created the following two functions to achieve the right result.

Function 1: SQL Query

The following function selects the term_taxonomy_id where the object_id is equal to meta_value of a meta_key; ‘menu_item_object_id’. Then you can insert this term_taxonomy_id into the get_term_by() function to return the id, name, slug etc. of the term.

function get_post_menu( $post_id = null, $output = 'term_id' ) {
    // Check if $post_id is set otherwise select from global $post variable
    if( ! isset( $post_id ) ) {
        global $post;
        $post_id = $post->ID;   
    }
    // Select term_taxonomy_id by comparing with '_menu_item_object_id'
    global $wpdb;
    $menu = $wpdb->get_results( "
        SELECT term_taxonomy_id 
        FROM $wpdb->term_relationships
        WHERE object_id = 
        (SELECT post_id 
        FROM $wpdb->postmeta 
        WHERE meta_key = '_menu_item_object_id' 
        AND meta_value = $post_id)"
        , OBJECT 
    );
    // Get all term information
    $term = get_term_by( 'term_taxonomy_id', $menu[0]->term_taxonomy_id, 'nav_menu' );
    return $term->$output;
}

This is one option to do it. But I found another way to reach the same result.

Function 2: get_posts() function

In the following function I use the get_posts() function to filter out posts by post_type; ‘nav_menu_item’ and then use the ‘meta_query’ argument to find the post with a meta_key ‘_menu_item_object_id’ and meta_value equal to the current post id. Now you have the id of the copy of the current page, you can use get_the_terms() to get the term information as you want it.

function get_post_menu( $post_id = null, $output = 'term_id' ) {
        // Check if $post_id is set otherwise select from global $post variable
	if( ! isset( $post_id ) ) {
		global $post;
		$post_id = $post->ID;	
	}
        // Get posts filtered by post_type, and postmeta
	$menu_items = get_posts( array(
		'post_type'  => 'nav_menu_item',
		'meta_query' => array(
			array(
				'key'   => '_menu_item_object_id',
				'value' => $post_id,
			)
		),
	) );
	$terms = array_values( get_the_terms( $menu_items[0]->ID, 'nav_menu' ) );
	return $terms[0]->$output;
}