WordPress как на ладони
Хостинг, VPS/VDS и отдельные сервера только на SSD дисках. 7 дней бесплатного тестирования.

Хлебные крошки для 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(' » '); ?>
443 коммента
Полезные 30 Вопросы 8 Все
  • Макс

    Не подскажите я вот зарегистировал свой тип записи:

    function register_post_mebel(){
    	// Раздел вопроса - faqcat
    	register_taxonomy('category_mebel', array('mebel'), array(
    		'label'                 => 'Категории', // определяется параметром $labels->name
    		'labels'                => array(
    			'name'              => 'Категории',
    			'singular_name'     => 'Категория',
    			'search_items'      => 'Искать категорию',
    			'all_items'         => 'Все категории',
    			'parent_item'       => 'Родительская категория',
    			'parent_item_colon' => 'Родительская категория',
    			'edit_item'         => 'Редактировать категорию',
    			'update_item'       => 'Обновить категорию',
    			'add_new_item'      => 'Добавить категорию',
    			'new_item_name'     => 'Новая категория',
    			'menu_name'         => 'Категории',
    			'not_found'         => 'Категорий не найдено'
    		),
    		'description'           => 'Категории для товаров', // описание таксономии
    		'public'                => true,
    		'show_in_nav_menus'     => false, // равен аргументу public
    		'show_ui'               => true, // равен аргументу public
    		'show_tagcloud'         => false, // равен аргументу show_ui
    		'hierarchical'          => true,
    		'query_var'             => true,
    		'rewrite'               => array('slug'=>'category', 'hierarchical'=>true, 'with_front'=>false, 'feed'=>false ),
    		'show_admin_column'     => true, // Позволить или нет авто-создание колонки таксономии в таблице ассоциированного типа записи. (с версии 3.5)
    	) );
    
    	register_post_type('mebel', array(
    		'labels'             => array(
    			'name'               => 'Каталог',
    			'singular_name'      => 'Товар',
    			'add_new'            => 'Добавить новый',
    			'add_new_item'       => 'Добавить новый товар',
    			'edit_item'          => 'Редактировать товар',
    			'new_item'           => 'Новый товар',
    			'view_item'          => 'Посмотреть товар',
    			'search_items'       => "Найти товар",
    			'not_found'          => 'Товаров не найдено',
    			'not_found_in_trash' => 'В корзине товаров не найдено',
    			'menu_name'          => 'Товары'
    
    		),
    		'public'             => true,
    		'publicly_queryable' => true,
    		'show_ui'            => true,
    		'show_in_menu'       => true,
    		'query_var'          => true,
    		'rewrite'            => true,
    		'capability_type'    => 'post',
    		'has_archive'        => true,
    		'hierarchical'       => false,
    		'menu_icon'          => 'dashicons-archive',
    		'menu_position'      => 3,
    		'supports'           => array('title','editor')
    	) );
    }
    

    После использую для вывода хлебных крошек ваш код в начале(большой), все хорошо выводиться, только когда я выбираю к примеру категорию для товара 1 уровня и ее потомка(2 уровня), то в хлебных крошках выводится только категория 1 уровня, а когда я выбераю только ее потомка(2 уровня), то выводится как нужно. Как сделать чтобы при выборе обеих категорий они выводились как нужно.

    • Kama7019

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

    • Александр

      Надеюсь автор не будет против, с этой проблемой справляются вот эти крошки.
      github.com/justintadlock/breadcrumb-trail

  • Сережа

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

    1
    • Kama7019

      Ну посмотри что делает код, там лишнего ничего нет, все нужно! И это еще мало кода, ты загляни в популярные плагины по этой теме - вот где большой код smile

      1
  • У меня вопрос по платной версии. Сейчас у нас на сайте стоит Ваш бесплатный код. Сможет ли платная версия решить нашу проблему.
    Есть товар в двух категориях:

    1. Главная > Магазин > Удилища > Ущилища карповые > Удилища карповые Daiwa
    2. Главная > Магазин > Hовинки > Новинки карпфишинга

    У товара в URL стоит путь: .../udilischa/udilischa-karpovye/udilischa-karpovye-daiwa/...
    А в крошках пишет: Главная > Магазин > Hовинки > Новинки карпфишинга

    Хотелось бы, чтобы крошки отображали тот же путь, что и в URL, а то путаница происходит. Платная версия лучше работает с приоритетными таксономиями или также?

  • @ Ilya

    Микроразметка гугла ругается - Необходимо указать значение для поля position. Как решить эту проблему ?

    2
    Ответить2 месяца назад #
    • Kama7019

      Ммм, а там что не указано значение разве? Можно ошибку посмотреть?

      Ответить2 месяца назад #
      • Василий

        Нет в коде position. Раньше гугл не ругался, а теперь ругается. Требует itemprop="position"

        Ответитьмесяц назад #
        • Kama7019

          Хм, в этой версии нет его. Я её больше не расширяю, только баги правлю если встретятся. Для itemprop="position" и других фишек, смотрите платную версию (ссылка на нее в статье).

          Ответитьмесяц назад #
          • Василий

            Ну, в общем-то, это не "фишка", отсутствие itemprop="position" выдает ошибку в валидаторе гугла, а значит это баг. Но Вам виднее. Поставил Breadcrumb NavXT, всё настроил и работает. Бесплатная версия. Неограниченная! Дело, опять же, Ваше, но 5000 руб. с учетом скидки только лишь за хлебные крошки (имею ввиду неограниченную лицензию) - это перебор.

            Ответитьмесяц назад #
            • Kama7019

              Время найду поправлю тут этот момент, спасибо за комменты.

              Ответитьмесяц назад #
  • @ Ирина

    Здравствуйте, есть проблема, идет поиск по нескольким тегам. В крошках показывает только первый тег, не подскажите, как вывести все?

    Ответитьмесяц назад #
  • роман

    Здрасте.. Простите а где взять такую форму коментариев? как вот у вас на сайте!

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