Класс current-menu-item для родительской страницы пользовательского типа записи

4 нояб. 2013 г., 19:48:02
Просмотры: 16K
Голосов: 1

У меня возникла проблема с меню и пользовательским типом записей.

У меня есть пользовательский тип записей "services" (услуги). Я создал новую страницу для него под названием "Услуги". На этой странице я отображаю список всех записей этого типа. Класс current-menu-item работает как положено.

Но проблема возникает, когда я нажимаю на одну из услуг и перехожу по адресу mysite.com/services/service-1 - класс current-menu-item у страницы "Услуги" в меню исчезает. Мне нужно показать, что текущая запись является дочерней для страницы "Услуги".

Все пункты меню имеют одинаковую HTML-структуру:

<li id="menu-item-23" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-23"><a href="http://localhost/wordpress/sluzby/">Услуги</a></li>

Нет CSS-класса, который я мог бы использовать для стилизации этой ссылки как родительской. Что-то вроде current-menu-parent или подобного. Как я могу решить эту проблему? Спасибо.

2
Комментарии

это можно сделать, вероятно, через jQuery... все эти записи типа Service действительно в меню?

GhostToast GhostToast
4 нояб. 2013 г. 20:00:52

@GhostToast на самом деле в меню только один пункт под названием "Услуги". При клике открывается страница "Услуги", на которой в цикле выводятся все записи услуг.

Richard Mišenčík Richard Mišenčík
4 нояб. 2013 г. 21:27:15
Все ответы на вопрос 4
9

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

class Plugin_Name {
    private $parent = 'services'; // в идеале это должно быть настройкой в вашем плагине, а не жестко заданной переменной, на случай изменения slug страницы

    function __construct() {
        // Добавляем классы к 'parent'
        add_filter( 'nav_menu_css_class', array( &$this, 'nav_parent_class' ), 10, 2 );
    }

    function nav_parent_class( $classes, $item ) {

        if ( $this->nicename == get_post_type() && ! is_admin() ) {
            global $wpdb;

            // удаляем любые активные классы из навигации (блог обычно получает класс currept_page_parent на страницах/записях CPT)
            $classes = array_filter($classes, ($class == 'current_page_item' || $class == 'current_page_parent' || $class == 'current_page_ancestor'  || $class == 'current-menu-item' ? false : true ));

            // получаем информацию о странице
            // - нам действительно нужен только post_name, чтобы сравнить его с slug типа записи
            $page = get_page_by_title( $item->title, OBJECT, 'page' );

            // проверяем, совпадает ли slug с post_name
            if( $page->post_name == $this->parent ) {
                $classes[] = 'current_page_parent';
            }

        }

        return $classes;
    }
}

По вашему запросу, вариант без плагина. Я не тестировал этот код на ошибки, просто адаптировал его из класса выше, но он должен хотя бы направить вас в правильном направлении:

add_filter( 'nav_menu_css_class', 'nav_parent_class', 10, 2 );

function nav_parent_class( $classes, $item ) {
    $cpt_name = 'service';
    $parent_slug = 'services';

    if ( $cpt_name == get_post_type() && ! is_admin() ) {
        global $wpdb;

        // удаляем любые активные классы из навигации (блог обычно получает класс currept_page_parent на страницах/записях CPT)
        $classes = array_filter($classes, ($class == 'current_page_item' || $class == 'current_page_parent' || $class == 'current_page_ancestor'  || $class == 'current-menu-item' ? false : true ));

        // получаем информацию о странице
        // - нам действительно нужен только post_name, чтобы сравнить его с slug типа записи
        $page = get_page_by_title( $item->title, OBJECT, 'page' );

        // проверяем, совпадает ли slug с post_name
        if( $page->post_name == $parent_slug ) {
            $classes[] = 'current_page_parent';
        }

    }

    return $classes;
}
4 нояб. 2013 г. 20:05:44
Комментарии

Как это можно сделать без использования плагина, я хотел бы добавить это в свой functions.php, но, предполагаю, код нужно будет модифицировать.

Richard Mišenčík Richard Mišenčík
4 нояб. 2013 г. 21:27:34

Я обновил свой ответ, добавив способ реализации, если ваш CPT не создан как плагин.

Joey Yax Joey Yax
4 нояб. 2013 г. 22:44:52

У меня это почему-то не работает. Я изменил переменные, но все равно. Если я правильно понял, код проверяет название записи и сравнивает его со слагом? Я думаю, это не сработает, так как мой CPT называется services. Но я использую rewrite на "sluzby", что в моем языке означает services. Однако мои записи услуг не содержат этот слаг, то есть услуга может называться Webdesign, а не Service Webdesign.

Страница, которая используется для отображения моих записей услуг, находится по адресу localhost/wordpress/sluzby. А отдельные записи доступны по localhost/wordpress/sluzby/name-of-post.

Richard Mišenčík Richard Mišenčík
4 нояб. 2013 г. 22:54:59

Он проверяет две вещи: 1) Является ли просматриваемая запись вашим пользовательским типом записи ($cpt_name) и 2) ищет элемент навигации с ярлыком (slug), равным $parent_slug. Если оба условия совпадают, он добавляет класс current_page_parent к этому элементу навигации.

Joey Yax Joey Yax
5 нояб. 2013 г. 02:01:26

Не уверен, что я делаю что-то не так, но это до сих пор не работает. Вот мой текущий код:

function nav_parent_class( $classes, $item ) { $cpt_name = 'services'; $parent_slug = 'sluzby';

if ...

return $classes;

}

Итак, мой пользовательский тип записи называется "services", а URL страницы услуг - localhost/wordpress/sluzby. Затем каждая отдельная услуга находится по адресу localhost/wordpress/sluzby/name-of-service.

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

Richard Mišenčík Richard Mišenčík
5 нояб. 2013 г. 13:19:51

Странная вещь: теперь, когда я закомментировал строку $classes = array_filter..., всё заработало. Что действительно странно.

Richard Mišenčík Richard Mišenčík
6 нояб. 2013 г. 14:23:56

Рад, что у вас получилось! Если эта строка закомментирована, это нормально. Я беспокоюсь, что из-за этого (если у вас есть блог в навигации) может быть небольшой шанс одновременного подсвечивания блога при просмотре отдельной страницы вашего CPT.

Joey Yax Joey Yax
8 нояб. 2013 г. 04:05:03

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

Richard Mišenčík Richard Mišenčík
9 нояб. 2013 г. 14:44:24

Обратите внимание, что это работает только если пункт навигации имеет то же название, что и страница. Помните, что пользователи могут установить в навигации другое название, отличное от заголовка страницы.

adamtomat adamtomat
26 июн. 2014 г. 11:06:10
Показать остальные 4 комментариев
1

Этот код добавляет класс 'current-menu-item' к родительскому пункту меню вашего дочернего CPT (пользовательского типа записи) или пользовательской таксономии, или стандартной записи, если у вас нет вложенной структуры меню в админ-панели — только если у вас есть меню 'уровня 0'. Например, если у вас есть страница "Продукты", которая отображает сетку товаров, и вы переходите на страницу отдельного продукта — WordPress не увидит родительский пункт меню. Код ниже исправляет это:

function additional_active_item_classes( $classes = array(), $menu_item = false ) {
    // пользовательская таксономия
    if ( $menu_item->title == 'Страница пользовательской таксономии' && is_tax('custom_tax') ) {
        $classes[] = 'current-menu-item';
    }
    // одиночная запись пользовательского типа
    if ( $menu_item->title == 'Страница пользовательского типа записи' && is_singular('products') ) {
        $classes[] = 'current-menu-item';
    }
    // одиночная запись блога
    if ( $menu_item->title == 'Страница блога' && is_singular('post') ) {
        $classes[] = 'current-menu-item';
    }
    return $classes;
}
add_filter( 'nav_menu_css_class', 'additional_active_item_classes', 10, 2 );
5 апр. 2019 г. 13:10:59
Комментарии

Привет, Марек, хотя твой код может быть правильным, не мог бы ты немного подробнее объяснить, почему это ответ и как это работает, чтобы другие люди могли научиться у тебя?

Krzysiek Dróżdż Krzysiek Dróżdż
5 апр. 2019 г. 13:40:12
0

Финальный код:

function nav_parent_class($classes, $item) {
    $cpt_name = 'services'; // название типа записи
    $parent_slug = 'sluzby'; // ярлык родительской страницы

    if ($cpt_name == get_post_type() && !is_admin()) {
        global $wpdb;

        // получаем информацию о странице (нам нужен только post_name для сравнения с ярлыком типа записи)
        $page = get_page_by_title($item->title, OBJECT, 'page');

        // проверяем совпадение ярлыка с post_name
        if( $page->post_name == $parent_slug ) {
            $classes[] = 'current_page_parent';
        }

    }

    return $classes;
}

add_filter('nav_menu_css_class', 'nav_parent_class', 10, 2);
6 нояб. 2013 г. 17:48:32
7

Обычно к родительским элементам в навигации добавляется класс .current-menu-ancestor.

Если его там нет, ознакомьтесь с этой статьей: Как добавить класс 'current-menu-ancestor' для меню пользовательского типа записи в WordPress?

5 нояб. 2013 г. 12:24:20
Комментарии

У меня не работает. Может ли это быть из-за того, что я использую rewrite и поэтому имею разные названия для типа записи и самой страницы?

Richard Mišenčík Richard Mišenčík
5 нояб. 2013 г. 13:24:02

Вы используете кастомное меню?

Joe Joe
5 нояб. 2013 г. 14:06:42

Вот код, который я использую: wp_nav_menu(array( 'container' => false, 'container_class' => '', 'menu' => '', 'theme_location' => 'main-nav', 'items_wrap' => '

', 'fallback_cb' => 'rm_main_nav_fallback' ));

Richard Mišenčík Richard Mišenčík
5 нояб. 2013 г. 14:29:02

И у вас есть меню, определенное в админке в разделе Внешний вид->Меню. Если это так, и меню по-прежнему не предоставляет класс. Я с такой проблемой не сталкивался.

Joe Joe
5 нояб. 2013 г. 14:40:32

Да, я создал меню со всеми ссылками. Думаю, проблема может быть в rewrite, так как название моего CPT - services, но URL для этой страницы - wordpress/sluzby. Я действительно в замешательстве. Есть ли что-то еще, что я могу попробовать?

Richard Mišenčík Richard Mišenčík
5 нояб. 2013 г. 14:50:58

Хммм, если вы считаете, что проблема может быть связана с rewrite, вы пробовали не перезаписывать CPT? Просто чтобы подтвердить, что дочерние страницы установлены как 'Подменю' в меню

Joe Joe
5 нояб. 2013 г. 15:03:03

Я только что попробовал, не сработало. Но я попробовал что-то другое, базовый пример из wp codex для этой функции. Вот он:

function rm_custom_services_class($classes, $item) {

 if(is_single() && $item->title == "Služby") {
         $classes[] = "current_page_parent";
 }

 return $classes;

}

Вот и всё, и это работает. Мне просто интересно, можно ли заменить $item->title = "Služby" на что-то вроде $item->slug == 'sluzby'. На случай, если название страницы изменится.

Richard Mišenčík Richard Mišenčík
5 нояб. 2013 г. 15:15:35
Показать остальные 2 комментариев