«Хлебные крошки» для WordPress без использования плагина
«Хлебные крошки» — это важный элемент навигации веб-сайта, который повышает его юзабилити. Особенно это касается сайтов со сложной структурой. Я, к сожалению (а, может, и не к сожалению), не использую их на большинстве своих сайтов, возможно, потому, что у них слишком простая структура (для такого сайта, как этот, они, вроде бы, и не нужны).
Когда я решаю какую-либо задачу на WordPress-сайте, то всегда стараюсь обходится без плагинов, где это бывает возможно. Зачастую одна и та же задача может быть решена с меньшим количеством кода и бывает менее ресурсоемкой по сравнению с применением плагинов.
В Интернете я находил разные варианты реализации «хлебных крошек» без использования плагинов, но ни один из них меня не устроил, поскольку все они не показывали полную цепочку ссылок. Поэтому я создал свою функцию «хлебных крошек» для WordPress. И в данном посте хочу поделиться этой функцией с вами.
Особенности функции
-
Отображается полная цепочка ссылок до текущей страницы. Например, если текущая страница находится в рубрике второго уровня, то цепочка будет выглядеть следующим образом:
Главная > Рубрика > Подрубрика > Название статьи
Во всех решениях, которые я встречал (за исключением плагинов), такая цепочка выглядела вот так:
Главная > Подрубрика > Название статьи
Т.е. одно звено потеряно.
Аналогично у меня выглядят и «крошки» для страниц. К примеру, для страницы 3-го уровня вложенности цепочка будет такой:
Главная > Страница 1-го уровня > Страница 2-го уровня > Страница 3-го уровня
-
«Хлебные крошки» выводятся для следующих типов страниц WordPress-сайта:
- постраничная навигация с главной страницы (вида
site.ru/page/2/
); - архив рубрики;
- архив тега;
- архив за день;
- архив за месяц;
- архив за год;
- архив автора;
- произвольный тип записи;
- страница;
- пост;
- результаты поиска;
- страница с ошибкой 404.
- постраничная навигация с главной страницы (вида
- Добавляется порядковый номер страницы, если это 2-я или больше страница архивов.
- Можно задать любой символ разделителя между ссылками.
- Можно задать текст для ссылка «Главная».
- Интегрирована микроразметка Schema.org.
Функция «Хлебные крошки» для WordPress (обновлено: 03.03.2019)
/*
* "Хлебные крошки" для WordPress
* автор: Dimox
* версия: 2019.03.03
* лицензия: MIT
*/
function dimox_breadcrumbs() {
/* === ОПЦИИ === */
$text['home'] = 'Главная'; // текст ссылки "Главная"
$text['category'] = '%s'; // текст для страницы рубрики
$text['search'] = 'Результаты поиска по запросу "%s"'; // текст для страницы с результатами поиска
$text['tag'] = 'Записи с тегом "%s"'; // текст для страницы тега
$text['author'] = 'Статьи автора %s'; // текст для страницы автора
$text['404'] = 'Ошибка 404'; // текст для страницы 404
$text['page'] = 'Страница %s'; // текст 'Страница N'
$text['cpage'] = 'Страница комментариев %s'; // текст 'Страница комментариев N'
$wrap_before = '<div class="breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">'; // открывающий тег обертки
$wrap_after = '</div><!-- .breadcrumbs -->'; // закрывающий тег обертки
$sep = '<span class="breadcrumbs__separator"> › </span>'; // разделитель между "крошками"
$before = '<span class="breadcrumbs__current">'; // тег перед текущей "крошкой"
$after = '</span>'; // тег после текущей "крошки"
$show_on_home = 0; // 1 - показывать "хлебные крошки" на главной странице, 0 - не показывать
$show_home_link = 1; // 1 - показывать ссылку "Главная", 0 - не показывать
$show_current = 1; // 1 - показывать название текущей страницы, 0 - не показывать
$show_last_sep = 1; // 1 - показывать последний разделитель, когда название текущей страницы не отображается, 0 - не показывать
/* === КОНЕЦ ОПЦИЙ === */
global $post;
$home_url = home_url('/');
$link = '<span itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem">';
$link .= '<a class="breadcrumbs__link" href="%1$s" itemprop="item"><span itemprop="name">%2$s</span></a>';
$link .= '<meta itemprop="position" content="%3$s" />';
$link .= '</span>';
$parent_id = ( $post ) ? $post->post_parent : '';
$home_link = sprintf( $link, $home_url, $text['home'], 1 );
if ( is_home() || is_front_page() ) {
if ( $show_on_home ) echo $wrap_before . $home_link . $wrap_after;
} else {
$position = 0;
echo $wrap_before;
if ( $show_home_link ) {
$position += 1;
echo $home_link;
}
if ( is_category() ) {
$parents = get_ancestors( get_query_var('cat'), 'category' );
foreach ( array_reverse( $parents ) as $cat ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
}
if ( get_query_var( 'paged' ) ) {
$position += 1;
$cat = get_query_var('cat');
echo $sep . sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_current ) {
if ( $position >= 1 ) echo $sep;
echo $before . sprintf( $text['category'], single_cat_title( '', false ) ) . $after;
} elseif ( $show_last_sep ) echo $sep;
}
} elseif ( is_search() ) {
if ( get_query_var( 'paged' ) ) {
$position += 1;
if ( $show_home_link ) echo $sep;
echo sprintf( $link, $home_url . '?s=' . get_search_query(), sprintf( $text['search'], get_search_query() ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_current ) {
if ( $position >= 1 ) echo $sep;
echo $before . sprintf( $text['search'], get_search_query() ) . $after;
} elseif ( $show_last_sep ) echo $sep;
}
} elseif ( is_year() ) {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . get_the_time('Y') . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
} elseif ( is_month() ) {
if ( $show_home_link ) echo $sep;
$position += 1;
echo sprintf( $link, get_year_link( get_the_time('Y') ), get_the_time('Y'), $position );
if ( $show_current ) echo $sep . $before . get_the_time('F') . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_day() ) {
if ( $show_home_link ) echo $sep;
$position += 1;
echo sprintf( $link, get_year_link( get_the_time('Y') ), get_the_time('Y'), $position ) . $sep;
$position += 1;
echo sprintf( $link, get_month_link( get_the_time('Y'), get_the_time('m') ), get_the_time('F'), $position );
if ( $show_current ) echo $sep . $before . get_the_time('d') . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_single() && ! is_attachment() ) {
if ( get_post_type() != 'post' ) {
$position += 1;
$post_type = get_post_type_object( get_post_type() );
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_post_type_archive_link( $post_type->name ), $post_type->labels->name, $position );
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
} else {
$cat = get_the_category(); $catID = $cat[0]->cat_ID;
$parents = get_ancestors( $catID, 'category' );
$parents = array_reverse( $parents );
$parents[] = $catID;
foreach ( $parents as $cat ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
}
if ( get_query_var( 'cpage' ) ) {
$position += 1;
echo $sep . sprintf( $link, get_permalink(), get_the_title(), $position );
echo $sep . $before . sprintf( $text['cpage'], get_query_var( 'cpage' ) ) . $after;
} else {
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
}
}
} elseif ( is_post_type_archive() ) {
$post_type = get_post_type_object( get_post_type() );
if ( get_query_var( 'paged' ) ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_post_type_archive_link( $post_type->name ), $post_type->label, $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . $post_type->label . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
}
} elseif ( is_attachment() ) {
$parent = get_post( $parent_id );
$cat = get_the_category( $parent->ID ); $catID = $cat[0]->cat_ID;
$parents = get_ancestors( $catID, 'category' );
$parents = array_reverse( $parents );
$parents[] = $catID;
foreach ( $parents as $cat ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_category_link( $cat ), get_cat_name( $cat ), $position );
}
$position += 1;
echo $sep . sprintf( $link, get_permalink( $parent ), $parent->post_title, $position );
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_page() && ! $parent_id ) {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . get_the_title() . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
} elseif ( is_page() && $parent_id ) {
$parents = get_post_ancestors( get_the_ID() );
foreach ( array_reverse( $parents ) as $pageID ) {
$position += 1;
if ( $position > 1 ) echo $sep;
echo sprintf( $link, get_page_link( $pageID ), get_the_title( $pageID ), $position );
}
if ( $show_current ) echo $sep . $before . get_the_title() . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( is_tag() ) {
if ( get_query_var( 'paged' ) ) {
$position += 1;
$tagID = get_query_var( 'tag_id' );
echo $sep . sprintf( $link, get_tag_link( $tagID ), single_tag_title( '', false ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . sprintf( $text['tag'], single_tag_title( '', false ) ) . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
}
} elseif ( is_author() ) {
$author = get_userdata( get_query_var( 'author' ) );
if ( get_query_var( 'paged' ) ) {
$position += 1;
echo $sep . sprintf( $link, get_author_posts_url( $author->ID ), sprintf( $text['author'], $author->display_name ), $position );
echo $sep . $before . sprintf( $text['page'], get_query_var( 'paged' ) ) . $after;
} else {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . sprintf( $text['author'], $author->display_name ) . $after;
elseif ( $show_home_link && $show_last_sep ) echo $sep;
}
} elseif ( is_404() ) {
if ( $show_home_link && $show_current ) echo $sep;
if ( $show_current ) echo $before . $text['404'] . $after;
elseif ( $show_last_sep ) echo $sep;
} elseif ( has_post_format() && ! is_singular() ) {
if ( $show_home_link && $show_current ) echo $sep;
echo get_post_format_string( get_post_format() );
}
echo $wrap_after;
}
} // end of dimox_breadcrumbs()
Функцию необходимо поместить в файл functions.php
вашей WordPress-темы. После этого в то место шаблона, где хотите выводить «хлебные крошки», добавьте следующий код:
<?php if ( function_exists( 'dimox_breadcrumbs' ) ) dimox_breadcrumbs(); ?>
Единственное, что теперь останется сделать — оформить их с помощью CSS. Для этого к блоку «хлебных крошек» предусмотрен класс .breadcrumbs
, для разделителя — .breadcrumbs__separator
а для текущей «крошки» — .breadcrumbs__current
.
Комментарии (693)
Отличное рабочее решение! Благодарен автору.
if ( $show_current ) {
if ( $position >= 1 )
echo $sep . $before . get_the_title() . $after; // — здесь не учитывается «position»
} elseif ( $show_last_sep ) echo $sep;
в своих проектах делаю так:
if ( $show_current ) {
$position += 1;
if ( $position >= 1 )
echo $sep . $before . get_the_title() . sprintf($after, $position); // — здесь учитывается «position»
} elseif ( $show_last_sep ) echo $sep;
кусок кода взят для примера, такая проблема присутствует в большинстве условий if ( $show_current ){ … } (возможно во всех, но не утверждаю, так как все не проверял)
Привет! Классная работа проделана! У меня вопрос:
дело в том, что у меня нет категорий, идет сразу http://url/news_post/text_of_post
Где news_post это рубрика.
Отображение на сайте верное, только ссылка на новости имеет такой вид http://url/category/news_post/ и получается ведет на несуществующую страницу
Вот скрин на всякий случай, чтобы более наглядно https://i.imgur.com/tLiNFbo.png
PS Сайт сейчас на локальном компе
Код использую уже много лет, но вот заметил ошибку.
Есть две испытуемые статьи. Всё обычно: одна главная (корневая) рубрика и одна подрубрика.
Так вот прикол в том, что из одной определённой главной рубрики код ваших крошек от 2017 года не выводит ни одну подрубрику! С другими категориями работает нормально.
Поэтому забрёл сюда в поисках новой версии и установил её. Подрубрики стали выводиться!
Но радость длилась не долго, т.к. я обнаружил статью из другой главной рубрики, в которой не отображаются подрубрики кодом 2019 года, но отображаются старым кодом 2017!!!
Плагин Breadcrumb NAVXT правильно отображает обе статьи. Не хочется плагин ставить, может подскажете куда хоть копать?
Пока что решил вопрос так: проверяются все подкатегории поста на длину цепочки и выбирается первая самая длинная цепочка. Таким образом получилось ещё выводить больше подкатегорий для постов, которые состояли во многих категориях, включая только корневую.
$max=-1;
foreach( $cat as $category ){
$parents1 = get_ancestors( $category->cat_ID, ‘category’ );
if (count($parents1)>$max) {
$max=count($parents1);
$catID = $category->cat_ID;
$parents = $parents1;
}
}
Здравствуйте. Могли бы подсказать как сделать? Вот у меня услуги выводятся страницами. Я добавил их в родительские категории, и сейчас выводится — Главная — Род. категория — Страница
можно сделать — Главная — Страница?
Не выводятся хлебные крошки на странице вывода записей (то есть в файле index.php).
В чем может быть дело и как это исправить?
Здравствуйте !
В статье вы пишите:
«Функцию необходимо поместить в файл functions.php вашей WordPress-темы. После этого в то место шаблона, где хотите выводить «хлебные крошки», добавьте следующий код:»
Я начинающий и не совсем понял куда именно в какой файл нужно будет добавить этот код?
И ещё вопрос: если я захочу вывести хлебные крошки внизу подвала, то куда мне нужно добавить этот код?
Подскажите пожалуйста, это у меня ошибка или этот код не работает на index.php странице? Суть проблемы: есть страница блога она формируется у меня с помощью index.php. При размещении
ничего выводится, хотя на внутренних страницах код работает. Может стоит для блога отдельную tpl-blog.php сделать?
СПАСИБО!
Здравствуйте !
Подскажите пожалуйста как с помощью вашего кода можно добавить мультиязычность ссылке на главную ?
$text[‘home’] = pll_e(‘fl-breadcrumbshome’); // текст ссылки «Главная»
С плагином полиланг, выше показал как не работает, подскажите пожалйста что не так ?(
Тут отвечал на этот же вопрос.
Спасибо еще раз, все получилось, извините за невнимательность.
Здравствуйте! Гугл ругается на отсутствие значения в поле position
Хотя фактически оно там есть. Как это можно исправить?
Только что проверил, у меня все в порядке, не ругается. Видимо, что-то у вас неправильно в коде.
Здравствуйте. Все круто, всегда пользовался. Но щас на вукомерсе поставил, тема нулевая(своя) ничего особого.
remove_action(‘woocommerce_before_main_content’,’woocommerce_breadcrumb’,20);
add_action(‘woocommerce_before_main_content’,’dimox_breadcrumbs’,20);
так вывожу, в категориях товаров, не выводится, только ссылка на главную, на странице магазина выводится. Подскажите, что можно сделать?
примерный линк
site.ru/product-category/sortovoj-prokat/
WooCommerce не использую, поэтому не могу подсказать.
Добрый день! Очень благодарен за эту крутую разметку. Скажите, а можно ли заставить работать крошки через какой-то шорткод […]?
Здравствуйте!
Использовал функцию, всё отображается, путь полный, но есть проблема — не работает переход в родительский раздел:
Находясь по адресу «Главная>Услуги>Услуга 1» не могу перейти на страницу «Услуги» — при клике просто обновляется текущая страница.
В чем может быть проблема?
P.S. Нашел в интернете версию функции от 2017 г. — всё работает, но там гугл ругается на position.
Точно такая же проблема. Подскажите плз ссылку на версию функции 2017
Предыдущие версии можно найти здесь.
А можно ли перевести значение %2$s если я хочу сделать перевод хлебных крошек. Суть такова, что иерархия получается такая ( Главная — Блог — Название статьи), вот соответственно Блог хочу перевести на английский. Может какой-то инной есть способ вывести название ссылки?
Спасибо за код)) очень пригодился))
Спасибо за работу!
Перечитал все комменты. Близкий ответ к своей проблемме нашел на 13 странице комментариев про произвольное поле с title. Сделал все как вы советовали. Изменил ваш код, создал произвольное поле с title, но эффекта не увидел.
А можно просто вызывать в хлебных крошках не тайтлы страницы а заголовки h1?
Произвольные поля у меня прописанны в functions.php следующим образом:
Есть еще вариант просто дать ограничение на количество слов в названии каждой хлебной крошки:
C помощью функции:
Но пока не понял как это прикрутить к вашему коду.
БЛАГО-ДАРЮ за пост.
Полезен. Важен. Выручил.
Приветствую! Ух… давно использую ваш метод, но вот возникла задача. Можно ли исключить из хлебных крошек подкатегории (если они имеются)? Например, если структура такая Главная/Машины/Маленькие/Лада Веста, то изменить ее на такую Главная/Машины/Лада Веста.
Маленькие в данном случае является подкатегорией категории Машины. Лада Веста — это запись.
Если это возможно, то подскажите, что нужно добавить/изменить в вашем коде.
Заранее спасибо, если откликнетесь)
Здравствуйте. Найдите этот кусок кода (быстро находится по поиску первой строки):
и поменяйте его на такой: