2026年5月17日
2026年5月17日
WordPressのサイドバーが表示されない原因と直し方|register_sidebar・dynamic_sidebar
WordPress で「サイドバーが表示されない」「ウィジェットを置いたのに出てこない」「ウィジェット画面にエリアが出ない」といった問題は、多くの場合、ウィジェットエリア(サイドバー)の登録・呼び出し・ウィジェットの配置のどこかが食い違っていることが原因です。
この記事では、原因の切り分け方と、テーマで正しくサイドバーを登録・表示するコードを説明します。関数の動きは WordPress 6.9 のソースと developer.wordpress.org のリファレンスで確認しています(2026年10月時点)。
最初に: 使っているテーマの種類を確認する
Twenty Twenty-Four や Twenty Twenty-Five のようなブロックテーマは、register_sidebar() によるウィジェットエリアを使わず、サイドバーもテンプレートパーツとしてサイトエディターで作ります。ウィジェットエリアを登録していないテーマでは、管理画面の「外観」に「ウィジェット」のメニュー自体が出ません。
- 「外観」に「エディター」があり、「ウィジェット」が無い → ブロックテーマです。サイドバーは「外観」→「エディター」でテンプレートを編集して追加します。以下の手順は当てはまりません。
- 「外観」に「ウィジェット」がある → クラシックテーマ(またはウィジェットエリアを登録したテーマ)です。以下の手順で確認します。
症状と原因の対応
| 症状 | 主な原因 |
|---|---|
| ウィジェット画面に目的のエリアが出ない | register_sidebar() が実行されていない(フックの名前の誤り、条件分岐の中にある、別のテーマの functions.php に書いた) |
| ウィジェットを置いたのに表示されない | テンプレートの dynamic_sidebar() に渡した ID が、登録時の id と一致していない |
| サイドバーの枠ごと出ない | テンプレートで get_sidebar() を呼んでいない、sidebar.php が無い、is_active_sidebar() が false |
| テーマを変えたらウィジェットが消えた | 新しいテーマのエリアの ID が違い、ウィジェットがどのエリアにも割り当てられていない |
WP-CLI で状態を確かめる
WP-CLI が使える環境なら、登録されているエリアと、そこに置かれたウィジェットを一覧で確認できます。
# 登録されているウィジェットエリア(name・id・description)
wp sidebar list
# エリアに置かれているウィジェット(main-sidebar は確認したいエリアの ID)
wp widget list main-sidebar
# エリアにウィジェットが入っているか(true / false)
wp eval 'var_dump( is_active_sidebar( "main-sidebar" ) );'
# テーマに sidebar.php があるか(パスが出れば存在する)
wp eval 'echo locate_template( "sidebar.php" ), PHP_EOL;'
wp sidebar list に目的のエリアが無ければ登録の問題、エリアはあるのに wp widget list が空ならウィジェットを置いていない、ウィジェットはあるのに表示されなければテンプレート側の呼び出しの問題、と切り分けられます。
サイドバーを登録する
ウィジェットエリアは、テーマの functions.php で register_sidebar() を使って登録します。リファレンスの例と同じく、widgets_init アクションの中で呼ぶのが基本の書き方です。
<?php
// functions.php
add_action( 'widgets_init', 'my_theme_register_sidebars' );
function my_theme_register_sidebars() {
register_sidebar( array(
'name' => 'メインサイドバー',
'id' => 'main-sidebar', // dynamic_sidebar() に渡す ID と同じにする
'description' => '投稿と固定ページの右側に表示されます。',
'before_widget' => '<section id="%1$s" class="widget %2$s">',
'after_widget' => '</section>',
'before_title' => '<h2 class="widget-title">',
'after_title' => '</h2>',
) );
register_sidebar( array(
'name' => 'ショップサイドバー',
'id' => 'shop-sidebar',
'description' => 'WooCommerce のショップページ用です。',
'before_widget' => '<div id="%1$s" class="widget %2$s">',
'after_widget' => '</div>',
'before_title' => '<h3 class="widget-title">',
'after_title' => '</h3>',
) );
}
登録時の注意は次のとおりです。
functions.phpの直下でregister_sidebar()を呼んでも、登録自体は行われます(widgets_initより前に実行されるので「遅すぎる」わけではありません)。ただし、ウィジェット関連の処理をまとめて動かすタイミングとして用意されているのがwidgets_initなので、こちらに合わせておくのが無難です。- テンプレートファイル(
sidebar.phpなど)の中で登録すると、管理画面ではそのファイルが読み込まれないため、ウィジェット画面にエリアが出ません。 idは省略するとsidebar-1のような連番になり、WordPress 4.2 以降では「ID を指定するように」という通知が出ます。エリアの増減で連番がずれるとウィジェットの割り当てが崩れるので、idは省略せずに指定し、英小文字・数字・ハイフンでスペースを含めない名前にします。register_sidebar()を呼ぶと、テーマがwidgetsに対応していることが自動で登録され、「外観」に「ウィジェット」のメニューが出ます。
テンプレートでサイドバーを表示する
登録しただけでは表示されません。テーマのテンプレートで get_sidebar() を呼び、sidebar.php の中で dynamic_sidebar() を呼びます。
sidebar.php はテーマのフォルダーに置く、次のようなファイルです。
<?php
/**
* sidebar.php
*/
if ( ! is_active_sidebar( 'main-sidebar' ) ) {
return; // ウィジェットが1つも無ければ何も出さない
}
?>
<aside id="secondary" class="widget-area">
<?php dynamic_sidebar( 'main-sidebar' ); ?>
</aside>
single.php や page.php など、サイドバーを出したいテンプレートで次のように呼びます。
<?php
get_sidebar(); // sidebar.php を読み込む
get_sidebar( 'shop' ); // sidebar-shop.php を読み込む(無ければ sidebar.php)
get_sidebar( 'shop' ) は sidebar-shop.php、無ければ sidebar.php の順に探し、どちらも無ければ何も読み込まずに false を返します。エラーは出ないので、ファイル名の綴りを確認してください。
HTML の中にコメントを書くときは、PHP のコメント(//)を <?php ?> の外に書かないよう注意します。PHP タグの外にある文字はそのままページに出力されるため、サイドバーの上に // で始まる文字列が表示される原因になります。
ページによってサイドバーを切り替える
表示中のページの種類で使うエリアを変えるには、ID を返す関数を用意して sidebar.php から使います。
<?php
// functions.php
function my_theme_sidebar_id() {
if ( function_exists( 'is_woocommerce' ) && is_woocommerce() ) {
return 'shop-sidebar';
}
return 'main-sidebar';
}
<?php
/**
* sidebar.php(切り替える場合)
*/
$sidebar_id = my_theme_sidebar_id();
if ( ! is_active_sidebar( $sidebar_id ) ) {
return;
}
?>
<aside id="secondary" class="widget-area">
<?php dynamic_sidebar( $sidebar_id ); ?>
</aside>
is_woocommerce() は WooCommerce が有効なときだけ存在する関数なので、function_exists() で確かめてから呼びます。
カスタムウィジェットを作る
独自のウィジェットは WP_Widget を継承して作り、widgets_init で register_widget() に渡します。
<?php
// functions.php
class My_Recent_Posts_Widget extends WP_Widget {
public function __construct() {
parent::__construct(
'my_recent_posts',
'最近の投稿(カスタム)',
array( 'description' => '件数を指定できる最近の投稿一覧' )
);
}
// 親クラスと同じく、引数に型を付けない
public function widget( $args, $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : '最近の投稿';
$title = apply_filters( 'widget_title', $title, $instance, $this->id_base );
$count = ! empty( $instance['count'] ) ? absint( $instance['count'] ) : 5;
$posts = get_posts( array(
'numberposts' => $count,
'post_status' => 'publish',
) );
echo $args['before_widget'];
if ( $title ) {
echo $args['before_title'] . esc_html( $title ) . $args['after_title'];
}
if ( $posts ) {
echo '<ul>';
foreach ( $posts as $p ) {
printf(
'<li><a href="%s">%s</a></li>',
esc_url( get_permalink( $p ) ),
esc_html( get_the_title( $p ) )
);
}
echo '</ul>';
}
echo $args['after_widget'];
}
// 管理画面の設定フォーム
public function form( $instance ) {
$title = isset( $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 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 esc_attr( $title ); ?>">
</p>
<p>
<label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>">表示件数:</label>
<input class="tiny-text" id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>" name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>" type="number" min="1" max="20" value="<?php echo esc_attr( $count ); ?>">
</p>
<?php
return '';
}
// 保存時の値の整形
public function update( $new_instance, $old_instance ) {
return array(
'title' => sanitize_text_field( $new_instance['title'] ?? '' ),
'count' => max( 1, min( 20, absint( $new_instance['count'] ?? 5 ) ) ),
);
}
}
add_action( 'widgets_init', function () {
register_widget( 'My_Recent_Posts_Widget' );
} );
WP_Widget の widget()・form()・update() は、親クラスで引数に型を付けずに定義されています。子クラスで widget( array $args, array $instance ) のように引数へ型を足すと、PHP 8 では「親のメソッドと互換性が無い」という致命的エラーになり、サイトが表示されなくなります。form() を書かないと、ウィジェットの設定欄には設定項目が無いという案内だけが表示され、タイトルや件数を入力できません。
テーマを変えたときのウィジェット
ウィジェットの配置は、エリアの ID ごとに sidebars_widgets オプションに保存されています。テーマを変えると、WordPress は同じ ID や似た役割のエリアにウィジェットを移そうとしますが、移せなかったものはどのエリアにも割り当てられない状態になり、表示されなくなります(ウィジェット自体は削除されず、ウィジェット画面から配置し直せます)。
自作テーマを作り直すときは、以前と同じ id でエリアを登録すると、配置がそのまま引き継がれます。テーマを切り替える前に、配置を控えておくと戻しやすくなります。
# ウィジェットの配置をファイルに保存しておく
wp option get sidebars_widgets --format=json > sidebars_widgets_backup.json
ブロックウィジェットエディターが合わない場合
WordPress 5.8 から、クラシックテーマのウィジェット画面もブロックエディター形式になりました。古いウィジェットの設定画面を使いたい場合は、公式の Classic Widgets プラグインを有効にするか、テーマで次のように無効にします。
<?php
// functions.php
add_action( 'after_setup_theme', function () {
remove_theme_support( 'widgets-block-editor' );
} );
まとめ
- ブロックテーマにはウィジェット画面が無い。サイドバーはサイトエディターで作る。
wp sidebar listとwp widget listで、登録とウィジェットの配置を切り分ける。register_sidebar()はwidgets_initで呼び、idを明示してdynamic_sidebar()と同じ値にする。- テンプレートで
get_sidebar()、sidebar.phpでis_active_sidebar()とdynamic_sidebar()を使う。PHP のコメントを PHP タグの外に書かない。 - カスタムウィジェットのメソッドには引数の型を付けず、
form()とupdate()も実装する。