Destacando wp_nav_menu () Classe de ancestral sem filhos na estrutura de navegação?

30

( Nota dos moderadores: foi originalmente intitulado "wp_nav_menu classe de ancestral sem filhos na estrutura de navegação")

Eu tenho um wp_nav_menuno meu cabeçalho que tinha três páginas. Quando estou em uma dessas páginas, o liconteúdo dessa página no menu recebe a classe .current_page_item. Essas três páginas têm modelos e contêm consultas personalizadas para obter todas as postagens de um determinado tipo de conteúdo. Com efeito, os "filhos" percebidos desta página de nível superior não são realmente filhos, são apenas do tipo de conteúdo que eu associei a essa página de nível superior usando um modelo.

Gostaria que os itens de menu de nível superior recebessem uma 'current-ancestor'classe quando o usuário estivesse navegando em uma única página de um tipo de postagem específico, novamente associado a essa página apenas em uma consulta personalizada no arquivo de modelo.

Espero que faça sentido - se não, deixe-me saber onde eu te perdi! Aprecio muito qualquer ajuda.

- Editado para detalhes: por exemplo, eu tenho uma página estática chamada Workshops que está usando um modelo. Sua lesma é oficinas . O modelo possui uma função get_posts personalizada e um loop dentro dele, que puxa e exibe todas as postagens de um tipo de conteúdo personalizado chamado workshops . Se eu clicar no título de um desses workshops, sou levado ao conteúdo completo dessa parte do conteúdo. A estrutura do link permanente do tipo de postagem personalizada é definida como workshops / postname, para o usuário, essas partes do conteúdo são filhos da página Oficinas, quando, na realidade, são todos de um tipo de conteúdo, mas não relacionados à página. É essa lacuna que preciso fechar efetivamente no menu, destacando o item de menu 'Oficinas' ao navegar pelo conteúdo do tipo 'oficina'.

Mais uma vez, espero que faça sentido, acho que disse 'workshop' mais de 20 vezes em um parágrafo!

Gavin
fonte
@ Gavin - Você pode incluir mais alguns detalhes do que você está tentando realizar. É mais fácil escrever uma resposta em termos concretos do que se tentarmos fazê-lo em abstrato. Além disso, se você pudesse explicar sua estrutura de URL relacionada a eles, seria útil.
MikeSchinkel
11
@ Gavin - Isso ajuda. Portanto, sua opção de menu de nível superior é uma lista de workshops em "Workshops" com um caminho /workshops/e quando um usuário está em uma página de workshop (por exemplo, /workshops/example-workshop/você deseja que o item de menu "Workshops" tenha a classe current_page_itematribuída, correto?
19410 MikeSchinkel
wp_nav_menu () expõe a classe atual do ancestral do menu
Daniel Sachs

Respostas:

29

Existe uma solução mais simples. Esqueça a criação de páginas para cada tipo de postagem, para que você possa ter itens de navegação, porque, como aprendeu, o WP não tem como reconhecer que os tipos personalizados que você está navegando estão relacionados a essa página.

Em vez disso, crie um link personalizado em Aparência-> Menus. Basta colocar o URL que retornará seu tipo personalizado e atribuir um rótulo a ele, depois pressione "Adicionar ao menu".

http://example.com/workshops/

ou links não muito bonitos:

http://example.com/?post_type=workshops

isso sozinho cria um botão de navegação que exibe todas as postagens com esse tipo de postagem personalizada e também adiciona a classe de item de menu atual quando você clica nesse item de navegação - mas ainda não adiciona a classe de navegação em nenhuma URL diferente deste

Depois de criado, entre na configuração desse novo item e insira a lesma do tipo de postagem personalizada no campo "Atributo do título" (você também pode usar o campo de descrição, mas esse está oculto nas opções da tela de administração por padrão).

Agora, você precisa conectar o nav_menu_css_classfiltro (que é acionado para cada item de navegação) e verificar se o conteúdo que está sendo visualizado é do tipo de postagem indicado em seu item de navegação personalizado:

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

Nesse caso, verificaremos se o conteúdo do campo Atributo do título não está vazio e se corresponde ao post_type atual que está sendo consultado. Nesse caso, adicionamos a classe item de menu atual à sua matriz de classes e, em seguida, retornamos a matriz modificada.

Você pode modificá-lo para simplesmente corresponder ao título do item de navegação, mas se, por algum motivo, desejar nomear o item de navegação de maneira diferente da lesma simples do tipo de postagem, o uso do campo Atributo ou Descrição do título oferece essa flexibilidade.

Agora, sempre que você visualizar um único item (ou provavelmente até arquivar listagens) de um tipo de postagem que corresponda a um item do menu nav, esse item receberá a classe CSS current-menu-item da classe CSS para que seu destaque funcione.

Não são necessárias páginas ou modelos de página ;-) A consulta de URL cuida da busca das postagens corretas. Seu modelo de loop cuida da exibição da saída da consulta. Esta função cuida do reconhecimento do que está sendo mostrado e da adição da classe CSS.

BÔNUS

Você pode até automatizar o processo usando wp_update_nav_menu_item, gerando itens de menu automaticamente para todos os seus tipos de postagem. Neste exemplo, você precisaria primeiro recuperar o $menu_idmenu de navegação ao qual deseja adicionar esses itens.

$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'
        )
    );
}
somático
fonte
Essa é a coisa! Estou usando modelos de página apenas porque os layouts são bastante complexos para essas páginas e não apenas as listam, mas ainda posso utilizar o filtro que você forneceu para verificar o ID da página. A natureza desse tema é que as opções de tema permitem que você faça a correspondência de páginas ('home' é esta página, 'about' é esta página etc.), para que funcione perfeitamente. Obrigado pela assistência (incrivelmente detalhada)!
Gavin
Eu tive que remover o current_page_parentitem de navegação que era o meu blog - mas, caso contrário, funcionou. thx
pkyeck 10/10
isso não estava funcionando para mim, pois $item->attr_titleretirou o TITLE e escrevi o título em letras maiúsculas. então eu mudei o atributo para $item->post_namee agora funciona bem para mim.
honk31
Tentei fazer o código funcionar para o meu tema, mas não consigo. Não haverá aula aplicada ao meu item pai no menu, quando eu estiver no tipo de postagem personalizada portfolio. Eu usei o código acima. Qual pode ser o problema?
Casper
4

ao invés de usar

$ post_type = get_query_var ('post_type');

Você pode tentar:

$ post_type = get_post_type ();

Às vezes, o tipo de postagem não está definido na consulta var. Esse é o caso do post_type padrão de "post", portanto, se você quiser destacar uma postagem que foi listada em uma página de listagem, será necessário usá-la. get_very_var () retorna apenas uma string vazia para tipos de postagem que não são personalizados.

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;
}
Eric
fonte
2

@ Somática - isso é fantástico! Modifiquei um pouco o seu código para que ele também funcione para uma taxonomia específica (que estou usando apenas para o post_type relacionado). A idéia é usar o atributo Título do item de menu para armazenar o nome do post_type E o nome da taxonomia, separados por ponto e vírgula e depois explodidos pela função.

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;
}
tzeldin88
fonte
2

Aqui está minha solução, se você deseja trabalhar com wp_list_pages.

adicione isso no seu 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;
}

Agora basta adicionar na tabela wp_options uma nova linha com um option_name de page_for_custom_post_type-xxxx e uma option_value com a página-ID u deseja se conectar.

Talvez você tenha reconhecido que já existe uma opção chamada page_for_posts . Se você tiver apenas um tipo de postagem personalizado, poderá definir sua página em /wp-admin/options-reading.php no menu suspenso e a navegação definirá a página atual corretamente.

Eu acho que o núcleo do wordpress deve estender esta seção com uma lista suspensa para cada tipo de post registrado.

Temo
fonte
2

Decidi ficar com as páginas e usar o nome do modelo da página como uma classe no item de navegação. Isso me permite evitar bagunçar o atributo title, que eu não gostei em algumas das outras soluções.

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

Eu também tenho classes de corpo adicionadas ao header.php

<body <?php body_class(); ?>>

Finalmente, esta solução requer alguns CSS adicionais para aplicar o estado selecionado / ativo aos itens do menu de navegação. Eu o uso para mostrar arquivos de taxonomia e tipos de postagem personalizados relacionados à página como filhos desta página:

/* 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;}
Steve
fonte
Isso me deu o seguinte erro: Warning: join() [function.join]: Invalid arguments passed in /home/path/to/wp-includes/nav-menu-template.php on line 76 Alguma idéia do que aconteceu aqui?
Jeff K.
Oh, acho que vejo o que está acontecendo. É porque você está retornando $ classes dentro da instrução if. Simplesmente return $classessair e depois disso ifparece resolver o erro acima.
Jeff K.
1

@ Somática - Ótimo código! Eu mesmo fiz uma mudança. Queria manter o Atributo do título para a finalidade pretendida; em vez disso, coloquei a lesma Custom Post Type nas propriedades do menu avançado Link Relationship (XFN) que você pode ativar nas Opções da tela. eu modifiquei

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

e mudou para

if ($item->xfn != '' && $item->xfn == $post_type) {
user8899
fonte
0

Bom trabalho somático.

Infelizmente, não entendo como você pode listar seus tipos de postagem personalizados em uma página da maneira que você explica. Se eu não uso um page-portfolio.php e o adiciono a uma página, tudo o que recebo é a página 404.

Se eu faço como Gavin, modifiquei a sua função para remover também o "current_page_parent" da página do blog como esta.

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;

}

Vayu
fonte