Динамічно виключайте пункти меню з wp_nav_menu


17

Я намагався шукати інформацію про те, як виключити / видалити елементи навігаційного меню зі спеціальних меню, і єдиний знайдений нами потік не мав жодних корисних для мене відповідей.

1. Передумови:

Я склав меню Dock за допомогою спеціальних меню WP (wp_nav_menu) та jqDock на своєму сайті. Оскільки jqDock потребує постійних зображень або посилань на зображення, щоб виконувати свою магію, я використовую користувальницьку ходунку, щоб вихідний HTML-код меню виглядав приблизно так:

<div id="menu-first" class="nav">
<a><img src="http://path/to/image-1.png"/></a>
<a><img src="http://path/to/image-2.png"/></a>
<a><img src="http://path/to/image-3.png"/></a>
etc...
</div>

Код моєї користувальницької ходунки:

class custom_nav_walker extends Walker_Nav_Menu 
{
    var $tree_type = array( 'post_type', 'taxonomy', 'custom' );
    var $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id' );

    function start_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        $output .= "\n$indent<ul class=\"sub-menu\">\n";
    }

    function end_lvl(&$output, $depth) {
        $indent = str_repeat("\t", $depth);
        $output .= "$indent</ul>\n";
    }

    function start_el(&$output, $item, $depth, $args) {
        global $wp_query;
        $indent = ( $depth ) ? str_repeat( "\t", $depth ) : '';

        $class_names = $value = '';

        $classes = empty( $item->classes ) ? array() : (array) $item->classes;
        $classes[] = 'menu-item-' . $item->ID;

        $class_names = join( ' ', apply_filters( 'nav_menu_css_class', array_filter( $classes ), $item, $args ) );
        $class_names = ' class="' . esc_attr( $class_names ) . '"';

        $id = apply_filters( 'nav_menu_item_id', 'menu-item-'. $item->ID, $item, $args );
        $id = strlen( $id ) ? ' id="' . esc_attr( $id ) . '"' : '';

        //$output .= $indent . '<li' . $id . $value . $class_names .'>';

        $attributes  = ! empty( $item->attr_title ) ? ' title="'  . esc_attr( $item->attr_title ) .'"' : '';
        $attributes .= ! empty( $item->target )     ? ' target="' . esc_attr( $item->target     ) .'"' : '';
        $attributes .= ! empty( $item->xfn )        ? ' rel="'    . esc_attr( $item->xfn        ) .'"' : '';
        $attributes .= ! empty( $item->url )        ? ' href="'   . esc_attr( $item->url        ) .'"' : '';

        $description  = ! empty( $item->description ) ? esc_attr( strtolower( $item->description )) : '';
        $item_title   = ! empty( $item->attr_title )  ? esc_attr( $item->attr_title ) : '';

        if ( strpos($description, ';') !== false ) {
        $description_array = explode (';', $description);
            $image_name = $description_array[0];
            $image_alt = $description_array[1];
        } else {
            $image_name = $description;
            $image_alt = $item_title;
        }

        $item_output = $args->before;
        $item_output .= '<a'. $attributes .'>';
        $item_output .= $args->link_before .'<img src="'.get_bloginfo('template_url').'/images/skin1/'.$image_name.'" alt="'.$image_alt.'" title="'.$item_title.'" />'.$args->link_after;
        $item_output .= '</a>';
        $item_output .= $args->after;

        $output .= apply_filters( 'walker_nav_menu_start_el', $item_output, $item, $depth, $args );
    }

    function end_el(&$output, $item, $depth) {
        $output .= "";
    }

}

Потім сценарій jqDock вловлює ідентифікатор меню ("menu-first") і замінює вихід wp_nav_menu на меню Dock. Вихід HTML у меню Dock змінюється на основі параметрів, вказаних під час завантаження jqDock.

2. Питання:

Я хотів би не відображати (тобто виключати) певні пункти меню відповідно до того, де користувач перебуває на сайті. Наприклад, я хотів би показати елемент «Головна» лише тоді, коли користувача немає вдома, а пункт «Випадкова публікація» лише тоді, коли він є.

3. Відхилені рішення:

а. Muliple меню: Реєстрація та створення декількох меню, а потім умовне їх виклик може працювати; однак, я не вважаю це ідеальним чи чистим рішенням з багатьох причин. Крім того, кілька меню нелегко в обслуговуванні або оновлення.

б. Пошук і заміна Regex: Це може змусити мене змінювати параметр голки щоразу, коли я змінюю параметри jqDock, оскільки вихід HTML змінюється.

c. Властивість 'display' CSS: приховування елементів через властивість відображення CSS працює, але оскільки його потрібно застосувати до виводу меню jqDock, це впливає на візуальне відображення меню.

4. Невдалі рішення:

а. Фільтр до wp_nav_menu_items : Я спробував зловити змінну '$ items' (рядок) і призначити їй різні значення за допомогою умовних тегів із наступним кодом:

function userf_dynamic_nav_menu ($items) {
    $items_array_home = explode('<a', $items);
    $items_array_nothome = $items_array_home;

    unset($items_array_home[1]);
    unset($items_array_nothome[2]);

    $items_home = implode('<a', $items_array_home);
    $items_nothome = implode('<a', $items_array_nothome);

    if ( is_home() ) {
        $items = $items_home;
    } else {
        $items = $items_nothome;
    }
    return $items;
}
add_filter('wp_nav_menu_first_items', 'userf_dynamic_nav_menu');

Це працює лише частково, оскільки пункти меню дійсно змінюються, але умовні теги ігноруються. Я думаю, це має сенс через момент, коли застосовується фільтр.

б. Функція користувальницького навігаційного меню : Я спробував створити свою власну функцію меню наві, щоб можна було додати аргумент виключення до масиву $ за замовчуванням та використовувати цей трохи змінений код wp_list_pagesдля заповнення додаткового аргументу:

$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );

Будь-які ідеї?


Чи можете ви показати нам свій власний дитячий клас ходунків?
соулєсеках

Привіт Souleseekah, я щойно додав його до свого початкового поста. Спасибі!
Марвентус

Я думав також передавати excludeаргумент, але, всупереч wp_list_pagesі багатьом іншим функціям WP, wp_nav_menuне включає жодного. Так що навіть якщо я вказую його під час виклику меню або в прогулянці, він не потрапляє всередину wp_nav_menu, чи не так?
Марвентус

Вибачте, не думав прямо, коли написав це, видалив негайно.
соулсееках

Не хвилюйтеся з цього приводу!
Марвентус

Відповіді:


26

Спосіб 1

Ви можете додати конструктор у свій власний Walker, щоб зберігати додаткові аргументи виключення, наприклад:

class custom_nav_walker extends Walker_Nav_Menu {
    function __construct( $exclude = null ) {
        $this->exclude = $exclude;
    }

    function skip( $item ) {
        return in_array($item->ID, (array)$this->exclude);
        // or
        return in_array($item->title, (array)$this->exclude);
        // etc.
    }

    // ...inside start_el, end_el
    if ( $this->skip( $item ) ) return;
}

Або киньте конструктор і встановіть його $excludeвластивість, перш ніж передавати його як ходунку, щоб wp_nav_menu()так.

$my_custom_nav_walker = new custom_nav_walker;
$my_custom_nav_walker->exclude = array( ... );

Залежно від того, що ви виключаєте, надайте правильну форму для виключення.

Спосіб 2

Ось як би ви це зробили, зачепившись у wp_get_nav_menu_itemsфільтр.

function wpse31748_exclude_menu_items( $items, $menu, $args ) {
    // Iterate over the items to search and destroy
    foreach ( $items as $key => $item ) {
        if ( $item->object_id == 168 ) unset( $items[$key] );
    }

    return $items;
}

add_filter( 'wp_get_nav_menu_items', 'wpse31748_exclude_menu_items', null, 3 );

Примітка: object_idце об'єкт, на який вказує меню, а IDID - це різні.

Розкажи мені свої думки.


Спасибі! Це може спрацювати. Я спробую і дам вам знати.
Марвентус

Я спробував підхід конструктора і, незалежно від того, що я намагаюся, я продовжую отримувати помилку "Неправильний тип даних для другого аргументу" для in_arrayфункції. Я щось роблю не так?
Марвентус

$excludeВластивість має бути масивом. Тому переконайтеся, що ви передаєте масив у конструктор або дивіться оновлений код у моїй відповіді. Зокрема, typecast для $this->exclude, на випадок, якщо масив не буде переданий.
соулсееках

Вибачте з цього приводу: у мене була помилка друку на моїй функції. Я просто спробував $exclude = array ('4', '7');і використовувати слизи, але це не впливає на вихід ходунка. Я спробую другий підхід і дам вам знати.
Марвентус

Ні, це теж не спрацювало. Я думаю, що я загинув від мозку, намагаючись зрозуміти це, так що це може вплинути на мою ... "виставу", :-)
Marventus

0

чи допомагає це?

$exclude_array = ( $args->exclude ) ? explode(',', $args->exclude) : array();
$args->exclude = implode( ',', apply_filters('wp_nav_menu_excludes', $exclude_array) );

як приклад

< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>

Привіт Saq, я забув згадати, що одне з рішень, яке не працювало, було створити власну функцію nav_menu та додати цей код як додатковий аргумент до значень за замовчуванням функції. На жаль, це не вийшло. Я не намагався включити його в ходок, але не думаю, що це спрацювало б з тієї ж причини, про яку я згадував вище, головним чином, що wp_nav_menuаргумент не має аргументу "виключити", але я можу помилитися.
Марвентус

Я оновив свій початковий пост, щоб включити це для наочності.
Марвентус

Що робити, якщо ви не користуєтеся користувальницьким ходунком, натомість використовуєте звичайний nav_menu та витягуєте елементи з wp_get_nav_menu_items () із власним зображенням
saq

Це взагалі було б хорошим рішенням, але в цьому конкретному випадку wp_get_nav_menu_itemsне витягуватимуть зображення, оскільки теги img не зберігаються у фактичному користувальницькому меню (лише їхні імена файлів містяться у полі опису, наприклад, "image1.png" ). Спеціальний ходунок - це те, що дозволяє мені вставляти теги img у вихідний пункт меню.
Марвентус
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.