Выделение wp_nav_menu () Класс предков без детей в структуре Nav?

30

( Примечание модератора: изначально называлось "класс предков wp_nav_menu без дочерних элементов в структуре навигации")

У меня wp_nav_menuв заголовке есть три страницы. Когда я нахожусь на одной из этих страниц, liсодержащая эту страницу в меню получает класс .current_page_item. Эти три страницы имеют шаблоны, и эти шаблоны содержат пользовательские запросы для получения всех сообщений определенного типа контента. По сути, воспринимаемые «дети» этой страницы верхнего уровня на самом деле не являются детьми, они просто относятся к типу контента, который я связал с этой страницей верхнего уровня с помощью шаблона.

Мне бы хотелось, чтобы элементы меню верхнего уровня получали 'current-ancestor'класс, когда пользователь просматривает одну страницу определенного типа, опять же, связанную с этой страницей только в пользовательском запросе в файле шаблона.

Надеюсь, что это имеет смысл - если нет, дайте мне знать, где я потерял тебя! Очень ценю любую помощь.

- Отредактировано для специфики: например, у меня есть статическая страница под названием Мастерские, которая использует шаблон. Его слизняк - мастерские . Шаблон имеет собственную функцию get_posts и цикл внутри нее, который извлекает и отображает все сообщения с пользовательским типом контента, называемым мастер- классами . Если я нажму на название одного из этих семинаров, я перейду к полному содержанию этого фрагмента контента. Структура постоянной ссылки для пользовательского типа сообщения установлена ​​на мастер-класс / имя сообщениятак что, как видит пользователь, эти фрагменты контента являются дочерними элементами страницы «Семинары», когда на самом деле все они относятся к одному типу контента, но не связаны со страницей. Это тот пробел, который мне нужно эффективно закрыть в меню, выделив пункт меню «Мастерские» при просмотре контента типа «мастерская».

Опять же, надеюсь, что это имеет смысл, я думаю, я сказал «семинар» более 20 раз в одном абзаце!

Gavin
источник
@Gavin - Можете ли вы включить еще несколько подробностей того, что вы пытаетесь достичь. Проще написать ответ в конкретных терминах, чем если бы мы попытались сделать это абстрактно. Также, если бы вы могли объяснить свою структуру URL, связанную с ними, это было бы полезно.
MikeSchinkel
1
@ Гавин - Это помогает. Таким образом, ваш пункт меню верхнего уровня представляет собой список семинаров в «Мастерских» с указанием пути, /workshops/и когда пользователь находится на странице семинара (т. Е. /workshops/example-workshop/), Вы хотите, чтобы пункт меню «Мастерские» имел current_page_itemназначенный класс , правильно?
MikeSchinkel
wp_nav_menu () представляет класс предков текущего меню
Даниэль Сакс

Ответы:

29

Есть более простое решение. Забудьте о создании страниц для каждого типа сообщений, чтобы иметь элементы навигации, поскольку, как вы узнали, WP не может распознать, что пользовательские типы, которые вы просматриваете, связаны с этой страницей.

Вместо этого создайте пользовательскую ссылку в Appearance-> Menus. Просто введите URL-адрес, который вернет ваш пользовательский тип, и присвойте ему метку, затем нажмите «Добавить в меню».

http://example.com/workshops/

или non-pretty-permalinks:

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

одно это просто создаст кнопку навигации, которая отображает все сообщения с этим пользовательским типом записи, а также добавит класс элемента текущего меню, когда вы щелкнете по этому элементу навигации, но пока не добавит класс навигации URL, отличный от этого

Затем, после того, как он будет создан, перейдите в конфигурацию для этого нового элемента и введите кусок настраиваемого типа записи в поле «Атрибут заголовка» (вы также можете использовать поле описания, но это скрыто в настройках экрана администратора). по умолчанию).

Теперь вам нужно подключить 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 в его массив классов, а затем возвращаем модифицированный массив.

Вы можете изменить это так, чтобы он просто совпадал с заголовком элемента навигации, но если по какой-то причине вы хотите присвоить заголовку элемента навигации другой заголовок, чем обычный фрагмент типа сообщения, использование поля «Атрибут заголовка» или «Описание» дает вам такую ​​гибкость.

Теперь каждый раз, когда вы просматриваете один элемент (или, возможно, даже архивные списки) с типом записи, который соответствует элементу навигационного меню, этому элементу будет присвоен класс current-menu-item класса CSS, чтобы ваше выделение работало.

Нет страниц или шаблонов страниц, необходимых ;-) 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'
        )
    );
}
соматический
источник
Вот и все! Я использую шаблоны страниц только потому, что макеты довольно сложны для этих страниц и не просто выводят список страниц, однако я все еще могу использовать предоставленный вами фильтр для проверки идентификатора страницы. Природа этой темы заключается в том, что параметры темы позволяют вам сопоставлять страницы («home» - это страница, «about» - это страница и т. Д.), Поэтому это должно работать идеально. Спасибо за (невероятно подробную) помощь!
Гэвин
current_page_parentМне пришлось удалить из элемента навигации, который был мой блог - но в противном случае это сработало. thx
pkyeck
это не работает для меня, так как $item->attr_titleвытащил название, и я написал заглавными буквами. поэтому я изменил атрибут на $item->post_nameи теперь он отлично работает для меня.
honk31
Я пытался заставить код работать для моей темы, но не могу заставить его работать. Там не будет класс применяется к моему родительскому элементу в меню, когда я нахожусь на пользовательский тип сообщения portfolio. Я использовал приведенный выше код. В чем может быть проблема?
Каспер
4

вместо использования

$ post_type = get_query_var ('post_type');

Вы можете попробовать:

$ post_type = get_post_type ();

Как правило, тип сообщения не указывается в запросе var. Это случай для 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

@ Соматик - это фантастика! Я немного изменил ваш код, чтобы он также работал для конкретной таксономии (которую я использую только для соответствующего 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;
}
tzeldin88
источник
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_name из page_for_custom_post_type-хххх и OPTION_VALUE с страницы-ID и хотите подключиться.

Возможно, вы узнали, что уже есть опция с именем page_for_posts . Если у вас есть только 1 пользовательский тип записи, вы можете установить свою страницу в /wp-admin/options-reading.php в раскрывающемся списке, и навигация установит правильную текущую страницу.

Я думаю, что ядро ​​WordPress должно расширить этот раздел выпадающим списком для каждого зарегистрированного типа поста.

Temo
источник
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 Есть идеи, что здесь произошло?
Джефф К.
О, я думаю, я вижу, что происходит. Это потому, что вы возвращаете $ классы в операторе if. Просто переместиться return $classesнаружу и после этого, ifпохоже, решить вышеуказанную ошибку.
Джефф К.
1

@ Соматик - Отличный код! Я сделал одно изменение сам. Я хотел сохранить атрибут заголовка по назначению, поэтому вместо этого я поместил слаг «Настраиваемый тип публикации» в свойствах расширенного меню «Связь» (XFN), которые можно включить в «Параметры экрана». Я модифицировал

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

и изменил его на

if ($item->xfn != '' && $item->xfn == $post_type) {
user8899
источник
0

Отличная работа Соматика.

К сожалению, я не понимаю, как вы можете перечислить ваши собственные типы сообщений на странице, как вы объясняете. Если я не использую page-portfolio.php и не добавляю его на страницу, все, что я получаю, - это страница 404.

Если я делаю так, как делает Гэвин, я немного изменил вашу функцию, чтобы также убрать «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;

}

Ваю
источник