Search code examples
phpwordpresswoocommerceshortcodecustom-taxonomy

Create shortcode to show specific nav menu depending on product category


I need to create a shortcode that displays a specific wordpress menu on a Woocommerce product depending on the category the product belongs to. Both the category and menu are identified by ID but I can't seem to make it work.

Here's my code:

function view_color_menu( $category ) {
    $catarray = get_the_category( $post->ID );
    foreach ($catarray as $cat) {
        $catid = $cat->term_id;
        if ($catid == 31) {
          wp_nav_menu( array( 'menu_id' => '16' ) ); 
        }
        if ($catid == 35) {
          wp_nav_menu( array( 'menu_id' => '17' ) ); 
        }
        if ($catid == 42) {
          wp_nav_menu( array( 'menu_id' => '21' ) ); 
        }
    }
}
add_shortcode('get_color_menu', 'view_color_menu');

Solution

  • There are multiple mistakes with your code:

    • get_the_category() only works for WordPress blog post categories, not with product categories (which is a custom taxonomy),
    • wp_nav_menu() function is echoed by default, but inside a shortcode code, it should always be returned.
    • The best way to get the current product post ID is to use:
      • the WordPress functionget_the_ID(),
      • or global $post; with $post->ID.
    • Your settings for wp_nav_menu() seems incorrect as 'menu' parameter accepts, among other things, the menu ID (integer)

    Try the following revised code:

    add_shortcode('color_menu', 'color_menu_shortcode');
    function color_menu_shortcode( $atts ) {
        extract( shortcode_atts( array(
            'product_id'  => get_the_ID()
        ), $atts, 'color_menu' ) );
    
        // Array of associated term ID with Menu ID pairs
        $data_term_menu = array(
            '31' => '16',
            '35' => '17',
            '42' => '21',
        );
    
        ob_start(); // start buffering printed content
        
        // Loop through associated Term ID(s) Key / Menu ID(s) value
        foreach ( $data_term_menu as $term_id => $menu_id ) {
            // Check if the current term ID is set in the product
            if ( has_term( intval($term_id), 'product_cat', $product_id ) ) {
                wp_nav_menu( array( 'menu' => intval($menu_id) ) );
            }
        }
        return ob_get_clean(); // Return the buffered content
    }
    

    It should work…

    Shortcode usage

    • Simple usage in a product page: [color_menu],
    • Or specifying a product ID: [color_menu product_id="18"].