Custom dashboard menu does not stay open for the custom Taxonomy within it

Short Version:

Custom menu with a custom post type that supports a custom taxonomy. The custom post type works, the menu for it works and stays open. The custom taxonomy works, but the sidebar menu doesn’t stay open. I need to make the category keep the submenu open, as it does natively (when not placed in another menu).

Long version:

I’ve got a custom menu created with add_menu_page:

Read More
add_menu_page(
  'Directory',           // Page Title
  'Directory',           // Menu Title
  'manage_options',      // Capability
  'directory',           // Slug
  null,                  // Rendering Function
  'div'                  // Menu Icon (or "div" for CSS)
);

I have also created a custom Post Type and a custom Taxonomy. I want to make these appear within my custom menu, which according to the show_in_menu argument (See wiki, can’t post the link), this should be supported natively.

However, it simply does not work correctly. True, this option does stick the “Manage Directory” link into my custom menu, but it does not move the “Add Contact” or “Directory Categories (Custom taxonomy)” links into the menu.

Here are a few previews:

Custom Menu: http://radleygh.com/images/chrome_2013-114-14-14-16-91.png

Default Menu: http://radleygh.com/images/chrome_2013-114-14-14-53-25.png

As you can see, the Default Menu has three links. I need to move all of these to my custom men (Where I will be adding submenus).

One trick I learned awhile back is that you can create submenus for existing pages, and they will behave as if they are the real menu. At least, this works for most things. It does not work with my taxonomy. See the code below:

add_submenu_page( // Manage Directory
  'directory',
  'Manage Directory',                  // Page Title
  'Manage Directory',                          // Menu Title
  'manage_options',                    // Capability
  'edit.php?post_type=directory_post'  // Slug
);
add_submenu_page( // Add Contact
  'directory',
  'Add Contact',                            // Page Title
  'Add Contact',                            // Menu Title
  'manage_options',                         // Capability
  'post-new.php?post_type=directory_post'   // Slug
);
add_submenu_page( // Categories
  'directory',
  'Categories',                             // Page Title
  'Categories',                             // Menu Title
  'manage_options',                         // Capability
  'edit-tags.php?taxonomy=directory_category&post_type=directory_post'  // Slug
);

The above code gives me the links I want, and the “slug” for each is smart enough to point to the correct pages. In fact, it’s as if the links are the native ones. But of course, they aren’t.

The problem though, is that for some reason the “Categories” link alone does not keep the menu open. The others do.

I believe the issue is that the taxonomy does not support the “show_in_menu” argument. Even though the argument is “broken” as I explained above, it does at least keep the menu open.


Here is the definition for the directory post type and taxonomy, in full

// Register the post type and custom category (aka taxonomy)
function dir_register_directory() {
  $args = array(
    'labels' => array(
          'name' => 'Directory Listings',
          'singular_name' => 'Directory Listing',
          'add_new' => 'Add Contact',
          'add_new_item' => 'Add New Contact',
          'edit_item' => 'Edit Contact',
          'new_item' => 'New Contact',
          'all_items' => 'Manage Directory',
          'view_item' => null, // Don't need to view these
          'search_items' => 'Search Directory',
          'not_found' =>  'No contacts found',
          'not_found_in_trash' => 'No contacts found in Trash', 
          'parent_item_colon' => '',
          'menu_name' => 'Directory'
        ),
    'capability_type'     => 'post',
    'hierarchical'        => false,

    'public'              => true,
    'show_in_menu'        => 'directory', // Nest the link under custom menu
    'show_in_nav_menus'   => false, // Do NOT show these listings under Appearance > Menus

    'publicly_queryable'  => false, // Will not show up in search results
    'query_var'           => false, // Cannot access via ?{query_var}=
    'rewrite'             => false, // Entries should not be accessed by URL

    'has_archive'         => 'directory_category', // Use our custom taxonomy
    'menu_position'       => 1,  // Should be on top of the parent menu's list
    'supports'            => array(
          'page-attributes', // Used for Sort Order
        )
   );
   register_post_type( 'directory_post', $args );

  // Create a custom category section for the Directory page
  register_taxonomy(
    'directory_category',
    'directory_post',
    array(
      'rewrite' => false,
      'hierarchical' => true,
      'sort' => true,
      'public' => true,
      'show_in_nav_menus'   => false, // Do NOT show these listings under Appearance > Menus
    )
  );

  register_taxonomy_for_object_type( 'directory_category', 'directory_post' );
}
add_action('init', 'dir_register_directory');

Related posts

Leave a Reply

2 comments

  1. I solved this by adding following function,

        add_action('parent_file', 'keep_taxonomy_menu_open');
        function keep_taxonomy_menu_open($parent_file) {
          global $current_screen;
          $taxonomy = $current_screen->taxonomy;
          if ($taxonomy == 'directory_category')
            $parent_file = 'directory';
          return $parent_file;
        }
    

    If you are adding more taxonomies, just change if condition in above code like following

        if ($taxonomy == 'directory_category' or $taxonomy=='tax2' or $taxonomy=='tax3)
    
  2. I could not find a built-in way to accomplish this solution, but I have created a workaround

    I realized, if the menu won’t stay open, why not open it myself?

    I created the following two functions, which are easy enough to understand. They need to be called in a javascript file which is loaded via admin script (see the function wp_enqueue_script and the action hook admin_enqueue_scripts).

    Usage:

    jQuery(function() {
      // Deactivate all currently active menus
      wp_deactivate_menus();
    
      // Activate the parent menu with an id #menu-pages, as well as the submenu item with
      // the specific slug "edit.php?post_type=page"
      wp_activate_menu('#menu-pages', 'edit.php?post_type=page');
    });
    

    Functions:

    // Deactivate all active / expanded WordPress menus
    function wp_deactivate_menus() {
      var $sidebar = jQuery("#adminmenu");
      var $active_menus = $sidebar.children('li.current, li.wp-has-current-submenu, li.wp-menu-open');
    
      // Close all open menus
      $active_menus.each(function() {
        var $this = jQuery(this);
    
        // Conditional classes
        if ($this.hasClass('wp-has-current-submenu')) 
          $this.addClass('wp-not-current-submenu');
    
        // Unconditional classes
        $this
          .removeClass('current')
          .removeClass('wp-menu-open')
          .removeClass('wp-has-current-submenu')
          .addClass('wp-not-current-submenu');
    
        // Remove "current" from all submenu items, too
        $this.find('ul.wp-submenu li a.current').removeClass('current');
      });
    }
    
    // Activate a WordPress menu and optionally highlight a submenu slug within that category
    // menu_id = String, such as "#my-menu-id". (Not necessarily an ID, but a selector to select the <li>) 
    // slug = String, such as "edit.php?post-type=page". Must be exactly the same href as the submenus a[href]
    function wp_activate_menu( menu_id, slug ) {
      var $sidebar = jQuery("#adminmenu");
      var $menu = $sidebar.find( menu_id );
    
      if (!$menu || $menu.length < 1) return false;
    
      // Conditional classes
      if ($menu.hasClass('wp-has-submenu'))
        $menu.addClass('wp-has-current-submenu');
    
      // Unconditional classes
      $menu
        .addClass('current')
        .addClass('wp-menu-open')
        .removeClass('wp-not-current-submenu');
    
      if (typeof slug == 'undefined') return;
    
      // Begin activating the submenu
      var $submenu = $menu.find('a[href="' + slug + '"]');
    
      if (!$submenu || $submenu.length < 1) return;
    
      $submenu.parent('li').addClass('current');
    }
    

    A little extra

    This code can activate a wordpress menu. Any menu. However, it does not check if it should activate the menu. Do that yourself. I used the following if statement:

    // getParameterByName function provided by:
    // http://stackoverflow.com/questions/901115/how-can-i-get-query-string-values
    if (
      getParameterByName('taxonomy') == 'directory_category'
      && getParameterByName('post_type') == 'directory_post'
    )