2026年6月2日

2026年6月2日

WordPressのウィジェットエラーを解決する方法

はじめに

WordPressの管理画面でウィジェットをサイドバーにドラッグしても保存されない・テーマを変更したらサイドバーのウィジェットが全て消えた・カスタムウィジェットを作成したがエラーが発生して表示されない・ブロックエディターに移行したらウィジェット画面が変わって操作できないといった問題は、テーマのサイドバー登録ミス・ウィジェットクラスの実装ミス・データ保存の不整合が原因です。

症状・原因

  • 外観 → ウィジェットでサイドバーが表示されず「このウィジェットエリアはありません」と表示される
  • ウィジェットの設定を変更して保存しても次回開くと元に戻っている
  • テーマを新しいものに変更したらサイドバーのウィジェット設定が全て消えた
  • PHPエラー「Cannot redeclare class MyWidget」が発生している

解決手順

ステップ1:ウィジェットの状態を診断する

# WP-CLIでウィジェット情報を確認
wp widget list sidebar-1 --format=table
wp sidebar list --format=table

# 登録されているサイドバーを確認
wp eval "
global \$wp_registered_sidebars;
foreach (\$wp_registered_sidebars as \$id => \$sidebar) {
    echo \$id . ': ' . \$sidebar['name'] . PHP_EOL;
}
"

# ウィジェットのデータを確認
wp eval "
\$widgets = get_option('sidebars_widgets');
foreach (\$widgets as \$sidebar => \$widget_list) {
    if (is_array(\$widget_list)) {
        echo \$sidebar . ': ' . implode(', ', \$widget_list) . PHP_EOL;
    }
}
"
# 孤立したウィジェットデータをリセット
wp option delete sidebars_widgets
wp option delete widget_text
wp option delete widget_recent-posts

ステップ2:サイドバーを正しく登録する

// functions.php: サイドバーの正しい登録方法
add_action('widgets_init', function(): void {
    // メインサイドバー
    register_sidebar([
        'name'          => 'メインサイドバー',
        'id'            => 'sidebar-main',
        'description'   => '投稿・固定ページのサイドバー',
        'before_widget' => '<div id="%1$s" class="widget %2$s">',
        'after_widget'  => '</div>',
        'before_title'  => '<h3 class="widget-title">',
        'after_title'   => '</h3>',
    ]);

    // フッターウィジェットエリア
    for ($i = 1; $i <= 3; $i++) {
        register_sidebar([
            'name'          => sprintf('フッター %d', $i),
            'id'            => sprintf('footer-%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>',
        ]);
    }
});
// テンプレートファイル: ウィジェットエリアを表示
<?php if (is_active_sidebar('sidebar-main')): ?>
<aside id="secondary" class="widget-area">
    <?php dynamic_sidebar('sidebar-main'); ?>
</aside>
<?php endif; ?>

ステップ3:カスタムウィジェットを実装する

// functions.php: カスタムウィジェットの正しい実装

class My_Custom_Widget extends WP_Widget {

    public function __construct() {
        parent::__construct(
            'my_custom_widget',
            'カスタムウィジェット',
            ['description' => 'カスタム情報を表示するウィジェット']
        );
    }

    // フロントエンド表示
    public function widget(array $args, array $instance): void {
        $title   = apply_filters('widget_title', $instance['title'] ?? '');
        $content = $instance['content'] ?? '';

        echo $args['before_widget'];
        if (!empty($title)) {
            echo $args['before_title'] . esc_html($title) . $args['after_title'];
        }
        echo '<div class="widget-content">' . wp_kses_post($content) . '</div>';
        echo $args['after_widget'];
    }

    // 管理画面フォーム
    public function form(array $instance): void {
        $title   = $instance['title'] ?? '';
        $content = $instance['content'] ?? '';
        ?>
        <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>
        <?php
    }

    // 設定の保存
    public function update(array $new_instance, array $old_instance): array {
        return [
            'title'   => sanitize_text_field($new_instance['title'] ?? ''),
            'content' => wp_kses_post($new_instance['content'] ?? ''),
        ];
    }
}

add_action('widgets_init', fn() => register_widget('My_Custom_Widget'));

ステップ4:ウィジェットデータを移行・復元する

# テーマ変更前にウィジェットをエクスポート
wp eval "
\$data = [
    'sidebars_widgets' => get_option('sidebars_widgets'),
    'widget_options'   => [],
];
// 全ウィジェットオプションを収集
global \$wp_registered_widgets;
foreach (\$wp_registered_widgets as \$widget) {
    \$opt = get_option('widget_' . \$widget['callback'][0]->id_base);
    if (\$opt) {
        \$data['widget_options'][\$widget['callback'][0]->id_base] = \$opt;
    }
}
file_put_contents('/tmp/widget_backup.json', json_encode(\$data, JSON_PRETTY_PRINT));
echo 'Widget data exported.' . PHP_EOL;
"

# テーマ変更後にウィジェットをインポート
wp eval "
\$data = json_decode(file_get_contents('/tmp/widget_backup.json'), true);
update_option('sidebars_widgets', \$data['sidebars_widgets']);
foreach (\$data['widget_options'] as \$key => \$value) {
    update_option('widget_' . \$key, \$value);
}
echo 'Widget data restored.' . PHP_EOL;
"

ステップ5:ブロックウィジェットとの互換性を確保する

// functions.php: ブロックウィジェットエディターの制御

// ① レガシーウィジェットエディターを使用(ブロックエディター無効化)
add_filter('use_widgets_block_editor', '__return_false');

// ② 特定のブロックウィジェットを許可リストで制御
add_filter('widget_types_to_hide_from_legacy_widget_block', function(array $widgets): array {
    // レガシーウィジェットブロックから除外するウィジェット
    return array_merge($widgets, ['my_custom_widget']);
});

// ③ ウィジェットのキャッシュを実装(パフォーマンス改善)
add_action('widgets_init', function(): void {
    // ウィジェット表示をキャッシュ
});

add_filter('widget_display_callback', function(array $instance, WP_Widget $widget, array $args): array {
    $cache_key = 'widget_' . $widget->id . '_' . md5(serialize($args));

    if (false !== ($cached = get_transient($cache_key))) {
        echo $cached;
        return false;  // デフォルト表示をスキップ
    }

    // ウィジェット出力をキャプチャしてキャッシュ
    ob_start();
    $widget->widget($args, $instance);
    $output = ob_get_clean();

    set_transient($cache_key, $output, HOUR_IN_SECONDS);
    echo $output;
    return false;
}, 10, 3);

注意事項

  • register_sidebar()idパラメーターはユニークである必要があります。テーマを変更する場合、新しいテーマで同じIDを使用することでウィジェットの設定が引き継がれます。テーマ間で同じサイドバーIDを使用することをお勧めします
  • ブロックウィジェットエディターを無効化する(use_widgets_block_editorfalseにする)と、WordPress 5.8以降で導入されたブロックベースのウィジェット編集機能が使えなくなります。既存の従来型ウィジェットが多い場合の一時的な回避策として使用してください
  • ウィジェットのキャッシュを実装する場合、ウィジェットの内容が動的に変わる(ログインユーザーによって異なるなど)場合はキャッシュを使用しないか、ユーザーごとに異なるキャッシュキーを使用してください

まとめ

WordPressウィジェットエラーの解決は①wp widget list sidebar-1でウィジェット確認・$wp_registered_sidebarsで登録済みサイドバー一覧・sidebars_widgetsオプションのデータ確認、②register_sidebarでID・name・before/after_widgetを正しく設定・dynamic_sidebar()で表示・is_active_sidebar()で条件分岐、③WP_Widgetを継承したクラスでwidget()/form()/update()の3メソッドを実装・register_widget()で登録、④テーマ変更前後のウィジェットデータのJSON書き出し・update_optionでのリストア・wp option deleteで破損データ削除、⑤use_widgets_block_editor=falseでブロックエディター無効化・widget_display_callbackでウィジェット出力を1時間キャッシュの手順で解決します。

お気軽にご相談ください

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