Статьи

Настройка активных элементов навигации, когда WordPress не поддерживает

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


Решение простое. Мы написали несколько строк кода, которые создают страницу настроек, где вы будете указывать элементы меню, которые нужно выделить для каждого пользовательского типа контента. Следующим шагом является переопределение стандартного класса Walker для навигации WordPress, чтобы при необходимости создать класс выделения. Просто и эффективно.


Создайте новый файл с именем navigation.php и включите его из файла functions.php .

1
include_once ( get_template_directory() . ‘/navigation.php’ );

Теперь мы готовы начать с реального кода.


Сначала зарегистрируйте новую группу настроек, чтобы создать новую страницу настроек wp-admin. В вашем пустом файле navigation.php вставьте следующий код.

1
2
3
4
add_action( ‘admin_init’, ‘ns_register_navigation_settings’ );
function ns_register_navigation_settings() {
    register_setting( ‘ns_navigation’, ‘ns_navigation_predefined_values’ );
}

Затем создайте новый элемент меню для доступа к нашей новой странице настроек в wp-admin.

1
2
3
4
add_action(‘admin_menu’, ‘ns_navigation_options’);
function ns_navigation_options() {
    add_submenu_page( ‘themes.php’, ‘Predefined Menus’, ‘Predefined Menus’, ‘edit_theme_options’, ‘menu-defaults’, ‘menu_defaults_page’ );
}

Функция menu_defaults_page () печатает страницу настроек внутри WordPress Admin. Перед печатью входных данных формы get_option (‘ms_navigation_predefined_values’) запрашивает значения, хранящиеся в базе данных, и сохраняет их в $ ns_navigation_predefined_values в виде массива.

В этом случае еще ничего не сохраняется, поэтому значения пусты. Использование settings_field () необходимо для печати связанных и обязательных скрытых полей, а также для обеспечения безопасности. Остальная часть кода печатает входные элементы, используя значения в $ ns_navigation_predefined_values .

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
function menu_defaults_page() {
    ?>
    <div class=»wrap»>
        <div class=»icon32″ id=»icon-options-general»><br></div>
        <h2><?php _e(‘Predefined menus for custom posts and taxonomies’);
        <form method=»post» action=»options.php»>
     
    <?php
    $ns_navigation_predefined_values = get_option(‘ns_navigation_predefined_values’);
    settings_fields( ‘ns_navigation’ );
    ?>
     
    <h3 class=»title»><?php _e(‘Pages’);
    <table class=»form-table» cellpadding=»0″ cellspacing=»0″>
     
    <?php
    foreach (ns_get_post_types() as $k => $v) {
    ?>
        <tr valign=»top»>
        <th scope=»row»><?php echo $v ?></th>
        <td>
            <?php
            $current_dropdown_value = get_option(‘ns_navigation_predefined_values’);
            wp_dropdown_pages( array( ‘name’ => ‘ns_navigation_predefined_values[‘ . $k . ‘]’, ‘echo’ => 1, ‘show_option_none’ => __( ‘&mdash; Select &mdash;’ ), ‘option_none_value’ => ‘0’, ‘selected’ => $current_dropdown_value[$k] ) );
            ?>
        </td>
        </tr>
    <?php
    }
    ?>
     
    </table>
    <?php if (ns_get_taxonomies()): ?>
    <br /><hr />
    <h3 class=»title»><?php _e(‘Categories’) ?></h3>
    <table class=»form-table» cellpadding=»0″ cellspacing=»0″>
     
    <?php
    foreach (ns_get_taxonomies() as $k => $v) {
    ?>
        <tr valign=»top»>
        <th scope=»row»><?php echo $v ?></th>
        <td>
            <?php
            $current_dropdown_value = get_option(‘ns_navigation_predefined_values’);
            wp_dropdown_pages( array( ‘name’ => ‘ns_navigation_predefined_values[‘ . $k . ‘]’, ‘echo’ => 1, ‘show_option_none’ => __( ‘&mdash; Select &mdash;’ ), ‘option_none_value’ => ‘0’, ‘selected’ => $current_dropdown_value[$k] ) );
            ?>
        </td>
        </tr>
    <?php
    }
    ?>
     
    </table>
    <?php endif;
    <p class=»submit»>
    <input type=»submit» class=»button-primary» value=»<?php _e(‘Update’); ?>» />
    </p>
    </form>
    </div>
     
    <?php
}

Страница настроек теперь создана, но нам все еще нужно определить функции, вызываемые в приведенном выше коде. Вставьте следующий код.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
function ns_get_post_types() {
    $post_types = get_post_types(array(‘public’ => true, ‘_builtin’ => false), ‘objects’);
    foreach ( $post_types as $k => $v ) {
        $ns_registered_post_types->$k = $v->labels->name;
    }
    return $ns_registered_post_types;
}
 
function ns_get_taxonomies() {
    $taxonomies_types = get_taxonomies(array(‘public’ => true, ‘_builtin’ => false), ‘objects’);
    foreach ( $taxonomies_types as $k => $v ) {
        $ns_registered_taxonomies_types->$k = $v->labels->name;
    }
    return $ns_registered_taxonomies_types;
}

Функция ns_get_post_types извлекает все доступные типы записей и выводит только те, которые являются пользовательскими. Функция ns_get_taxonomies делает то же самое, но, конечно, для таксономий.


У нас есть объявленная страница настроек и объявлено несколько пользовательских постов и таксономий. Следующий шаг — заставить его работать в теме, которую мы используем. В целях тестирования мы работаем с темой WordPress Twenty Eleven, но этот код должен работать с любой темой.

Давайте изменим класс WordPress Menu Walker, чтобы переопределить вывод по умолчанию. Мы читаем наши настройки и используем значения, чтобы добавить новый класс current_page_item ns_current_page_item на соответствующей странице, когда мы отображаем пользовательский цикл записи или связанную с ним отдельную страницу.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
class NS_Walker_Nav_Menu extends Walker_Nav_Menu {
    function start_el(&$output, $item, $depth, $args) {
        global $wp_query;
        $indent = ( $depth ) ?
         
        if ( isset( $args->current_nav_element ) ) {
            $current_nav_element = $args->current_nav_element;
        }
             
        $class_names = $value = »;
 
        $classes = empty( $item->classes ) ?
        $classes[] = ‘menu-item-‘ .
        $classes[] = ‘page-gui-‘ .
 
        $class_names = join( ‘ ‘, apply_filters( ‘nav_menu_css_class’, array_filter( $classes ), $item, $args ) );
        $class_names = ‘ class=»‘ . esc_attr( $class_names );
         
        if ($current_nav_element == $item->object_id) {
            $class_names.= ‘ current_page_item ns_current_page_item’;
        }
         
        $class_names.= ‘»‘;
         
        $id = apply_filters( ‘nav_menu_item_id’, ‘menu-item-‘. $item->ID, $item, $args );
        $id = strlen( $id ) ?
 
        $output .= $indent .
 
        $attributes = !
        $attributes .= !
        $attributes .= !
        $attributes .= !
 
        $item_output = $args->before;
        $item_output .= ‘<a’.
        $item_output .= $args->link_before .
        $item_output .= ‘</a>’;
        $item_output .= $args->after;
 
        $output .= apply_filters( ‘walker_nav_menu_start_el’, $item_output, $item, $depth, $args );
    }
}

Новый класс NS_Walker_Nav_Menu считывает значения навигации, сохраненные в массиве, перед печатью. В этом случае используется управляющая структура if() для оценки соответствия текущего элемента навигации предыдущему сохраненному значению для страницы, которую WordPress печатает в данный момент. Если условие истинно, то классы «current_page_item» и «ns_current_page_item» добавляются к существующим классам, хранящимся в переменной $ class_names .

Тогда нам нужно использовать еще одну пользовательскую функцию. Когда мы его вызываем, эта функция напечатает меню в теме.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
function ns_wp_nav_menu($args) {
    global $post;
    $ns_walker = new NS_Walker_Nav_Menu();
    $args[‘walker’] = $ns_walker;
     
    $ns_navigation_predefined_values = get_option(‘ns_navigation_predefined_values’);
 
    $custom_post_type = get_post_type($post);
    $available_post_types = (array) ns_get_post_types();
    $taxonomy_type = get_queried_object();
    $taxonomy_type = $taxonomy_type->taxonomy;
    $available_taxonomy_types = (array) ns_get_taxonomies();
     
    if (is_singular($custom_post_type) && array_key_exists($custom_post_type, $available_post_types)) {
        $args[‘current_nav_element’] = (function_exists(‘icl_object_id’)) ?
    } elseif (is_tax($taxonomy_type) && array_key_exists($taxonomy_type, $available_taxonomy_types)) {
        $args[‘current_nav_element’] = (function_exists(‘icl_object_id’)) ?
    } else {
        unset($args[‘current_nav_element’]);
    }
     
    wp_nav_menu($args);
}

Ns_wp_nav_menu () создан для упрощения использования встроенной функции wp_nav_menu (). Первый шаг — заставить функцию загружать новый класс Walker с помощью $ ns_walker = new NS_Walker_Nav_Menu () и добавлять в массив параметров с помощью $ args [‘walker’] = $ ns_walker; ,

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

Сначала оцените, находится ли страница в отдельном представлении, с помощью is_singular () и получите из базы данных соответствующее сохраненное значение. Второй возможный выбор для оценки — это если текущая страница является запросом таксономии с использованием is_tax () . Если нет, то выбирать нечего, и код освобождает текущий элемент навигации, используя unset ($ args [‘current_nav_element’])


Откройте файл header.php в своей теме Twenty Eleven, найдите функцию wp_nav_menu () примерно в строке 118 и замените ее на ns_wp_nav_menu, сохраняя те же параметры и ничего больше, потому что новая функция по умолчанию обрабатывает остальные обязательные параметры. Новый код должен выглядеть так:

1
<?php ns_wp_nav_menu( array( ‘container_class’ => », ‘theme_location’ => ‘primary’ ); ?>

Эта функция использует те же аргументы, что и стандартная функция wp_nav_menu, поэтому не стесняйтесь настраивать столько, сколько вам нужно или нужно.

Откройте также style.css и замените код в строке 617 на:

1
2
3
    #access .current-menu-item > a, #access .current-menu- ancestor > a, #access .current_page_item > a, #access .current_page_ancestor > a, #access .ns_current_page_item > a {
    font-weight: bold;
}

У вас есть пользовательские записи, пользовательские таксономии, и вы создали новые страницы с шаблонами для отображения этих пользовательских циклов. Вы, вероятно, создали новое меню в вашем wp-admin и также добавили эти страницы. Откройте предварительно заданную страницу настроек меню, расположенную в разделе «Внешний вид», и установите выбранные страницы для каждой пользовательской публикации и таксономии, которые вы создали.

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


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

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

Я призываю вас продолжать исследовать класс навигации Уокера. Там скрыто множество возможностей, на которые можно делать ставки.