WordPressのデフォルトのウィジェットに任意のテキストやHTMLを挿入できる「テキスト」というウィジェットがあり、サイドバーなどのウィジェットエリアに手軽に広告バナーなどのHTMLコンテンツを挿入したい時に重宝する(下図参照)。

enter image description here

ただ、このウィジェット、そのままではコンテンツ内のショートコードが有効にならなかったり1、タイトルを表示しなくない場合はタイトル蘭を空にしないといけないため、管理パネルでの保守性が悪かったりと今ひとつ使い勝手が良くない。

そこで、ウィジェット管理用のタイトル名とフロントエンド側に表示されるタイトル名を別々に設定でき、コンテンツ内にショートコードも使え、さらにウィジェットを表示する固定ページや投稿タイプ(カスタム投稿タイプにも対応)を指定できるテキストウィジェットを作ってみた(下図参照)2

enter image description here

例えば、広告バナーなどのコンテンツで、投稿ページには表示したいけど、特定の固定ページには表示したくないなど、ウィジェットを表示するページを限定したい時などに使えるのではないだろうか。

利用方法としては、利用しているWordPressテーマのfunctions.phpに下記のウィジェットクラスを追加する。

function extend_widgets_init() {
    // サイドバーウィジェットエリアを定義する
    register_sidebar(array(
        'name'      => 'Main Sidebar', 
        'id'        => 'main-sidebar', 
        'before_widget' => '<div class="sidebar-widget %1$s %2$s">', 
        'after_widget'  => '</div>', 
        'before_title'  => '<h3 class="widget-title">', 
        'after_title'   => '</h3>', 
    ));

    register_widget('SimpleContentsWidget');
}
add_action('widgets_init', 'extend_widgets_init');

class SimpleContentsWidget extends WP_Widget {
    private $fields = array(
        'title' => 'contents name',
        'display_title' => 'display widget title', 
        'content' => 'input contents',
        'display' => 'display pages'
    );

    function __construct() {
        $widget_ops = array('classname' => 'simple_content_widget', 'description' => __('This widget is HTML extension field can be freely inserted.'));
        $this->WP_Widget('simple_content_widget', __('Extension Field Widget'), $widget_ops);
        $this->alt_option_name = 'simple_content_widget';

        add_action('save_post', array(&$this, 'flush_widget_cache'));
        add_action('deleted_post', array(&$this, 'flush_widget_cache'));
        add_action('switch_theme', array(&$this, 'flush_widget_cache'));
    }

    function widget($args, $instance) {
        $cache = wp_cache_get('simple_content_widget', 'widget');

        if(!is_array($cache)){
            $cache = array();
        }
        if(!isset($args['widget_id'])){
            $args['widget_id'] = null;
        }
        if(isset($cache[$args['widget_id']])){
            echo $cache[$args['widget_id']];
            return;
        }
        ob_start();
        extract($args, EXTR_SKIP);
        $title = apply_filters('widget_title', empty($instance['title']) ? __('Extension Field Widget') : $instance['title'], $instance, $this->id_base);
        $display_title = $instance['display_title'];

        foreach($this->fields as $name => $label){
            if(!isset($instance[$name])){ $instance[$name] = ''; }
        }

        $is_displays = array();
        if(!empty($instance['display'])){
            foreach($instance['display'] as $buff){
                array_push($is_displays, explode('|', $buff));
            }
        }else{
            array_push($is_displays, $instance['display']);
        }
        $show = false;
        $now_display = get_post();
        if (!empty($is_displays) && !empty($now_display)) {
            foreach($is_displays as $is_display){
                if($is_display[3] == 'static_page'){
                    if($now_display->ID == $is_display[0]){
                        $show = true;
                        break;
                    }
                }
                if($is_display[3] == 'post_type'){
                    if($now_display->post_type == $is_display[2]){
                        $show = true;
                        break;
                    }
                }
            }
        }
        if($show){
            echo $before_widget;
            if ($display_title) {
                echo $before_title, $display_title, $after_title;
            }
            echo do_shortcode($instance['content']);
            echo $after_widget;
        }
        $cache[$args['widget_id']] = ob_get_flush();
        wp_cache_set('simple_content_widget', $cache, 'widget');
    }
    function update($new_instance, $old_instance) {
        $instance['title'] = strip_tags(trim($new_instance['title']));
        $instance['display_title'] = trim($new_instance['display_title']);
        $instance['content'] = trim($new_instance['content']);
        $instance['display'] = $new_instance['display'];
        $this->flush_widget_cache();
        $alloptions = wp_cache_get('alloptions', 'options');
        if(isset($alloptions['simple_content_widget'])) {
            delete_option('simple_content_widget');
        }
        return $instance;
    }
    function flush_widget_cache() {
        wp_cache_delete('simple_content_widget', 'widget');
    }
    function form($instance) {
        foreach($this->fields as $name => $label) {
            if($name == 'title' || $name == 'display_title'){
                ${$name} = isset($instance[$name]) ? esc_attr($instance[$name]) : '';
                $label_names = array(
                    'title' => __('contents name:'), 
                    'display_title' => __('display widget title:'), 
                );
?>
<p>
    <label for="<?php echo esc_attr($this->get_field_id($name)); ?>"><?php echo $label_names[$name]; ?></label>
    <input class="widefat" id="<?php echo esc_attr($this->get_field_id($name)); ?>" name="<?php echo esc_attr($this->get_field_name($name)); ?>" type="text" value="<?php echo ${$name}; ?>" />
</p>
<?php
            }elseif($name == 'content'){
                ${$name} = isset($instance[$name]) ? esc_attr($instance[$name]) : '';
?>
<p>
    <label for="<?php echo esc_attr($this->get_field_id($name)); ?>"><?php _e('input contents:'); ?></label>
    <textarea class="widefat" rows="10" cols="24" id="<?php echo esc_attr($this->get_field_id($name)); ?>" name="<?php echo esc_attr($this->get_field_name($name)); ?>"><?php echo ${$name}; ?></textarea>
</p>
<?php
            }else{
                ${$name} = isset($instance[$name]) ? $instance[$name] : array();
                $page_list = array();
                $pages = get_pages( array('number'=>'', 'sort_column'=>'menu_order', 'sort_order'=>'ASC') );
                foreach($pages as $page){
                    array_push($page_list, array($page->ID, $page->post_title, $page->post_name, 'static_page'));
                }

                $post_types = get_post_types( array('public'=>true, '_builtin'=>false), 'names', 'and' );
                if (is_array($post_types) && !empty($post_types)) {
                    array_unshift($post_types, 'post');
                }
                $posts = get_posts( array('numberposts'=>-1, 'post_type'=>$post_types, 'orderby'=>'ID', 'order'=>'ASC') );
                $post_types = array();
                foreach($posts as $post){
                    if(!in_array($post->post_type, $post_types)){
                        $pt_obj = get_post_type_object($post->post_type);
                        $post_type_name = $pt_obj->labels->name;
                        array_push($post_types, $post->post_type);
                        array_push($page_list, array($post->ID, $post_type_name, $post->post_type, 'post_type'));
                    }
                }
                $rows_height = count($page_list) * 20;
?>
<p>
    <label for="<?php echo esc_attr($this->get_field_id($name)); ?>"><?php _e('display pages:'); ?></label>
    <select class="widefat" id="<?php echo esc_attr($this->get_field_id($name)); ?>" name="<?php echo esc_attr($this->get_field_name($name)); ?>[]" style="height: <?php echo $rows_height; ?>px;" multiple>
<?php
    foreach($page_list as $page_data){
        $selected = (in_array(implode('|', $page_data), ${$name})) ? ' selected="selected"' : '';
        echo '<option value="'.implode('|', $page_data).'"'.$selected.'>'.($page_data[3] == 'static_page' ? __('Static Page:') : __('Post Type:')).$page_data[1].'</option>';
    }
?>
    </select>
</p>
<?php
            }
        }
    }
}

何気にけっこうなコード量があるので、上記のコードのみを含んだwidgets.phpなどをテーマディレクトリ内に置いて、functions.phpからは下記のようにインクルードだけするという方式にするとfunctions.phpの可読性や保守性が向上して良いかもしれない。

require_once locate_template('/widgets.php');

  1. テーマのfunction.phpなどにadd_filter('widget_text', 'do_shortcode');と記述することで利用できるようになる。 
  2. 掲載画像は後述のスクリプトを組み込んだ後に、テーマ側の言語ファイルで日本語化したもの。さらに各入力フォームにはplaceholderも追加したサンプルです。