WordPress 的文章导航

May 24th, 2009 Add Comment

文章导航是什么? 一个外国朋友告诉我, 他们管它叫 Breadcrumb trail 或者 Breadcrumb navigation, 翻译过来就是文章导航或者文章路径, 对吧? 具体叫什么我真不确定, 或者看看下面的截图你就会知道我在说什么了.

Breadcrumb trail

这个友好的导航功能, 我最先是在论坛上看到的, 形式一般如下:
首页 > 模块 > 文章

有了它, 访客就可以方便地访问同类的文章, 并明确文章的所属, 对提高用户体验和网站的 PV 值都很有帮助. 我在制作 iNove 主题的时候也加上了这个功能, 但是只能处理子分类, 形式如下:
首页 > 分类 > 文章

最近我在制作一个主题, 客户要求能实现多层次的文章导航, 形式如下:
首页 > 分类 > 子分类 > 第二层子分类 > ... > 第 N 层子分类 > 文章

一般我们会在 the_post() 后面调用 the_category() 生成分类内容. 为此我翻了一下 WordPress 的源代码, 发现 the_category() 方法可能会用到 category-template.php 文件里的另两个方法. 下面我将以注释的形式讲解一下这两个方法, 如发现误解之处, 请指正.

获取父级分类 get_category_parents

/**
 * 获取父级分类 (包含分隔符).
 *
 * @since 1.2.0
 *
 * @param int $id 分类 ID.
 * @param bool $link 默认为 false, 为真时返回的分类包含链接.
 * @param string $separator 分类间分隔符, 默认是 '/'.
 * @param bool $nicename 默认为 false, 为真时返回分类显示为分类别名, 否则显示分类名.
 * @param array $visited 防止分类重复显示 (调用该方法时请不用理会这个参数, 本人认为这只是为了顺利完成迭代处理).
 * @return string
 */
function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
	// 准备返回的 HTML 字符串
	$chain = '';
 
	// 通过 ID 获取分类
	$parent = &get_category( $id );
 
	// 如果该分类已经定义过, 立即返回
	if ( is_wp_error( $parent ) )
		return $parent;
 
	// 以分类别名或者分类名作为分类链接的显示文本
	if ( $nicename )
		$name = $parent->slug;
	else
		$name = $parent->cat_name;
 
	// 如果该分类还有父分类, 分类不是连向自己, 并且还没有处理过
	if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
		// 把当前分类的父分类添加到已处理的数组中, 避免以后被重复处理
		$visited[] = $parent->parent;
		// 迭代处理父分类
		$chain .= get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
	}
 
	// 以链接或者文本形式 (包含分隔符) 将分类拼接到准备返回的 HTML 字符串中
	if ( $link )
		$chain .= '<a href="' . get_category_link( $parent->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $parent->cat_name ) . '">'.$name.'</a>' . $separator;
	else
		$chain .= $name.$separator;
 
	// 返回 HTML 字符串 (结果)
	return $chain;
}

获取父级分类 get_the_category_list

/**
 * 获取分类列表, 并以 HTML 列表方式或者自定义格式返回.
 *
 * @since 1.5.1
 *
 * @param string $separator 默认为空, 显示在各分类之间的分隔符.
 * @param string $parents 指示如何显示父级的分类.
 * @param int $post_id 获取某一文章 ID 对应的分类.
 * @return string
 */
function get_the_category_list( $separator = '', $parents='', $post_id = false ) {
	global $wp_rewrite;
 
	// 找到当前文章对应的分类 (数组, 因为文章可以属于多个分类)
	$categories = get_the_category( $post_id );
 
	// 如果分类数组为空, 在 the_category 方法中当作 '未分类' 进行处理
	if ( empty( $categories ) )
		return apply_filters( 'the_category', __( 'Uncategorized' ), $separator, $parents );
 
	$rel = ( is_object( $wp_rewrite ) && $wp_rewrite->using_permalinks() ) ? 'rel="category tag"' : 'rel="category"';
 
	// 准备返回的 HTML 字符串
	$thelist = '';
 
	// 如果分隔符为空, 返回分类的 HTML 列表
	if ( '' == $separator ) {
		// 列表的开头, 是一个 unordered list
		$thelist .= '<ul class="post-categories">';
 
		// 循环处理所有分类
		foreach ( $categories as $category ) {
			// 每个分类项的开头
			$thelist .= "\n\t<li>";
			switch ( strtolower( $parents ) ) {
 
				// 如果以 'multiple' 模式显示父分类, 每层的分类会独立成一个链接
				case 'multiple':
					// 父分类存在的话, 获取父分类的 HTML 代码并拼接到准备输出的 HTML 字符串中
					if ( $category->parent )
						$thelist .= get_category_parents( $category->parent, true, $separator );
					// 最后把当前分类的 HTML 代码和分类也拼接到准备输出的 HTML 字符串中
					$thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . $rel . '>' . $category->name.'</a></li>';
					break;
 
				// 如果以 'single' 模式显示父分类, 所有分类作为一个链接
				case 'single':
					// 链接的开头
					$thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . $rel . '>';
					// 父分类存在的话, 获取父分类的 HTML 代码并拼接到准备输出的 HTML 字符串中
					if ( $category->parent )
						$thelist .= get_category_parents( $category->parent, false, $separator );
					// 当然分类的名字和链接的结尾
					$thelist .= $category->name.'</a></li>';
					break;
 
				// 如果以默认模式显示父分类, 即不显示父分类
				case '':
				default:
					$thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . $rel . '>' . $category->cat_name.'</a></li>';
			}
		}
 
		// 列表的结尾
		$thelist .= '</ul>';
 
	// 如果分隔符不为空, 返回一段格式化的 HTML
	} else {
		// 计数器
		$i = 0;
 
		// 循环处理所有分类
		foreach ( $categories as $category ) {
			// 第一个分类的前面不显示分隔符
			if ( 0 < $i )
				$thelist .= $separator . ' ';
			switch ( strtolower( $parents ) ) {
 
				// 如果以 'multiple' 模式显示父分类, 每层的分类会独立成一个链接
				case 'multiple':
					if ( $category->parent )
						$thelist .= get_category_parents( $category->parent, true, $separator );
					$thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . $rel . '>' . $category->cat_name.'</a>';
					break;
 
				// 如果以 'single' 模式显示父分类, 所有分类作为一个链接
				case 'single':
					$thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . $rel . '>';
					if ( $category->parent )
						$thelist .= get_category_parents( $category->parent, false, $separator );
					$thelist .= "$category->cat_name</a>";
					break;
				case '':
 
				// 如果以默认模式显示父分类, 即不显示父分类
				default:
					$thelist .= '<a href="' . get_category_link( $category->term_id ) . '" title="' . sprintf( __( "View all posts in %s" ), $category->name ) . '" ' . $rel . '>' . $category->name.'</a>';
			}
 
			// 计数器自增
			++$i;
		}
	}
 
	return apply_filters( 'the_category', $thelist, $separator, $parents );
}

在主题中加入文章导航

1. 不包含父级分类的文章导航
这里用到 the_category() 方法的默认模式, 会调用 get_the_category_list() 生成最后一层的子分类 (分类可能不只一个) 组成的 HTML 字符串并打印到页面上. 代码如下:

<a title="Go to homepage" href="<?php echo get_settings('home'); ?>/">Home</a> <!-- 首页链接 -->
 &gt; <?php the_category(', '); ?> <!-- 每个分类以逗号分隔 -->
 &gt; <?php the_title(); ?> <!-- 文章链接 -->

2. 包含父级分类的文章导航
我们要用的是 the_category() 方法的 multiple 模式, 而他会调用 get_the_category_list()get_category_parents() 两个方法生成一个包含所有父分类的 HTML 字符串并打印到页面上. 代码如下:

<a title="Go to homepage" href="<?php echo get_settings('home'); ?>/">Home</a> <!-- 首页链接 -->
 &gt; <?php the_category(' &gt; ', 'multiple'); ?> <!-- 每个分类以 > 分隔, 父级分类在前, 子分类在后 -->
 &gt; <?php the_title(); ?> <!-- 文章链接 -->

当然, 只要你愿意, 可以将这段代码取代 iNove 主题里 single.php 文件的 id="postpath" 部分, 我并不准备在以后版本的 iNove 主题中使用这个多级的文章导航.

声明: 本文采用 BY-NC-SA 协议进行授权. 转载请注明转自: WordPress 的文章导航

  1. http://1.gravatar.com/avatar/b038aa429bca535fb8466cc20828851b?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    谢谢,看了后非常受益。

  2. http://0.gravatar.com/avatar/83d050e9832cf22c5743063a58eafe49?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    你好 我在使用你所说的函数的时候出现第一篇文字会出现多了一个父级的情况 请教一下哈 如http://www.cksky.cc/archives/2344

  3. http://0.gravatar.com/avatar/2ce1c5c5226ee100d92c299de9ea4a0e?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G
  4. http://0.gravatar.com/avatar/0e8539284d0de2e079b93eab7ff13ce2?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    朋友 能告诉我这个调用文章分类是有a标签的 ,怎么去掉a标签呢

  5. http://1.gravatar.com/avatar/547ac95549782812cf9687caa9451ab0?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    路过。。。
    这篇文章好,学习中、
    关注博主

  6. http://0.gravatar.com/avatar/2bf504cf5211cca176793459dc3b2705?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    厉害.

    通用版本的iNove可能不是个个需要这种功能, 但不见得别人下载了 iNove 全部都是拿来当博客来用,很可能还有其他想都想不到的用途,有这个资料到时候用得上的地方就容易了.

    也许大家的想法也都和我差不多,不管以后的iNove会添加什么样的功能,可能大家都希望能保持iNove的继续更新,也许不会全部使用iNove的外观,但iNove作为一个成熟的主题,代码和结构是很赞的, 怎么改都比从那个默认的主题开始干容易,

    mg12老大千万不要因为要弄别的主题结果把iNove给冷落了才好, 真的是太爱死iNove了.就像WordPress, 每次的新版本都带着那个默认主题, 不离不弃的,想想就感觉很舒服,虽然从来没用过.

    也许会有人和我一样, 从修改iNove开始学弄WP, 从一个什么代码都不会写, 只会依瓢画葫芦的新手到一个能做出点自己觉得还不错的东西出来的熟手, 对iNove的感激也都是会真心诚意的吧.

  7. http://1.gravatar.com/avatar/714041d884c340fe3bd3fd90f49afa30?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    太好了!酷!

  8. http://0.gravatar.com/avatar/ef80dad0d2bc90ef0bc99104c8821c5f?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    非常好的wordpress学习的网站,以及制作的本网站使用的自己制作的主题,也是我想找的主题。

  9. http://1.gravatar.com/avatar/92e1b090675baff6f765913264921e61?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    哦,谢谢你们的回

  10. http://0.gravatar.com/avatar/cfcfba626329d93eff1115f31584b26b?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    哦,谢谢你们的回

  11. http://0.gravatar.com/avatar/490cf262668eebb0f0f1a50d9d48d702?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    @yimin
    放到 single.php 中...

    @zenntou
    自己去弄.

  12. http://1.gravatar.com/avatar/3a6c199001847ac2b882facac0ca8c6a?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我正好需要这个插件
    Home > WordPress > WP Trick > WordPress 的文章导航

    可以发一份到我邮箱吗?谢谢!

  13. http://1.gravatar.com/avatar/98f4fe6018daa0b726041345210dad24?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    @itlobo
    MG12,这个是怎么实现的啊?

  14. http://1.gravatar.com/avatar/98f4fe6018daa0b726041345210dad24?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G
  15. http://1.gravatar.com/avatar/98f4fe6018daa0b726041345210dad24?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我也想知道这是怎么实现的?

  16. http://1.gravatar.com/avatar/bcfd1aef6b88b0c60e972f2c91a21f87?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    博主好:
    @mg12

    虽然看了哪些有点头绪,但是还是不知道该到代码放到什么合适的网页里,我尝试分别放在templates/header.php和templates/start.php里,但是没有成功,再麻烦博主一下,我该把代码放到什么网页里的哪个位置啊?
    我用的是inove这个主题,谢谢!

  17. http://0.gravatar.com/avatar/490cf262668eebb0f0f1a50d9d48d702?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    @yimin
    嗯, 你可以参考一下这里: http://www.itlobo.com/articles/1082.htm
    他的虽然不能像你说的那样智能处理, 但原理是这样.
    或者你可以参考我的 blocks 主题. (趁主题还没被我升级去下载个, 下个版本就不会有这个功能了)

    @cyclone77
    请参考这个文章: http://wordpress.org/support/topic/233834

    @园子
    因为你的站太多页面 bug, 无法进行测试, 文章书写和插件也需要规范, 主题不能为你提供一切.

  18. http://1.gravatar.com/avatar/bcfd1aef6b88b0c60e972f2c91a21f87?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    博主好:

    请问一下:在不使用all-in-one-seo-pack 插件的前提下,怎么通过修改源代码实现对标题、关键词和描述的优化? 并且打开单篇日记,其标题只显示日记的标题,而不包含博客标题!

    请博主在百忙中抽出一点时间回一下,谢谢!

  19. http://1.gravatar.com/avatar/bcfd1aef6b88b0c60e972f2c91a21f87?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    @itlobo
    谢谢!不过不是我想要的!

  20. http://1.gravatar.com/avatar/94edba5ccaf4f54d0891cf3a7b1e1280?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    您好
    我使用了您的主题
    但是在校验XHTML 1.1 时却无法通过
    提示:Sorry! This document can not be checked.
    我不清楚这是什么原因
    希望能够帮我看看,谢谢您哦~

  21. http://0.gravatar.com/avatar/440608b37b9f69c7f35e62e2f4f2d134?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    如何将 iNove 主题的侧边栏改宽一些???
    你看我的已经到下面了 http://www.cyclone77.cn/?s=%E5%9F%BA%E6%95%B0

  22. http://1.gravatar.com/avatar/98f4fe6018daa0b726041345210dad24?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    一直在用你的主题,赞一个...... :smile:

  23. http://1.gravatar.com/avatar/9464bb55ca1c2be9dd5f4b10ac00dd00?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    看到了一点变化,首页是加载了全部标题,再加载内容的.不像其他的,从上往下加载.

  24. http://1.gravatar.com/avatar/9464bb55ca1c2be9dd5f4b10ac00dd00?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G
  25. http://1.gravatar.com/avatar/bb3664adbe5be014683bfa0c1d5c1b56?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    留言投票的东西是怎么做的

  26. http://1.gravatar.com/avatar/1ec4717231e96f16618449f9ebb32c5c?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    哦,谢谢你们的回答

  27. http://0.gravatar.com/avatar/4e17998e8a3fd950b8d990bdd5ec7c84?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    博主好:

    请问一下:在不使用all-in-one-seo-pack 插件的前提下,怎么通过修改源代码实现对标题、关键词和描述的优化? 谢谢!

    麻烦博主回一下,谢谢!

  28. http://1.gravatar.com/avatar/ffa60157af668384f5325116efd02385?s=32&d=http%3A%2F%2F1.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我想知道你現在文章的異步加載的實現方法哈~

  29. http://0.gravatar.com/avatar/aa9d768e03c356fbb409bcdc316a0ff4?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    我想问问你的 分页插件 和文章首页只显示一部分的插件是什么? 能够告诉我吗?

  30. http://0.gravatar.com/avatar/4e17998e8a3fd950b8d990bdd5ec7c84?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    大家好:

    我装了“all-in-one-seo-pack”这个插件,但是看到相关的文章说,这个插件不仅对SEO没有起到作用,反而会被百度K,这是真的吗?

    如果是真的话,我想要在blog里添加 title 、 description 和 keywords 该怎么办啊,麻烦知道的朋友回一下,谢谢你们!

  31. http://0.gravatar.com/avatar/4e17998e8a3fd950b8d990bdd5ec7c84?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    大家好:

    我修改成了浮动导航后,第一项变成了“首页”,我想改成“Home”,应该怎么改啊?谢谢!

  32. http://0.gravatar.com/avatar/8bc5a10d6cd90aec2d2e24b53042856f?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    留言投票的东西是怎么做的? :?:

  33. http://0.gravatar.com/avatar/4e17998e8a3fd950b8d990bdd5ec7c84?s=32&d=http%3A%2F%2F0.gravatar.com%2Favatar%2Fad516503a11cd5ca435acc9bb6523536%3Fs%3D32&r=G

    @顏真卿

    @Calcifer

    哦,谢谢你们的回答。

Comment pages
  1. Loading...