パラメータでカスタマイズしやすいWordPressのパンくずナビを作ってみた

前回のパラメータでカスタマイズしやすいWordPressのページナビを作ってみたに続き、パンくずナビも作ってみました。

カスタム投稿タイプの年月アーカイブとか、カスタム投稿タイプの寄稿者など複合条件までは対応できていませんが、カスタム投稿タイプ、カスタムタクソノミー、フロントページの表示設定など、多彩な設定に対応できています。

[2011.06.30追記]
プラグイン版を公開いたしました。一部修正してありますので、こちらをご利用ください。

導入方法

  1. 使っているテーマのfunctions.phpにCODE 1を、ページナビを使っていない方は、CODE 2も追記してください。あるいは、独自プラグインにしてしまってもいいです。(独自プラグインの作り方は、初心者でも10秒でできる WordPress プラグインの作り方WordPress でスニペットを簡単に管理する方法あたりを参考に)
  2. テーマファイルのページナビを表示したい位置に<?php bread_crumb(); ?>を追加してください。

これだけでも一応は、表示されるようになりますが、いくつかのパラメータで表示方法を変更することができます。

指定可能なパラメータ

type
stringを指定すると、リストではなく文字列として出力します。デフォルトはlist
home_label
トップページの表示テキスト。デフォルトは「トップページ」
search_label
検索結果の表示テキスト。デフォルトは「『%s』の検索結果」(%sが検索文字列)
404_label
404ページの表示テキスト。デフォルトは「404 Not Found」
category_label
カテゴリーの表示テキスト。デフォルトは「%s」(%sがカテゴリー名)
tag_label
投稿タグの表示テキスト。デフォルトは「%s」(%sが投稿タグ名)
taxonomy_label
カスタムタクソノミーの表示テキスト。デフォルトは「%s」(%sがタクソノミー名)
author_label
寄稿者の表示テキスト。デフォルトは「%s」(%sが寄稿者名)
attachment_label
アタッチメントの表示テキスト。デフォルトは「%s」(%sがアタッチメント名)
year_label
年の表示テキスト。デフォルトは「%s年」(%sが年の数字)
month_label
月の表示テキスト。デフォルトは「%s月」(%sが月の数字)
day_label
日の表示テキスト。デフォルトは「%s日」(%sが日の数字)
joint_string
typeでstringを指定した場合の結合文字列。デフォルトは「&gt;」(>)
navi_element
ラッパー要素名。divまたはnavを選択可能。デフォルトは空(要素無し)
elm_class
ラッパー要素のクラス名。ラッパー要素がなくタイプがリストの場合は、ulのクラス名となる。デフォルトは、「bread_crumb」
elm_id
ラッパー要素のid名。ラッパー要素がなくタイプがリストの場合は、ulのid名となる。デフォルトは、空。(idなし)
li_class
タイプがリストの場合のliに付くクラス名。デフォルトは空(なし)
class_prefix
各クラスに付く接頭辞。デフォルトは空(なし)
current_class
表示中のページのパンくずナビに付与されるクラス名。デフォルトは「current」
indent
タブでのインデント数。デフォルトは0。
echo
出力を行うか。デフォルトはtrue(出力する)。0またはfalseの指定でPHPの値としてreturnする。

CODE 1

function bread_crumb( $args = '' ) {
	$default = array(
		'type'				=> 'list',
		'home_label'		=> 'トップページ',
		'search_label'		=> '『%s』の検索結果',
		'404_label'			=> '404 Not Found',
		'category_label'	=> '%s',
		'tag_label'			=> '%s',
		'taxonomy_label'	=> '%s',
		'author_label'		=> '%s',
		'attachment_label'	=> '%s',
		'year_label'		=> '%s年',
		'month_label'		=> '%s月',
		'day_label'			=> '%s日',
		'joint_string'		=> ' &gt; ',
		'navi_element'		=> '',
		'elm_class'			=> 'bread_crumb',
		'elm_id'			=> '',
		'li_class'			=> '',
		'class_prefix'		=> '',
		'current_class'		=> 'current',
		'indent'			=> 0,
		'echo'				=> true,
	);
	$default = apply_filters( 'bread_crumb_default', $default );
	$args = wp_parse_args( $args, $default );

	$elm = in_array( $args['navi_element'], array( 'nav', 'div', '' ) ) ? $args['navi_element'] : 'div';
	$args['elm_id'] = is_array( $args['elm_id'] ) ? $default['elm_id'] : $args['elm_id'];
	$args['elm_id'] = preg_replace( '/[^\w_-]+/', '', $args['elm_id'] );
	$args['elm_id'] = preg_replace( '/^[\d_-]+/', '', $args['elm_id'] );

	$args['class_prefix'] = is_array( $args['class_prefix'] ) ? $default['class_prefix'] : $args['class_prefix'];
	$args['class_prefix'] = preg_replace( '/[^\w_-]+/', '', $args['class_prefix'] );
	$args['class_prefix'] = preg_replace( '/^[\d_-]+/', '', $args['class_prefix'] );
	
	$args['elm_class'] = sanitize_attr_classes( $args['elm_class'], $args['class_prefix'] );
	$args['li_class'] = sanitize_attr_classes( $args['li_class'], $args['class_prefix'] );
	$args['current_class'] = sanitize_attr_classes( $args['current_class'], $args['class_prefix'] );
	$args['current_class'] = $args['current_class'] ? $args['current_class'] : $args['class_prefix'] . $default['current_class'];

	$tabs = str_repeat( "\t", (int)$args['indent'] );
	
	$bread_crumb_arr = get_bread_crumb_array( $args );
	
	$elm_attrs = '';
	if ( $args['elm_id'] ) {
		$elm_attrs = ' id="' . $args['elm_id'] . '"';
	}
	if ( $args['elm_class'] ) {
		$elm_attrs .= ' class="' . $args['elm_class'] . '"';
	}
	
	$output = '';
	$elm_tabs = '';

	$output = '';
	if ( $elm ) {
		$elm_tabs = "\t";
		$output = $tabs . '<' . $elm;
		if ( $elm_attrs ) {
			$output .= $elm_attrs . ">\n";
		}
	}
	
	if ( $args['type'] == 'string' ) {
		$output = array();
		$cnt = 1;
		foreach ( $bread_crumb_arr as $ancestor ) {
			if ( $cnt == count( $bread_crumb_arr ) ) {
				$output[] = '<strong class="' . $args['current_class'] . '">' . apply_filters( 'the_title', $ancestor['title'] ) . '</strong>';
			} else {
				$output[] = '<a href="' . $ancestor['link'] . '">' . apply_filters( 'the_title', $ancestor['title'] ) . '</a>';
			}
			$cnt++;
		}
		$output = $elm_tabs . $tabs . implode( esc_html( $args['joint_string'] ), $output );
		$output = apply_filters( 'bread_crumb_after', $output, $args );

	} else {
		$output .= $elm_tabs . $tabs . '<ul';
		if ( ! $elm && $elm_attrs ) {
			$output .= $elm_attrs;
		}
		$output .= ">\n";
		
		$output = apply_filters( 'bread_crumb_before', $output, $args );
		
		$cnt = 1;
		foreach ( $bread_crumb_arr as $ancestor ) {
			$classes = array();
			$classes[] = $args['class_prefix'] . 'level-' . $cnt;
			if ( $cnt == 1 ) {
				$classes[] = $args['class_prefix'] . 'top';
			} else {
				$classes[] = $args['class_prefix'] . 'sub';
			}
			if ( $cnt == count( $bread_crumb_arr ) ) {
				$classes[] = $args['class_prefix'] . 'tail';
				$output .= $elm_tabs . $tabs . '	<li class="' . implode( ' ', $classes );
				if ( $args['li_class'] ) {
					$output .= ' ' . $args['li_class'];
				}
				$output .= ' ' .  $args['current_class'];
				$output .= '">' . apply_filters( 'the_title', $ancestor['title'] ) . '</li>' . "\n";
			} else {
				$output .= $elm_tabs . $tabs . '	<li class="' . implode( ' ', $classes );
				if ( $args['li_class'] ) {
					$output .= ' ' . $args['li_class'];
				}
				$output .= '"><a href="' . $ancestor['link'] . '">' . apply_filters( 'the_title', $ancestor['title'] ) . '</a></li>' . "\n";
			}
			$cnt++;
		}
		$output = apply_filters( 'bread_crumb_after', $output, $args );

		$output .= $elm_tabs . $tabs . '</ul>' . "\n";
	}
	
	if ( $elm ) {
		$output .= $tabs . '</' . $elm . ">\n";
	}
	
	$output = apply_filters( 'bread_crumb', $output, $args );
	
	if ( $args['echo'] ) {
		echo $output;
	} else {
		return $output;
	}
}


function get_bread_crumb_array( $args ) {
	global $post;
	
	$bread_crumb_arr = array();
	$bread_crumb_arr[] = array( 'title' => $args['home_label'], 'link' => get_bloginfo( 'url' ) . '/' );
	$bread_crumb_arr = add_posts_page_array( $bread_crumb_arr );
	if ( is_404() ) {
		$bread_crumb_arr[] = array( 'title' => $args['404_label'], 'link' => false );
	} elseif ( is_search() ) {
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['search_label'], get_search_query() ), 'link' => false );
	} elseif ( is_tax() ) {
		$taxonomy = get_query_var( 'taxonomy' );
		$term = get_term_by( 'slug', get_query_var( 'term' ), $taxonomy );
		if ( is_taxonomy_hierarchical( $taxonomy ) && $term->parent != 0 ) {
			$ancestors = array_reverse( get_ancestors( $term->term_id, $taxonomy ) );
			foreach ( $ancestors as $ancestor_id ) {
				$ancestor = get_term( $ancestor_id, $taxonomy );
				$bread_crumb_arr[] = array( 'title' => $ancestor->name, 'link' => get_term_link( $ancestor, $term->slug ) );
			}
		}
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['taxonomy_label'], $term->name ), 'link' => get_term_link( $term->term_id, $term->slug ) );
	} elseif ( is_attachment() ) {
		if ( $post->post_parent ) {
			if ( $parent_post = get_post( $post->post_parent ) ) {
				$singular_bread_crumb_arr = get_singular_bread_crumb_array( $parent_post );
				$bread_crumb_arr = array_merge( $bread_crumb_arr, $singular_bread_crumb_arr );
			}
		}
		$bread_crumb_arr[] = array( 'title' => $parent_post->post_title, 'link' => get_permalink( $parent_post->ID ) );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['attachment_label'], $post->post_title ), 'link' => get_permalink( $post->ID ) );
	} elseif ( is_singular() && ! is_front_page() ) {
		$singular_bread_crumb_arr = get_singular_bread_crumb_array( $post );
		$bread_crumb_arr = array_merge( $bread_crumb_arr, $singular_bread_crumb_arr );
		$bread_crumb_arr[] = array( 'title' => $post->post_title, 'link' => get_permalink( $post->ID ) );
	} elseif ( is_category() ) {
		global $cat;
		
		$category = get_category( $cat );
		if ( $category->parent != 0 ) {
			$ancestors = array_reverse( get_ancestors( $category->term_id, 'category' ) );
			foreach ( $ancestors as $ancestor_id ) {
				$ancestor = get_category( $ancestor_id );
				$bread_crumb_arr[] = array( 'title' => $ancestor->name, 'link' => get_category_link( $ancestor->term_id ) );
			}
		}
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['category_label'], $category->name ), 'link' => get_category_link( $cat ) );
	} elseif ( is_tag() ) {
		global $tag_id;
		$tag = get_tag( $tag_id );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['tag_label'], $tag->name ), 'link' => get_tag_link( $tag_id ) );
	} elseif ( is_author() ) {
		$author = get_query_var( 'author' );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['author_label'], get_author_name( get_query_var( 'author' ) ) ), 'link' => get_author_posts_url( $author ) );
	} elseif ( is_day() ) {
		$year = get_query_var( 'year' );
		$month = get_query_var( 'monthnum' );
		$day = get_query_var( 'day' );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['year_label'], $year ), 'link' => get_year_link( $year ) );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['month_label'], $month ), 'link' => get_month_link( $year, $month ) );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['day_label'], $day ), 'link' => get_day_link( $year, $month, $day ) );
	} elseif ( is_month() ) {
		$year = get_query_var( 'year' );
		$month = get_query_var( 'monthnum' );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['year_label'], $year ), 'link' => get_year_link( $year ) );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['month_label'], $month ), 'link' => get_month_link( $year, $month ) );
	} elseif ( is_year() ) {
		$year = get_query_var( 'year' );
		$bread_crumb_arr[] = array( 'title' => sprintf( $args['year_label'], $year ), 'link' => get_year_link( $year ) );
	}
	return $bread_crumb_arr;
}


function get_singular_bread_crumb_array( $post ) {
	$bread_crumb_arr = array();
	$post_type = $post->post_type;
	if ( is_post_type_hierarchical( $post_type ) ) {
		$ancestors = array_reverse( get_post_ancestors( $post ) );
		if ( count( $ancestors ) ) {
			$ancestor_posts = get_posts( 'post_type=' . $post_type . '&include=' . implode( ',', $ancestors ) );
			foreach( $ancestors as $ancestor ) {
				foreach ( $ancestor_posts as $ancestor_post ) {
					if ( $ancestor == $ancestor_post->ID ) {
						$bread_crumb_arr[] = array( 'title' => $ancestor_post->post_title, 'link' => get_permalink( $ancestor_post->ID ) );
					}
				}
			}
		}
	} else {
		$post_type_taxonomies = get_object_taxonomies( $post_type, false );
		if ( is_array( $post_type_taxonomies ) && count( $post_type_taxonomies ) ) {
			foreach( $post_type_taxonomies as $tax_slug => $taxonomy ) {
				if ( $taxonomy->hierarchical ) {
					$terms = get_the_terms( $post->ID, $tax_slug );
					if ( $terms ) {
						$term = array_shift( $terms );
						if ( $term->parent != 0 ) {
							$ancestors = array_reverse( get_ancestors( $term->term_id, $tax_slug ) );
							foreach ( $ancestors as $ancestor_id ) {
								$ancestor = get_term( $ancestor_id, $tax_slug );
								$bread_crumb_arr[] = array( 'title' => $ancestor->name, 'link' => get_term_link( $ancestor, $tax_slug ) );
							}
						}
						$bread_crumb_arr[] = array( 'title' => $term->name, 'link' => get_term_link( $term, $tax_slug ) );
						break;
					}
				}
			}
		}
	}
	return $bread_crumb_arr;
}

function add_posts_page_array( $bread_crumb_arr ) {
	if ( is_page() || is_front_page() ) {
		return $bread_crumb_arr;
	} elseif ( is_category() ) {
		$tax = get_taxonomy( 'category' );
		if ( count( $tax->object_type ) != 1 || $tax->object_type[0] != 'post' ) {
			return $bread_crumb_arr;
		}
	} elseif ( is_tag() ) {
		$tax = get_taxonomy( 'post_tag' );
		if ( count( $tax->object_type ) != 1 || $tax->object_type[0] != 'post' ) {
			return $bread_crumb_arr;
		}
	} elseif ( is_tax() ) {
		$tax = get_taxonomy( get_query_var( 'taxonomy' ) );
		if ( count( $tax->object_type ) != 1 || $tax->object_type[0] != 'post' ) {
			return $bread_crumb_arr;
		}
	} elseif ( is_home() && ! get_query_var( 'pagename' ) ) {
		return $bread_crumb_arr;
	} else {
		$post_type = get_query_var( 'post_type' ) ? get_query_var( 'post_type' ) : 'post';
		if ( $post_type != 'post' ) {
			return $bread_crumb_arr;
		}
	}
	if ( get_option( 'show_on_front' ) == 'page' && $posts_page_id = get_option( 'page_for_posts' ) ) {
		$posts_page = get_post( $posts_page_id );
		$bread_crumb_arr[] = array( 'title' => $posts_page->post_title, 'link' => get_permalink( $posts_page->ID ) );
	}
	return $bread_crumb_arr;
}

CODE 2
CODE 2も必要ではありますが、パラメータでカスタマイズしやすいWordPressのページナビを作ってみたでも使っているものなので、ページナビのコードを使っている方は、CODE 2を追加する必要はありません。

function sanitize_attr_classes( $classes, $prefix = '' ) {
	if ( ! is_array( $classes ) ) {
		$classes = preg_replace( '/[^\s\w_-]+/', '', $classes );
		$classes = preg_split( '/[\s]+/', $classes );
	}

	foreach ( $classes as $key => $class ) {
		if ( is_array( $class ) ) {
			unset( $classes[$key] );
		} else {
			$class = preg_replace( '/[^\w_-]+/', '', $class );
			$class = preg_replace( '/^[\d_-]+/', '', $class );
			if ( $class ) {
				$classes[$key] = $prefix . $class;
			}
		}
	}
	$classes = implode( ' ', $classes );

	return $classes;
}

パンくずナビで出力されるHTMLソース

リスト形式

<ul class="bread_crumb">
	<li class="level-1 top"><a href="http://www.example.com/">トップページ</a></li>
	<li class="level-2 sub"><a href="http://www.example.com/category/honda/">HONDA</a></li>
	<li class="level-3 sub"><a href="http://www.example.com/category/honda/sports/">スポーツ</a></li>
	<li class="level-4 sub"><a href="http://www.example.com/category/honda/sports/coupe/">クーペ</a></li>
	<li class="level-5 sub tail current">インテグラ</li>
</ul>

文字列形式

<a href="http://www.example.com/">トップページ</a> &gt; <a href="http://www.example.com/category/honda/">HONDA</a> &gt; <a href="http://www.example.com/category/honda/sports/">スポーツ</a> &gt; <a href="http://www.example.com/category/honda/sports/coupe/">クーペ</a> &gt; <strong class="current">インテグラ</strong>

「パラメータでカスタマイズしやすいWordPressのパンくずナビを作ってみた」への2件のフィードバック

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です