【WordPress】関連記事を自作する方法

2018年12月26日
関連記事

WordPressで関連記事を設置する際に、プラグインを使いたくなかったため自作した。

前提

下記のクラスを定義済みの想定とする。

手順

関連記事を表示するクラスを定義する

下記のクラスをPHPで定義する。

クラス内に定義されている定数のTHUMBNAIL_WIDTHTHUMBNAIL_HEIGHTには任意のサムネイルサイズを指定し、POST_COUNTには表示する記事数を指定する。

final class RelatedPost extends StaticClass {
    const THUMBNAIL_NAME    = 'related-post';
    const THUMBNAIL_WIDTH   = 140;
    const THUMBNAIL_HEIGHT  = 84;
    const POST_COUNT        = 8;

    public static function show() {
        $has_category       = has_category();
        $has_tag            = has_tag();
        $has_not_article    = !$has_category && !$has_tag;
        if ( $has_not_article ) return;

        $datas = self::get_post_datas( $has_category, $has_tag );
        if ( !$datas->have_posts() ) return;

        echo <<< 'EOT'
<section id="related-post">
    <h3 class="title">関連記事</h3>
EOT;

        echo '<ul class="content">';
        
        while ( $datas->have_posts() ) {
            $datas->the_post();
            
            echo <<< EOT
<li class="post">
    <div class="inner">
EOT;

            self::show_post_thumbnail_or_no_image();
            self::show_post_title();

            echo '</div></li>';
        }

        wp_reset_postdata();
        self::show_dummy_post_if_odd( $datas->post_count );
        
        echo '</ul></section>';
    }

    private static function get_post_datas( $has_category, $has_tag ) {
        $query_conditions   = [
            'posts_per_page'        => self::POST_COUNT,
            'post__not_in'          => [ get_the_ID() ],
            'ignore_sticky_posts'   => 1,
            'orderby'               => 'rand',
        ];

        $taxonomy_conditions = [ 'relation' => 'OR' ];
        if ( $has_category  ) $taxonomy_conditions[] = self::get_category_condition();
        if ( $has_tag       ) $taxonomy_conditions[] = self::get_tag_condition();

        $query_conditions['tax_query']  = $taxonomy_conditions;
        $datas                          = new WP_Query( $query_conditions );

        return $datas;
    }

    private static function get_category_condition() {
        $categories     = get_the_category();
        $category       = $categories[0];
        $category_ids   = [ $category->cat_ID ];

        return [
            'taxonomy'  => 'category',
            'field'     => 'term_id',
            'terms'     => $category_ids,
        ];
    }

    private static function get_tag_condition() {
        $tags       = get_the_tags();
        $on_map     = function( $tag ) { return $tag->term_id; };
        $tag_ids    = array_map( $on_map, $tags );

        return [
            'taxonomy'  => 'post_tag',
            'field'     => 'term_id',
            'terms'     => $tag_ids,
        ];
    }

    private static function show_post_thumbnail_or_no_image() {
        echo '<div class="thumbnail">';

        has_post_thumbnail() ? 
            self::show_post_thumbnail() : 
            self::show_post_no_image()
        ;

        echo '</div>';
    }

    private static function show_post_thumbnail() {
        the_post_thumbnail( self::THUMBNAIL_NAME );
    }

    private static function show_post_no_image() {
        $width  = self::THUMBNAIL_WIDTH;
        $height = self::THUMBNAIL_HEIGHT;

        echo <<< EOT
<div class="no-image" style="width: {$width}px; height: {$height}px;">
    NO IMAGE
</div>
EOT;
    }

    private static function show_post_title() {
        $permalink  = esc_url( get_the_permalink() );
        $title      = esc_html( get_the_title() );

        echo <<< EOT
<h4 class="title">
    <a href="$permalink">
        <span class="text">$title</span>
    </a>
</h4>
EOT;
    }

    public static function show_dummy_post_if_odd( $count ) {
        if ( $count % 2 === 0 ) return;
        
        echo <<< 'EOT'
<li class="dummy-post">
    <div class="inner"></div>
</li>
EOT;
    }
}

サムネイルのサイズを追加する

after_setup_themeアクションフックを用いて、サムネイルのサイズを追加する。

( ※ 既にメディアに入っている画像は、追加したサイズのサムネイルが作られていないため再作成が必要となる。 )

function setup_theme() {
    add_theme_support( 'post-thumbnails' );

    add_image_size( 
        RelatedPost::THUMBNAIL_NAME, 
        RelatedPost::THUMBNAIL_WIDTH, 
        RelatedPost::THUMBNAIL_HEIGHT,
        true
    );
}

add_action( 'after_setup_theme', 'setup_theme' );

表示させたい箇所で関数を呼ぶ

テンプレートファイルの表示させたい箇所で下記の関数を呼ぶ。

RelatedPost::show();

これでその箇所に次のようなHTMLが出力される。( img要素が長いため大部分は省略した。 )

<section id="related-post">
    <h3 class="title">関連記事</h3>
	<ul class="content">
		<li class="post">
    		<div class="inner">
				<div class="thumbnail">
					<img width="140" height="84" src="http://sample.com/post1.png">
				</div>
				<h4 class="title">
					<a href="http://sample.com/post1/">
						<span class="text">記事1</span>
					</a>
				</h4>
			</div>
		</li>
		<li class="post">
    		<div class="inner">
				<div class="thumbnail">
					<img width="140" height="84" src="http://sample.com/post2.png">
				</div>
				<h4 class="title">
					<a href="http://sample.com/post2/">
						<span class="text">記事2</span>
					</a>
				</h4>
			</div>
		</li>
	</ul>
</section>

CSSで見た目を整える

後は出力されたHTMLの各要素に付いているIDとクラスを用いて、CSSで見た目を整える。