WordPress の独自 widget を作成する

WordPress を利用する際によく使用する表示領域は Widget を作成しておけば、(1)再利用や(2)設定の変更を管理画面でできる、などのメリットがあるらしい。そこで、Widget はどのように作成するか調べてみた。

基本形

Widget は WP_Widget クラスを継承した以下の形が基本形となる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
class Widget_Template extends WP_Widget {

public function __construct() {
// 初期化処理を行う
parent::__construct( false, 'ウィジェット名' );
}

public function widget( $args, $instance ) {
// Widget の内容を HTML 形式で出力する
}

public function form( $instance ) {
// 管理画面に Widget 設定フォームを出力します。
}

public function update( $new_instance, $old_instance ) {
// データの検証・無害化を行い、データを安全な値で保存する
}
}

コンストラクター

コンストラクターでは、主に3つの処理を行う。

  • ウィジェットの情報用の設定値を配列で用意
  • ウィジェットの操作用の設定値を配列で用意
  • 親クラスのコンストラクタで初期化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* 初期化処理を行う
*/
public function __construct() {
// 情報用の設定値
$widget_options = [
'classname' => 'widget-template',
'description' => 'テンプレートウィジェットの説明文です。',
'customize_selective_refresh' => true,
];

// 操作用の設定値
$control_options = [
'width' => 400,
'height' => 350
];

// 親クラスのコンストラクタに値を設定
parent::__construct(
'widget-template',
'サンプルウィジェット',
$widget_options,
$control_options
);
}

管理画面に Widget 設定フォームを出力する

WordPress の管理画面で Widget の設定を行うフォームを表示するメソッド。必要であれば、表示する値の無害化を行う。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public function form( $instance ) {
// デフォルトのオプション値
$defaults = array(
'title' => '',
'text' => ''
);

// デフォルトのオプション値と現在のオプション値を結合
$instance = wp_parse_args( (array) $instance, $defaults );

// タイトル値の無害化(サニタイズ)
$title = sanitize_text_field( $instance['title'] );
?>
<!-- 設定フォーム: タイトル -->
<p>
<label for="<?php echo $this->get_field_id( 'title' ); ?>">タイトル</label>
<input class="widefat" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" type="text" value="<?php echo esc_attr( $title ); ?>" />
</p>

<!-- 設定フォーム: テキスト -->
<p>
<label for="<?php echo $this->get_field_id( 'text' ); ?>">内容</label>
<textarea class="widefat" rows="4" cols="20" id="<?php echo $this->get_field_id( 'text' ); ?>" name="<?php echo $this->get_field_name( 'text' ); ?>"><?php echo esc_textarea( $instance['text'] ); ?></textarea>
</p>
<?php
}

Widget の内容を HTML 形式で出力する

実際に WordPress 上に HTML を出力するメソッド。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/**
* ウィジェットの内容をWebページに出力します(HTML表示)
*
* @param array $args register_sidebar()で設定したウィジェットの開始/終了タグ、タイトルの開始/終了タグなどが渡される。
* @param array $instance 管理画面から入力した値が渡される。
*/
public function widget( $args, $instance ) {
$title = empty( $instance['title'] ) ? '' : $instance['title'];

$widget_text = ! empty( $instance['text'] ) ? $instance['text'] : '';

echo $args['before_widget'];
if ( ! empty( $title ) ) {
echo $args['before_title'] . $title . $args['after_title'];
} ?>

<!-- 入力されたテキストを出力 -->
<div class="textwidget"><?php echo $widget_text; ?></div>
<?php
echo $args['after_widget'];
}

引数 $arg は、register_sidebar() でサイドバー領域を登録した際の、

1
2
3
4
5
6
7
8
9
10
11
12
register_sidebars(
1,
[
'name' => 'サンプルサイドバー',
'id' => 'sidebar-1',
'description' => 'サイドバーのサンプル',
'before_widget' => '<li>',
'after_widget' => '</li>',
'before_title' => '<h2 class="widgettitle">',
'after_title' => '</h2>'
]
);

表示オプションが渡される。

引数 $instance は Widget 登録画面で設定した値が渡される。

データの検証・無害化を行い、データを安全な値で保存する

WordPress の管理画面で Widget の設定を変更した際に、設定内容をDBに保存するメソッド。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* ウィジェットオプションのデータ検証/無害化
*
* @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'] );

// ユーザがHTMLマークアップ権限を持っている場合(ユーザ権限の確認)
if ( current_user_can( 'unfiltered_html' ) ) {

// 全てのHTMLタグをそのまま保存
$instance['text'] = $new_instance['text'];
} else {

// 許可されたHTMLタグはそのままで、それ以外は無害化されて保存(サニタイズ)
$instance['text'] = wp_kses_post( $new_instance['text'] );
}

return $instance;
}

これで、 WordPress の Widget の基本形を一通り確認したので、次は実際に独自 Widget を作成したい。