Tell me more ×
WordPress Answers is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

Is there a way (besides adding a Custom Link) to add a custom post type archive to a menu in WordPress? If it's added using a custom link (e.g. /cpt-archive-slug/), WordPress does not apply classes like current-menu-item to the list element, which presents challenges when styling the menu.

If the custom link contains the entire URL (e.g. http://site.com/cpt-archive-slug/), those classes are added. However, that's probably not a 'best practice'.

share|improve this question

7 Answers

up vote 5 down vote accepted

your best opption is custom link with full url as Custom post types archives are different form taxonomy based archives (categories,tags,any custom taxonomy) and date based archives which have there own archive slug.

share|improve this answer

I know this is old but I have this problem too and I found a rather clean way to handle it is to use a custom menu walker

class KB_Custom_Menu_Walker extends Walker_Nav_Menu {

  protected static $custom_post_types = array();

  public function start_el(&$output, $item, $depth=0, $args=array(), $id=0) {
    if (isset( self::$custom_post_types[ $item->url ] )) {
      $item->url = get_post_type_archive_link( self::$custom_post_types[$item->url] );
    }
    parent::start_el($output, $item, $depth, $args, $id);
  }

  public static function custom_post_types($type=null) {
    if ($type) {
      self::$custom_post_types[ '#post_type_'.$type ] = $type;
    }
    return self::$custom_post_types;
  }
}

Having a custom link menu item with URL of #post_type_album, you can use it like this:

# Where you defined your custom post type (could be anywhere anyway)
KB_Custom_Menu_Walker::custom_post_types('album');

# And display the menu
wp_nav_menu(array(
  'theme_location' => 'primary-nav',
  'walker' => new KB_Custom_Menu_Walker(),
));

Note: This assume that your post type's slug and name are the same.

share|improve this answer
+1 for the late quality answer. This is good for the community! – Brian Fegter Sep 23 '12 at 3:13

You can create a Page and then apply a custom archive template to it. I create and use archive-{post-type}.php fo the template name just like you would for the default archive, I just manually apply it to the Page.

If you do this, I'd recommend setting your CPT to has_archive='false' to avoid permalink collisions, regardless just make sure your Page has a different permalink slug than your CPT archive slug is set to.

share|improve this answer

I ran into the same exact problem, and found this solution:

// $menu is the menu as a string 
if ( check if youa re on the page you are looking for )
    $menu = str_replace( '<li class="menu-item"><a href="http://bla.com/bloop/">', '<li class="current-menu-item menu-item"><a href="http://bla.com/bloop/">'>, $menu );  

Source: http://www.wptavern.com/forum/plugins-hacks/2169-current-page-custom-post-type-archive.html

share|improve this answer

I have expanded a bit on tungd's answer to provide more genericity with that approach. This implementation allows adding arbitrary mappings between menu 'macros' and internal Wordpress URLs that only the backend knows about.

I've also decided to use ! as the prefix for these macros to avoid them clashing with named anchors - this includes an overhead to strip off the 'http://' from the link URL (as Wordpress will attempt to normalise these weird links). If that implementation bothers you, you can always remove the preg_replace() call and use # as your link prefix as before.

class Extendable_Menu_Walker extends Walker_Nav_Menu
{
    protected static $custom_urls = array();

    public static function setupUrls()
    {
        // calls to self::mapPostType($postTypeName) and 
        // self::createMapping($wildcard, $url) go here...
    }

    public function start_el(&$output, $item, $depth=0, $args=array(), $id=0)
    {
        $url = preg_replace('@^https?://@', '', $item->url);
        if (isset( self::$custom_urls[ $url ] )) {
            $item->url = self::$custom_urls[ $url ];
        }
        parent::start_el($output, $item, $depth, $args, $id);
    }

    public static function createMapping($urlKey, $realUrl)
    {
        self::$custom_urls['!' . $urlKey] = $realUrl;
    }

    public static function mapPostType($type)
    {
        self::createMapping('post_type_' . $type, get_post_type_archive_link($type));
    }
}

add_action('init', array('Extendable_Menu_Walker', 'setupUrls'));
share|improve this answer

I think I'd have to create a new "parent" post-type, so the custom-post-type I want to show becomes a "child", and that parent WILL be listed in the menu.

This should be an option. Creating a dummy parent just for getting it listed in the menu is too much work.

I'd like a way to do it from the template, or functions, so I don't have to do it in each menu settings for each site in my multisite installation.

share|improve this answer
1  
I meant, the custom-post-type posts I wanted to show in the menu will be the only sub-type of the new-created parent, and I hope it gets listed under the parent in the menu settings. – sergio Sep 27 '11 at 15:06

I Found this answer when searching for a similar issue. I just copied the code into my finctions.php file and it worked right out of the box :) hope it helps!

Dynamic navigation for custom post type (pages)

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.