WordPress как на ладони
wordpress jino

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

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

Хлебные крошки (с англ. 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.1
 */
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 = $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(' » '); ?>
Хлебные крошки для WordPress (breadcrumbs) 463 комментария
Полезные 27 Вопросы 12 Все
  • Denis Semenov13 cайт: denisemenov.com

    Ох, не хватает <meta itemprop="position" content="#позиция" /> для совсем идеального варианта... smile

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

      Эта старая версия кода, есть новая усовершенствованная. В новой версии это есть, но я пока её не выкладывал, наверное будет плагин, возможно платный... Если интересно, напиши в личку.

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

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

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

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

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

    Здравствуйте! Спасибо за сайт и готовые полезные решения!
    Использовал 1 вариант хлебных крошек, всё работает отлично.

    Но возникла необходимость сделать индивидуальное отображение сайта в зависимости от передаваемого параметра в урле.

    Например, если заходят с мобилы такой-то, то показывать другой баннер и меню к примеру.

    Всё получилось хорошо, только вот в хлебных крошках не знаю как этот параметр приделать.

    Нужно, чтобы каждая ссылка в крошках содержала в урле параметр (and=1).

    Если не трудно, помогите. Возможно за оплату.

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

    Kama, привет еще раз! Осталась небольшая проблемка со страницей архива произвольного типа записей: на сайте есть произвольный тип записи "project", при нахождении на странице объекта крошки формируются корректно, элементы обернуты в соответствующий код:
    Главная / Проекты / Проект1,
    а уровнем выше:
    Главная / Проекты , но к "Проекты" не применяется оформление $args['title_patt'] = '<li class="active">%s</li>';

    Строка кода $arg->sep = '<span class="kb_sep">'. $arg->sep .'</span>'; // дополним мной закомментированна из-за того что генерирует лишний код, у меня крошки имеют формат списка, где разделитель формируется посредством css.

    Не могу понять как в крошках заголовок страницы архива произвольного типа записей "Проекты" обернуть в <li class="active">%s</li>

    1
    Ответить28 дней назад #
  • Дмитрий

    Здравствуйте, ваш код хорошо подошел спасибо вам за вашу работу, часто смотрю ваши статьи очень полезно.

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

    Ответить22 дня назад #

Здравствуйте, !

Ваш комментарий