WordPress как на ладони
Недорогой хостинг для сайтов на WordPress: wordpress.jino.ru Купить персональные IPV4 и IPV6 прокси

Хлебные крошки для WordPress (breadcrumbs)

Вы наверняка уже знакомы с понятием «Хлебные крошки» в веб-разработке и возможно даже приходилось реализовывать эти самые «крошки» на WordPress.

Хлебные крошки (с англ. breadcrumbs) — это элемент навигации по сайту, выглядит как путь от главной страницы до текущей, на которой находится пользователь. Более логичное название — навигационная цепочка. Хлебные крошки называются так по ироничной аналогии со сказкой, в которой дети, когда их завели в лес во второй раз, не смогли найти обратную дорогу, так как на этот раз вместо маленьких камешков они оставляли за собой хлебные крошки, впоследствии склеванные лесными птицами.

Если этот код работает не так как нужно, есть платная версия в виде плагина. Этот код я больше не поддерживаю.

Смотреть платную версию Kama Breadcrumbs

Выглядят «хлебные крошки» так:

Главная страница » Раздел » Подраздел » Текущая страница

«Хлебные крошки» наиболее рекомендуются сайтам со сложной структурой разделов (рубрик), ведь с ними гораздо легче и понятнее разобраться посетителю в каком разделе сайта он находится и если нужно, можно легко подняться на уровень выше и осмотреть ветку целиком.

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

Функция будет показывать «хлебные крошки» для страниц следующих типов:
  • Главная страница;
  • Постоянная страница;
  • Страница любого древовидного типа записи;
  • Страница поста;
  • Страница вложения (учитывается прикреплено вложение к записи или нет);
  • Любой не древовидный тип записи (прикрепленный к любой таксономии, например, к стандартным "рубрикам");
  • Страница рубрики;
  • Страница меток;
  • Страница таксономии (как древовидной, так и одноуровневой (метки));
  • Страницы архивов по датам, авторам;
  • Страница пагинации для всех типов где предусмотрена пагинация
    (отображается как: Главная » Рубрика » Страница 2,3,4).
  • Поддерживает микроразметку. Инструменты для проверки: для Яндекса и для Google.

Из особенностей, которые я не встретил в аналогичных функциях представленных в сети, стоит отметить правильный показ "хлебных крошек" для произвольных типов записей и произвольных таксономий, также в аналогах страница пагинации отображалась как, например, "Рубрика (страница 2)", а не "Рубрика > Страница 2", что, на мой взгляд, неправильно.

Для визуального восприятия, взгляните как выглядят «хлебные крошки» разных типов:

Хлебные крошки

Также, я старался написать как можно менее прожорливый вариант функции.

Что касается плагина Breadcrumb NavXT, который повсеместно рекомендуется для вывода «хлебных крошек» — он мне не понравился из-за своей громоздкости. Моя функция не хуже, а в чем-то даже лучше: за счет функциональности, компактности и местами быстродействия!

Также функция поддерживает микроразметки: schema.org или RDF, смотрите параметр 'markup'.

меню

Функция «хлебных крошек» для WordPress

<?php

/**
 * Хлебные крошки для WordPress (breadcrumbs)
 *
 * @param  string [$sep  = '']      Разделитель. По умолчанию ' » '
 * @param  array  [$l10n = array()] Для локализации. См. переменную $default_l10n.
 * @param  array  [$args = array()] Опции. См. переменную $def_args
 * @return string Выводит на экран HTML код
 *
 * version 3.3.2
 */
function kama_breadcrumbs( $sep = ' » ', $l10n = array(), $args = array() ){
	$kb = new Kama_Breadcrumbs;
	echo $kb->get_crumbs( $sep, $l10n, $args );
}

class Kama_Breadcrumbs {

	public $arg;

	// Локализация
	static $l10n = array(
		'home'       => 'Главная',
		'paged'      => 'Страница %d',
		'_404'       => 'Ошибка 404',
		'search'     => 'Результаты поиска по запросу - <b>%s</b>',
		'author'     => 'Архив автора: <b>%s</b>',
		'year'       => 'Архив за <b>%d</b> год',
		'month'      => 'Архив за: <b>%s</b>',
		'day'        => '',
		'attachment' => 'Медиа: %s',
		'tag'        => 'Записи по метке: <b>%s</b>',
		'tax_tag'    => '%1$s из "%2$s" по тегу: <b>%3$s</b>',
		// tax_tag выведет: 'тип_записи из "название_таксы" по тегу: имя_термина'.
		// Если нужны отдельные холдеры, например только имя термина, пишем так: 'записи по тегу: %3$s'
	);

	// Параметры по умолчанию
	static $args = array(
		'on_front_page'   => true,  // выводить крошки на главной странице
		'show_post_title' => true,  // показывать ли название записи в конце (последний элемент). Для записей, страниц, вложений
		'show_term_title' => true,  // показывать ли название элемента таксономии в конце (последний элемент). Для меток, рубрик и других такс
		'title_patt'      => '<span class="kb_title">%s</span>', // шаблон для последнего заголовка. Если включено: show_post_title или show_term_title
		'last_sep'        => true,  // показывать последний разделитель, когда заголовок в конце не отображается
		'markup'          => 'schema.org', // 'markup' - микроразметка. Может быть: 'rdf.data-vocabulary.org', 'schema.org', '' - без микроразметки
										   // или можно указать свой массив разметки:
										   // array( 'wrappatt'=>'<div class="kama_breadcrumbs">%s</div>', 'linkpatt'=>'<a href="%s">%s</a>', 'sep_after'=>'', )
		'priority_tax'    => array('category'), // приоритетные таксономии, нужно когда запись в нескольких таксах
		'priority_terms'  => array(), // 'priority_terms' - приоритетные элементы таксономий, когда запись находится в нескольких элементах одной таксы одновременно.
									  // Например: array( 'category'=>array(45,'term_name'), 'tax_name'=>array(1,2,'name') )
									  // 'category' - такса для которой указываются приор. элементы: 45 - ID термина и 'term_name' - ярлык.
									  // порядок 45 и 'term_name' имеет значение: чем раньше тем важнее. Все указанные термины важнее неуказанных...
		'nofollow' => false, // добавлять rel=nofollow к ссылкам?

		// служебные
		'sep'             => '',
		'linkpatt'        => '',
		'pg_end'          => '',
	);

	function get_crumbs( $sep, $l10n, $args ){
		global $post, $wp_query, $wp_post_types;

		self::$args['sep'] = $sep;

		// Фильтрует дефолты и сливает
		$loc = (object) array_merge( apply_filters('kama_breadcrumbs_default_loc', self::$l10n ), $l10n );
		$arg = (object) array_merge( apply_filters('kama_breadcrumbs_default_args', self::$args ), $args );

		$arg->sep = '<span class="kb_sep">'. $arg->sep .'</span>'; // дополним

		// упростим
		$sep = & $arg->sep;
		$this->arg = & $arg;

		// микроразметка ---
		if(1){
			$mark = & $arg->markup;

			// Разметка по умолчанию
			if( ! $mark ) $mark = array(
				'wrappatt'  => '<div class="kama_breadcrumbs">%s</div>',
				'linkpatt'  => '<a href="%s">%s</a>',
				'sep_after' => '',
			);
			// rdf
			elseif( $mark === 'rdf.data-vocabulary.org' ) $mark = array(
				'wrappatt'   => '<div class="kama_breadcrumbs" prefix="v: http://rdf.data-vocabulary.org/#">%s</div>',
				'linkpatt'   => '<span typeof="v:Breadcrumb"><a href="%s" rel="v:url" property="v:title">%s</a>',
				'sep_after'  => '</span>', // закрываем span после разделителя!
			);
			// schema.org
			elseif( $mark === 'schema.org' ) $mark = array(
				'wrappatt'   => '<div class="kama_breadcrumbs" itemscope itemtype="http://schema.org/BreadcrumbList">%s</div>',
				'linkpatt'   => '<span itemprop="itemListElement" itemscope itemtype="http://schema.org/ListItem"><a href="%s" itemprop="item"><span itemprop="name">%s</span></a></span>',
				'sep_after'  => '',
			);

			elseif( ! is_array($mark) )
				die( __CLASS__ .': "markup" parameter must be array...');

			$wrappatt  = $mark['wrappatt'];
			$arg->linkpatt  = $arg->nofollow ? str_replace('<a ','<a rel="nofollow"', $mark['linkpatt']) : $mark['linkpatt'];
			$arg->sep      .= $mark['sep_after']."\n";
		}

		$linkpatt = $arg->linkpatt; // упростим

		$q_obj = get_queried_object();

		// может это архив пустой таксы?
		$ptype = null;
		if( empty($post) ){
			if( isset($q_obj->taxonomy) )
				$ptype = & $wp_post_types[ get_taxonomy($q_obj->taxonomy)->object_type[0] ];
		}
		else $ptype = & $wp_post_types[ $post->post_type ];

		// paged
		$arg->pg_end = '';
		if( ($paged_num = get_query_var('paged')) || ($paged_num = get_query_var('page')) )
			$arg->pg_end = $sep . sprintf( $loc->paged, (int) $paged_num );

		$pg_end = $arg->pg_end; // упростим

		$out = '';

		if( is_front_page() ){
			return $arg->on_front_page ? sprintf( $wrappatt, ( $paged_num ? sprintf($linkpatt, get_home_url(), $loc->home) . $pg_end : $loc->home ) ) : '';
		}
		// страница записей, когда для главной установлена отдельная страница.
		elseif( is_home() ) {
			$out = $paged_num ? ( sprintf( $linkpatt, get_permalink($q_obj), esc_html($q_obj->post_title) ) . $pg_end ) : esc_html($q_obj->post_title);
		}
		elseif( is_404() ){
			$out = $loc->_404;
		}
		elseif( is_search() ){
			$out = sprintf( $loc->search, esc_html( $GLOBALS['s'] ) );
		}
		elseif( is_author() ){
			$tit = sprintf( $loc->author, esc_html($q_obj->display_name) );
			$out = ( $paged_num ? sprintf( $linkpatt, get_author_posts_url( $q_obj->ID, $q_obj->user_nicename ) . $pg_end, $tit ) : $tit );
		}
		elseif( is_year() || is_month() || is_day() ){
			$y_url  = get_year_link( $year = get_the_time('Y') );

			if( is_year() ){
				$tit = sprintf( $loc->year, $year );
				$out = ( $paged_num ? sprintf($linkpatt, $y_url, $tit) . $pg_end : $tit );
			}
			// month day
			else {
				$y_link = sprintf( $linkpatt, $y_url, $year);
				$m_url  = get_month_link( $year, get_the_time('m') );

				if( is_month() ){
					$tit = sprintf( $loc->month, get_the_time('F') );
					$out = $y_link . $sep . ( $paged_num ? sprintf( $linkpatt, $m_url, $tit ) . $pg_end : $tit );
				}
				elseif( is_day() ){
					$m_link = sprintf( $linkpatt, $m_url, get_the_time('F'));
					$out = $y_link . $sep . $m_link . $sep . get_the_time('l');
				}
			}
		}
		// Древовидные записи
		elseif( is_singular() && $ptype->hierarchical ){
			$out = $this->_add_title( $this->_page_crumbs($post), $post );
		}
		// Таксы, плоские записи и вложения
		else {
			$term = $q_obj; // таксономии

			// определяем термин для записей (включая вложения attachments)
			if( is_singular() ){
				// изменим $post, чтобы определить термин родителя вложения
				if( is_attachment() && $post->post_parent ){
					$save_post = $post; // сохраним
					$post = get_post($post->post_parent);
				}

				// учитывает если вложения прикрепляются к таксам древовидным - все бывает :)
				$taxonomies = get_object_taxonomies( $post->post_type );
				// оставим только древовидные и публичные, мало ли...
				$taxonomies = array_intersect( $taxonomies, get_taxonomies( array('hierarchical' => true, 'public' => true) ) );

				if( $taxonomies ){
					// сортируем по приоритету
					if( ! empty($arg->priority_tax) ){
						usort( $taxonomies, function($a,$b)use($arg){
							$a_index = array_search($a, $arg->priority_tax);
							if( $a_index === false ) $a_index = 9999999;

							$b_index = array_search($b, $arg->priority_tax);
							if( $b_index === false ) $b_index = 9999999;

							return ( $b_index === $a_index ) ? 0 : ( $b_index < $a_index ? 1 : -1 ); // меньше индекс - выше
						} );
					}

					// пробуем получить термины, в порядке приоритета такс
					foreach( $taxonomies as $taxname ){
						if( $terms = get_the_terms( $post->ID, $taxname ) ){
							// проверим приоритетные термины для таксы
							$prior_terms = & $arg->priority_terms[ $taxname ];
							if( $prior_terms && count($terms) > 2 ){
								foreach( (array) $prior_terms as $term_id ){
									$filter_field = is_numeric($term_id) ? 'term_id' : 'slug';
									$_terms = wp_list_filter( $terms, array($filter_field=>$term_id) );

									if( $_terms ){
										$term = array_shift( $_terms );
										break;
									}
								}
							}
							else
								$term = array_shift( $terms );

							break;
						}
					}
				}

				if( isset($save_post) ) $post = $save_post; // вернем обратно (для вложений)
			}

			// вывод

			// все виды записей с терминами или термины
			if( $term && isset($term->term_id) ){
				$term = apply_filters('kama_breadcrumbs_term', $term );

				// attachment
				if( is_attachment() ){
					if( ! $post->post_parent )
						$out = sprintf( $loc->attachment, esc_html($post->post_title) );
					else {
						if( ! $out = apply_filters('attachment_tax_crumbs', '', $term, $this ) ){
							$_crumbs    = $this->_tax_crumbs( $term, 'self' );
							$parent_tit = sprintf( $linkpatt, get_permalink($post->post_parent), get_the_title($post->post_parent) );
							$_out = implode( $sep, array($_crumbs, $parent_tit) );
							$out = $this->_add_title( $_out, $post );
						}
					}
				}
				// single
				elseif( is_single() ){
					if( ! $out = apply_filters('post_tax_crumbs', '', $term, $this ) ){
						$_crumbs = $this->_tax_crumbs( $term, 'self' );
						$out = $this->_add_title( $_crumbs, $post );
					}
				}
				// не древовидная такса (метки)
				elseif( ! is_taxonomy_hierarchical($term->taxonomy) ){
					// метка
					if( is_tag() )
						$out = $this->_add_title('', $term, sprintf( $loc->tag, esc_html($term->name) ) );
					// такса
					elseif( is_tax() ){
						$post_label = $ptype->labels->name;
						$tax_label = $GLOBALS['wp_taxonomies'][ $term->taxonomy ]->labels->name;
						$out = $this->_add_title('', $term, sprintf( $loc->tax_tag, $post_label, $tax_label, esc_html($term->name) ) );
					}
				}
				// древовидная такса (рибрики)
				else {
					if( ! $out = apply_filters('term_tax_crumbs', '', $term, $this ) ){
						$_crumbs = $this->_tax_crumbs( $term, 'parent' );
						$out = $this->_add_title( $_crumbs, $term, esc_html($term->name) );                     
					}
				}
			}
			// влоежния от записи без терминов
			elseif( is_attachment() ){
				$parent = get_post($post->post_parent);
				$parent_link = sprintf( $linkpatt, get_permalink($parent), esc_html($parent->post_title) );
				$_out = $parent_link;

				// вложение от записи древовидного типа записи
				if( is_post_type_hierarchical($parent->post_type) ){
					$parent_crumbs = $this->_page_crumbs($parent);
					$_out = implode( $sep, array( $parent_crumbs, $parent_link ) );
				}

				$out = $this->_add_title( $_out, $post );
			}
			// записи без терминов
			elseif( is_singular() ){
				$out = $this->_add_title( '', $post );
			}
		}

		// замена ссылки на архивную страницу для типа записи
		$home_after = apply_filters('kama_breadcrumbs_home_after', '', $linkpatt, $sep, $ptype );

		if( '' === $home_after ){
			// Ссылка на архивную страницу типа записи для: отдельных страниц этого типа; архивов этого типа; таксономий связанных с этим типом.
			if( $ptype && $ptype->has_archive && ! in_array( $ptype->name, array('post','page','attachment') )
				&& ( is_post_type_archive() || is_singular() || (is_tax() && in_array($term->taxonomy, $ptype->taxonomies)) )
			){
				$pt_title = $ptype->labels->name;

				// первая страница архива типа записи
				if( is_post_type_archive() && ! $paged_num )
					$home_after = sprintf( $this->arg->title_patt, $pt_title );
				// singular, paged post_type_archive, tax
				else{
					$home_after = sprintf( $linkpatt, get_post_type_archive_link($ptype->name), $pt_title );

					$home_after .= ( ($paged_num && ! is_tax()) ? $pg_end : $sep ); // пагинация
				}
			}
		}

		$before_out = sprintf( $linkpatt, home_url(), $loc->home ) . ( $home_after ? $sep.$home_after : ($out ? $sep : '') );

		$out = apply_filters('kama_breadcrumbs_pre_out', $out, $sep, $loc, $arg );

		$out = sprintf( $wrappatt, $before_out . $out );

		return apply_filters('kama_breadcrumbs', $out, $sep, $loc, $arg );
	}

	function _page_crumbs( $post ){
		$parent = $post->post_parent;

		$crumbs = array();
		while( $parent ){
			$page = get_post( $parent );
			$crumbs[] = sprintf( $this->arg->linkpatt, get_permalink($page), esc_html($page->post_title) );
			$parent = $page->post_parent;
		}

		return implode( $this->arg->sep, array_reverse($crumbs) );
	}

	function _tax_crumbs( $term, $start_from = 'self' ){
		$termlinks = array();
		$term_id = ($start_from === 'parent') ? $term->parent : $term->term_id;
		while( $term_id ){
			$term       = get_term( $term_id, $term->taxonomy );
			$termlinks[] = sprintf( $this->arg->linkpatt, get_term_link($term), esc_html($term->name) );
			$term_id    = $term->parent;
		}

		if( $termlinks )
			return implode( $this->arg->sep, array_reverse($termlinks) ) /*. $this->arg->sep*/;
		return '';
	}

	// добалвяет заголовок к переданному тексту, с учетом всех опций. Добавляет разделитель в начало, если надо.
	function _add_title( $add_to, $obj, $term_title = '' ){
		$arg = & $this->arg; // упростим...
		$title = $term_title ? $term_title : esc_html($obj->post_title); // $term_title чиститься отдельно, теги моугт быть...
		$show_title = $term_title ? $arg->show_term_title : $arg->show_post_title;

		// пагинация
		if( $arg->pg_end ){
			$link = $term_title ? get_term_link($obj) : get_permalink($obj);
			$add_to .= ($add_to ? $arg->sep : '') . sprintf( $arg->linkpatt, $link, $title ) . $arg->pg_end;
		}
		// дополняем - ставим sep
		elseif( $add_to ){
			if( $show_title )
				$add_to .= $arg->sep . sprintf( $arg->title_patt, $title );
			elseif( $arg->last_sep )
				$add_to .= $arg->sep;
		}
		// sep будет потом...
		elseif( $show_title )
			$add_to = sprintf( $arg->title_patt, $title );

		return $add_to;
	}

}

/**
 * Изменения:
 * 3.3 - новые хуки: attachment_tax_crumbs, post_tax_crumbs, term_tax_crumbs. Позволяют дополнить крошки таксономий.
 * 3.2 - баг с разделителем, с отключенным 'show_term_title'. Стабилизировал логику.
 * 3.1 - баг с esc_html() для заголовка терминов - с тегами получалось криво...
 * 3.0 - Обернул в класс. Добавил опции: 'title_patt', 'last_sep'. Доработал код. Добавил пагинацию для постов.
 * 2.5 - ADD: Опция 'show_term_title'
 * 2.4 - Мелкие правки кода
 * 2.3 - ADD: Страница записей, когда для главной установлена отделенная страница.
 * 2.2 - ADD: Link to post type archive on taxonomies page
 * 2.1 - ADD: $sep, $loc, $args params to hooks
 * 2.0 - ADD: в фильтр 'kama_breadcrumbs_home_after' добавлен четвертый аргумент $ptype
 * 1.9 - ADD: фильтр 'kama_breadcrumbs_default_loc' для изменения локализации по умолчанию
 * 1.8 - FIX: заметки, когда в рубрике нет записей
 * 1.7 - Улучшена работа с приоритетными таксономиями.
 */

Вставлять этот код нужно в файл шаблона functions.php или непосредственно в тот файл где вызывается функция.

Вызывать функцию нужно в шаблоне, в том месте, где должны выводится крошки, так:

<?php if( function_exists('kama_breadcrumbs') ) kama_breadcrumbs(); ?>

Если нужно поменять разделитель между ссылками, укажите первый параметр:

<?php if( function_exists('kama_breadcrumbs') ) kama_breadcrumbs(' » '); ?>
меню

Примеры использование фильтров

#1 Установка параметров через фильтр

Измени дефолтные параметры через фильтр

add_filter('kama_breadcrumbs_default_args', function($args){
	$args['on_front_page']   = 0;
	$args['show_post_title'] = '';
	$args['priority_tax']    = array('mytax');
	return $args;
} );

Если установить параметры при вызове функции в третьем аргументе функции, то они перебьют параметры указанные в фильтре...

#3 Пример перевода крошек на английский

Эти примеры показывают как перевести крошки на нужный язык или просто изменить дефолтные значения:

Вариант 1

При вызове функции нужно указать строки локализации так:

// Локализация
if( function_exists('kama_breadcrumbs') ){

	$myl10n = array(
		'home'       => 'Front page',
		'paged'      => 'Page %d',
		'_404'       => 'Error 404',
		'search'     => 'Search results by query - <b>%s</b>',
		'author'     => 'Author archve: <b>%s</b>',
		'year'       => 'Archive by <b>%d</b> год',
		'month'      => 'Archive by: <b>%s</b>',
		'day'        => '',
		'attachment' => 'Media: %s',
		'tag'        => 'Posts by tag: <b>%s</b>',
		'tax_tag'    => '%1$s from "%2$s" by tag: <b>%3$s</b>',
		// tax_tag выведет: 'тип_записи из "название_таксы" по тегу: имя_термина'. 
		// Если нужны отдельные холдеры, например только имя термина, пишем так: 'записи по тегу: %3$s'
	);

	kama_breadcrumbs(' » ', $myl10n );

}
Вариант 2

C версии 1.9. Можно использовать хук kama_breadcrumbs_default_loc, чтобы для каждого вызова одно и тоже не указывать. Для этого рядом с исходным кодом крошек добавьте такой хук:

add_filter('kama_breadcrumbs_default_loc', function($l10n){
	// Локализация
	return array(
		'home'       => 'Front page',
		'paged'      => 'Page %d',
		'_404'       => 'Error 404',
		'search'     => 'Search results by query - <b>%s</b>',
		'author'     => 'Author archve: <b>%s</b>',
		'year'       => 'Archive by <b>%d</b> год',
		'month'      => 'Archive by: <b>%s</b>',
		'day'        => '',
		'attachment' => 'Media: %s',
		'tag'        => 'Posts by tag: <b>%s</b>',
		'tax_tag'    => '%1$s from "%2$s" by tag: <b>%3$s</b>',
		// tax_tag выведет: 'тип_записи из "название_таксы" по тегу: имя_термина'. 
		// Если нужны отдельные холдеры, например только имя термина, пишем так: 'записи по тегу: %3$s'
	);
});

Далее, используйте вызов в шаблоне как обычно, крошки будут переведены на англ.:

function_exists('kama_breadcrumbs') && kama_breadcrumbs();

Установки через хук имеют меньший приоритет, чем через вызов функции из варианта 1. Это значит, что если указать локализацию через хук, то потом через вызов можно перебить локализацию отдельных строк.

#3 Добавление произвольной ссылки в начало крошек

Допустим нам нужно добавить после пункта "Главная" ссылку на страницу 7, если в текущий момент мы находимся в категории 5 или в её дочерней категории (учитывается один уровень вложенности).

Для этого добавьте такой хук рядом с кодом крошек:

add_action('kama_breadcrumbs_home_after', 'my_breadcrumbs_home_after', 10, 4);
function my_breadcrumbs_home_after( $false, $linkpatt, $sep, $ptype ){
	// если мы в рубрике с ID 5 или в дочерней рубрике,
	// то дополним начало крошек ссылкой на страницу с ID 7
	$qo = get_queried_object();
	if( is_category() && ( $qo->term_id == 5 || $qo->parent == 5 ) ){
		$page = get_post( 7 );
		return sprintf( $linkpatt, get_permalink($page), $page->post_title ) . $sep;
	}

	return $false;
}

#4 Добавление еще таксономий в крошки

По умолчанию в крошках обрабатывается только одна таксономи. Но иногда нужно несколько, для этого в версии 3.3 я вставил хуки: 'attachment_tax_crumbs', 'post_tax_crumbs', 'term_tax_crumbs'.

Допустим, у нас есть тип записи realty и 3 таксы для него: country, type_deal, type_realty. Нужно, чтобы у страницы записи в крошках отображались все таксы в указанном порядке. Также нужно, чтобы на каждой странице таксы указывались все предыдущие таксы и текущая в указанном порядке: country > type_deal > type_realty...

// apply_filters('term_tax_crumbs', '', $term, $that );
add_filter('term_tax_crumbs', 'more_tax_crumbs', 10, 3);
add_filter('post_tax_crumbs', 'more_tax_crumbs', 10, 3);
function more_tax_crumbs( $empty, $term, $that ){
	$is_post_filter = doing_filter('post_tax_crumbs'); // else 'term_tax_crumbs'

	if(  ( $is_post_filter && is_singular('realty') ) || is_tax('country') ){
		global $post;

		$out = '';

		$out = $that->_tax_crumbs( $term, 'self' ) . $that->arg->sep; // базовая такса - country

		// тип сделки
		$term = get_query_var('type_deal');
		if( $term && ($term = get_term_by('slug', $term, 'type_deal')) )
			$out .= $that->_tax_crumbs( $term, 'self' ) . $that->arg->sep; // тип сделки

		// тип недвижимости
		$term = get_query_var('type_realty');
		if( $term && ($term = get_term_by('slug', $term, 'type_realty')) ){
			// запись
			if( $is_post_filter ){
				$_crumbs = $that->_tax_crumbs( $term, 'self' );
				$out .= $that->_add_title( $_crumbs, $post );   
			}
			// такса
			else {
				$_crumbs = $that->_tax_crumbs( $term, 'parent' );
				$out .= $that->_add_title( $_crumbs, $term, esc_html($term->name) );                
			}

		}

		return $out;
	}

	return $empty;
}
меню

Другой вариант крошек

Этот вариант я стянул по ссылке, которую в комментариях дал Master. Весьма занимательное решение, потому и не удержался.

Условно, этот код подойдет не только к WordPress, а вообще к любому движку. Для WordPress он подойдет:

  • во-первых, если включены ЧПУ;
  • во-вторых, если в ссылках присутствуют названия категории;
  • в-третьих, если названия статей и категорий в УРЛ пишутся в кириллице или это вообще англ. блог.

В других случаях будет работать, но, думаю, как-то не круто получится. Такие условия, потому что этот вариант разбирает ссылку на страницу (УРЛ) и по её элементам создает хлебные крошки. Ссылка разбивается разделителем /.

Допустим у нас УРЛ на статью имеет вид:
http://wptest.ru/рецепты/торт/готовим наполеон
тогда, мы получим цепочку крошек вида:
Главная » Рецепты » Торт » Готовим наполеон

function breadcrumbs($separator = ' » ', $home = 'Главная') {

	$path = array_filter(explode('/', parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH)));
	$base_url = ($_SERVER['HTTPS'] ? 'https' : 'http') . '://' . $_SERVER['HTTP_HOST'] . '/';
	$breadcrumbs = array("<a href=\"$base_url\">$home</a>");

	$last = end( array_keys($path) );

	foreach( $path as $x => $crumb ){
		$title = ucwords(str_replace(array('.php', '_'), Array('', ' '), $crumb));
		if( $x != $last ){
			$breadcrumbs[] = '<a href="'.$base_url.$crumb.'">'.$title.'</a>';
		}
		else {
			$breadcrumbs[] = $title;
		}
	}

	return implode( $separator, $breadcrumbs );
}

Используется аналогично моей функции, только на экран выводить надо через echo:

<?php echo breadcrumbs(' » '); ?>
445 комментов
Полезные 31 Вопросы 5 Все
  • ANTON

    что-то не понятно как работают фильтры post_tax_crumbs и term_tax_crumbs. Ничего не добавляется даже если просто возвращать в фильтре вручную забитую строчку, не понятно какие типы данных должен возвращать фильтр, не понятно что делают функции и какие параметры принимают. Есть какая-то документация к этому плагину или еще что-то? Какие типы таксономий можно добавлять?
    например я добавляю вот такой фильтр, но с ним абсолютно никаких изменений

    add_filter('post_tax_crumbs', 'more_tax_crumbs1', 11, 3);
    function more_tax_crumbs1( $empty, $term, $that ){
    	return 'напечатай это!';
    }
    Ответить2.5 года назад #
    • Kama7566

      Это не плагин. Документации нет - все тут. Доков по фильтрам этим нет, нужно смотреть код...

      Эти фильтры позволяют переопределить вывод крошек, т.е. если фильтр возвращает хоть что-то, то базовый код функции работать не будет, а будет работать фильтр. В твоем примере, текст будет показан только на отдельной странице...

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

      Ответить2.5 года назад #
  • Денис

    Спасибо огромное автору! Классное решение и очень удобное!!! Все работает!

    1
    Ответить2.5 года назад #
  • Alex

    Здравствуйте Тимур. Я установил ваш код хлебных крошек еще в 2015 году, помню микроразметка там была RDF. В прошлом году зашел к вам еще раз, и скопировал новый код, в этот раз была возможность поменять микроразметку на schema, что я и сделал. Теперь в выдаче гугл не отображаются крошки, а раньше были. Посмотрев код вашего сайта, заметил что у вас есть метатег property для крошек, у меня его нет. Скажите пожалуйста, в чем может быть дело, в этом теге или что то еще?

    Ответить2.3 года назад #
    • Kama7566

      Сейчас уже не помню... Сравни мой код и что у тебя получается... У меня используется код из этой статьи ничего отдельно я не добавлял... Возможно тебе нужно обновить код?

      Ответить2.3 года назад #
      • Alex

        Сейчас попробую и отпишусь

        Поменял, все тоже самое нет ни одного метатега property, может их руками в head прописать нужно?

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

        Я сейчас только заметил, что у тебя этот мета тег "Опен граф", может из за него у тебя отображаются крошки в гугле? Пойду искать инфу про эту разметку, внедрю, лишней не будет smile

        Ответить2.3 года назад #
  • Здравствуйте, Кама!
    Однажды вы помогли убрать custom post type из крошек, в версии 2.0
    Сейчас обновился до крайней новой версии 3.3 и решение :
    add_filter('kama_breadcrumbs_home_after', '__return_empty_string');
    не помогает избавиться от названия кастомного типа записи после "Главной" в крошках.
    Т.е. на single-page записи, крошки имеют вид:
    Главная » Продукция » Кухни » Классические кухни » Кухня Мария
    А хотелось бы:
    Главная » Кухни » Классические кухни » Кухня Мария
    Помогите пожалуйста, как это исправить?
    Указанный выше фильтр добавляю сразу после кода крошек.
    Спасибо за ваши Breadcrumbs.

    Ответить2.3 года назад #
    • Kama7566

      Замени

      add_filter('kama_breadcrumbs_home_after', '__return_empty_string');
      
      // на 
      
      add_filter('kama_breadcrumbs_home_after', '__return_false');
      1
      Ответить2.3 года назад #
      • Спасибо, Кама!)
        Если можно вопрос.
        А возможно ли добавить произвольную ссылку в крошки сразу после главной на определенной странице, например, на single?
        Почему спрашиваю?!
        Есть custom post type записи "Новости", но отдельной таксономии для них нет.
        Выше я просил помочь избавиться от названия типа кастомных записей в крошках - это да, так и нужно, и тогда крошки имеют вид:
        Главная >> Заголовок новости 1
        В идеале было бы:
        Главная >> Новости >> Заголовок новости 1

        Сама страница "Новости" - это шаблон "Template Name: Новости"

        Если не скрывать произвольный тип - "Новости" будут в крошках, но линк на них будет "https://site.ru/news/", где "news" - custom post type, но ведь такой страницы не существует, это всего лишь название типа.

        Посоветуй пожалуйста, как лучше сделать? Добавить таксономию "Новости"? И тогда она появится в крошках в нужном виде или можно в крошки добавить произвольную ссылку сразу после "Главная"?

        Извини за муторный вопрос, спасибо большое!

        Ответить2.3 года назад #
        • Kama7566

          Как раз через этот фильтр kama_breadcrumbs_home_after можно это сделать. Тебе придется написать функцию свою...

          // $home_after = apply_filters('kama_breadcrumbs_home_after', '', $linkpatt, $sep, $ptype );
          
          add_filter('kama_breadcrumbs_home_after', 'add_my_page_to_bc', 10, 4);
          function add_my_page_to_bc( $empty, $linkpatt, $sep, $ptype ){
          	$empty = false; // отключаем стандартный вывод
          
          	// добавляем ссылку на главную страницу новостей в новостях
          	if( is_single() ){
          		$empty = sprintf( $linkpatt, get_permalink(111), 'Новости' );
          	}
          
          	return $empty;
          }

          И смотри пример из статьи: #3 Добавление произвольной ссылки в начало крошек

          1
          Ответить2.3 года назад #
  • Alex ecoverm.com

    Помогите пожалуйста, в е-магазине на странице конкретного товара путь в крошках не всегда отображается правильно (вместо категории товара отображает один из его атрибутов).

    Как сейчас отображается:
    Главная » Товары » один из атрибутов товара (рандомно выбрало походу) » Имя товара

    Как нужно:
    Главная » Товары » Категория товара » Имя товара

    (вот ссылка на один из товаров, где крошки НЕ правильно работают: http://ecoverm.com/ru/shop/vermiculite-thermal-insulating-board-40/)
    (вот ссылка на один из товаров, где крошки правильно работают: http://ecoverm.com/ru/shop/exfoliated-vermiculite-fine/)

    Почему в некоторых товарах правильно (отображает категорию товара), а в некоторых - нет (отображает вместо категории рандомный атрибут товара)?ъ

    Спасибо за ответ!

    Ответить2.3 года назад #
    • Kama7566

      Причина в приоритетах. Укажи параметр priority_tax там укажи название таксономии категории товаров, чтобы она была в приоритете и выводилась в первую очередь.

      Ответить2.3 года назад #
  • Тимур wp-masters.ru

    Добрый день, Тимур.
    Очень благодарен за функцию, конечно невероятно огромная О_О )) но похоже на все случаи "жизни" сайта ))

    Ответить2.2 года назад #
  • Юрий zastolami.ru/product/stol-chikago-st-619...

    Приветствую. Использую данные хлебные крошки у себя в WOOCOMMERCE. Обнаружил проблему, а точнее не понимаю как регулировать какую категорию отображать в хлебных крошках если товар находиться в нескольких. https://zastolami.ru/product/stol-chikago-st-6191/ Вот этот стол находится и в деревянных столах и в белых столах и в раздвижных, все это категории woocoommerce, а в хлебных крошках отображается белые столы, я догадываюсь тут дело в алфавитном порядке, но хотелось бы как то управлять, что показывать в хлебных крошках. Пробовал сделать нужную мне категории главной из админки woocoommerce но не помогло. Подскажите как это решить...

    Ответить2 года назад #
    • Kama7566

      Нужно указать параметр 'priority_terms':

      'priority_terms' - приоритетные элементы таксономий, когда запись находится в нескольких элементах одной таксы одновременно. Например:

      array( 'category'=>array(45,'term_name'), 'tax_name'=>array(1,2,'name') )

      'category' - такса для которой указываются приор.
      элементы: 45 - ID термина и 'term_name' - ярлык.

      Порядок 45 и 'term_name' имеет значение: чем раньше тем важнее. Все указанные термины важнее неуказанных...

      Ответить2 года назад #
      • @ Andrey

        Спасибо за крошки и Ваш ответ про 'priority_terms'.

        WP, если запись входит в несколько элементов одной таксы, всегда делает одну из них "Основной", сделать основным другой элемент легко просто кликом по "Сделать первичным". Эти "Основной" и "Сделать первичным" - нативные элементы самого WP.

        Возможно ли выводить в крошках "Основной" элемент таксы?
        Хочешь в крошках другой элемент таксы? - идешь в запись, один клик и этот элемент стал основным и он выводится в крошках.

        Это было бы просто шикарно, идеально smile
        Спасибо!

        1
        Ответить2 года назад #
        • Kama7566

          Не понял, где в ВП такое есть?

          Ответить2 года назад #
          • @ Andrey

            Виноват, Kama, нифига это не нативные элементы, добрые люди подсказали, что это yoast seo добавляет эти "Основной" и "Сделать основным".
            К сожалению не нативные.
            Придется как-то пробовать своими силами добавить совместимость Ваших крошек и этих элементов плагина, ибо использовать это для управления крошками - трудно придумать вариант лучше.
            А возможно ли рассчитывать на Вашу помощь за посильный вклад в развитие Вашего замечательного сайта? Без нее вряд ли сам справлюсь

            Ответить2 года назад #
            • Kama7566

              Да, думаю можно. Напиши в личку. Вообще код крошек у меня есть новый лучше этого по логике...

              Ответить2 года назад #
            • Kama7566

              Yoast плагин хранит ID первичного терма в метаполе _yoast_wpseo_primary_category. Вместо category может быть название другой таксы.

                  public function set_primary_term( $new_primary_term ) {
              		update_post_meta( $this->post_ID, WPSEO_Meta::$meta_prefix . 'primary_' . $this->taxonomy_name, $new_primary_term );
              	}

              От сюда нужно плясать... Нужно налету проверять есть ли такое метаполе у записи и добавлять его в параметры крошек...

              Ответить2 года назад #
  • Сергей

    Приветствую!

    Прочитал все кооментарии, начиная с 20-й страницы по 1-ю и наоборот, но осталось два вопроса. Пожалуйста помогите разобраться.

    1 . Правильно ли я понимаю, что избавиться от <span class="kb_sep"></span> в HTML коде можно только закомментировав строку?:

    // $arg->sep = '<span class="kb_sep">'. $arg->sep .'</span>'; // дополним

    В Bootstrap 3 Breadcrumbs - список, где даже пустой <span> может быть лишним.

    2 . Где необходимо указывать свои параметры переменных, учитывая праведное недовольство Автора редактированием кода?

    Есть комментарий

    // или можно указать свой массив разметки:
    // array( 'wrappatt'=>'<div class="kama_breadcrumbs">%s</div>', 'linkpatt'=>'<a href="%s">%s</a>', 'sep_after'=>'', )

    при 'markup' => '', подхватываются параметры:

                // Разметка по умолчанию
    			if( ! $mark ) $mark = array(
    				'wrappatt'  => '<div class="kama_breadcrumbs">%s</div>',
    				'linkpatt'  => '<a href="%s">%s</a>',
    				'sep_after' => '',
    			);

    здесь менять и дополнять список или...?

    Пробовал разместить в конце:

    add_filter('kama_breadcrumbs_default_args', function($args){
    	$args['wrappatt']      = '<ol class="breadcrumb">%s</ol>';
    	$args['linkpatt']      = '<li><a href="%s">%s</a></li>';
    	$args['sep_after']     = '';
    	$args['sep']     = '';
    	return $args;
    } );

    , но все равно подхватываются параметры по умолчанию.

    Заранее благодарен за ответ!

    Ответить2 года назад #
    • Kama7566

      Тебе нужно передать в архументах через хук параметр markup в со значением массива:

      add_filter('kama_breadcrumbs_default_args', function($args){
      	$args['markup'] = array(
      		'wrappatt' => '<ol class="breadcrumb">%s</ol>',
      		'linkpatt' => '<li><a href="%s">%s</a></li>',
      		'sep_after' => '',
      	);
      
      	return $args;
      } );
      Ответить2 года назад #
  • Андрей start-luck.ru

    Молодец и спасибо. Всё прекрасно работает. Хорошее решение.

    1
    Ответить2 года назад #
  • Дина

    Пожалуйста, подскажите как именно использовать код, чтобы убрать название поста? Им нужно заменить какую-то строчку или куда-то добавить?

    Ответить2 года назад #
    • Kama7566

      Чтобы убрать название поста есть параметр 'show_post_title', переключи его в false - 'show_post_title' => false

      Ответить2 года назад #
Здравствуйте, !     Войти . Зарегистрироваться