2026年5月20日
2026年5月20日
WordPressプラグインでウィジェットを作成する方法(WP_Widgetの継承・登録・WP-CLIでの確認)
WordPress のウィジェットは、サイドバーやフッターなどの「ウィジェットエリア」に置く部品です。プラグインから自作のウィジェットを追加するには、WP_Widget クラスを継承したクラスを作り、widgets_init アクションで register_widget() に渡します。
この記事のコードは、2026年11月時点の WordPress 7.1 と PHP 8.3 で、有効化・ウィジェットの追加・表示まで動作を確かめています。
ウィジェットを使える場面
自作ウィジェットが使えるのは、ウィジェットエリア(サイドバー)を登録しているテーマです。
- クラシックテーマ(Twenty Twenty-One など): 「外観」→「ウィジェット」から追加します。WordPress 5.8 以降、この画面はブロックで編集する形(ブロックウィジェットエディター)になりましたが、
WP_Widgetで作ったウィジェットもそのまま追加できます。 - ブロックテーマ(Twenty Twenty-Five など): ウィジェットエリアが無いため、「外観」に「ウィジェット」が表示されません。サイトエディターで使える部品を作りたい場合は、ウィジェットではなくブロックとして作ります。
ウィジェットのプラグインを作る
wp-content/plugins/my-recent-posts-widget/ フォルダーを作り、その中に my-recent-posts-widget.php として次の内容を保存します。最近の投稿を指定した件数だけ表示するウィジェットです。
<?php
/**
* Plugin Name: My Recent Posts Widget
* Description: 最近の投稿を表示するウィジェットのサンプル
* Version: 1.0.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
class Myplugin_Recent_Posts_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'myplugin_recent_posts', // ID のもとになる名前(id_base)
'MY: 最近の投稿', // 管理画面に表示する名前
array(
'description' => '最近の投稿を一覧で表示します',
'classname' => 'myplugin-recent-posts',
'show_instance_in_rest' => true,
)
);
}
// サイトに表示する内容
public function widget( $args, $instance ) {
$title = apply_filters( 'widget_title', $instance['title'] ?? '', $instance, $this->id_base );
$count = isset( $instance['count'] ) ? absint( $instance['count'] ) : 5;
$posts = get_posts(
array(
'numberposts' => $count,
'post_status' => 'publish',
)
);
if ( ! $posts ) {
return;
}
echo $args['before_widget'];
if ( $title ) {
echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
}
echo '<ul class="myplugin-recent-list">';
foreach ( $posts as $post ) {
printf(
'<li><a href="%s">%s</a></li>',
esc_url( get_permalink( $post ) ),
esc_html( get_the_title( $post ) )
);
}
echo '</ul>';
echo $args['after_widget'];
}
// 管理画面の設定フォーム
public function form( $instance ) {
$title = $instance['title'] ?? '最近の投稿';
$count = isset( $instance['count'] ) ? absint( $instance['count'] ) : 5;
?>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">タイトル:</label>
<input type="text" class="widefat"
id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
value="<?php echo esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>">表示件数:</label>
<input type="number" class="tiny-text" min="1" max="20"
id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"
name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>"
value="<?php echo esc_attr( $count ); ?>">
</p>
<?php
}
// 保存する値の整形
public function update( $new_instance, $old_instance ) {
$count = absint( $new_instance['count'] ?? 5 );
return array(
'title' => sanitize_text_field( $new_instance['title'] ?? '' ),
'count' => min( max( $count, 1 ), 20 ),
);
}
}
add_action(
'widgets_init',
function () {
register_widget( 'Myplugin_Recent_Posts_Widget' );
}
);
保存したら、「プラグイン」→「インストール済みプラグイン」で「My Recent Posts Widget」を有効化します。クラシックテーマなら、「外観」→「ウィジェット」でウィジェットエリアに「従来のウィジェット」ブロックを追加し、ウィジェットの一覧から「MY: 最近の投稿」を選びます。
4つのメソッドの役割
| メソッド | 役割 |
|---|---|
__construct() |
ID のもとになる名前(id_base)、表示名、説明などを parent::__construct() に渡す |
widget( $args, $instance ) |
サイトに出力する HTML。$args にはウィジェットエリア側で決めた前後のタグ、$instance には保存された設定が入る |
form( $instance ) |
管理画面に出す設定フォーム。get_field_id() と get_field_name() で項目の id と name を作る |
update( $new_instance, $old_instance ) |
保存前に入力値を整形して返す。返した配列がそのまま保存される |
引数に型を付けない
WP_Widget の widget()・form()・update() は、引数に型の指定がありません。子クラスで widget( array $args, array $instance ) のように型を付けると、PHP 8 では親クラスのメソッドと互換がないと判断され、プラグインを読み込んだ時点で次のような致命的エラーになります。
PHP Fatal error: Declaration of Bad_Widget::widget(array $args, array $instance): void must be compatible with WP_Widget::widget($args, $instance)
子クラスの引数は、親クラスと同じく型なしで書いてください。
出力のエスケープ
widget() では、タイトルは esc_html()、URL は esc_url() で出力しています。$args['before_widget'] などはテーマ(ウィジェットエリアの登録側)が用意したHTMLなので、そのまま出力します。
show_instance_in_rest を true にすると、ウィジェットの設定値が REST API(ブロックウィジェットエディターが使う)にそのままの形で出ます。WordPress 標準のウィジェットも true にしています。パスワードなど公開したくない値を設定に持つウィジェットでは true にしないでください。
ウィジェットエリアを追加する
使っているテーマにウィジェットエリアが無い場合や、プラグイン用の場所を増やしたい場合は、register_sidebar() で登録します。ブロックテーマでもこれを登録すると「外観」→「ウィジェット」が表示されますが、テンプレートにウィジェットエリアを出力する仕組みが無いため、サイトには表示されません。
<?php
add_action( 'widgets_init', function () {
register_sidebar(
array(
'id' => 'myplugin-sidebar',
'name' => 'プラグイン用サイドバー',
'description' => 'プラグインが追加するウィジェットエリア',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
)
);
} );
クラシックテーマのテンプレートファイル(sidebar.php など)で、ウィジェットが置かれているときだけ出力します。
<?php if ( is_active_sidebar( 'myplugin-sidebar' ) ) : ?>
<aside class="myplugin-sidebar">
<?php dynamic_sidebar( 'myplugin-sidebar' ); ?>
</aside>
<?php endif; ?>
before_widget の %1$s にはウィジェットのID(例: myplugin_recent_posts-2)、%2$s には classname に指定したクラス名が入ります。
WP-CLIでウィジェットを追加・確認する
WP-CLI の wp widget コマンドで、ウィジェットエリアへの追加・変更・削除ができます。ウィジェットの種類は id_base(この例では myplugin_recent_posts)で指定し、設定の項目は --項目名=値 で渡します。
# ウィジェットエリアの一覧
wp sidebar list --fields=name,id
# 1番目の位置に追加
wp widget add myplugin_recent_posts myplugin-sidebar 1 --title="新着記事" --count=3
# 置かれているウィジェットと設定を確認
wp widget list myplugin-sidebar --fields=name,id,position,options
# 設定を変更(指定しなかった項目は update() の既定値に戻るので、すべて指定する)
wp widget update myplugin_recent_posts-1 --title="最新記事" --count=3
# 削除
wp widget delete myplugin_recent_posts-1
試したところ、wp widget update で --title だけを渡すと、count は update() の既定値の 5 に戻りました。変更するときは、残したい項目も含めてすべて指定してください。
旧来のウィジェット画面に戻す場合
ブロックウィジェットエディターをやめ、WordPress 5.7 までのウィジェット画面に戻すには、use_widgets_block_editor フィルターで false を返します。
<?php
add_filter( 'use_widgets_block_editor', '__return_false' );
公式の「Classic Widgets」プラグインを有効にしても同じ結果になります。