前回に引き続き、プラグインを作りながらWordPressの知識を深めていきます。
今回は記事をランダムに表示するウィジェットをプラグインで作ってみたいと思います。
記事をランダムに表示できると、埋もれがちな過去の記事もユーザーの目にとまりやすくなります。
プラグインでやりたいこと
- ランダムに記事を表示するウィジェットを作る
- ウィジェットにはタイトルと表示する投稿数を設定できる
- ウィジェットを作成する
- ウィジェットのオプション設定用の入力フォームを用意する
- 入力された値を保存する
- 入力値を使って、ページ上に記事を表示する
今回はプラグインで作っていきますが、同じコードをfunctions.phpに記載する形でも作れます。
作る前の準備
開発環境の準備
コードに不備があると、WordPressのサイトが動かなくなってしまうので、開発環境でプラグインを作りましょう。
事前準備で、プラグインフォルダに、自作するプラグイン「my-plugin」を用意します。
plugins/
└ my-plugin/
└ my-plugin.php
ウィジェットを作る
Widgetは、WordPressの WP_Widget クラスを拡張して作成します。
【ウィジェット作成時に使う4つの関数】
- __construct :Widgetの名前、説明など各種設定するコンストラクタ(ウィジェットの初期化をする)
- form :管理画面でのWidgetの入力フォームを出力するメソッド
- update :入力値をチェックし保存するメソッド
- widget : Widget をページに出力するメソッド
class Widget_Template extends WP_Widget {
public function __construct() {
// 1.初期化処理
parent::__construct( false, 'テンプレートウィジェット' );
}
public function form( $instance ) {
// 2.管理画面でウィジェット設定フォームを出力します。
}
public function update( $new_instance, $old_instance ) {
// 3.ウィジェットオプションのデータを検証/無害化します。
}
public function widget( $args, $instance ) {
// 4.ウィジェットの内容をWebページに出力します。
}
}
ウィジェットを登録する
まずはウィジェットを作成していきます。
コンストラクタを定義します
コンストラクタはクラスが作られたときにうごく初期化処理のこと。
ここには、IDや名前、説明などウィジェットの概要を設定します。
<?php
/*
* Plugin Name: My Plugin Customize
* Description: Customization for this blog
*/
class Random_Posts_Widget extends WP_Widget{
/**
* Widgetを登録する
*/
function __construct() {
//親クラスのコンストラクタに値を設定
parent::__construct(
'random_posts_widget', // ウィジ<meta charset="utf-8">ェットID
'Random Posts', // ウィジ<meta charset="utf-8">ェット名
array( 'description' => 'this widget shows random posts', ) // Args
);
}
}
コンストラクタでは、3つの処理を行います。
- 情報用の設定値を定義
- 操作用の設定値を定義
- 親クラスのコンストラクタを呼び出し値を設定
public function __construct() {
// ①情報用の設定値(widget otions)
$widget_options = [
'classname' => 'widget-template',
'description' => 'テンプレートウィジェットの説明文',
'customize_selective_refresh' => true,
];
// ②操作用の設定値(control options)
$control_options = [
'width' => 400,
'height' => 350
];
// ③親クラスのコンストラクタに値を設定
parent::__construct(
'widget-template', // base id
'テンプレートウィジェット', // widget name
$widget_options, // widget otions
$control_options // control options
);
}
情報用の設定値を
class_name : ウィジェットのクラス名に設定される文字列
description:管理画面のウィジェット名の下に表示されるウィジェットの説明。
操作用の設定値(control options)
widthは、ウィジェットが横幅に入りきらないとき、指定した横幅で表示される。(ウィジェット設定ページ、カスタマイズページで有効)
heightは、ウィジェットが横幅に入りきらないとき、指定した高さで表示される。(カスタマイズページで有効)
親クラスのコンストラクタを呼び出し値を設定
base Id:ベースID。ウィジェットのidに設定される文字列。
widget name’:管理画面で表示されるウィジェットの名前。
②WidgetをWordPressに登録します。
// ウィジェットをWordPressに登録する
function theme_register_widget() {
register_widget( 'Random_Posts_Widget' );
}
add_action( 'widgets_init', 'theme_register_widget' );
register_widgetはウィジェットを登録する関数。パラメータにウィジェットのクラス名を指定します。
register_widget( $widget_class )
そして、 アクションフックに、ウィジェットの登録関数をセットします。
add_action( 'widgets_init', 'theme_register_widget' );
do_action( ‘widgets_init’ )
Fires after all default WordPress widgets have been registered.
widget_initはデフォルトのウィジェットが全て登録された後に呼ばれます。
自分で作ったウィジェットはこのタイミングで追加するんですね。
これで、中身は空っぽですが、ウィジェットページに、ウィジェットが表示されるようになりました。
ウィジェットのオプションを設定する:form関数
管理画面で、ウィジェットにタイトルと表示件数を設定できるようにします。
Widgetクラス内にform関数を記載します。ここに入力フォームを記述します。
/** Widgetの管理用のオプションのフォームを出力
*
* @param array $instance 現在の設定項目
* @return string|void
*/
public function form( $instance ) {
$title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
$number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
?>
<p>
<?php /* タイトル */ ?>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">タイトル</label>
<input type="text"
class="widefat"
id="<?php echo $this->get_field_id( 'title' ); ?>"
name="<?php echo $this->get_field_name( 'title' ); ?>"
value ="<?php echo $title; ?>" />
</p>
<p>
<?php /* 表示する投稿数 */ ?>
<label for="<?php echo $this->get_field_id( 'number' ); ?>">表示する投稿数 :</label>
<input class="tiny-text"
id="<?php echo $this->get_field_id( 'number' ); ?>"
name="<?php echo $this->get_field_name( 'number' ); ?>"
type="number" step="1" min="1"
value="<?php echo $number; ?>" size="3" required/>
</p>
<?php
}
WordPressのコアファイルにある最新記事の表示ウィジェットのプログラム(
/wp-includes/widgets/class-wp-widget-recent-posts.php)に揃えて書きました。
初期値を取得
$instanceにはWordPressに保存されたオプションの設定値が入っています。
ここからtitle(タイトル)とnumber(表示する投稿数)を取得します。
未設定の場合は、タイトルは空の文字列に、表示する投稿数は初期値5を設定します。
$title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
$number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
- isset関数は、変数に値がセットされていて、かつNULLでないときに、TRUEを戻り値として返します。
- esc_attr関数はHTML 要素の属性(alt, value, title, class など)の値に出力する文字をエスケープします。
- absint関数は値を負ではない整数に変換します。
タイトル欄の表示
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">タイトル</label>
<input type="text"
class="widefat"
id="<?php echo $this->get_field_id( 'title' ); ?>"
name="<?php echo $this->get_field_name( 'title' ); ?>"
value ="<?php echo $title; ?>" />
</p>
- class=”widefat”には要素を横幅一杯に表示するCSSプロパティが設定されています。(WordPressで用意されているクラス)
- フォームに指定するid属性には
$this->get_field_id( ‘キー名’ )
、name属性には$this->get_field_name( ‘キー名’ )
を指定します。
表示する投稿数の入力欄を表示
<p>
<label for="<?php echo $this->get_field_id( 'number' ); ?>">表示する投稿数 :</label>
<input type="number"
class="tiny-text"
id="<?php echo $this->get_field_id( 'number' ); ?>"
name="<?php echo $this->get_field_name( 'number' ); ?>"
value="<?php echo $number; ?>"
min="1" max="15" step="1" size="3" required />
</p>
- class=“tiny-text” :width:45pxが指定されています(WordPressで用意されているクラス)
- min :最小値
- max :最大値
- step :入力可能な数値の間隔
- size : 入力できる文字数(3桁まで)
- required :入力必須
オプションの入力値を保存する:update関数
update関数は、フォームに入力された値をチェックし、無害化します。
/**
* Widgetオプションのサニタイズ
*
* @param array $new_instance 新しいオプション値
* @param array $old_instance 以前のオプション値
*
* @return array サニタイズした値を返す
*/
public function update( $new_instance, $old_instance ) {
// 一時的に以前のオプションを別変数に退避
$instance = $old_instance;
// タイトル値を無害化(サニタイズ)
$instance['title'] = sanitize_text_field( $new_instance['title'] );
// 投稿数の検証
$instance['number'] = (int) $new_instance['number'];
return $instance;
}
WordPressのコアファイルにある最新記事の表示ウィジェットのプログラム(
/wp-includes/widgets/class-wp-widget-recent-posts.php)に揃えて書きました。
sanitize_text_field
ユーザーが入力、またはデータベースから取得した文字列を無害化します。
無効な UTF-8 をチェックし、独立した ‘<‘ 文字をエンティティーへ変換し、タグをすべて除去し、改行・タブ・余分な空白を削除し、オクテット(’%’ に続く 2 桁の 16 進数)を除去します。
関数リファレンス/sanitize text field – WordPress Codex 日本語版
ウィジェットの内容を出力する
widget関数に、widgetの内容をHTML出力するコードを記述します。
/**
* Widgetの内容を出力する
*
* @param array $args ウィジェットの引数(「before_title, after_title, before_widget, after_widget」)が入る
* @param array $instance Widgetの設定項目
*/
public function widget( $args, $instance ) {
// ウィジェットオプションを取得・サニタイズ
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : '';
$number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
if ( ! $number ) {
$number = 5;
}
// ウィジェット開始タグを出力
echo $args['before_widget'];
// ウィジェットのタイトルを出力
if ( $title ) {
echo $args['before_title'] . $title . $args['after_title'];
}
// ウィジェットの内容を出力
$args = array(
'post_type' => 'post',// 投稿タイプを投稿に指定
'post_status' => 'publish',
'orderby' => 'rand',// ランダム表示
'posts_per_page' => $number,// 表示する投稿数
);
$posts_query = new WP_Query( $args );
if( $posts_query -> have_posts() ):
?>
<ul>
<?php while( $posts_query -> have_posts() ): $posts_query -> the_post(); ?>
<li class="randomPostList__item">
<a href="<?php the_permalink(); ?>" class="randomPostList__link">
<?php if( has_post_thumbnail() ): ?>
<div class="randomPostList__thumb">
<figure>
<?php the_post_thumbnail('large'); ?>
</figure>
</div>
<?php endif; ?>
<div class="randomPostList__body">
<div class="randomPostList__title"><?php the_title(); ?></div>
</div>
</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif;
wp_reset_postdata();
// ウィジェット終了タグを出力
echo $args['after_widget'];
}
- ウィジェットのオプションを取得する
- ウィジェット開始タグを出力
- ウィジェットのタイトルを出力
- ウィジェットの内容を出力
- ウィジェット終了タグを出力
ウィジェットのオプションを取得する
WordPressに保存されていたタイトル、表示する投稿数を取得し、データが空でないかをチェック、空の場合は初期値に変換しています。
タイトルは未設定の場合は空の文字列。
投稿数は0の場合は初期値5に変換するようになっています。
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : '';
$number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
if ( ! $number ) {
$number = 5;
}
- empty関数:変数の値が0あるいは空、NULLである場合はTRUEを、それ以外である場合はFALSEを返します。
ウィジェット開始タグを出力
// ウィジェット開始タグを出力
echo $args['before_widget'];
ウィジェットのタイトルを出力
// ウィジェットのタイトルを出力
if ( $title ) {
echo $args['before_title'] . $title . $args['after_title'];
}
ウィジェットの内容を出力
WP_Queryに記事の取得条件を設定して、記事を取り出します。
// ウィジェットの内容を出力
$args = array(
'post_type' => 'post',// 投稿タイプを投稿に指定
'post_status' => 'publish',
'orderby' => 'rand',// ランダム表示
'posts_per_page' => $number,// 表示する投稿数
);
$posts_query = new WP_Query( $args );
if( $posts_query -> have_posts() ):
?>
<ul>
<?php while( $posts_query -> have_posts() ): $posts_query -> the_post(); ?>
<li class="randomPostList__item">
<a href="<?php the_permalink(); ?>" class="randomPostList__link">
<?php if( has_post_thumbnail() ): ?>
<div class="randomPostList__thumb">
<figure>
<?php the_post_thumbnail('large'); ?>
</figure>
</div>
<?php endif; ?>
<div class="randomPostList__body">
<div class="randomPostList__title"><?php the_title(); ?></div>
</div>
</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif;
wp_reset_postdata();
ウィジェット終了タグを出力
echo $args['after_widget'];
これで、ランダムに記事が表示されるようになりました。
ランダムに記事を表示するが完成ウィジット
ここまでに作成したコードはこんな感じです。
<?php
/*
* Plugin Name: My Plugin Customize
* Description: Customization for this blog
* Version: 1.0.0
*/
class Random_Posts_Widget extends WP_Widget{
/**
* Widgetを登録する
*/
function __construct() {
parent::__construct(
'random_posts_widget', // Base ID
'Random Posts', // Name
array( 'description' => 'this widget shows random posts', ) // Args
);
}
/** Widgetの管理用のオプションのフォームを出力
*
* @param array $instance 現在の設定項目
* @return string|void
*/
public function form( $instance ) {
$title = isset( $instance['title'] ) ? esc_attr( $instance['title'] ) : '';
$number = isset( $instance['number'] ) ? absint( $instance['number'] ) : 5;
?>
<p>
<?php /* タイトル */ ?>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">タイトル</label>
<input type="text"
class="widefat"
id="<?php echo $this->get_field_id( 'title' ); ?>"
name="<?php echo $this->get_field_name( 'title' ); ?>"
value ="<?php echo $title; ?>" />
</p>
<p>
<?php /* 表示する投稿数 */ ?>
<label for="<?php echo $this->get_field_id( 'number' ); ?>">表示する投稿数 :</label>
<input class="tiny-text"
id="<?php echo $this->get_field_id( 'number' ); ?>"
name="<?php echo $this->get_field_name( 'number' ); ?>"
type="number" step="1" min="1"
value="<?php echo $number; ?>" size="3" required/>
</p>
<?php
}
/**
* Widgetオプションのサニタイズ
*
* @param array $new_instance 新しいオプション値
* @param array $old_instance 以前のオプション値
*
* @return array サニタイズした値を返す
*/
public function update( $new_instance, $old_instance ) {
// 一時的に以前のオプションを別変数に退避
$instance = $old_instance;
// タイトル値を無害化(サニタイズ)
$instance['title'] = sanitize_text_field( $new_instance['title'] );
// 投稿数の検証
$instance['number'] = (int) $new_instance['number'];
return $instance;
}
/**
* Widgetの内容を出力する
*
* @param array $args ウィジェットの引数(「before_title, after_title, before_widget, after_widget」)が入る
* @param array $instance Widgetの設定項目
*/
public function widget( $args, $instance ) {
// ウィジェットオプションを取得・サニタイズ
$title = ( ! empty( $instance['title'] ) ) ? $instance['title'] : '';
$number = ( ! empty( $instance['number'] ) ) ? absint( $instance['number'] ) : 5;
if ( ! $number ) {
$number = 5;
}
// ウィジェット開始タグを出力
echo $args['before_widget'];
// ウィジェットのタイトルを出力
if ( $title ) {
echo $args['before_title'] . $title . $args['after_title'];
}
// ウィジェットの内容を出力
$args = array(
'post_type' => 'post',// 投稿タイプを投稿に指定
'post_status' => 'publish',
'orderby' => 'rand',// ランダム表示
'posts_per_page' => $number,// 表示する投稿数
);
$posts_query = new WP_Query( $args );
if( $posts_query -> have_posts() ):
?>
<ul>
<?php while( $posts_query -> have_posts() ): $posts_query -> the_post(); ?>
<li class="randomPostList__item">
<a href="<?php the_permalink(); ?>" class="randomPostList__link">
<?php if( has_post_thumbnail() ): ?>
<div class="randomPostList__thumb">
<figure>
<?php the_post_thumbnail('large'); ?>
</figure>
</div>
<?php endif; ?>
<div class="randomPostList__body">
<div class="randomPostList__title"><?php the_title(); ?></div>
</div>
</a>
</li>
<?php endwhile; ?>
</ul>
<?php endif;
wp_reset_postdata();
// ウィジェット終了タグを出力
echo $args['after_widget'];
}
}
// ウィジェットをWordPressに登録する
function theme_register_widget() {
register_widget( 'Random_Posts_Widget' );
}
add_action( 'widgets_init', 'theme_register_widget' );
デザインを修正する
リストのように、画像とタイトルを並べて表示させます。
プラグインのコードを整理する
プログラムを追加していく際に、my-plugin.phpに全て書くと、煩雑になるので用途別にプログラムファイルを分けておきす。
- フォルダを分けて、機能別にファイルを作成
my-plugin
├ lib
│ └ widgets.php
└ my-plugin.php
- プラグインの大元のファイル(コメントにプラグイン情報が書かれているファイル)で、1のファイルを読み込む
<?php
/*
* Plugin Name: My Plugin Customize
* Description: Customization for this blog
* Version: 1.0.0
*/
/* Directory url of this plugin */
define( 'MY_PLUGIN_URL', untrailingslashit( plugin_dir_url( __FILE__ ) ) );
/* Directory path of this plugin */
define( 'MY_PLUGIN_PATH', untrailingslashit( plugin_dir_path( __FILE__ ) ) );
require_once( MY_PLUGIN_PATH . '/lib/widgets.php' );
こうしておくと、他の機能を追加していく時も、管理しやすいですね。
CSSを設定
assetsフォルダ、そしてその下にCSSフォルダを用意し、その中にCSSファイルを作成します。
my-plugin
├ assets
│ └ css
│ └ widget.css
├ lib
│ └ widgets.php
└ my-plugin.php
/**
* CSSの読み込み
*/
add_action('wp_enqueue_scripts', 'my_enqueue_style_script');
function my_enqueue_style_script()
{
/* css読み込み */
wp_enqueue_style(
'my_style',
MY_PLUGIN_URL . '/assets/css/style.css',
[],
filemtime(MY_PLUGIN_PATH . '/assets/css/style.css')
);
}
CSSは、現在使っているテーマSWELLと同じデザインにしてみました。
.randomPostList__link {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
justify-content: space-between;
color: inherit;
}
.randomPostList__item {
margin-bottom: 1.5em;
}
.randomPostList__thumb {
width: 36%;
}
.randomPostList__body {
width: 60%;
}
.randomPostList__title {
font-size: 13px;
margin: 0;
font-weight: 700;
line-height: 1.5;
}