2026年7月4日

2026年7月4日

WordPressのウィジェットエリアを追加する方法

はじめに

「WordPressにフッター用のウィジェットエリアを追加したい」「サイドバー以外に投稿ページ専用のウィジェットエリアが欲しい」「独自のウィジェットを作成してカスタマイズしたい」——ウィジェットエリアはテーマの柔軟性を高める重要な機能です。

症状・原因

WordPressのデフォルトテーマは1〜2つのサイドバーしか持たないことが多く、フッター・ヘッダー・投稿後など特定箇所にウィジェットを配置したい場合は自前で追加が必要です。register_sidebar()で登録し、テンプレートでdynamic_sidebar()を呼び出して表示します。

解決手順

ステップ1:ウィジェットエリアを登録する

// functions.php: 複数のウィジェットエリアを登録
add_action( 'widgets_init', function(): void {

    // メインサイドバー
    register_sidebar( [
        'name'          => 'メインサイドバー',
        'id'            => 'sidebar-main',
        'description'   => '投稿・固定ページのサイドバー',
        'before_widget' => '<section id="%1$s" class="widget %2$s">',
        'after_widget'  => '</section>',
        'before_title'  => '<h3 class="widget__title">',
        'after_title'   => '</h3>',
    ] );

    // フッターウィジェット(3カラム)
    for ( $i = 1; $i <= 3; $i++ ) {
        register_sidebar( [
            'name'          => sprintf( 'フッター %d', $i ),
            'id'            => sprintf( 'footer-%d', $i ),
            'description'   => sprintf( 'フッターの%d列目', $i ),
            'before_widget' => '<div id="%1$s" class="footer-widget %2$s">',
            'after_widget'  => '</div>',
            'before_title'  => '<h4 class="footer-widget__title">',
            'after_title'   => '</h4>',
        ] );
    }

    // 投稿本文下ウィジェット
    register_sidebar( [
        'name'          => '投稿本文下',
        'id'            => 'after-post',
        'description'   => '投稿コンテンツの直下に表示',
        'before_widget' => '<div id="%1$s" class="after-post-widget %2$s">',
        'after_widget'  => '</div>',
        'before_title'  => '<h3 class="after-post-widget__title">',
        'after_title'   => '</h3>',
    ] );

    // ヘッダーバナーエリア
    register_sidebar( [
        'name'          => 'ヘッダーバナー',
        'id'            => 'header-banner',
        'description'   => 'ヘッダー下のバナーエリア',
        'before_widget' => '<div id="%1$s" class="%2$s">',
        'after_widget'  => '</div>',
        'before_title'  => '',
        'after_title'   => '',
    ] );
} );

ステップ2:テンプレートにウィジェットエリアを表示する

// sidebar.php: メインサイドバーを表示
?>
<aside id="sidebar" class="sidebar" role="complementary">
    <?php
    if ( is_active_sidebar( 'sidebar-main' ) ) {
        dynamic_sidebar( 'sidebar-main' );
    } else {
        // ウィジェットが未設定の場合のデフォルト表示
        ?>
        <section class="widget">
            <h3 class="widget__title">最近の投稿</h3>
            <ul>
                <?php
                $recent = wp_get_recent_posts( [ 'numberposts' => 5, 'post_status' => 'publish' ] );
                foreach ( $recent as $post ) {
                    printf(
                        '<li><a href="%s">%s</a></li>',
                        esc_url( get_permalink( $post['ID'] ) ),
                        esc_html( $post['post_title'] )
                    );
                }
                wp_reset_postdata();
                ?>
            </ul>
        </section>
        <?php
    }
    ?>
</aside>

<?php
// footer.php: フッターウィジェットを3カラムで表示
if ( is_active_sidebar( 'footer-1' ) || is_active_sidebar( 'footer-2' ) || is_active_sidebar( 'footer-3' ) ) : ?>
<div class="footer-widgets">
    <div class="footer-widgets__inner">
        <?php for ( $i = 1; $i <= 3; $i++ ) : ?>
        <div class="footer-widgets__col">
            <?php dynamic_sidebar( "footer-{$i}" ); ?>
        </div>
        <?php endfor; ?>
    </div>
</div>
<?php endif;

ステップ3:カスタムウィジェットクラスを作成する

// functions.php: カスタムウィジェット(最新ニュース)
class My_Latest_News_Widget extends WP_Widget {

    public function __construct() {
        parent::__construct(
            'my_latest_news',
            '最新ニュース',
            [ 'description' => '最新のニュース投稿を表示します' ]
        );
    }

    // ウィジェットの出力
    public function widget( $args, $instance ): void {
        $title  = apply_filters( 'widget_title', $instance['title'] ?? '' );
        $number = absint( $instance['number'] ?? 5 );

        echo $args['before_widget'];
        if ( $title ) {
            echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
        }

        $query = new WP_Query( [
            'post_type'      => 'news',
            'posts_per_page' => $number,
            'no_found_rows'  => true,
        ] );

        if ( $query->have_posts() ) {
            echo '<ul class="latest-news-widget">';
            while ( $query->have_posts() ) {
                $query->the_post();
                printf(
                    '<li><a href="%s">%s</a><time datetime="%s">%s</time></li>',
                    esc_url( get_permalink() ),
                    esc_html( get_the_title() ),
                    esc_attr( get_the_date( 'c' ) ),
                    esc_html( get_the_date() )
                );
            }
            echo '</ul>';
            wp_reset_postdata();
        }

        echo $args['after_widget'];
    }

    // ウィジェットの設定フォーム(管理画面)
    public function form( $instance ): void {
        $title  = esc_attr( $instance['title']  ?? '最新ニュース' );
        $number = absint( $instance['number'] ?? 5 );
        ?>
        <p>
            <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">タイトル:</label>
            <input class="widefat" id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
                name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
                type="text" value="<?php echo $title; ?>">
        </p>
        <p>
            <label for="<?php echo esc_attr( $this->get_field_id( 'number' ) ); ?>">表示件数:</label>
            <input class="tiny-text" id="<?php echo esc_attr( $this->get_field_id( 'number' ) ); ?>"
                name="<?php echo esc_attr( $this->get_field_name( 'number' ) ); ?>"
                type="number" value="<?php echo $number; ?>" min="1" max="20">
        </p>
        <?php
    }

    // ウィジェット設定の保存
    public function update( $new_instance, $old_instance ): array {
        return [
            'title'  => sanitize_text_field( $new_instance['title'] ),
            'number' => absint( $new_instance['number'] ),
        ];
    }
}

// ウィジェットを登録
add_action( 'widgets_init', function(): void {
    register_widget( 'My_Latest_News_Widget' );
} );

ステップ4:条件に応じてウィジェットエリアを切り替える

// sidebar.php: 投稿タイプや条件によってサイドバーを切り替え
function my_get_sidebar_id(): string {
    if ( is_singular( 'product' ) ) {
        return 'sidebar-product';
    }
    if ( is_singular( 'post' ) ) {
        return 'sidebar-blog';
    }
    if ( is_page() ) {
        return 'sidebar-page';
    }
    if ( is_archive() ) {
        return 'sidebar-archive';
    }
    return 'sidebar-main';
}

$sidebar_id = my_get_sidebar_id();
if ( is_active_sidebar( $sidebar_id ) ) {
    dynamic_sidebar( $sidebar_id );
}

ステップ5:ウィジェットのCSSスタイリング

/* style.css: ウィジェットの共通スタイル */
.widget {
    margin-bottom: 2rem;
}

.widget__title {
    font-size: 1rem;
    font-weight: 700;
    padding-bottom: 0.5rem;
    margin-bottom: 1rem;
    border-bottom: 2px solid #0073aa;
}

/* フッターウィジェット */
.footer-widgets {
    background: #1d2327;
    padding: 3rem 0;
    color: #a7aaad;
}

.footer-widgets__inner {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 2rem;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 1rem;
}

.footer-widget__title {
    color: #fff;
    font-size: 0.9rem;
    font-weight: 600;
    margin-bottom: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
}

@media (max-width: 768px) {
    .footer-widgets__inner {
        grid-template-columns: 1fr;
    }
}

注意事項

  • register_sidebar()idはURLで使用できる文字(英数字・ハイフン・アンダースコア)のみ使用してください。日本語は使えません。
  • dynamic_sidebar()の前にis_active_sidebar()でウィジェットが設定されているか確認することを推奨します。未設定のエリアでは何も表示されませんが、ラッパーHTMLだけ出力されてしまう場合があります。
  • WordPress 5.8以降ではブロックベースのウィジェットエディターが使用されます。クラシックウィジェットに戻す場合はClassic Widgetsプラグインを使用してください。

まとめ

ウィジェットエリアの追加は「widgets_initフックでregister_sidebar()によりエリアを登録→テンプレートでis_active_sidebar()確認後dynamic_sidebar()で表示→WP_Widgetクラスを継承してカスタムウィジェットを作成→条件分岐で投稿タイプ別にサイドバーを切り替え→CSSでフッターグリッドを実装」の流れで整備します。関連記事:WordPressのナビゲーションメニューをカスタマイズする方法WordPressのダッシュボードウィジェットをカスタマイズする方法

お気軽にご相談ください

お見積りへ お問い合わせへ