WordPress で記事の途中で「関連記事」を出す必要に駆られたので、DIY でプラグインを作成しました。

 

 

一応テーマの方で、ページの下部に関連記事が出力されるようになっているのですが、記事中にも関連記事のリンクを、アイキャッチ画像付で貼り付けたくなったので、DIY で作成してみました。

このプラグインのファイル配置

WordPress インストールディレクトリをルートとした場合、次のようになります。

wp-content/
+-- plugins/
    +-- zblog_related_posts/
        +-- zblog-related-posts.php
        +-- css/
            +-- style.css

いきなり PHP コード

というわけでいきなりPHPコードです。

<?php
/*
Plugin Name: Zblog Related Posts
Plugin URI:
Description: 関連ページを表示するためのショートコードを提供します。
Author: Studio Rough and Cheap.
Version: 0.0.1
Author URI: https://www.rough-and-cheap.jp/
*/
// (1)
define( 'BEFORE_ZBLOG_RELATED_POSTS', '<div class="zblog_related_posts">' );
define( 'AFTER_ZBLOG_RELATED_POSTS', '</div>');

// (2)
function regist_zblog_related_posts_style() {
    $plugin_url = plugin_dir_url( __FILE__ );
    wp_enqueue_style( 'zblog-related-posts-style', $plugin_url . 'css/style.css' );
}

add_action( 'wp_enqueue_scripts' , 'regist_zblog_related_posts_style' );

// (3)
function zblog_related_posts($atts) {
    // (4)
    extract(shortcode_atts(array(
        'year' => null,
        'month' => null,
        'day' => null,
        'numberposts' => 5,
        'offset' => null,
        'order' => 'DESC',
        'orderby' => 'post_date',
        'meta_key' => null,
        'meta_value' => null,
        'post_type' => null,
        'include' => null,
        'exclude' => null,
        'custom' => false,
        'before' => null,
        'after' => null,
    ),$atts));

    // (5)
    $query = array(
        'year' => $year,
        'monthnum' => $month,
        'day' => $day,
        'numberposts' => $numberposts,
        'offset' => $offset,
        'order' => $order,
        'orderby' => $orderby,
        'post_type' => $post_type,
        'include' => $include,
        'exclude' => $exclude != null ? get_the_ID() . ',' .$exclude : get_the_ID()
    );

    $posts = get_posts( $query );
    $result = "";
    $count = 1;

    // (6)
    foreach ($posts as $post) {
        $post_thumb_src = wp_get_attachment_image_src( get_post_thumbnail_id( $post->ID ) );
        $post_thumb_url = ( $post_thumb_src != false ) ? $post_thumb_src[0] : null;
        $post_date = date( 'Y-m-d', strtotime( $post->post_date ) );
        $modify_date = date( 'Y-m-d', strtotime( $post->post_modified ));
        $post_url = get_permalink( $post->ID );
        $post_title = get_the_title( $post->ID );
        $title = ( ! empty( $post_title) ) ? $post_title : __( '(no title)' );

        $temp = '<div class="zblog_related_post_imagepart">' . "\n";
        $temp .= '<div class="zblog_related_post_image zblog_related_post_image' . $count . '">' . "\n";

        if ( $post_thumb_url != null ) {
            $temp .= '<a href="' . $post_url . '" target="_blank" title="' . $title . '" rel="noopener noreferrer"><img src="' . $post_thumb_url . '" alt="" title="' . $title . '"></a>' . "\n";
        } else {
            $temp .= ' ' . "\n";
        }

        $temp .= '</div>' . "\n";
        $temp .= '</div>' . "\n";
        $temp .= '<div class="zblog_related_post_descpart">' . "\n";
        $temp .= '<p class="zblog_related_post_title zblog_related_post_title' . $count . '"><a href="' . $post_url . '" target="_blank" title="' . $title . '" rel="noopener noreferrer">関連記事:' . $title . '</a></p>' . "\n";
        $temp .= '<p class="zblog_related_post_excerpt zblog_related_post_excerpt' . $count . '">' . get_the_excerpt($post->ID) . "</p>\n";
        $temp .= '<p class="zblog_related_post_date zblog_related_post_date' . $count . '">投稿日:' . $post_date . '</p>' . "\n";
        $temp .= '</div>' . "\n";

        $result .= '<div class="zblog_related_post zblog_related_post' . $count . '">' . "\n" . $temp . "\n" . '</div>';
        $result .= "\n";

        $count++;
    }

    // (7)
    return $custom ? $before . "\n" . $result . "\n" . $after . "\n" : BEFORE_ZBLOG_RELATED_POSTS . "\n" . $result . "\n" . AFTER_ZBLOG_RELATED_POSTS . "\n";
}

// (8)
add_shortcode('kanren','zblog_related_posts');
?>

(1) 定数

整形された関連機にの前後に出力する文字列を定数として定義しています。ショートコードのオプションで上書きされます。

BEFORE_ZBLOG_RELATED_POSTS
整形された「関連記事」を出力する前に出力したい文字列。<div class="zblog_related_posts"> を定義しています。
AFTER_ZBLOG_RELATED_POSTS
整形された「関連記事」を出力した後に出力したい文字列。</div>を定義しています。

(2) CSS 登録

後で示す、このショートコードで必要なCSSファイルを読み込むための処理をしています。

(3) 関数本体

ショートコードの本体の処理をする関数です。

(4) オプション処理

ショートコードから渡されたオプションを変数に落とし込みます。このオプションは、get_posts() 関数にある程度似せています。オプションがなかった値に関しては、null を代入していますが、一部はデフォルトの値を代入しています。

(5) クエリ配列の作成

get_posts() 関数に渡すクエリ配列を作成します。

exclude には、get_the_ID() として、検索結果に自身のページが含まれないようにしています。

(6) メインループ

get_posts() 関数で取得された結果セットをループさせて、結果となるHTMLを整形しています。

(7) 結果を返す

メインループで整形されたHTMLの前後に、先の定数を前後に付加して、結果を返します。

$custom オプションが true のときは、定数の代わりにオプション中の beforeafter を付加します。

結果としてハキ出す HTML の構造

このショートコードで処理した結果は、次のようなHTMLが出力されます。

.zblog_related_post からが、ループで処理している部分になります。

それぞれの項目にクラスを割り当てているので、CSSで見た目やレイアウトを当て込んでいきます。

<div class="zblog_related_posts">
  <div class="zblog_related_post zblog_related_post1">
    <div class="zblog_related_post_imagepart">
      <div class="zblog_related_post_image zblog_related_post_image1">
        [アイキャッチ画像とリンク]
      </div>
    </div>
    <div class="zblog_related_post_descpart">
      <p class="zblog_related_post_title zblog_related_post_title1">[タイトルとリンク]</p>
      <p class="zblog_related_post_excerpt zblog_related_post_excerpt1">[記事抜粋]</p>
      <p class="zblog_related_post_date zblog_related_post_date1">[投稿日]</p>
    </div>
  </div>
</div>

CSS

続いて、CSSファイルです。

/* CSS for zblog related posts plugin */

.zblog_related_post {
    border: 1px solid #dedede;
    border-radius: 4px;
    box-sizing: border-box;
    width: 100%;
    margin: 1rem 0;
    padding: 1rem;
}

.zblog_related_post:hover {
    background-color: #efffff;
}

.zblog_related_post::before,
.zblog_related_post::after {
    content: "";
    clear : both;
    display: block;
}

.zblog_related_post_imagepart {
    float: left;
}

.zblog_related_post_imagepart img {
    width: 10rem;
    height: 10rem;
}

.zblog_related_post_image {
    width: 10rem;
}

.zblog_related_post_descpart {
    box-sizing: border-box;
    float: left;
    padding-left: 1rem;
    width: calc(100% - 10rem);
}

.zblog_related_post_descpart p {
    line-height: 1.0 !important;
}

.zblog_related_post .zblog_related_post_title a {
    font-size: 120%;
    font-weight: 800;
}

.zblog_related_post_descpart
p.zblog_related_post_excerpt {
    font-size:100%;
}

.zblog_related_post
p.zblog_related_post_date {
    font-size: 95%;
    font-style: italic;
}

.zblog_related_posts .zblog_related_post .zblog_related_post_descpart p {
    margin: 0 0 8px !important;
}

.zblog_related_posts .zblog_related_post .zblog_related_post_descpart .zblog_related_post_date {
    text-align: right;
}

前回の記事の元ネタ部分になりますね。ホバーした時に色が変わる部分は余計かな?

このCSSを当てて表示させると次のようになります。

 

記事の抜粋(excerpt)の「続きを読む」リンクは、テーマの方で自動的に付加されています。

他のテーマによっては、単純に […] だったり、リンクがなかったりする場合もあります。

このショートコードについて

このショートコードの使用方法は、記事内に、

[kanren オプション]

を記入するだけです。

オプションは任意です。何も指定しない場合は、最近の投稿と同じく、投稿日の順で最新の記事を最大5件出力します。

オプションの使用例:

[kanren include="2300,1650" ]

オプション

主なオプションは以下の通り。

year
(整数) (任意) 年を数字で指定
初期値: null
month
(整数) (任意) 月を数字で指定
初期値: null
day
(整数) (任意) 日付を数字で指定
初期値: null
numberposts
(整数) (任意) 抽出する記事の最大件数
初期値: 5
include
(文字列) (任意) 記事のIDを指定します。複数ある場合は、, で区切ります
初期値: null
exclude
(文字列) (任意) 検索結果に含めたくないIDを指定します。複数ある場合は、, で区切ります
初期値: ショートコードを指定している記事自身
custom
(真偽値) (任意) 整形されたHTMLの前後を、カスタムの文字列で囲むかどうか
初期値: false
before
(文字列) (任意) 整形されたHTMLの前に出力したい文字列。custom == true 時にのみ有効
初期値: null
after
(文字列) (任意) 整形されたHTMLの後に出力したい文字列。custom == true 時にのみ有効
初期値: null

改善点

一番良く使いそうな、include オプションはもう少し短いオプション名にしたいな。

単純に id でも良さそう。

まとめ

このショートコードについては、ぶっちゃけinclude オプションしか試していないのが現状です。他のオプションについてはあまりしっかりと検証していないので、気をつけてください。

また、オプションで与えられた値は、バリデーションしていませんので、予期しない結果になるかもしれません(コード見たらわかりますが、記事が消えたりする、とかはないです)。

最近は、機能豊富なプラグインを使わずとも、自身に必要なミニマムなプラグイン程度であれば、自身でDIYしてしまっています。こちらの方が他のプラグインとの相性問題などを気にせず自分自身で制御できる範囲で作れるので、ある意味気楽です。

あくまでも、個人的な記事でもあるので、もし参考にされる際は自己責任でお願いしたいですが、少しでもお役に立てると幸いです。


 

 

zaturendo

中小企業社内SE。

2件のコメント

LOCK · 2020年5月22日 1:45 PM

こちらのプラグインを使用させてもらっていたのですが、amp化に伴いエラーが出てしまいました。
height、widthの書き出しがないためかと思うのですが、どのようにコードを変更すればいいのでしょうか?
突然のコメントで申し訳ありませんが、教えていただけると嬉しいです。
宜しくお願い致します。

    zaturendo · 2020年5月22日 8:24 PM

    コメントありがとうございます。
    具体的にはどんな形でエラーが出るのでしょうか?
    同時に使用されているプラグインや、テーマなども影響している可能性もあります。

コメントを残す

アバタープレースホルダー

メールアドレスが公開されることはありません。 が付いている欄は必須項目です