【WordPress】特定の投稿を表示するウィジェットを自作する方法
こんにちは。あきのりです。
フリーランスプログラマーとしてwebページ・サービスを作っています。
今回はwordpressで特定の投稿を表示するウェジェットを作成する方法について見ていきます。
最初からあるウィジェットだと「最近の投稿」や「人気の投稿」などはあるんですが「特定の投稿」が無いようで、おそらくプラグインを利用しないといけないです。
プラグインを使っても良いのですが、できるなら機能を自作できた方がプラグインによる不具合も起こさずに済むので、今回はそんな投稿表示ウィジェットを作成していきましょう。
下準備:ウィジェット用のファイルを作成しておく
wordpressをカスタマイズするには基本的にfunctions.php
というファイルを編集する必要があります。
が、いろんなものをこのファイルに直接書くと見づらくなってしまうので、別ファイルにコードを書きそのファイルをfunctions.php
で読み込むようにします。
まず、現在使っているテーマフォルダの中にfunctions
というフォルダを作成し、その中に以下の2つのファイルを作ります。
widgets.php
: ウィジェットを作成するファイルwidgets-area.php
: ウィジェットエリアを作成するファイル
そしてfunctions.php
でこれらファイルを読み込みましょう。
ファイルの一番上(<php
の直後)に書いてください。
//functions.php
<?php
/**
* ファイルのインポート
*/
require_once get_template_directory() . '/functions/widgets.php';
require_once get_template_directory() . '/functions/widgets-area.php';
//~ 省略 ~
widgets-area.php
でウィジェットエリアを作成する
次はwidgets-area.php
にコードを書いていきます。
今回はヘッダー画像下にウィジェットエリアを作ります。
以下のように書いてください。
//widgets-area.php
<?php
/**
* ウェジェットエリア登録
*/
//ヘッダー下
function below_header() {
register_sidebar(array(
'id' => 'below_header',
'name' => 'ヘッダー下',
'before_widget' => '<div class="recommended-posts">',
'after_widget' => '</div>'
));
}
add_action( 'widgets_init', 'below_header' );
このように書くと、外観 -> ウィジェット
で、画像のように「ヘッダー下」という欄が現れます。
プログラム解説(プログラマー向け)
ウィジェットエリアを作成するにはregister_sidebar
という関数を使います。
この引数に配列で情報を渡します。
ここで渡した情報は以下の通りです。
id
:ウィジェットエリアを特定するためのものname
:管理画面に表示させるための名前before_widget
:このウィジェットエリアを囲うためのHTML開始タグafter_widget
: このウィジェットエリアを囲うためのHTML開始タグ
idやnameは分かりやすいものにしておき、タグに関しては汎用性を考えてdiv
タグにしています。
他にも設定はできるのですが詳しくは公式ドキュメントを読んでください。
wordpressのフックについて
また、wordpressでは作成した関数をどの時点で呼び出すかを決めることができます。フック関数っていうやつです。
今回の例では最後の部分ですね。
add_action( 'widgets_init', 'below_header' );
add_action('フックのタイミング', '呼び出す関数')
という形で書きます。
今回は単純に「ウィジェットが読み込まれるタイミング」で呼び出しています。
widgets.php
で特定の投稿を表示する自作ウィジェットを作成する
次はwidgets.php
にコードを書いて、ウィジェットを作っていきます。
先ほど言った通り、特定の投稿を表示するウィジェットを作ります。
//widgets.php
<?php
//ウィジェットの登録
function theme_register_widget() {
register_widget('PostWidget');
}
add_action('widgets_init', 'theme_register_widget');
//クラスの作成
class PostWidget extends WP_Widget {
//初期設定
public function __construct() {
$widget_options = array(
'classname' => 'widget-post',
'description' => '特定の表示を表示する',
'customize_selective_refresh' => true
);
$control_options = array();
parent::__construct(
'widget-post',
'投稿表示',
$widget_options.
$control_options,
);
}
//ウィジェットの管理画面上での設定表示
public function form($instance) {
$post_id = !empty($instance['post_ids']) ? esc_attr(implode(',', $instance['post_ids'])) : '1';
?>
<!-- 管理画面での表示 -->
<p>
<label for="<?php echo $this->get_field_id('post_ids'); ?>"><?php _e('投稿ID(カンマ区切りで入力):'); ?></label>
<input
type="text"
class="widefat"
id="<?php echo $this->get_field_id( 'post_ids' ); ?>"
name="<?php echo $this->get_field_name( 'post_ids' ); ?>"
value ="<?php echo $post_id; ?>"
required
/>
</p>
<!-- ここまで -->
<?php
}
//入力フォームの更新
public function update($new_instance, $old_instance) {
$instance = $old_instance;
$instance['post_ids'] = sanitize_text_field($new_instance['post_ids']);
//数字、カンマのみを受け付ける
$regex = "/[0-9\, ]+/";
preg_match($regex, $instance['post_ids'], $matches);
$matches[0] = str_replace(' ', '', $matches[0]);
//文字列を配列化
$post_ids = explode(',', $matches[0]);
foreach($post_ids as $key => $value) {
//空白は消す
if($value == '') {
unset($post_ids[$key]);
} else {
$value = (int)$value;
//0は許可しない
if($value == 0) {
unset($post_ids[$key]);
} else {
$post_ids[$key] = $value;
}
}
}
$post_ids = array_values($post_ids);
$instance['post_ids'] = $post_ids;
return $instance;
}
// ウィジェットのページ上での出力処理
public function widget($args, $instance) {
$post_ids = (!empty($instance['post_ids'])) ? $instance['post_ids'] : array(1);
$args = array(
'post_type' => 'post',
'post__in' => $post_ids,
'ignore_sticky_posts' => true,
);
echo $args['before_widget'];
//投稿データを取得
$my_query = new WP_Query($args);
if($my_query->have_posts());
?>
<!-- オススメ記事一覧 -->
<div class="row">
<?php if($my_query->have_posts()) : while($my_query->have_posts()) : $my_query->the_post(); ?>
<div class="col-4 position-relative mb-3">
<div class="img-container thumbnail-container">
<img src="<?= has_post_thumbnail() ? get_the_post_thumbnail_url('', 'full') : get_template_directory_uri() . '/images/no-image.jpg' ?>" alt="<?php the_title(); ?>">
</div>
<div>
<p><?php the_title() ?></p>
</div>
<a href="<?php the_permalink() ?>" class="stretched-link"></a>
</div>
<?php endwhile; endif; ?>
</div>
<!-- ここまで -->
<?php
}
}
するとウィジェット欄に「投稿表示」という項目が追加された思います。
これを「ヘッダー下」に追加してデータを入力して保存しましょう。今回は投稿IDをカンマ区切りで入力するように構築しています。
ウィジェット情報を表示させる
最後にこのウィジェットをウェブページで表示させます。
今回はヘッダー下なので、そこに当たる場所に表示させるコードを書いていきます。
例として投稿一覧ページ(index.php)に書きます。
//index.php
<?php get_header(); ?>
<div class="container">
<?php if(is_active_sidebar('below_header')) : ?>
<?php dynamic_sidebar('below_header'); ?>
<?php endif; ?>
</div>
<?php get_footer(); ?>
するとIDで設定した投稿が表示されます。
今回のコードだと3投稿が一番見やすいです。これをスライダー形式で表示させればより多くの投稿を表示させることができ、「オススメ記事」が完成します。
コード解説(プログラマー向け)
ウィジェットの登録
widgets.php
の最初でウィジェットの登録を行っています。
//ウィジェットの登録
function theme_register_widget() {
register_widget('PostWidget');
}
add_action('widgets_init', 'theme_register_widget');
これはウィジェットエリアを作ったときとほぼ同じです。
ウィジェットクラスの作成
ウィジェットを作成するにはウィジェット用のクラスを作る必要があります。
クラスの中身は決まっていて大枠として以下のようになっています。
//クラスの作成
class クラス名 extends WP_Widget {
//初期設定
public function __construct() {
parent::__construct(
'id',
'name',
);
}
//ウィジェットの管理画面上での設定表示
public function form($instance) {
}
//入力フォームの更新
public function update($new_instance, $old_instance) {
}
// ウィジェットのページ上での出力処理
public function widget($args, $instance) {
}
}
それぞれのメソッド(関数)にコードを書いて自作をしていきます。
ウィジェットの初期設定
まず、初期設定です。__construct()
の部分です。
ここでは、管理画面でウィジェット項目を表示させるための処理を行います。
さっきの例を見てみるとこんな感じ。
public function __construct() {
$widget_options = array(
'classname' => 'widget-post',
'description' => '特定の表示を表示する',
'customize_selective_refresh' => true
);
$control_options = array();
parent::__construct(
'widget-post',
'投稿表示',
$widget_options,
$control_options,
);
}
いろいろ書いてありますが、最後のparent::__construct
の部分で初期設定を行っています。
ここで設定するものは次の通り
ID
: ウィジェットを区別するためのIDname
: ウィジェットの名前widget_options
: ウィジェットの追加情報(説明文など)control_options
: ダッシュボード上で展開した際の幅や高さを指定
上2つは文字列で、下2つは配列で定義します。
ウェジェットのフォーム作成
次は、ウェジェットに情報を入力する部分、form
についてです。
ここはシンプルにフォームを作成するだけでOKです。
今回だとこんな感じ。
//ウィジェットの管理画面上での設定表示
public function form($instance) {
$post_id = !empty($instance['post_ids']) ? esc_attr(implode(',', $instance['post_ids'])) : '1';
?>
<!-- 管理画面での表示 -->
<p>
<label for="<?php echo $this->get_field_id('post_ids'); ?>"><?php _e('投稿ID(カンマ区切りで入力):'); ?></label>
<input
type="text"
class="widefat"
id="<?php echo $this->get_field_id( 'post_ids' ); ?>"
name="<?php echo $this->get_field_name( 'post_ids' ); ?>"
value ="<?php echo $post_id; ?>"
required
/>
</p>
<!-- ここまで -->
<?php
一番最初の部分
$post_id = !empty($instance['post_ids']) ? esc_attr(implode(',', $instance['post_ids'])) : '1';
では、初期値をを設定しています。
以降のpタグから始まる部分は、おなじみのフォームです。
入力データの更新
次は、このフォームで入力されたデータを更新する部分、update
のについてです。
これもフォームを作成した人なら分かるかと思います。
データを取得して保存するだけです(違いは、$_POST
ではなく$new_instance
変数を使います)。
//入力フォームの更新
public function update($new_instance, $old_instance) {
$instance = $old_instance;
$instance['post_ids'] = sanitize_text_field($new_instance['post_ids']);
//数字、カンマのみを受け付ける
$regex = "/[0-9\, ]+/";
preg_match($regex, $instance['post_ids'], $matches);
$matches[0] = str_replace(' ', '', $matches[0]);
//文字列を配列化
$post_ids = explode(',', $matches[0]);
foreach($post_ids as $key => $value) {
//空白は消す
if($value == '') {
unset($post_ids[$key]);
} else {
$value = (int)$value;
//0は許可しない
if($value == 0) {
unset($post_ids[$key]);
} else {
$post_ids[$key] = $value;
}
}
}
$post_ids = array_values($post_ids);
$instance['post_ids'] = $post_ids;
return $instance;
}
今回は数字のカンマ区切りで入力してほしいので、正規表現を使ってデータを確認しています。
また、空白も取り除いています。
//数字、カンマのみを受け付ける
$regex = "/[0-9\, ]+/";
preg_match($regex, $instance['post_ids'], $matches);
//空白を除く
$matches[0] = str_replace(' ', '', $matches[0]);
これをカンマを切るポイントにして配列に変換しています。
//文字列を配列化
$post_ids = explode(',', $matches[0]);
ただ、カンマ(,)が続いたときに空白の要素が含まれてしまうので、それを消去します。
また、IDが0の投稿は無いので、0があったらそれも抜き取ります。
foreach($post_ids as $key => $value) {
//空白は消す
if($value == '') {
unset($post_ids[$key]);
} else {
$value = (int)$value;
//0は許可しない
if($value == 0) {
unset($post_ids[$key]);
} else {
$post_ids[$key] = $value;
}
}
}
webページに実際に表示させる
最後は、実際に表示させる部分、widget
についてです。
ここでは、入力されたデータを受けて、(必要な処理があればして)表示させればOKです。
// ウィジェットのページ上での出力処理
public function widget($args, $instance) {
$post_ids = (!empty($instance['post_ids'])) ? $instance['post_ids'] : array(1);
$args = array(
'post_type' => 'post',
'post__in' => $post_ids,
'ignore_sticky_posts' => true,
);
echo $args['before_widget'];
//投稿データを取得
$my_query = new WP_Query($args);
if($my_query->have_posts());
?>
<!-- オススメ記事一覧 -->
<div class="row">
<?php if($my_query->have_posts()) : while($my_query->have_posts()) : $my_query->the_post(); ?>
<div class="col-4 position-relative mb-3">
<div class="img-container thumbnail-container">
<img src="<?= has_post_thumbnail() ? get_the_post_thumbnail_url('', 'full') : get_template_directory_uri() . '/images/no-image.jpg' ?>" alt="<?php the_title(); ?>">
</div>
<div>
<p><?php the_title() ?></p>
</div>
<a href="<?php the_permalink() ?>" class="stretched-link"></a>
</div>
<?php endwhile; endif; ?>
</div>
<!-- ここまで -->
<?php
}
今回は、配列にした投稿IDを元に、投稿データを取得しています。
$query_args = array(
'post_type' => 'post',
'post__in' => $post_ids,
'ignore_sticky_posts' => true,
);
//投稿データを取得
$my_query = new WP_Query($query_args);
投稿データを取得するのにWP_Query
というもの使っていて、条件を引数として設定しています。
今回の条件については以下の通り
post_type
: 投稿タイプpost__in
:投稿IDignore_sticky_posts
:「トップに固定」の記事を無効
取得した投稿データはループ処理で表示させています。これは投稿一覧ページなどで使っているものと同じです。
<div class="row">
<?php if($my_query->have_posts()) : while($my_query->have_posts()) : $my_query->the_post(); ?>
<div class="col-4 position-relative mb-3">
<div class="img-container thumbnail-container">
<img src="<?= has_post_thumbnail() ? get_the_post_thumbnail_url('', 'full') : get_template_directory_uri() . '/images/no-image.jpg' ?>" alt="<?php the_title(); ?>">
</div>
<div>
<p><?php the_title() ?></p>
</div>
<a href="<?php the_permalink() ?>" class="stretched-link"></a>
</div>
<?php endwhile; endif; ?>
</div>
最後に表示させたい場所に以下のコードを書きました。
<?php if(is_active_sidebar('below_header')) : ?>
<?php dynamic_sidebar('below_header'); ?>
<?php endif; ?>
まとめ
というわけで以上です。
これで特定の投稿を表示させることができました。
また、新しくウィジェットを自作することもできると思うので挑戦してみてください。
それでは、良い1日を。
スポンサードサーチ
人気記事英語学習用SNSをLaravelで作ってみた【システム解説あり】