Familiarizando-se com a classe WordPress Walker

Publicados: 2020-11-27

Se você não está familiarizado com a Walker Class, prepare-se para se surpreender com o quanto ela pode ser útil para o seu trabalho. A WordPress Walker Class foi implementada no WordPress 2.1 para fornecer aos desenvolvedores um meio de percorrer estruturas de dados semelhantes a árvores com a finalidade de renderizar HTML. Neste artigo estudaremos como funciona o parâmetro walker e como customizar as saídas em menus, categorias e comentários.

Vamos indo!

Visão geral da classe Walker

No WordPress, frequentemente vemos objetos que possuem uma estrutura hierárquica, como menus de navegação, listas de categorias ou listas de comentários

Como você já deve saber, no caso de uma estrutura de dados em árvore, alguns elementos são pais e outros são seus filhos. “Post Subcategory 1” é filho de “Post Category 1”, uma resposta a um comentário é um comentário filho do próprio comentário e “Service 1” é um item de menu filho do item “Services”.

O Walker é nomeado como tal, pois simplesmente “caminha” por cada objeto ou array associativo e executa uma função em cada nó. O que gostaríamos de alcançar com isso é a capacidade de listar os links de 'nível superior', com seus itens 'filhos' de diferentes maneiras, de acordo com nossos requisitos específicos.

Em outras palavras, o WordPress oferece uma estrutura padrão <ul> <li> e você pode personalizar seus argumentos, mas, estendendo o Walker, você pode personalizar a própria estrutura modificando seu conteúdo HTML.

O arquivo principal relacionado à classe Walker é wp-includes/class-wp-walker.php e governa todos os tipos de dados em forma de árvore que listamos anteriormente.

Por ser uma classe PHP abstrata, para gerar qualquer HTML, ela precisa ser estendida pelo desenvolvedor que definirá uma versão customizada de suas propriedades e métodos. Então vamos estudar as classes filhas no arquivo class-wp-walker.php uma por uma.

Classes filhas

O $tree_type é uma variável opcional que vem em um tipo ou array de tipos e define o que a classe trata.

 public $tree_type = array( 'post_type', 'taxonomy', 'custom' );

O $db_fields é uma variável obrigatória e define quais campos do banco de dados usar. Esta propriedade é um array com duas chaves: 'parent' e 'id' cujos valores são os nomes das propriedades do objeto que contém o id pai e o id do item, respectivamente.

 public $db_fields = array( 'parent' => 'menu_item_parent', 'id' => 'db_id', );

A propriedade $max_pages também é opcional e sua função é especificar o número máximo de páginas percorridas pelo caminhante paginado.

 public $max_pages = 1;

O $has_children é realmente autoexplicativo e tem um valor verdadeiro ou falso dependendo se o elemento atual tem filhos.

 public $has_children;

O método start_lvl é executado na raiz de um novo objeto em forma de árvore e recebe os argumentos $output, $depth e $args.

 public function start_lvl( &$output, $depth = 0, $args = array() ) {}

O argumento $output acrescenta conteúdo adicional, o $depth especifica a profundidade do item e $args é uma matriz de argumentos adicionais.

O método end_lvl fecha qualquer tag que tenha sido aberta anteriormente pelo método start_lvl.

 public function end_lvl( &$output, $depth = 0, $args = array() ) {}

O start_el (Start Element) é usado para exibir a tag HTML de abertura do elemento atual. No caso de um menu, por exemplo, geralmente é uma tag <li>.

 public function start_el( &$output, $object, $depth = 0, $args = array(), $current_object_id = 0 ) {}

A função end_el é chamada após o Walker passar um elemento com todos os seus filhos e retornar uma tag de fechamento.

 public function end_el( &$output, $object, $depth = 0, $args = array() ) {}

O display_element na verdade exibe os elementos do objeto tree. Ele chama start_el , start_lvl , display_element , end_lvl , end_el nesta ordem. Agora vamos dar uma olhada em seus argumentos.

  • $element : o elemento atual
  • $children_elements : todos os elementos filhos do objeto árvore
  • $max_depth : o limite máximo de profundidade que podemos explorar
  • $profundidade : O nível em que estamos atualmente
  • $args : argumentos opcionais adicionais
  • $output : A saída HTML atual.

Agora vamos demonstrar um exemplo para cada tipo de dados usando uma instalação do WordPress com o tema Twenty Twenty ativado.

Personalizando uma estrutura de menu

A função wp_nav_menu() que o WordPress usa para exibir menus está incluída no arquivo wp-includes/nav-menu-template.php . Neste arquivo, o WordPress também chama a classe Walker_Nav_Menu em torno da linha 605.

 function walk_nav_menu_tree( $items, $depth, $r ) { $walker = ( empty( $r->walker ) ) ? new Walker_Nav_Menu : $r->walker; return $walker->walk( $items, $depth, $r ); }

A classe Walker_Nav_Menu é definida dentro do arquivo wp-includes/class-walker-nav-menu.php e basicamente é todo o conteúdo do arquivo.

Para exibir a saída do menu, o código do WordPress usa as propriedades e métodos da classe Walker_Nav_Menu descritos dentro deste arquivo.

Vamos, por exemplo, corrigir um problema bem conhecido que muitos desenvolvedores enfrentam, que é alterar o elemento dos itens de menu pai com um link personalizado vazio ('#') para impedir que os visitantes cliquem neles.

Para nos permitir comparar nossos resultados, primeiro criaremos um clone do menu primário apenas adicionando o código abaixo no header.php logo após o início do elemento <header> .

 <header class="header-footer-group" role="banner"> <?php wp_nav_menu( array( 'menu_class' => 'primary-menu reset-list-style' ) ); ?>

O que realmente fizemos aqui foi regenerar o menu principal e herdar sua funcionalidade suspensa e CSS adicionando suas classes primary-menu reset-list-style ao novo menu também.

Agora em nosso arquivo functions.php vamos criar uma classe que estende a classe Walker_Nav_Menu. Como queremos alterar o tipo de elemento, substituiremos o método start_el .

 if ( !class_exists('My_Custom_Nav_Walker') ) { class My_Custom_Nav_Walker extends Walker_Nav_Menu { function start_el(&$output, $item, $depth=0, $args=[], $id=0) { $output .= "<li class='" . implode(" ", $item->classes) . "'>"; if ($item->url && $item->url != '#') { $output .= '<a href="' . $item->url . '">'; } else { $output .= '<span>'; } $output .= $item->title; if ($item->url && $item->url != '#') { $output .= '</a>'; } else { $output .= '</span>'; } } } }

Então nós envolvemos cada elemento normalmente com uma tag <li> e então, com o uso da instrução if anexamos um span quando um link é “#” e uma tag <a> para o resto.

Para aplicar isso ao nosso menu, voltamos ao código do menu que adicionamos anteriormente e especificamos o parâmetro walker:

 wp_nav_menu( array( 'walker' => new My_Custom_Nav_Walker, 'menu_class' => 'primary-menu reset-list-style' ) );

Agora o resultado deve ficar assim:

Se você passar o mouse sobre 'Serviços' no item de menu, nenhum cursor de mão aparecerá e nem este item de menu é clicável. No entanto, o submenu suspenso ainda será mostrado corretamente.

Personalizando categorias

Primeiro vá na área de administração e crie algumas categorias e subcategorias de postagem para ter uma árvore de categorias para a demonstração.

Depois disso vamos gerar uma lista de categorias adicionando este código em algum lugar no header.php . Você pode colocá-lo após o início do elemento de cabeçalho como anteriormente.

 <header class="header-footer-group" role="banner"> <?php wp_list_categories( array('hide_empty' => FALSE) ); ?>

A função é uma função interna do WordPress que gera uma saída HTML de uma árvore de categorias. Por padrão, ele mostra apenas as categorias que contêm postagens, por isso usamos a opção hide_empty para exibir também as categorias vazias e ver toda a hierarquia para os propósitos deste exemplo.

Como anteriormente, podemos criar uma classe personalizada em functions.php para estender a classe Walker_Category padrão descrita no arquivo wp-includes/class-walker-category.php e aplicar nossas alterações. Por exemplo, adicionaremos alguns ícones antes dos nomes das categorias adicionando este código:

 if ( !class_exists('My_Category_tree_Walker') ) { class My_Category_tree_Walker extends Walker_Category { function start_el(&$output, $item, $depth=0, $args=array(),$current_object_id = 0) { $output.= '<li><a href="'.home_url('category/'.$item->slug).'"> <img src="http://path/to/mages/'.($item->slug).'.jpg"> '.esc_attr($item->name); } } }

Para que isso funcione, é claro que você precisa preparar imagens adequadas e salvá-las na pasta definida. Essas imagens precisariam seguir um formato de nome específico que neste exemplo seria “post-category-1”, “post-subcategory-1”, “post-category-3.jpg” etc.

Personalizando comentários

Atualizar o menu e a lista de categorias é de longe as razões mais comuns pelas quais você pode personalizar uma classe Walker, mas às vezes você precisa implementar a mesma técnica para comentários também. Se, por exemplo, você quiser alterar as meta-informações ao lado da imagem do Gravatar na seção de comentários, podemos fazer isso facilmente estendendo a classe Walker_Comment encontrada no arquivo wp-includes/class-walker-comment.php.

No arquivo functions.php adicione este código

 if ( !class_exists('My_Comment_Walker') ) { class My_Comment_Walker extends Walker_Comment { protected function html5_comment( $comment, $depth, $args ) { $tag = ( 'div' === $args['style'] ) ? 'div' : 'li'; ?> <<?php echo $tag; ?> <?php comment_class( $this->has_children ? 'parent' : '', $comment ); ?>> <article class="comment-body"> <footer class="comment-meta"> <div class="comment-author vcard"> <?php if ( 0 != $args['avatar_size'] ) echo get_avatar( $comment, $args['avatar_size'] ); ?> <?php printf( __( '%s <span class="says">says:</span>' ), sprintf( '<span class="fn">%s</span>', get_comment_author_link( $comment ) ) ); ?> </div><!-- .comment-author --> <div class="comment-metadata"> <?php $user_id=$comment->user_id; ?> <p class="commenter-bio"><?php the_author_meta('description',$user_id); ?></p> <p class="commenter-url"><a href="<?php the_author_meta('user_url',$user_id); ?>" target="_blank"><?php the_author_meta('user_url',$user_id); ?></a></p> </div><!-- .comment-metadata --> <?php if ( '0' == $comment->comment_approved ) : ?> <p class="comment-awaiting-moderation"><?php _e( 'Your comment is awaiting moderation.' ); ?></p> <?php endif; ?> </footer><!-- .comment-meta --> <div class="comment-content"> <?php comment_text(); ?> </div><!-- .comment-content --> <?php comment_reply_link( array_merge( $args, array( 'add_below' => 'div-comment', 'depth' => $depth, 'max_depth' => $args['max_depth'], 'before' => '<div class="reply">', 'after' => '</div>' ) ) ); ?> </article><!-- .comment-body --> <?php } } }

Como você pode notar comparando o código about com o conteúdo do Walker_Comment original, a única mudança necessária foi no método html5_comment que basicamente produz um comentário no formato HTML5.

Depois disso, temos que exibir a lista de comentários usando a função interna wp_list_comments com os argumentos corretos para exibir o objeto HTML semelhante a uma árvore de comentários.

 wp_list_comments( array( 'page' => 143, 'walker' => new My_Comment_Walker ));

Inserimos o código na mesma linha do header.php que fizemos antes e usamos o ID do post que contém os comentários. Claro, você pode simplesmente substituir o código relacionado ao comentário do seu modelo e pular a opção 'página' para que ela se aplique a toda a seção de comentários de seus artigos.

Se você atualizar o front-end do seu site agora, notará as entradas de informações extras (biografia do autor e URL do autor) que adicionamos no código personalizado acima.

Conclusão

Espero que o acima tenha lhe dado algumas dicas sobre como usar a classe WordPress Walker. Em todos os exemplos, aplicamos as alterações diretamente nos arquivos do tema principal. Embora isso seja bom para fins de demonstração, você obviamente desejará ter certeza de aplicar apenas edições a um tema filho na prática para garantir que essas atualizações não sejam substituídas quando o WordPress ou o tema usado for atualizado.