Есть готовые решения, плагины, которые могут решать ваши задачи в области генерации хлебных крошек. Они отлично подойдут для готовых к использованию тем оформления. Здесь я их не рассматриваю.
В статье я покажу пару «собственных» подходов к генерации крошек, и это может стать основной для вашего решения.
У меня на сайте преимущественно два типа материалов — это посты в ленте (post) и страницы (page). Эти сущности хоть логически разделены, но хранятся в одной и тоже таблице базы данных. Т.е. деление весьма условное.
Тем не менее страницы не показываются в ленте. И они преимущественно используются в меню. Потому breadcrumbs для post и page имеют разную логику и по разному должны генерироваться.
Но у них есть общее правило, связанное с первым и последним элементами. 1-й элемент — это ссылка на главную страницу, а последний — не является даже ссылкой — это просто название самой страницы.
Breadcrumb для постов
Посты (post) у меня объединяются в категории, и у них могут быть теги. Основную категорию и один из тегов я добавляю в бредкрамб. Вообще, это против правил — т.к. бредкрамб должен отображать иерархию элементов, а не их горизонтальные связи. Но мой сайт — мои правила.
Breadcrumb для страниц
Для страниц (page) всё проще и сложнее одновременно. Простота связана с использованием меню. Нужно пройтись по меню и составить хлебные крошки согласно иерархии меню. Но сложность в том, что меню в WP хранится в той же таблице, что и публикации, с определенными допущениями и внутренними соглашениями.
Пришлось потратить немного времени, чтобы разобраться как вытащить от туда нужные данные.
Реализация
Я решил создать статический класс для хранения функций бредкрамба, а также вспомогательный DTO класс для хранения отдельных позиций хлебных крошек.
Класс BreadcrumbItem — элемент крошки
Это простой DTO (Data Transfer Object) для хранения информации об одном элементе хлебных крошек:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
<?php namespace shraRu; class BreadcrumbItem { public string $label; // Текст ссылки public string $url; // URL (пустая строка для последнего элемента) public string $title; // Всплывающая подсказка public function __construct(string $label, string $url, string $title = '') { $this->label = $label; $this->url = $url; $this->title = $title; } } |
Класс Breadcrumb — генерация и рендеринг
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<?php namespace shraRu; require_once __DIR__ . '/BreadcrumbItem.php'; class Breadcrumb { /** * Генерирует массив хлебных крошек для постов. */ public static function buildPostBreadcrumb($post): array { ... } /** * Генерирует массив хлебных крошек для страниц (на базе меню) */ public static function buildPageBreadcrumb($page): array { ... } /** * Создаёт HTML для массива объектов хлебных крошек */ public static function render(array $crumbs): string { ... } } |
Всего три статические функции — две наполняют массив крошек, и одна производит рендер из этого массива. Рассмотрим их по очереди.
Для постов:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
public static function buildPostBreadcrumb($post): array { $br[] = new BreadcrumbItem('На главную', '/', 'Блог'); // Добавляем категорию $cats = get_the_category($post->ID); if (!empty($cats)) { $cat = array_pop($cats); $br[] = new BreadcrumbItem( strip_tags($cat->name), get_term_link($cat), 'Архив рубрики ' . $cat->name ); } // Добавляем тег (если есть) $tags = get_the_tags($post->ID); if (!empty($tags)) { $tag = array_pop($tags); $br[] = new BreadcrumbItem( $tag->name, get_tag_link($tag), 'Статьи с меткой - ' . $tag->name ); } // Текущий пост (без ссылки) $br[] = new BreadcrumbItem(get_the_title($post->ID), ''); return $br; } |
Для страниц из меню:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
public static function buildPageBreadcrumb($page): array { $br = []; $pageID = $page->ID; // Получаем связанные пункты меню $elms = wp_get_associated_nav_menu_items($pageID); $itemID = array_pop($elms); // Рекурсивно собираем родительские пункты while ($itemID) { $item = get_post($itemID); $meta = get_post_meta($itemID); // Чтение данных из пункта меню $label = $item->post_title; $url = get_permalink($itemID); $title = $item->post_excerpt; // Если это ссылка на пост/страницу - получаем данные из оригинала $meta_object_type = $meta['_menu_item_object'][0]; if ($meta_object_type == 'page' || $meta_object_type == 'post') { $post = get_post($meta['_menu_item_object_id'][0]); if (empty($label)) $label = $post->post_title; $url = get_permalink($post->ID); } if (empty($br)) { $br[] = new BreadcrumbItem($label, ''); // Текущий элемент } else { $br[] = new BreadcrumbItem($label, $url, $title); } // ссылка на родительский пункт $itemID = array_pop($meta['_menu_item_menu_item_parent']); } $br[] = new BreadcrumbItem('На главную', '/', 'Блог'); // т.к. мы собираем крошки с хвоста, то надо перевернуть массив return array_reverse($br); } |
Рендеринг HTML:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
public static function render(array $crumbs): string { $out = []; foreach ($crumbs as $crumb) { // главная страница if ($crumb->url === '/') { $out[] = '<a href="/" title="' . esc_attr($crumb->title) . '"> <span class="fa-house" aria-hidden="true"></span> ' . esc_html($crumb->label) . '</a>'; // последняя в цепочке страниц } else if ($crumb->url === '') { $out[] = esc_html($crumb->label); } else { $out[] = '<a href="' . esc_url($crumb->url) . '" title="' . esc_attr($crumb->title) . '">' . esc_html($crumb->label) . '</a>'; } } return '<div class="breadcrumb">' . implode(' / ', $out) . '</div>'; } |
Использование в шаблонах
Для вставки в шаблон, нужно вызвать одну из двух функций генерации, а затем функцию рендера.
|
1 2 3 4 5 6 |
<?php if (is_single()): ?> <?php $br = Breadcrumb::buildPostBreadcrumb(get_post()); echo Breadcrumb::render($br); ?> <?php endif; ?> |
Для страниц:
|
1 2 3 4 5 6 |
<?php if (is_page()): ?> <?php $br = Breadcrumb::buildPageBreadcrumb(get_post()); echo Breadcrumb::render($br); ?> <?php endif; ?> |
Такая система хлебных крошек отлично подходит для большинства сайтов на WordPress. Главное преимущество — использование реальной структуры меню для страниц, что делает навигацию интуитивно понятной для пользователей.
Вы можете адаптировать этот код или дополнить его своими кейсами. Каждый сайт уникален, и сложно бывает найти готовое решение, работающее как надо из коробки. Важен, конечно, баланс — что то пишете сами, а что то используете готовое.