[WordPress] ウィジェトエリアとウィジェットをカスタマイズで作成する方法

WordPressのウィジェットの作り方

WordPressをカスタマイズして新しくウィジェットとウィジェットエリアを作成する方法をまとめます。

ウィジェットエリアの作成

ウィジェットエリアとは用意されているウィジェットを配置するためのエリアのことです。サイドバーとかのことです。

functions.php に以下のコードを追加し、ウィジェットエリアを新しく定義します。。

add_action( 'widgets_init', function () {
    // フッターのウィジェットエリアを登録
    register_sidebar( array(
        'name' => 'フッター' ,
        'id' => 'footer-area' ,
        'description' => 'フッターにコンテンツを表示します。',
        'before_widget' => '<aside class="widget footer-widget">',
        'after_widget' => '</aside>',
        'before_title' => '<h3>',
        'after_title' => '</h3>'
    ) );
} );

widget_init イベント と register_sidebar 関数

_widget_init_イベントをフックして、ウィジェットエリアを追加します。上のコードでは例として、フッター(という名前)のウィジェットエリアを登録しています。

register_sidebar という関数を使うことで、ウィジェットエリアを登録することが可能です。sidebar という名前は、歴史的経緯からこうなっているだけで、サイドバー以外のウィジェットエリアももちろん登録可能です。

register_sidebar 関数のパラメータ

基本的には書いてあるとおりです。id はウィジェットエリアを一意に判定する値を設定します。namedescription はウィジェット画面で表示される文言です。

before_widgetafter_widget は、ウィジェットエリア表示するウィジェットをラップする要素を設定します。before_titleafter_title は、ウィジェットエリアに表示するウィジェットのタイトルをどのような要素で表示するかを設定します。

上の例だとウィジェットエリアとウィジェットは次のように表示されます。

<!-- ここからウィジェットエリア -->
<aside class="widget footer-widget">
    <h3>ウィジェットのタイトル2</h3>
    <!-- 以下ウィジェットのコンテンツ -->
    .
    .
    .
</aside>

before_widgetafter_widget は、適宜divタグに変更したり、適当なクラスやidを設定しておくといいでしょう。before_titleafter_title は、表示する箇所に応じて、h2やh3タグとして表示するのが良いかと思います。

もちろん余計なタグ無しウィジェットのコンテンツのみを出力したければそれぞれ空文字で登録すれば良いです。

ウィジェットエリアの登録確認

ここまででウィジェット画面で新しいウィジェットエリアが登録されていることが確認できます。必要なウィジェットを登録して保存することも可能です。

ウィジェットエリアの出力

ウィジェットエリアの登録と保存はできましたが、まだ出力処理を定義していないので、表示されることはありません。ウィジェットエリアを出力するには、ウィジェットエリアを表示したい箇所に次のように追記します。

<?php dynamic_sidebar( 'footer-area' ); ?>

dynamic_sidebar 関数でウィジェットエリアを出力します。引数はウィジェットエリアの登録時に指定したidです。これで任意の箇所にウィジェットエリアを出力できます。ウィジェットが管理画面から登録されていれば、その内容も出力されます。

ウィジェットの自作・カスタマイズ方法

functions.php にコードを追加することで、独自のウィジェットを作成したり、既存のウィジェットをカスタマイズすることが可能です。ここでは、ウィジェットクラスの定義方法を確認し、新しくウィジェットを作成してみます。

WP_Widget クラスを実装する

WordPressで自作のウィジェットを作成するには、以下のように WP_Widget クラスを継承したクラスを実装します。上の公式ページが参考になります。

class My_Widget extends WP_Widget {

    /**
     * ウィジェット名などを設定
     */
    public function __construct() {
        // widget actual processes
    }

    /**
     * ウィジェットのフロントエンド表示
     *
     * @see WP_Widget::widget()
     *
     * @param array $args     ウィジェットの引数
     * @param array $instance データベースの保存値
     */
    public function widget( $args, $instance ) {
        // outputs the content of the widget
    }

    /**
     * 管理用のオプションのフォームを出力
     *
     * @param array $instance ウィジェットオプション
     */
    public function form( $instance ) {
        // 管理用のオプションのフォームを出力
    }

    /**
     * ウィジェットオプションの保存処理
     *
     * @param array $new_instance 新しいオプション
     * @param array $old_instance 以前のオプション
     */
    public function update( $new_instance, $old_instance ) {
        // ウィジェットオプションの保存処理
    }
}

/* 自作したウィジェットを使えるように登録する処理 */
add_action( 'widgets_init', function(){
     register_widget( 'My_Widget' );
} );

順番に実装する関数を見ていきます。

__construct

/**
 * ウィジェット名などを設定
 */
function __construct() {
    parent::__construct(
        'my_widget', // ID
        'マイウィジェット', // ウィジェットの名前
        array( 'description' => 'ここにウィジェットの説明文を書きます。', ) // Args
    );
}

コンストラクタでは、ウィジェットの情報を設定します。IDは一意になるようにすればよいと思います。

名前と説明文は、ウィジェットの管理画面で表示される情報です。

widget 関数

/**
 * ウィジェットのフロントエンド表示
 *
 * @see WP_Widget::widget()
 *
 * @param array $args     ウィジェットの引数
 * @param array $instance データベースの保存値
 */
public function widget( $args, $instance ) {
    // ウィジェットエリアの定義情報(開始タグ)
    echo $args['before_widget'];

    if ( ! empty( $instance['title'] ) ) {
        // ウィジェットエリアの定義情報(タイトル開始タグ<h2>とか)
        echo $args['before_title'];

        // ウィジェットに登録されたタイトル情報
        // フィルターフックも登録しておく
        echo apply_filters( 'widget_title', $instance['title'] );

        // ウィジェットエリアの定義情報(タイトル終了タグ</h2>とか)
        echo $args['after_title'];
    }

    if ( ! empty( $instance['title'] ) ) {
        echo '<div>'.$instance['text'].'</div>';
    }

    // ウィジェットエリアの定義情報(終了タグ)
    echo $args['after_widget'];
}

widget 関数では、フロントエンドでどのようにウィジェットの出力処理を定義します。

例えば、「カテゴリ」のウィジェットではタイトルが表示され、設定された情報に基づき記事の件数が出たり、プルダウンで表示されたりしますが、そういった出力を定義するのがこの関数の役割です。

つまり、ウィジェットが呼び出されるとこのメソッドでウィジェットが出力されます。

ここの例では、単純にウィジェット管理画面で定義したタイトルと、文字列情報をdivタグで出力しています。

_apply_filters_ は、定義しておくとフィルターフックに登録された関数を適応できます。自分だけが使うウィジェットなら、自分で必要な処理を追加すればよいだけなのでなくてもよいです。ただ、テーマとして不特定多数の人に使ってもらうならあったほうがカスタマイズ性が向上するので良いかもしれません。

form 関数

form 関数は、管理画面での入力フォームを定義します。例えば「カテゴリ」ウィジェットでは次のような入力項目が用意されています。

今回は、タイトルとテキストを登録できるようにします。

/**
 * 管理用のオプションのフォームを出力
 *
 * @param array $instance 前回保存された値をデータベースから取得したもの
 * @return string|void
 */
public function form( $instance ) {
    $title = ! empty( $instance['title'] ) ? $instance['title'] : '';
    $text = ! empty( $instance['text'] ) ? $instance['text'] : '';
    ?>
    <p>
        <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'タイトル:' ); ?></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="16" cols="20" 
            id="<?php echo $this->get_field_id( 'text' ); ?>" 
            name="<?php echo $this->get_field_name( 'text' ); ?>"><?php echo esc_textarea($text); ?></textarea>
    </p>
    <?php
}

update 関数

最後に update 関数です。これは先ほど定義したformから送られるデータを、設定値としてデータベースに保存する処理を定義します。

文字列の入力値は必要に応じてサニタイズしておきます。

/**
 * ウィジェットオプションのサニタイズと保存処理
 *
 * @param array $new_instance 新しいオプション(入力値)
 * @param array $old_instance 以前のオプション
 * @return array 保存するオプション
 */
public function update( $new_instance, $old_instance ) {
    $instance = array();
    $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
    $instance['text'] = ( ! empty( $new_instance['text'] ) ) ? strip_tags( $new_instance['text'] ) : '';

    return $instance;
}

引数 $new_instance に入力された設定値が入っています。文字列の入力値なので strip_tags 関数でタグを取り除いています。

引数 $old_instance は、以前の設定値が入っています。ここでは特に必要ないので利用していません。

return値は保存する連想配列です。

自作ウィジェットの登録

/* 自作したウィジェットを使えるように登録する処理 */
add_action( 'widgets_init', function(){
     register_widget( 'My_Widget' );
} );

ウィジェットエリアと同様、widgets_init イベントをフックして登録します。登録には register_widget 関数を利用します。

ウィジェットの確認

最後に定義したウィジェットがちゃんと機能しているか確認して完了です。

ウィジェットが用意されているのが確認できます。

作成したウィジェットエリアに追加して入力できるようになっています。

入力値が保存されることと、ウィジェットが表示されることを確認して完成です。

サンプルコードまとめ

上記サンプルコードをまとめて貼っておきます。functions.php にコピペすればなんちゃってウィジェットの完成です。適宜設定値などを修正してください。

class My_Widget extends WP_Widget {
    /**
     * ウィジェット名などを設定
     */
    function __construct() {
        parent::__construct(
            'my_widget', // ID
            'マイウィジェット', // ウィジェットの名前
            array( 'description' => 'ここにウィジェットの説明文を書きます。', ) // Args
        );
    }

    /**
     * ウィジェットのフロントエンド表示
     *
     * @see WP_Widget::widget()
     *
     * @param array $args     ウィジェットの引数
     * @param array $instance データベースの保存値
     */
    public function widget( $args, $instance ) {
        // ウィジェットエリアの定義情報(開始タグ)
        echo $args['before_widget'];

        if ( ! empty( $instance['title'] ) ) {
            // ウィジェットエリアの定義情報(タイトル開始タグ<h2>とか)
            echo $args['before_title'];

            // ウィジェットに登録されたタイトル情報
            // フィルターフックも登録しておく
            echo apply_filters( 'widget_title', $instance['title'] );

            // ウィジェットエリアの定義情報(タイトル終了タグ</h2>とか)
            echo $args['after_title'];
        }

        if ( ! empty( $instance['title'] ) ) {

            echo '<div>'.$instance['text'].'</div>';
        }

        // ウィジェットエリアの定義情報(終了タグ)
        echo $args['after_widget'];
    }

    /**
     * 管理用のオプションのフォームを出力
     *
     * @param array $instance 前回保存された値をデータベースから取得したもの
     * @return string|void
     */
    public function form( $instance ) {
        $title = ! empty( $instance['title'] ) ? $instance['title'] : '';
        $text = ! empty( $instance['text'] ) ? $instance['text'] : '';
        ?>
        <p>
            <label for="<?php echo $this->get_field_id( 'title' ); ?>"><?php _e( 'タイトル:' ); ?></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="16" cols="20" 
                id="<?php echo $this->get_field_id( 'text' ); ?>" 
                name="<?php echo $this->get_field_name( 'text' ); ?>"><?php echo esc_textarea($text); ?></textarea>
        </p>
        <?php
    }

    /**
     * ウィジェットオプションのサニタイズと保存処理
     *
     * @param array $new_instance 新しいオプション(入力値)
     * @param array $old_instance 以前のオプション
     * @return array 保存するオプション
     */
    public function update( $new_instance, $old_instance ) {
        $instance = array();
        $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
        $instance['text'] = ( ! empty( $new_instance['text'] ) ) ? strip_tags( $new_instance['text'] ) : '';

        return $instance;
    }
}

/* 自作したウィジェットを使えるように登録する処理 */
add_action( 'widgets_init', function(){
     register_widget( 'My_Widget' );
} );

add_action( 'widgets_init', function () {
    // フッターのウィジェットエリアを登録
    register_sidebar( array(
        'name' => 'フッター' ,
        'id' => 'footer-area' ,
        'description' => 'フッターにコンテンツを表示します。',
        'before_widget' => '<aside class="widget footer-widget">',
        'after_widget' => '</aside>',
        'before_title' => '<h3>',
        'after_title' => '</h3>'
    ) );
} );

以上。