gavin
  • 0
Новичок

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

  • 0

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

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

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

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

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

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

Share
  1. @Gavin — Можете ли вы указать еще несколько деталей того, чего вы пытаетесь достичь. Легче написать ответ в конкретных терминах, чем если мы попытаемся сделать это в абстрактном виде. Кроме того, если бы вы могли объяснить свою структуру URL, связанную с этим, это было бы полезно.

    • 0
    • @Гэвин — это помогает. Таким образом, ваш пункт меню верхнего уровня представляет собой список семинаров в «Мастерских» с путем, /workshops/ и когда пользователь находится на странице семинара (т.е. /workshops/example-workshop/ ), вы хотите, чтобы элемент меню «Мастерские»current_page_item имел назначенный класс, правильно?

      • 0
    • wp_nav_menu() предоставляет класс предка текущего меню

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

      • 0
    • мне пришлось удалить current_page_parent из элемента навигации, который был моим блогом, но в остальном это сработало. Спасибо

      • 0
    • это не сработало для меня, так как $item->attr_title вытащил НАЗВАНИЕ, и я написал название заглавными буквами. поэтому я изменил атрибут на $item->post_name и теперь он отлично работает для меня.

      • 0
    • Я пытался заставить код работать для моей темы, но не могу заставить его работать. К моему родительскому элементу в меню не будет применен класс, когда я нахожусь в пользовательском типе сообщения portfolio . Я использовал приведенный выше код. В чем может быть проблема?

      • 0
    • Это дало мне следующую ошибку: Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76 Любая идея, что здесь произошло?

      • 0
    • О, кажется, я вижу, что происходит. Это потому, что вы возвращаете $classes в операторе if. Просто выйдите return $classes наружу и после этого, if похоже, решит вышеуказанную ошибку.

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

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

    http://example.com/workshops/
    

    или некрасивые постоянные ссылки:

    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. Если это так, мы добавляем класс текущего элемента меню в его массив классов, а затем возвращаем измененный массив.

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

    Теперь каждый раз, когда вы просматриваете один элемент (или, возможно, даже архивные списки) типа сообщения, который соответствует элементу навигационного меню, этому элементу будет присвоен текущий элемент меню класса 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'
            )
        );
    }
    
    • 0
  3. Вместо того, чтобы использовать

    $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;
    }
    
    • 0
  4. @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;
    }
    
    • 0
  5. Вот мое решение, если вы хотите работать с 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-xxxx и option_value с идентификатором страницы, которую вы хотите подключить.

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

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

    • 0
  6. Я решил придерживаться страниц и использовать имя шаблона страницы в качестве класса элемента навигации. Это позволяет мне не загромождать атрибут 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;}
    
    • 0
  7. @Somatic — Отличный код! Я сделал одно изменение сам. Я хотел сохранить атрибут заголовка по назначению, поэтому вместо этого я поместил слаг Custom Post Type в расширенные свойства меню Link Relationship (XFN), которые вы можете включить в параметрах экрана. я изменил

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

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

    if ($item->xfn != '' && $item->xfn == $post_type) {
    
    • 0
  8. Хорошая работа, Соматик.

    К сожалению, я не понимаю, как вы можете перечислить свои пользовательские типы сообщений на странице так, как вы объясняете. Если я не использую 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;
    

    }

    • 0

Оставить ответ

You must login to add an answer.