行き着く先はあんこ

WordPressにプラグインを使わずそこそこ精度の高い関連記事を表示する

スポンサーリンク

WordPress にプラグインを使わずに、そこそこ精度の高い関連記事を表示させる方法を備忘録もかねてまとめておきます。

WordPress に関連記事を表示する

WordPress に関連記事を表示させるには「YARPP」といったプラグインがとても便利です。手軽に導入できるうえに、カテゴリやタグやタイトルなどから関連記事を選び出すため精度も非常に優れています。

しかし、今回はプラグインに頼らずに関連記事を表示させます。以下のサイトで紹介されている方法を元にしています。

この方法では、記事に登録されているタグ、カテゴリ、カスタムタクソノミーの重複回数によって関連記事を選ぶようになっています。デフォルトではタグの優先度が最も高くなっています。

関連記事コード

以下のコードをfunctions.phpに追加します。

//そこそこ精度が良い関連記事コード
function get_related_posts($show_post = 5) {
    $post_id = get_post()->ID;

    // 個別記事、カスタム投稿 で表示する
    if (empty($post_id) || is_singular(array('page','attachment')))
        return false;

    $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); // ブログの最終更新日
    $post_type = get_post()->post_type;
    $post_status = get_post()->post_status;

    $rel_ids = array();
    $taxes = get_object_taxonomies($post_type, 'names'); // 使用タクソノミを取得(カテゴリ+カスタムタクソノミ)
    $tax_array = array();

    if (isset($taxes)) {
        foreach ($taxes as $taxname) {
            $terms = get_the_terms($post_id, $taxname);

            if ($terms !== false) {
                foreach ($terms as $term) {
                    $rel_ids[$taxname][] = $term->term_id; // タームIDを配列に入れる
                }
                $tax_array[] = array(
                    'taxonomy' => $taxname, // categoryとかpost_tagとか
                    'field' => 'term_id', // 'id' または 'slug'
                    'terms' => $rel_ids[$taxname], // int または string または array
                    'include_children' => 'false', // 子カテゴリを含まない
                    'operator' => 'IN',
                );
            }
        }
    }

    $args = array(
        'post__not_in' => array( $post_id ), // この記事を除外
        'posts_per_page' => -1, // 検索する記事数 -1で全ての記事
        'post_status' => 'publish', // 公開記事に限定
        'post_type' => $post_type, // ターゲットポストタイプ
        'tax_query' => array_merge( array('relation' => 'OR'), $tax_array )
    );
    $rel_query = get_posts($args);

    if ($rel_query !== false) {
        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) {
                        // 関連IDを含むかチェック
                        if (isset($rel_ids[$taxname]) && in_array($term->term_id , $rel_ids[$taxname])) {
                            $rel_point++;
                            if($taxname === 'post_tag')
                                $rel_point++; // タグの優先度を高くする
                        }
                    }
                }
            }
            $rel_with[$set_id] = intval($rel_point); // 関連度数
        }
    } else {
        return false;
    }

    // 日時が未登録 or 登録日以降にブログが更新されている or 表示数が変わった ときに関連記事を登録する
    if(empty($rel_date) || $modified_date > $rel_date || $show_post !== $ex_show_post) {
        arsort($rel_with); // 関連度数でソート
        $i = 0;
        foreach ($rel_with as $key => $val) {
            if($i >= $show_post) {
                break;
            } else {
                $rel_posts[] = $key;
                $i++;
            }
        }
        // 記事が公開時のみカスタムフィールドに登録する
        if ($post_status === 'publish') {
            update_post_meta($post_id, '_my_relatedposts', $rel_posts);
            update_post_meta($post_id, '_my_relatedposts_update', date('Ymd'));
            update_post_meta($post_id, '_my_relatedposts_shownum', $show_post);
        }
    } else {
        $rel_posts = false;
    }

    return $rel_posts;
}

全体としては

  • 記事に登録されている全てのカテゴリ、タグを取得
  • 各カテゴリ、タグに登録されている記事を取得
  • 取得した記事と元の記事のカテゴリ、タグを比較
  • 一致数が多い上位の記事をカスタムフィールドに登録

という流れで関連記事を取得します。

関連記事を表示するのは個別記事のみで、固定ページと添付ファイルページでは関連記事を取得しないようにしています。また、関連記事は個々の記事のカスタムフィールドに記事 ID の配列として登録されています。

標準ではタグの優先度が高くなっていますが、カテゴリの優先度を高くしたければ

if($taxname === 'post_tag')

のとろこを

if($taxname === 'category')

に変更することで対応できます。

関連記事 ID を取得して表示する

上で作成した関数get_related_posts()を呼ぶと、関連記事の記事 ID が配列で取得できます。あとは表示したいところでループさせて関連記事を表示させます。

一例としてこのサイトではこんな感じで表示させています。

<?php $related_posts = get_related_posts(6); ?>
<div id="related-posts">
    <h3>関連記事</h3>
    <div class="related-posts-box">
        <?php if ( $related_posts ): foreach( $related_posts as $rid ): ?>
            <article>
                <a href="<?php the_permalink( $rid ); ?>" title="<?php echo get_the_title( $rid );>
                    <?php if ( has_post_thumbnail( $rid ) ):
                        $thumb_id = get_post_thumbnail_id( $rid );
                        $thumb_url = wp_get_attachment_image_src($thumb_id, 'thumbnail'); ?>
                        <img src="<?php echo $thumb_url[0]; ?>">
                    <?php endif; ?>
                    <div><h4><?php echo get_the_title( $rid ); ?></h4>
                </a>
            </article>
        <?php endforeach;
        else: ?>
            <p>関連する記事はありませんでした。</p>
        <?php endif; ?>

関連記事の表示数はデフォルトで 5 つになっていますが、

<?php $related_posts = get_related_posts(6); ?>

のように関数get_related_postsに引数を渡すことで表示数を変更できます。

また、サムネイル画像のサイズ変更には

wp_get_attachment_image_src($thumb_id, 'thumbnail')

thumbnail部分を

wp_get_attachment_image_src($thumb_id, 'medium')
wp_get_attachment_image_src($thumb_id, array( 100, 100 ))

のように変更することで対応できます。

改良できそうなポイント

今回の方法は登録されているカテゴリやタグの一致回数で関連記事を取得しています。しかしこれは要素 1 つの重みが考慮されていません。これらを考慮するとわずかですが関連記事の精度向上が期待できます。

さいごに

これでプラグインを使わなくてもそこそこ精度の高い関連記事を表示することができるようになりました。より精度を高めるにはタグ付けが非常に重要になりますが、タグに関して考え改めるいい機会にもなるのではないでしょうか。

更新内容:

2016 年 12 月 29 日

公開されている個別ページとカスタム投稿ページのみに表示するように変更。それに伴った関数全体の見直し

スポンサーリンク

スポンサーリンク