Знакомство с классом WordPress Walker

Опубликовано: 2020-11-27

Если вы не знакомы с классом Уокера, будьте готовы удивиться тому, насколько полезным он может быть для вашей работы. Класс WordPress Walker был реализован в WordPress 2.1, чтобы предоставить разработчикам средства для обхода древовидных структур данных с целью рендеринга HTML. В этой статье мы изучим, как работает параметр Walker и как настроить вывод в меню, категории и комментарии.

Давайте идти!

Обзор класса Уокера

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

Как вы, возможно, уже знаете, в случае древовидной структуры данных одни элементы являются родительскими, а другие — их дочерними. «Подкатегория сообщений 1» является дочерним элементом «Категория сообщений 1», ответ на комментарий является дочерним комментарием к самому комментарию, а «Сервис 1» является дочерним пунктом меню для пункта «Услуги».

Walker назван так, потому что он просто «проходит» через каждый объект или ассоциативный массив и выполняет функцию в каждом узле. Чего мы хотели бы достичь с помощью этого, так это возможности отображать ссылки «верхнего уровня» с их «дочерними» элементами различными способами в соответствии с нашими конкретными требованиями.

Другими словами, WordPress предоставляет вам стандартную структуру <ul> <li>, и вы можете настраивать ее аргументы, но, расширяя Walker, вы можете настраивать саму структуру, изменяя ее HTML-содержимое.

Основной файл, относящийся к классу Walker, называется wp-includes/class-wp-walker.php и управляет всеми типами древовидных данных, которые мы ранее перечислили.

Поскольку это абстрактный PHP-класс, для создания любого HTML-кода он должен быть расширен разработчиком, который определит настраиваемую версию его свойств и методов. Итак, давайте изучим дочерние классы в файле class-wp-walker.php один за другим.

Дочерние классы

$tree_type — необязательная переменная, которая входит в тип или массив типов и определяет, что обрабатывает класс.

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

$db_fields является обязательной переменной и определяет, какие поля базы данных использовать. Это свойство представляет собой массив с двумя ключами: «parent» и «id», значениями которых являются имена свойств объекта, которые содержат идентификатор родителя и идентификатор элемента соответственно.

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

Свойство $max_pages является необязательным, и его роль заключается в указании максимального количества страниц, пройденных постраничным обходчиком.

 public $max_pages = 1;

$has_children на самом деле не требует пояснений и имеет значение true или false в зависимости от того, есть ли у текущего элемента дочерние элементы.

 public $has_children;

Метод start_lvl выполняется в корне нового древовидного объекта и принимает аргументы $output, $depth и $args.

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

Аргумент $output добавляет дополнительное содержимое, $depth указывает глубину элемента, а $args представляет собой массив дополнительных аргументов.

Метод end_lvl закрывает любой тег, ранее открытый методом start_lvl.

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

Метод start_el (начальный элемент) используется для отображения открывающего тега HTML для текущего элемента. Например, в случае меню это обычно тег <li>.

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

Функция end_el вызывается после того, как Walker передает элемент со всеми его дочерними элементами и возвращает закрывающий тег.

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

display_element фактически отображает элементы объекта дерева. Он вызывает start_el , start_lvl , display_element , end_lvl , end_el в указанном порядке. Теперь давайте посмотрим на его аргументы.

  • $element : текущий элемент
  • $children_elements : все дочерние элементы объекта дерева
  • $max_depth : максимальный предел глубины, который мы можем исследовать
  • $depth : уровень, на котором мы сейчас находимся
  • $args : дополнительные необязательные аргументы
  • $output : Текущий вывод HTML.

Теперь мы продемонстрируем по одному примеру для каждого типа данных, используя установку WordPress с активированной темой Twenty Twenty.

Настройка структуры меню

Функция wp_nav_menu(), которую WordPress использует для отображения меню, включена в файл wp-includes/nav-menu-template.php . В этом файле WordPress также вызывает класс Walker_Nav_Menu в строке 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 ); }

Класс Walker_Nav_Menu определен внутри файла wp-includes/class-walker-nav-menu.php и, по сути, является всем содержимым файла.

Чтобы отобразить вывод меню, код WordPress использует свойства и методы класса Walker_Nav_Menu, описанные в этом файле.

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

Чтобы мы могли сравнить наши результаты, мы сначала создадим клон основного меню, просто добавив приведенный ниже код в header.php сразу после начала элемента <header> .

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

Что мы на самом деле сделали здесь, так это перегенерировали основное меню и наследовали его функциональность раскрывающегося списка и CSS, добавив его классы primary-menu reset-list-style в новое меню.

Теперь в нашем файле functions.php мы создадим класс, расширяющий класс Walker_Nav_Menu. Поскольку мы хотим изменить тип элемента, мы переопределим метод 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>'; } } } }

Таким образом, мы обычно обертывали каждый элемент тегом <li>, а затем с помощью оператора if добавляли диапазон, когда ссылка имеет вид «#», и тег <a> для остальных.

Чтобы применить это к нашему меню, мы вернемся к коду меню, который мы добавили ранее, и укажем параметр walker:

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

Теперь результат должен выглядеть так:

Если вы теперь наведете курсор на «Услуги» в пункте меню, курсор в виде руки не появится, и этот пункт меню нельзя будет щелкнуть. Однако выпадающее подменю по-прежнему будет правильно отображаться.

Настройка категорий

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

После этого мы сгенерируем список категорий, добавив этот код где-нибудь в header.php . Вы можете поместить его после начала элемента заголовка, как и раньше.

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

Это встроенная функция WordPress, которая генерирует HTML-вывод дерева категорий. По умолчанию он показывает только категории, которые содержат записи, поэтому мы использовали опцию hide_empty , чтобы отобразить также и пустые категории и увидеть всю иерархию для целей этого примера.

Как и ранее, мы можем создать собственный класс в functions.php , чтобы расширить класс Walker_Category по умолчанию, описанный в файле wp-includes/class-walker-category.php , и применить наши изменения. Например, мы добавим некоторые значки перед названиями категорий, добавив этот код:

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

Чтобы это работало, вам, конечно, нужно подготовить подходящие изображения и сохранить их в определенной папке. Эти изображения должны следовать определенному формату имени, который в этом примере будет «post-category-1», «post-subcategory-1», «post-category-3.jpg» и т. д.

Настройка комментариев

Обновление меню и списка категорий, безусловно, является наиболее распространенной причиной, по которой вы можете настроить класс Walker, но иногда вам необходимо реализовать ту же технику и для комментариев. Если, например, вы хотите изменить метаинформацию рядом с изображением Gravatar в разделе комментариев, мы можем легко сделать это, расширив класс Walker_Comment из файла wp-includes/class-walker-comment.php.

В файл functions.php добавьте этот код

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

Как вы можете заметить, сравнив код about с содержимым оригинального Walker_Comment, единственное необходимое изменение было в методе html5_comment , который в основном выводит комментарий в формате HTML5.

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

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

Мы вставили код в ту же строку header.php, что и раньше, и использовали идентификатор поста, содержащего комментарии. Конечно, вместо этого вы можете просто заменить код, связанный с комментариями, в своем шаблоне и пропустить параметр «страница», чтобы он применялся ко всем разделам комментариев к вашим статьям.

Если вы обновите внешний интерфейс своего веб-сайта сейчас, вы заметите дополнительные информационные записи (биография автора и URL-адрес автора), которые мы добавили в пользовательском коде выше.

Вывод

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