WordPressでrel="prev"とrel="next"の最適化

WordPressはデフォルトでwp_head()が"prev"や"next"をrel属性値に持つlinkタグを書き出しますが、投稿にだけ書き出されるので、これをアーカイブページなど適切なページに書き出されるようにします。

rel="prev"とrel="next"について

Googleはrel="prev"とrel="next"をサポートしています。Googleではこれらの値を分割されたコンテンツの関係を示すものとして認識するようです。

HTML5の仕様にはrel属性のnextについて、

Indicates that the current document is a part of a series, and that the next document in the series is the referenced document.

と、書かれています。大意は「現在のドキュメントが連続した物の一部であり、その次のドキュメントへの参照を示す」ということでしょうか。prevはこの逆です。

また、HTML 4.01の仕様にも、「続き物の一部を示す」とは書かれていませんが、おおよそ同じようなことが書かれています。

この仕様を見るに、Googleの解釈は適切で、記事の前後を示すWordPressの方はすこし違うような気がしますね。

記事でも続き物であれば問題ないでしょうが、ブログを書く上で必ずしも今日書いた記事が昨日書いた記事の続きであるとは限りません。むしろ無関係のことの方が多いでしょう。

ブログで前後関係が存在すると言えばやはりアーカイブページだと思います。

本題

というわけで、本題です。

まずwp_head()にlinkタグを出力させないようにしましょう。

以下のコードをfunctions.phpに書きます。すでにあるならいりません。

remove_action('wp_head', 'adjacent_posts_rel_link_wp_head');

そして次のコードを追加します。

function add_rel_link() {
	if(is_home() || is_archive()) {
		global $wp_query;
		$max_page  = $wp_query->max_num_pages;
		if($max_page > 1) {
			if(get_query_var('paged')) {
				echo '<link rel="prev" href="'.previous_posts(false).'" />'."\n";
			}
			if(get_query_var('paged') < $max_page) {
				echo '<link rel="next" href="'.next_posts($max_page, false).'" />'."\n";
			}
		}
	}
}
add_action('wp_head', 'add_rel_link');

ブログホームとカテゴリーや日付などのアーカイブページのときだけ、分割されたページ数を確認して、適切なrel属性値をとhref属性値を持つlinkタグを出力する関数です。

最後にadd_action()wp_head()に登録するのを忘れずに。

ページ分割にも対応させる

WordPressには一つの記事を複数ページに分割する機能があります。

分割したい場所に<!--nextpage-->と書き、あとはテンプレートにwp_link_pages()を追加すれば分割された複数のページへのリンクが表示されます。

これで分割された記事はまさしく「続き物の一部」です。なのでこれらにもlinkタグが出力されるようにしましょう。

function add_rel_link() {
	if(is_home() || is_archive()) {
		global $wp_query;
		$max_page  = $wp_query->max_num_pages;
		if($max_page > 1) {
			if(get_query_var('paged')) {
				echo '<link rel="prev" href="'.previous_posts(false).'" />'."\n";
			}
			if(get_query_var('paged') < $max_page) {
				echo '<link rel="next" href="'.next_posts($max_page, false).'" />'."\n";
			}
		} elseif(is_single() || is_page()) {
			global $multipage;
			if($multipage) {
				$prev = multipage_link('prev');
				$next = multipage_link('next');
				if($prev) {
					echo '<link rel="prev" href="'.$prev.'" />'."\n";
				}
				if($next) {
					echo '<link rel="next" href="'.$next.'" />'."\n";
				}
			}
		}
	}
}
add_action('wp_head', 'add_rel_link');

function multipage_link($rel='prev') {
	global $post, $page, $numpages, $multipage;
	$url = '';

	if($multipage) {
		$i = 'prev' == $rel? $page - 1: $page + 1;
		if($i && $i ≤= $numpages) {
			 if(1 == $i) {
				$url = get_permalink();
			 } else {
				if ('' == get_option('permalink_structure') || in_array($post->post_status, array('draft', 'pending'))) {
					$url = add_query_arg('page', $i, get_permalink());
				} else {
					$url = trailingslashit(get_permalink()).user_trailingslashit($i, 'single_paged');
				}
			 }
		}
	}

	return $url;
}

分割記事の次のページや前のページのURIだけを取得する関数は、どうやらWordPressには用意されていないようでした。なので、wp_link_pages()の内部で使われている_wp_link_page()パク一部拝借して関数を作りました。

wp_link_pages()のソースは wp-include/post-template.php にあります(Ver 4.0.1)。

分割された記事では$multipageというグローバル変数がtrueになるみたいです。

これでページ分割された記事にも、rel="prev"とrel="next"を持つlinkタグが書き出されます。勿論「ページ分割なんて使わないよ」というのであれば追加する必要はありません。

最後に

例えば小説を複数の記事に分けて投稿するといった場合、これも続き物の一部ですから、prevやnextがあってもいいかもしれません。その時はカテゴリーで判別したりと、なんらかの対応が必要でしょう。

そもそもブログ全体を一つのドキュメントであるとみなすのであれば、前後の記事を関連づけても良いでしょう。その辺の解釈は制作者の意図によると思います。

Googleとしても、あくまでページ間の関係のヒントとして使うだけのようです。

また、前後の記事へのリンクを表示するprevious_post_link()next_post_link()にもrel属性が設定されています。完全を期すならこれらも削除するべきかもしれません。特にページ分割を使う場合は、link要素とa要素で別のURIを参照することになるので、削除した方がいいと思います。
(Google的にはlink要素のrel属性値を参照するだけのようなので、おそらくあっても問題ないでしょう)

link要素を認識して、ナビゲーションに使用するようなユーザーエージェントの場合、記事にも前後関係があった方がいいかもしれません。でもこの場合、分割ページや検索との兼ね合いが難しくなってしまいますね。

迷ったらいっそなにも設定しないのも手かもしれませんね。

Comments