Excluir dinamicamente itens de menu do wp_nav_menu

17

Tentei procurar informações sobre como excluir / remover itens de menu de navegação de menus personalizados, e o único segmento que encontrei não tinha respostas úteis para mim.

1. Fundo:

Eu montei um menu do Dock usando os menus personalizados do WP (wp_nav_menu) e o jqDock no meu site. Como o jqDock precisa de imagens contínuas ou links de imagens para fazer sua mágica, estou usando um andador personalizado para que a saída HTML do menu de navegação fique assim:

<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>

O código para meu andador personalizado é:

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 .= "";
    }

}

O script jqDock captura o ID do menu ('menu-first') e substitui a saída wp_nav_menu pelos menus do Dock. A saída HTML do menu Dock é alterada com base nas opções especificadas ao carregar o jqDock.

2. A questão:

Gostaria de não exibir (ou seja, excluir) determinados itens do menu de acordo com o local do usuário. Por exemplo, eu gostaria de mostrar apenas o item Inicial quando o usuário não estiver na Página inicial e o item Postagem aleatória apenas quando ele estiver.

3. Soluções descartadas:

uma. Menus múltiplos : registrar e criar vários menus e depois chamá-los condicionalmente pode funcionar; no entanto, não acho que essa seja uma solução ideal nem limpa por muitas razões. Além disso, vários menus não são fáceis de manter ou atualizar.

b. Pesquisa e substituição de Regex: Isso pode me forçar a alterar o parâmetro da agulha sempre que altero as opções do jqDock porque a saída HTML é modificada.

c. Propriedade 'display' do CSS: ocultar os itens através da propriedade de exibição CSS funciona, mas como ele deve ser aplicado à saída do menu jqDock, afeta a renderização visual do menu.

4. Soluções com falha:

uma. Filtre para wp_nav_menu_items : tentei pegar a variável '$ items' (string) e atribuir valores diferentes por meio de tags condicionais com o seguinte código:

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');

Isso funciona apenas parcialmente, porque os itens de menu são alterados, mas as tags condicionais são ignoradas. Eu acho que isso faz sentido por causa do momento em que o filtro é aplicado.

b. Função de menu de navegação personalizada : tentei criar minha própria função de menu de navegação personalizada para poder adicionar um argumento de exclusão à matriz $ defaults e usar esse código ligeiramente modificado wp_list_pagespara preencher o argumento adicional:

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

Alguma ideia?

Marventus
fonte
Você pode nos mostrar sua classe infantil de andador personalizado?
soulseekah
Olá Souleseekah, acabei de adicioná-lo ao meu post original. Obrigado!
Marventus
Também pensei em passar um excludeargumento, mas, ao contrário de wp_list_pagesmuitas outras funções do WP, wp_nav_menunão inclui um. Portanto, mesmo se eu especificar um ao chamar o menu ou o andador, ele não será recolhido por dentro wp_nav_menu, não é?
Marventus
Desculpe, não estava pensando direito quando escrevi isso, excluído imediatamente.
soulseekah
Não se preocupe!
Marventus

Respostas:

26

Método 1

Você pode adicionar um construtor ao seu Walker personalizado para armazenar alguns argumentos de exclusão adicionais, como:

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;
}

Ou largue o construtor e defina sua $excludepropriedade antes de passá-lo como andador para wp_nav_menu()assim:

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

Dependendo do que você está excluindo, forneça o formulário correto para a exclusão.

Método 2

É assim que você faria isso conectando o wp_get_nav_menu_itemsfiltro.

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 );

Nota: object_idé o objeto para o qual o menu aponta, enquanto IDo ID do menu é diferente.

Deixe-me saber a sua opinião.

soulseekah
fonte
Obrigado! Isso pode funcionar. Vou tentar e informá-lo.
Marventus
Tentei a abordagem do construtor e, não importa o que tente, continuo recebendo um erro "Tipo de dados errado para o segundo argumento" para a in_arrayfunção. Estou fazendo algo errado?
Marventus
A $excludepropriedade deve ser uma matriz. Portanto, verifique se está passando uma matriz para o construtor ou observe o código atualizado na minha resposta. Especificamente, a conversão de tipo para $this->exclude, caso uma matriz não seja passada.
soulseekah
Desculpe por isso: tive um erro de digitação em minha função. Eu apenas tentei $exclude = array ('4', '7');usar as lesmas também, mas isso não está afetando a saída do andador. Vou tentar a segunda abordagem e informar você.
Marventus
Não, isso também não funcionou. Eu acho que estou com morte cerebral de tentar descobrir isso, de modo que pode estar afetando a minha ... "performance", :-)
Marventus
0

isso ajuda

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

como um exemplo

< ?php wp_nav_menu( array( 'container_class' => 'menu-header', 'theme_location' => 'primary', 'exclude' => '66' ) ); ?>
saq
fonte
Olá Saq, esqueci de mencionar que uma das soluções que não funcionou foi criar uma função nav_menu personalizada e adicionar esse código como um argumento adicional aos padrões da função. Infelizmente, não funcionou. Não tentei incluí-lo no andador, mas acho que não funcionaria pelo mesmo motivo que mencionei acima, principalmente porque o wp_nav_menuargumento não é "excluir", mas posso estar errado.
Marventus
Atualizei meu post original para incluir isso para maior clareza.
Marventus
E se você não usar um andador personalizado, em vez de utilizar um nav_menu regular e extrair os itens com wp_get_nav_menu_items () com a sua imagem personalizada
SAQ
Essa seria uma boa solução em geral, mas nesse caso em particular, wp_get_nav_menu_itemsnão recuperará as imagens porque as tags img não são armazenadas no menu personalizado real (apenas os nomes dos arquivos estão no campo de descrição, por exemplo, "image1.png" ) O andador personalizado é o que me permite inserir as tags img na saída do menu.
Marventus