在导航结构中突出显示wp_nav_menu()父类而没有子级吗?


30

主持人注意:最初的标题为“ wp_nav_menu在导航结构中没有子项的祖先类”)

wp_nav_menu标头中有一个页面,其中包含三个页面。当我在这些页面之一li上时,菜单中包含该页面的将获得class .current_page_item。这三个页面都有模板,并且这些模板包含自定义查询,以获取特定内容类型的所有帖子。实际上,此顶层页面的感知“孩子”实际上不是孩子,它们只是我使用模板与该顶层页面相关联的内容类型。

我希望顶级菜单项'current-ancestor'在用户浏览特定帖子类型的单个页面时再次获得一个类,该页面仅在模板文件中的自定义查询中与该页面相关联。

希望这是有道理的-如果没有,让我知道我在哪里失去了你!非常感谢您的帮助。

-针对特定内容进行了编辑: 例如,我有一个名为Workshops的静态页面,该页面正在使用模板。它的子弹是车间。模板具有一个自定义的get_posts函数并在其中循环,该模板将拉出并显示称为车间的自定义内容类型的所有帖子。如果单击这些研讨会的标题之一,那么我将被带到该内容的全部内容。自定义后类型的固定链接结构设置为车间/ postname,因此,正如用户所看到的那样,这些内容都是Workshops页面的子级,而实际上它们都是一种内容类型,但与页面无关。我需要有效地缩小菜单中的空隙,在浏览“车间”类型的内容时突出显示“车间”菜单项。

再一次,希望这是有意义的,我想我在一个段落中说了20次以上的“车间”!


@Gavin-您能提供更多您想要完成的事情的细节吗?用具体的术语来写答案比我们尝试抽象地回答要容易。 另外,如果您可以解释与这些内容有关的URL结构,则将很有帮助。
MikeSchinkel 2010年

1
@Gavin-有帮助。因此,您的顶级菜单选项是“车间”中的车间列表,其路径为/workshops/当用户在车间页面(即/workshops/example-workshop/)上时,您希望“车间”菜单项具有current_page_item分配的类,对吗?
MikeSchinkel 2010年

wp_nav_menu()公开了当前菜单的祖先类
Daniel Sachs

Answers:


29

有一个更简单的解决方案。只需为每种帖子类型创建页面就可以了,这样您就可以拥有导航项目,因为如您所知,WP无法识别正在浏览的自定义类型与该页面相关。

而是在外观->菜单中创建一个自定义链接。只需输入将返回您的自定义类型的URL并为其提供标签,然后按“添加到菜单”即可。

http://example.com/workshops/

或非漂亮的永久链接:

http://example.com/?post_type=workshops

仅此一项就可以简单地创建一个导航按钮,以显示具有该自定义帖子类型的所有帖子,并且在您单击该导航项时还将添加当前菜单项类-但它仍不会在任何导航项上添加导航类这个网址以外的网址

然后,一旦创建,就进入该新项目的配置,并在“标题属性”字段中输入自定义帖子类型的标签(您也可以使用描述字段,但该字段隐藏在管理屏幕选项中默认)。

现在,您需要挂钩nav_menu_css_class过滤器(每个导航项都会触发该过滤器),并检查所查看的内容是否属于您的自定义导航项中指示的帖子类型:

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
    $post_type = get_query_var('post_type');
    if ($item->attr_title != '' && $item->attr_title == $post_type) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}

在这种情况下,我们将检查“标题属性”字段的内容是否为空,以及它们是否与当前查询的post_type相匹配。如果是这样,我们将current-menu-item类添加到其类数组中,然后返回修改后的数组。

您可以修改它以简单地匹配导航项的标题,但是如果出于某种原因想要给导航项的标题与帖子类型的普通标题不同,则使用“标题属性”或“描述”字段可为您提供灵活性。

现在,每当您查看与导航菜单项匹配的帖子类型的单个项目(甚至可能是归档列表)时,该项目都将被赋予CSS类current-menu-item,因此突出显示将起作用。

无需页面或页面模板;-) URL查询负责获取正确的帖子。循环模板负责显示查询输出。该函数负责识别正在显示的内容并添加CSS类。

奖金

您甚至可以使用来自动执行此过程wp_update_nav_menu_item,方法是为所有帖子类型自动生成菜单项。对于此示例,您首先需要检索$menu_id要添加此项目的导航菜单的。

$types = get_post_types( array( 'exclude_from_search' => false, '_builtin' => false  ), 'objects' );
foreach ($types as $type) {
    wp_update_nav_menu_item( $menu_id, 0, array(
        'menu-item-type' => 'custom',
        'menu-item-title' => $type->labels->name,
        'menu-item-url' => get_bloginfo('url') . '/?post_type=' . $type->rewrite['slug'],
        'menu-item-attr-title' => $type->rewrite['slug'],
        'menu-item-status' => 'publish'
        )
    );
}

那是东西!我之所以使用页面模板,是因为这些页面的布局相当复杂,并且不仅仅列出这些页面,但是我仍然可以利用您提供的过滤器来检查页面ID。这个主题的本质是主题选项可以让您匹配页面(“ home”是此页面,“ about”是此页面,等等),因此应该可以完美地工作。感谢您的帮助(非常详尽)!
加文

我不得不从属于current_page_parent我的博客的导航项中删除了-否则它可以工作。thx
pkyeck 2011年

这对我来说不起作用,因为$item->attr_title拔出了TITLE,所以我用大写字母写了标题。所以我将属性更改为$item->post_name,现在对我来说效果很好。
honk31 2013年

我试图使代码适用于我的主题,但无法使其正常工作。当我使用自定义帖子类型时,菜单中没有适用于我的父项的类portfolio。我已经使用了上面的代码。可能是什么问题?
卡斯珀2014年

4

而不是使用

$ post_type = get_query_var('post_type');

您可能要尝试:

$ post_type = get_post_type();

有时,在查询变量中未设置帖子类型。默认的post_type为“ post”就是这种情况,因此,如果要突出显示从列表页面列出的帖子,则需要使用它。对于非自定义的帖子类型,get_very_var()仅返回一个空字符串。

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {
    $post_type = get_post_type();
    if ($item->attr_title != '' && $item->attr_title == $post_type) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}

2

@Somatic-太棒了!我对您的代码进行了一些修改,因此它也适用于特定的分类法(我仅将其用于相关的post_type)。这个想法是使用菜单项的Title属性来存储post_type的名称和分类法的名称,用分号分隔,然后通过函数进行分解。

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2 );
function current_type_nav_class($classes, $item) {

    # get Query Vars
    $post_type = get_query_var('post_type');  
    $taxonomy = get_query_var('taxonomy');

    # get and parse Title attribute of Menu item
    $title = $item->attr_title; // menu item Title attribute, as post_type;taxonomy
    $title_array = explode(";", $title);
    $title_posttype = $title_array[0];
    $title_taxonomy = $title_array[1];

    # add class if needed
    if ($title != '' && ($title_posttype == $post_type || $title_taxonomy == $taxonomy)) {
        array_push($classes, 'current-menu-item');
    };
    return $classes;
}

2

如果您想使用wp_list_pages,这里是我的解决方案。

将此添加到您的functions.php中

add_filter('page_css_class', 'my_page_css_class', 10, 2);
function my_page_css_class($css_class, $page){
    $post_type = get_post_type();
    if($post_type != "page"){
        $parent_page = get_option('page_for_custom_post_type-'.$post_type);
        if($page->ID == $parent_page)
            $css_class[] = 'current_page_parent';
    }
    return $css_class;
}

现在,只需在wp_options表中添加一个新行,其中option_namepage_for_custom_post_type-xxxx,option_value具有您要连接的页面ID

也许您认识到已经有一个名为page_for_posts的选项。如果您只有1种自定义帖子类型,则可以在下拉菜单中的/wp-admin/options-reading.php中设置页面,导航将正确设置current_page。

我认为wordpress核心应该为每个注册的帖子类型的下拉列表扩展此部分。


2

我决定坚持使用页面,并在导航项目上使用页面模板名称作为类。这使我避免使我对其他一些解决方案不满意的title属性变得混乱。

add_filter('nav_menu_css_class', 'mbudm_add_page_type_to_menu', 10, 2 );
//If a menu item is a page then add the template name to it as a css class 
function mbudm_add_page_type_to_menu($classes, $item) {
    if($item->object == 'page'){
        $template_name = get_post_meta( $item->object_id, '_wp_page_template', true );
        $new_class =str_replace(".php","",$template_name);
        array_push($classes, $new_class);
        return $classes;
    }   
}

我也有身体类添加到header.php

<body <?php body_class(); ?>>

最后,此解决方案需要一些额外的CSS才能将选定/活动状态应用于导航菜单项。我使用它来显示与该页面相关的分类档案和自定义帖子类型,作为此页面的子代:

/* selected states - include sub pages for anything related to products */
#nav-main li.current-menu-item a,
body.single-mbudm_product #nav-main li.lp_products a,
body.tax-mbudm_product_category #nav-main li.lp_products a,
#nav-main li.current_page_parent a{color:#c00;}

这给了我以下错误: Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76 知道这里发生了什么吗?
Jeff K.

哦,我想我知道发生了什么事。这是因为您正在if语句中返回$ classs。只需向return $classes外面移动,然后if再解决上述错误即可。
Jeff K.

1

@Somatic-很棒的代码!我自己做了一个改变。我想保留“标题属性”用于其预期目的,因此我将“自定义帖子类型”子句放置在“链接关系”(XFN)高级菜单属性中,可以在“屏幕选项”中启用该属性。我修改了

if ($item->attr_title != '' && $item->attr_title == $post_type) {

并将其更改为

if ($item->xfn != '' && $item->xfn == $post_type) {

0

做得好,Somatic。

不幸的是,我不了解如何以解释的方式在页面上列出自定义帖子类型。如果我不使用page-portfolio.php并将其添加到页面,那么我得到的只是404页。

如果我确实像Gavin一样,我已经对您的功能做了一些修改,以同样从博客页面中删除“ current_page_parent”。

add_filter('nav_menu_css_class', 'current_type_nav_class', 10, 2);
function current_type_nav_class($css_class, $item) {
$post_type = get_query_var('post_type');

if (get_post_type()=='portfolio') {
    $current_value = "current_page_parent"; 
    $css_class = array_filter($css_class, function ($element) use ($current_value) { return ($element != $current_value); } );
}

if ($item->attr_title != '' && $item->attr_title == $post_type) {       
    array_push($css_class, 'current_page_parent');
};
return $css_class;

}

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.