関連度に応じた関連記事を表示する
お題の通り、wordpress用の自作の関連記事表示ファンクションです。精度の高さを求めるなら記事内容に踏み込んだプラグイン(YARPPとか)を使うのが基本です。しかしそういったプラグインを回避したいこともある。その場合、タグで記事を表示したり、カテゴリ毎の新着記事を出力したりで充分なケースもあるが、やはり関連性という点でもの足らず、どうしても古い記事が埋もれてしまいがちに。で、ここで紹介する方法は、既存のプラグイン未満だけどもタグとタクソノミの重複度で関連度合いの評価を加えたものです。このページの下で使っています。
主な特徴
関数で処理するメリットとしてはやっぱりアレンジが容易いことです。主な特徴としては以下の通り。
カスタム投稿タイプやカスタムタクソノミに対応
タグ・カテゴリ・カスタムタクソノミの重複回数に応じて関連度を計測
カスタムフィールドに関連度の高い記事のIDを登録
ちなみに、デフォルトではタグが他のタクソノミよりも優先的に点数付けされる設定にしていますが、カスタムタクソノミなどケースバイケースで設定してください。
CODE : Related post IDs in a custom field
以下の関数に任意にアレンジを加えてfunctions.phpに記述します。
/*
* plugin name: Related post IDs in a custom field
* author: Mizuho Ogino
* author URI: //web.contempo.jp/wprs/
* license: //www.gnu.org/licenses/gpl.html GPL v2 or later
*/
/////////////////////// タグとカテゴリによる関連記事の表示 ///////////////////////
function get_related_posts( $show_post = 5, $target_posttype = '', $post_id = ''){
if ( empty( $post_id ) ) $post_id = get_post()->ID;
if ( empty( $post_id ) ) return;
if ( empty( $target_posttype ) ) $target_posttype = get_post( $post_id )->post_type;
$ex_show_post = get_post_meta( $post_id, '_my_relatedposts_shownum', true ); // 関連記事の表示数
$rel_date = get_post_meta( $post_id, '_my_relatedposts_update', true ); // 関連記事の登録日
$modified_date = mysql2date( 'Ymd', get_lastpostmodified(), false ); // ブログの最終更新日
$posts_per_page = -1; // 検索するpost数 [-1] で全て
//以下、 関連記事が登録されていない場合 || 関連記事登録日よりもあとに記事が更新されている場合 || 表示関連記事数の設定が変わった場合、のみ新規で関連記事を設定する
if( empty($rel_date) || $modified_date > $rel_date || $show_post != $ex_show_post ){
$rel_ids = array();
$taxes = get_object_taxonomies( get_post( $post_id )->post_type, 'names' ); // 使用タクソノミを取得(カテゴリ+カスタムタクソノミ)
unset( $taxes['post_format'] ); // post_formatを除外
$tax_count = 0;
$tax_count = count($taxes);
$tax_array = array_fill( 0, $tax_count, '' );
if ($taxes) {
foreach ( $taxes as $taxname ) {
$terms = get_the_terms( $post_id, $taxname );
if ( $terms ){
foreach ( $terms as $term ) {
$rel_ids[ $taxname ][] = $term->term_id; // タームIDを配列に入れる
}
$tax_array[] = array(
'taxonomy' => $taxname, // categoryとかpost_tagとか
'field' => 'id', // 'id' または 'slug'
'terms' => $rel_ids[ $taxname ], // int または string または array
'include_children' => false, // 子カテゴリを含まない
'operator' => 'IN',
);
}
}
}
$args = array(
'post__not_in' => array( $post_id ), // このpostを除外
'posts_per_page' => $posts_per_page, // 検索するpost数
'post_status' => 'publish', // 公開postに限定
'post_type' => $target_posttype, // ターゲットポストタイプ
'tax_query' => array_merge( array('relation' => 'OR'), $tax_array )
);
$rel_query = get_posts( $args );
if ( $rel_query ) : foreach ($rel_query as $rel ):
$rel_point = 0;
$set_id = $rel->ID;
foreach ( $taxes as $taxname ) {
$terms = get_the_terms( $set_id, $taxname );
if ( is_array($terms)) : foreach ( $terms as $term ):
if ( isset( $rel_ids[ $taxname ]) && in_array( $term->term_id , (array)$rel_ids[ $taxname ] ) ){ // 関連IDを含むかチェック
$rel_point++;
if( $taxname == 'post_tag' ){ $rel_point++; } // ポストタグを他タクソノミより優先するようにポイントを補正 必要に応じてコメントアウトや変更をして下さい。
}
endforeach; endif; // end $terms foreach
} // end $taxes foreach
$rel_with[ $set_id ] = intval($rel_point); // 関連度数
endforeach; endif;
if ( !empty( $rel_with ) ) {
arsort( $rel_with ); // 関連度数でソート
$i = 0;
foreach ( $rel_with as $key => $val ) {
if( $i >= $show_post ) {
break;
} else {
$rel_posts[] = $key;
echo '<!-- POST ID:'.$key. ' / RELATION POINT:' .$val. ' -->' ."n";
$i++;
}
}
update_post_meta( $post_id, '_my_relatedposts', $rel_posts );
echo '<!-- RELATED POSTS FOR POST-'.$post_id. ' ARE UPLOADED!! -->' ."n";
} else {
$no_related = false;
update_post_meta( $post_id, '_my_relatedposts', $no_related );
}
$timestamp = date( 'Ymd' );
update_post_meta( $post_id, '_my_relatedposts_update', $timestamp );
update_post_meta( $post_id, '_my_relatedposts_shownum', $show_post );
}
$return_array = get_post_meta( $post_id, '_my_relatedposts', true );
return $return_array;
}
関連記事IDをカスタムフィールドに登録しているので、通常表示には処理時間はかかりません。記事の新規作成があったときに関連記事が再設定されるため、そのページを訪れた最初のユーザーにだけ処理が発生します。関数の冒頭にある[ $modified_date ]は[ 20140430 ]のような日付型になっていますので、ブログの更新頻度が高い場合、更新後一ヶ月以上経っていたら関連記事も更新する[ $modified_date = mysql2date( ‘Ymd’, get_lastpostmodified(), false ) – 30; ]とすればかなりの程度負担が調整できます。また[ $posts_per_page = -1; ]を[ $posts_per_page = 200; ]としたりして新しい記事限定にすれば、検索にかかる時間が短縮できます。(wp_cronの使用に支障のある環境だったので上記のような手法で設計していますが、問題なく使える環境であればcronですべての投稿を処理してしまっても良いと思います。)
テーマ内で呼び出す方法
get_related_posts()という関数で呼び出すと、IDが配列で得られます。このサイトでは以下のように呼び出しています。
<?php
$related_posts = get_related_posts(5);
$related_links = "t". '<ul>' ."n";
if ( $related_posts ):
foreach( $related_posts as $rid ):
$related_links .= "tt". '<li id="related-post-'.$rid.'"><a href="'.get_permalink( $rid ).'">' .get_the_title( $rid ). '</a></li>'. "n";
endforeach;
$related_links .= "t". '</ul>' ."n";
?>
<!--関連記事リスト START-->
<div id="related-posts">
<strong>Related posts</strong>
<?php echo $related_links; ?>
</div><!--関連記事リスト END-->
<?php else: ?>
関連記事がない場合の処理
<?php endif; ?>