WordPress – プラグインの作成チュートリアル(4)

2026年11月10日

明日、続きから再開するための手順

明日新しいチャット(会話)を開いたら、以下の「引き継ぎテキスト」をそのままコピーして、最初のメッセージとして私に送信してください。

これだけで、私がこれまでの前提条件やコードの内容をすべて一瞬で思い出し、完全に続きからアシストできます。

📋 明日の最初に貼り付けるテキスト(ここをコピー)

昨日作成した「マイ季節別デフォルトアイキャッチプラグイン」の機能拡張の続きをお願いします。

【現在の前提条件と仕様】
・「オールシーズン」「春」「夏」「秋」「冬」の5パターン別に画像を複数登録できる管理画面が完成している。
・画像データはデータベースにカンマ区切りの画像ID(例: 12,45,78)として保存されている。
・アイキャッチ画像が設定されていない記事に対して、現在の月から判断した季節(またはオールシーズン用)の登録画像から、1枚をランダムに選んで自動適用する仕組み(get_post_metadataフィルター)が完璧に動作している。

ここからさらに機能を拡張していきたいです。

明日はどのような拡張(例:「特定のカテゴリーごとに画像を変えたい」「今の季節に関係なく全部混ぜてランダムにしたい」など)をされたいか、ぜひアイディアを聞かせてくださいね。

それでは、本日は本当にお疲れ様でした!また明日、いつでもお気軽にお声がけください。ゆっくりお休みくださいね。

ーーーーーーーーーーーーーーーーー

現在の状態、オールシーズンの画像がランダムに表示されているように見える。

組み合わせとしては、春のシーズンにはオールシーズンと春の画像を組み合わせてランダム表示したい、というようにシーズンによって切り替えることができるようにしたいのですが。
そのためには、オールシーズンと春だけを有効にして他のシーズンは無効にするというような設定を作成する。

そしてポイントとして、サムネイル画像をクリックした時、表示されるアイキャッチ画像をサムネイルと同じ画像にしたい。これが希望のポイントになる。

右サイドのアイキャッチ画像設定に指定のアイキャッチ画像を入れた場合はその投稿ページはランダム用の画像を表示しないで指定の画像を使うようにする。

ーーーーーーーーーーーーーーーーー

<?php
/**
 * Plugin Name: マイ季節別デフォルトアイキャッチプラグイン
 * Description: アイキャッチ画像が未設定の投稿に対して、設定画面から保存した画像から1枚をランダムに選んで自動適用します(バグ完全修正版)。
 * Version:     4.0.2
 * Author:      あなたの名前
 */

if ( ! defined( 'ABSPATH' ) ) { exit; }

// 1. 管理画面メニュー追加
function my_seasonal_gallery_menu() {
    add_menu_page( '季節別画像設定', '季節別画像設定', 'manage_options', 'my-default-thumbnail-gallery', 'my_seasonal_gallery_page', 'dashicons-images-alt2', 90 );
}
add_action( 'admin_menu', 'my_seasonal_gallery_menu' );

// 2. メディアライブラリ用アセット読み込み
function my_seasonal_gallery_assets( $hook ) {
    if ( 'toplevel_page_my-default-thumbnail-gallery' === $hook ) { wp_enqueue_media(); }
}
add_action( 'admin_enqueue_scripts', 'my_seasonal_gallery_assets' );

// 3. 設定画面のHTMLと保存処理
function my_seasonal_gallery_page() {
    if ( ! current_user_can( 'manage_options' ) ) { return; }
    $seasons = array( 'all_season' => 'オールシーズン用', 'spring' => '春(Spring)', 'summer' => '夏(Summer)', 'autumn' => '秋(Autumn)', 'winter' => '冬(Winter)' );

    if ( isset( $_POST['my_seasonal_nonce'] ) && wp_verify_nonce( $_POST['my_seasonal_nonce'], 'my_seasonal_action' ) ) {
        foreach ( $seasons as $key => $label ) {
            $field_name = 'my_plugin_image_ids_' . $key;
            update_option( $field_name, isset( $_POST[$field_name] ) ? sanitize_text_field( $_POST[$field_name] ) : '' );
        }
        echo '<div class="updated"><p>すべての季節の設定を保存しました。</p></div>';
    }
    ?>
    <div class="wrap">
        <h1>季節別デフォルトアイキャッチ設定</h1>
        <p>記事にアイキャッチ画像が設定されていない場合、ここで登録した画像の中から1枚がランダムで自動的に適用されます。</p>
        <form method="post" action="">
            <?php wp_nonce_field( 'my_seasonal_action', 'my_seasonal_nonce' ); ?>
            <table class="form-table">
                <?php foreach ( $seasons as $key => $label ) : 
                    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $key, '' );
                    $image_ids = ! empty( $saved_ids_str ) ? explode( ',', $saved_ids_str ) : array(); ?>
                <tr style="border-bottom: 1px solid #ccc;">
                    <th scope="row" style="width: 150px; font-weight: bold; font-size: 1.1em; padding: 20px 0;"><?php echo esc_html( $label ); ?></th>
                    <td style="padding: 20px 0;">
                        <div id="preview-<?php echo esc_attr( $key ); ?>" class="gallery-preview-box" style="display: flex; flex-wrap: wrap; gap: 15px; margin-bottom: 15px;">
                            <?php if ( ! empty( $image_ids ) ) {
                                foreach ( $image_ids as $id ) {
                                    $id = intval( $id );
                                    $img_src = wp_get_attachment_image_url( $id, 'thumbnail' );
                                    if ( $img_src ) {
                                        echo '<div class="gallery-item" data-id="' . esc_attr( $id ) . '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;">';
                                        echo '<img src="' . esc_url( $img_src ) . '" style="width: 100%; height: 100%; object-fit: cover;" />';
                                        echo '<button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button>';
                                        echo '</div>';
                                    }
                                }
                            } ?>
                        </div>
                        <input type="text" name="my_plugin_image_ids_<?php echo esc_attr( $key ); ?>" id="input-<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $saved_ids_str ); ?>" style="display:none;" />
                        <button type="button" class="button button-secondary upload-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>">画像を追加</button>
                        <button type="button" class="button clear-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>" style="<?php echo ! empty( $image_ids ) ? '' : 'display:none;'; ?>">すべてクリア</button>
                    </td>
                </tr>
                <?php endforeach; ?>
            </table>
            <?php submit_button( 'すべての設定を保存' ); ?>
        </form>
    </div>
    <script>
    jQuery(document).ready(function($){
        var gallery_uploader; var active_season = '';
        $('.upload-seasonal-btn').click(function(e) {
            e.preventDefault(); active_season = $(this).data('season');
            if (!gallery_uploader) {
                gallery_uploader = wp.media({ title: '画像を選択・追加してください', button: { text: 'ギャラリーに追加' }, multiple: true });
                gallery_uploader.on('select', function() {
                    var selection = gallery_uploader.state().get('selection');
                    var $input = $('#input-' + active_season);
                    var current_ids = $input.val() ? $input.val().split(',') : []; // ★タイポを完全に修正
                    selection.each(function(attachment) {
                        var file = attachment.toJSON(); var id_str = file.id.toString();
                        if (current_ids.indexOf(id_str) === -1) {
                            current_ids.push(id_str);
                            var img_url = file.sizes.thumbnail ? file.sizes.thumbnail.url : file.url;
                            var html = '<div class="gallery-item" data-id="' + file.id + '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;"><img src="' + img_url + '" style="width: 100%; height: 100%; object-fit: cover;" /><button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button></div>';
                            $('#preview-' + active_season).append(html);
                        }
                    });
                    $input.val(current_ids.join(','));
                    $('.clear-seasonal-btn[data-season="' + active_season + '"]').show();
                });
            }
            gallery_uploader.open();
        });
        $('.gallery-preview-box').on('click', '.remove-item-btn', function() {
            var $item = $(this).closest('.gallery-item'); var remove_id = $item.data('id').toString();
            var season = $(this).closest('.gallery-preview-box').attr('id').replace('preview-', ''); var $input = $('#input-' + season);
            var current_ids = $input.val().split(',').filter(function(id) { return id !== remove_id; });
            $input.val(current_ids.join(',')); $item.remove();
            if (current_ids.length === 0) { $('.clear-seasonal-btn[data-season="' + season + '"]').hide(); $input.val(''); }
        });
        $('.clear-seasonal-btn').click(function() {
            var season = $(this).data('season');
            if (confirm('この季節の画像一覧をクリアしますか?')) { $('#preview-' + season).empty(); $('#input-' + season).val(''); $(this).hide(); }
        });
    });
    </script>
    <?php
}

// 4. アイキャッチが無い場合に自動でランダム適用する割り込み処理
function my_seasonal_default_thumbnail_id( $value, $post_id, $meta_key, $single ) {
    // 編集画面・管理画面・あるいはアイキャッチ以外の情報取得時には、絶対に作動させない(バグ回避)
    if ( is_admin() || '_thumbnail_id' !== $meta_key ) { return $value; }
    if ( ! empty( $value ) ) { return $value; }

    // 現在の月(WordPress設定時間)から季節を判定
    $month = intval( current_time( 'm' ) );
    if ( $month >= 3 && $month <= 5 ) { $season = 'spring'; }
    elseif ( $month >= 6 && $month <= 8 ) { $season = 'summer'; }
    elseif ( $month >= 9 && $month <= 11 ) { $season = 'autumn'; }
    else { $season = 'winter'; }

    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $season, '' );
    if ( empty( $saved_ids_str ) ) { $saved_ids_str = get_option( 'my_plugin_image_ids_all_season', '' ); }
    if ( empty( $saved_ids_str ) ) { return $value; }

    $image_ids = explode( ',', $saved_ids_str );
    return intval( $image_ids[array_rand( $image_ids )] );
}
add_filter( 'get_post_metadata', 'my_seasonal_default_thumbnail_id', 10, 4 );
WordPress – プラグインの作成チュートリアル(4)

アイキャッチ画像を入れた場合はランダム画像をそのページには使わない

以下のコードでうまく動作している。

<?php
/**
 * Plugin Name: マイ季節別デフォルトアイキャッチプラグイン
 * Description: アイキャッチ画像が未設定の投稿に対して、手動優先かつランダム画像を固定して自動適用します。
 * Version:     5.0.3
 * Author:      あなたの名前
 */

if ( ! defined( 'ABSPATH' ) ) { exit; }

// 1. 管理画面メニュー追加
function my_seasonal_gallery_menu() {
    add_menu_page( '季節別画像設定', '季節別画像設定', 'manage_options', 'my-default-thumbnail-gallery', 'my_seasonal_gallery_page', 'dashicons-images-alt2', 90 );
}
add_action( 'admin_menu', 'my_seasonal_gallery_menu' );

// 2. メディアライブラリ用アセット読み込み
function my_seasonal_gallery_assets( $hook ) {
    if ( 'toplevel_page_my-default-thumbnail-gallery' === $hook ) { wp_enqueue_media(); }
}
add_action( 'admin_enqueue_scripts', 'my_seasonal_gallery_assets' );

// 3. 設定画面のHTMLと保存処理
function my_seasonal_gallery_page() {
    if ( ! current_user_can( 'manage_options' ) ) { return; }
    $seasons = array( 'all_season' => 'オールシーズン用', 'spring' => '春(Spring)', 'summer' => '夏(Summer)', 'autumn' => '秋(Autumn)', 'winter' => '冬(Winter)' );

    if ( isset( $_POST['my_seasonal_nonce'] ) && wp_verify_nonce( $_POST['my_seasonal_nonce'], 'my_seasonal_action' ) ) {
        foreach ( $seasons as $key => $label ) {
            $field_name = 'my_plugin_image_ids_' . $key;
            update_option( $field_name, isset( $_POST[$field_name] ) ? sanitize_text_field( $_POST[$field_name] ) : '' );
        }
        echo '<div class="updated"><p>すべての季節の設定を保存しました。</p></div>';
    }
    ?>
    <div class="wrap">
        <h1>季節別デフォルトアイキャッチ設定</h1>
        <p>記事にアイキャッチ画像が設定されていない場合、ここで登録した画像の中から1枚がランダムで自動的に適用されます。</p>
        <form method="post" action="">
            <?php wp_nonce_field( 'my_seasonal_action', 'my_seasonal_nonce' ); ?>
            <table class="form-table">
                <?php foreach ( $seasons as $key => $label ) : 
                    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $key, '' );
                    $image_ids = ! empty( $saved_ids_str ) ? explode( ',', $saved_ids_str ) : array(); ?>
                <tr style="border-bottom: 1px solid #ccc;">
                    <th scope="row" style="width: 150px; font-weight: bold; font-size: 1.1em; padding: 20px 0;"><?php echo esc_html( $label ); ?></th>
                    <td style="padding: 20px 0;">
                        <div id="preview-<?php echo esc_attr( $key ); ?>" class="gallery-preview-box" style="display: flex; flex-wrap: wrap; gap: 15px; margin-bottom: 15px;">
                            <?php if ( ! empty( $image_ids ) ) {
                                foreach ( $image_ids as $id ) {
                                    $id = intval( $id );
                                    $img_src = wp_get_attachment_image_url( $id, 'thumbnail' );
                                    if ( $img_src ) {
                                        echo '<div class="gallery-item" data-id="' . esc_attr( $id ) . '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;">';
                                        echo '<img src="' . esc_url( $img_src ) . '" style="width: 100%; height: 100%; object-fit: cover;" />';
                                        echo '<button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button>';
                                        echo '</div>';
                                    }
                                }
                            } ?>
                        </div>
                        <input type="text" name="my_plugin_image_ids_<?php echo esc_attr( $key ); ?>" id="input-<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $saved_ids_str ); ?>" style="display:none;" />
                        <button type="button" class="button button-secondary upload-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>">画像を追加</button>
                        <button type="button" class="button clear-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>" style="<?php echo ! empty( $image_ids ) ? '' : 'display:none;'; ?>">すべてクリア</button>
                    </td>
                </tr>
                <?php endforeach; ?>
            </table>
            <?php submit_button( 'すべての設定を保存' ); ?>
        </form>
    </div>
    <script>
    jQuery(document).ready(function($){
        var gallery_uploader; var active_season = '';
        $('.upload-seasonal-btn').click(function(e) {
            e.preventDefault(); active_season = $(this).data('season');
            if (!gallery_uploader) {
                gallery_uploader = wp.media({ title: '画像を選択・追加してください', button: { text: 'ギャラリーに追加' }, multiple: true });
                gallery_uploader.on('select', function() {
                    var selection = gallery_uploader.state().get('selection');
                    var $input = $('#input-' + active_season);
                    var current_ids = $input.val() ? $input.val().split(',') : [];
                    selection.each(function(attachment) {
                        var file = attachment.toJSON(); var id_str = file.id.toString();
                        if (current_ids.indexOf(id_str) === -1) {
                            current_ids.push(id_str);
                            var img_url = file.sizes.thumbnail ? file.sizes.thumbnail.url : file.url;
                            var html = '<div class="gallery-item" data-id="' + file.id + '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;"><img src="' + img_url + '" style="width: 100%; height: 100%; object-fit: cover;" /><button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button></div>';
                            $('#preview-' + active_season).append(html);
                        }
                    });
                    $input.val(current_ids.join(','));
                    $('.clear-seasonal-btn[data-season="' + active_season + '"]').show();
                });
            }
            gallery_uploader.open();
        });
        $('.gallery-preview-box').on('click', '.remove-item-btn', function() {
            var $item = $(this).closest('.gallery-item'); var remove_id = $item.data('id').toString();
            var season = $(this).closest('.gallery-preview-box').attr('id').replace('preview-', ''); var $input = $('#input-' + season);
            var current_ids = $input.val().split(',').filter(function(id) { return id !== remove_id; });
            $input.val(current_ids.join(',')); $item.remove();
            if (current_ids.length === 0) { $('.clear-seasonal-btn[data-season="' + season + '"]').hide(); $input.val(''); }
        });
        $('.clear-seasonal-btn').click(function() {
            var season = $(this).data('season');
            if (confirm('この季節の画像一覧をクリアしますか?')) { $('#preview-' + season).empty(); $('#input-' + season).val(''); $(this).hide(); }
        });
    });
    </script>
    <?php
}

// 4. 自動適用・固定化・無限ループ防止の割り込み処理
function my_seasonal_default_thumbnail_id( $value, $post_id, $meta_key, $single ) {
    if ( is_admin() || '_thumbnail_id' !== $meta_key ) { return $value; }

    static $is_filtering = false;
    if ( $is_filtering ) { return $value; }

    $is_filtering = true;
    $db_thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true );
    $is_auto_saved = get_post_meta( $post_id, '_my_seasonal_is_auto_saved', true );

    // 手動設定(自動保存フラグなし)があれば最優先
    if ( ! empty( $db_thumbnail_id ) && ! $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    // すでにランダム画像が確定して永続保存されていればそれを返す
    if ( ! empty( $db_thumbnail_id ) && $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    // 新規にランダム選出する処理
    $month = intval( current_time( 'm' ) );
    if ( $month >= 3 && $month <= 5 ) { $season = 'spring'; }
    elseif ( $month >= 6 && $month <= 8 ) { $season = 'summer'; }
    elseif ( $month >= 9 && $month <= 11 ) { $season = 'autumn'; }
    else { $season = 'winter'; }

    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $season, '' );
    if ( empty( $saved_ids_str ) ) { $saved_ids_str = get_option( 'my_plugin_image_ids_all_season', '' ); }
    
    if ( empty( $saved_ids_str ) ) { 
        $is_filtering = false;
        return $value; 
    }

    $image_ids = array_filter( array_map( 'intval', explode( ',', $saved_ids_str ) ) );

    if ( ! empty( $image_ids ) ) {
        $selected_thumb_id = $image_ids[ array_rand( $image_ids ) ];

        if ( $selected_thumb_id ) {
            update_post_meta( $post_id, '_thumbnail_id', $selected_thumb_id );
            update_post_meta( $post_id, '_my_seasonal_is_auto_saved', '1' );

            $is_filtering = false;
            return $single ? $selected_thumb_id : array( $selected_thumb_id );
        }
    }

    $is_filtering = false;
    return $value;
}
add_filter( 'get_post_metadata', 'my_seasonal_default_thumbnail_id', 10, 4 );

// 5. 手動変更された場合のフラグクリア
function my_seasonal_clear_auto_save_flag( $post_id, $post, $update ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( isset( $_POST['_thumbnail_id'] ) ) {
        delete_post_meta( $post_id, '_my_seasonal_is_auto_saved' );
    }
}
add_action( 'save_post', 'my_seasonal_clear_auto_save_flag', 10, 3 );

季節を自動と手動に切り替えて画像を入れる

<?php
/**
 * Plugin Name: マイ季節別デフォルトアイキャッチプラグイン
 * Description: 登録した画像から1枚をランダムに選んで自動適用します(手動モード切り替え対応・超軽量安全版)。
 * Version:     7.0.2
 * Author:      あなたの名前
 */

if ( ! defined( 'ABSPATH' ) ) { exit; }

// --- 1. シンプルな管理画面(HTML・JSの干渉を完全排除) ---
function my_seasonal_gallery_menu() {
    add_menu_page( '季節別画像設定', '季節別画像設定', 'manage_options', 'my-default-thumbnail-gallery', 'my_seasonal_gallery_page', 'dashicons-images-alt2', 90 );
}
add_action( 'admin_menu', 'my_seasonal_gallery_menu' );

function my_seasonal_gallery_assets( $hook ) {
    if ( 'toplevel_page_my-default-thumbnail-gallery' === $hook ) { wp_enqueue_media(); }
}
add_action( 'admin_enqueue_scripts', 'my_seasonal_gallery_assets' );

function my_seasonal_gallery_page() {
    if ( ! current_user_can( 'manage_options' ) ) { return; }
    $seasons = array( 'all_season' => 'オールシーズン用', 'spring' => '春', 'summer' => '夏', 'autumn' => '秋', 'winter' => '冬' );

    if ( isset( $_POST['my_seasonal_nonce'] ) && wp_verify_nonce( $_POST['my_seasonal_nonce'], 'my_seasonal_action' ) ) {
        foreach ( $seasons as $key => $label ) {
            $field_name = 'my_plugin_image_ids_' . $key;
            update_option( $field_name, isset( $_POST[$field_name] ) ? sanitize_text_field( $_POST[$field_name] ) : '' );
        }
        update_option( 'my_plugin_select_mode', isset( $_POST['my_plugin_select_mode'] ) ? sanitize_text_field( $_POST['my_plugin_select_mode'] ) : 'auto' );
        $active_seasons = isset( $_POST['my_plugin_active_seasons'] ) ? array_map( 'sanitize_text_field', $_POST['my_plugin_active_seasons'] ) : array();
        update_option( 'my_plugin_active_seasons', $active_seasons );
        echo '<div class="updated"><p>設定を保存しました。</p></div>';
    }

    $saved_mode = get_option( 'my_plugin_select_mode', 'auto' );
    $saved_active_seasons = get_option( 'my_plugin_active_seasons', array() );
    ?>
    <div class="wrap">
        <h1>季節別デフォルトアイキャッチ設定</h1>
        <form method="post" action="">
            <?php wp_nonce_field( 'my_seasonal_action', 'my_seasonal_nonce' ); ?>
            
            <div style="background: #fff; padding: 15px; margin-bottom: 20px; border: 1px solid #ccd0d4;">
                <h2>🎯 モード設定</h2>
                <label><input type="radio" name="my_plugin_select_mode" value="auto" <?php checked($saved_mode, 'auto'); ?>> <b>現在の月から自動判定</b></label><br><br>
                <label><input type="radio" name="my_plugin_select_mode" value="manual" <?php checked($saved_mode, 'manual'); ?>> <b>手動カスタム選択(下のチェックを入れた季節をミックス)</b></label>
                
                <div style="margin-top: 15px; padding-left: 20px;">
                    <?php foreach ( $seasons as $key => $label ) : ?>
                        <label style="margin-right: 15px;">
                            <input type="checkbox" name="my_plugin_active_seasons[]" value="<?php echo esc_attr( $key ); ?>" <?php checked( in_array( $key, $saved_active_seasons, true ) ); ?> />
                            <?php echo esc_html( $label ); ?>
                        </label>
                    <?php endforeach; ?>
                </div>
            </div>

            <table class="form-table">
                <?php foreach ( $seasons as $key => $label ) : 
                    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $key, '' ); ?>
                <tr>
                    <th scope="row"><?php echo esc_html( $label ); ?> (画像IDカンマ区切り)</th>
                    <td>
                        <input type="text" name="my_plugin_image_ids_<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $saved_ids_str ); ?>" class="regular-text" placeholder="例: 12,45,78" />
                        <p class="description">メディアライブラリの画像IDをカンマ区切りで入力するか、これまでのデータをそのまま利用できます。</p>
                    </td>
                </tr>
                <?php endforeach; ?>
            </table>
            <?php submit_button(); ?>
        </form>
    </div>
    <?php
}

// --- 2. 自動適用・固定化・ハイブリッド抽選ロジック ---
function my_seasonal_default_thumbnail_id( $value, $post_id, $meta_key, $single ) {
    if ( is_admin() || '_thumbnail_id' !== $meta_key ) { return $value; }

    static $is_filtering = false;
    if ( $is_filtering ) { return $value; }

    $is_filtering = true;
    $db_thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true );
    $is_auto_saved = get_post_meta( $post_id, '_my_seasonal_is_auto_saved', true );

    // 手動設定を最優先
    if ( ! empty( $db_thumbnail_id ) && ! $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    // すでに確定した自動適用画像があれば固定表示
    if ( ! empty( $db_thumbnail_id ) && $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    // 抽選処理
    $mode = get_option( 'my_plugin_select_mode', 'auto' );
    $target_seasons = array();

    if ( 'auto' === $mode ) {
        $month = intval( current_time( 'm' ) );
        if ( $month >= 3 && $month <= 5 ) { $target_seasons[] = 'spring'; }
        elseif ( $month >= 6 && $month <= 8 ) { $target_seasons[] = 'summer'; }
        elseif ( $month >= 9 && $month <= 11 ) { $target_seasons[] = 'autumn'; }
        else { $target_seasons[] = 'winter'; }
    } else {
        $target_seasons = get_option( 'my_plugin_active_seasons', array() );
    }

    $merged_image_ids = array();
    if ( ! empty( $target_seasons ) ) {
        foreach ( $target_seasons as $season_key ) {
            $saved_ids_str = get_option( 'my_plugin_image_ids_' . $season_key, '' );
            if ( ! empty( $saved_ids_str ) ) {
                $merged_image_ids = array_merge( $merged_image_ids, explode( ',', $saved_ids_str ) );
            }
        }
    }

    $merged_image_ids = array_filter( array_unique( array_map( 'intval', $merged_image_ids ) ) );

    // フォールバック
    if ( empty( $merged_image_ids ) ) {
        $fallback_str = get_option( 'my_plugin_image_ids_all_season', '' );
        if ( ! empty( $fallback_str ) ) {
            $merged_image_ids = array_filter( array_map( 'intval', explode( ',', $fallback_str ) ) );
        }
    }

    if ( empty( $merged_image_ids ) ) { 
        $is_filtering = false;
        return $value; 
    }

    $selected_thumb_id = $merged_image_ids[ array_rand( $merged_image_ids ) ];

    if ( $selected_thumb_id ) {
        update_post_meta( $post_id, '_thumbnail_id', $selected_thumb_id );
        update_post_meta( $post_id, '_my_seasonal_is_auto_saved', '1' );
        $is_filtering = false;
        return $single ? $selected_thumb_id : array( $selected_thumb_id );
    }

    $is_filtering = false;
    return $value;
}
add_filter( 'get_post_metadata', 'my_seasonal_default_thumbnail_id', 10, 4 );

// 手動変更時のフラグクリア
function my_seasonal_clear_auto_save_flag( $post_id, $post, $update ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( isset( $_POST['_thumbnail_id'] ) ) {
        delete_post_meta( $post_id, '_my_seasonal_is_auto_saved' );
    }
}
add_action( 'save_post', 'my_seasonal_clear_auto_save_flag', 10, 3 );
WordPress – プラグインの作成チュートリアル(4)

サムネイル画像が表示されなくなった。

<?php
/**
 * Plugin Name: マイ季節別デフォルトアイキャッチプラグイン
 * Description: アイキャッチ未設定の投稿に対して、登録画像から1枚をランダム自動適用します(自動・手動切り替え・画像プレビュー完全両立版)。
 * Version:     7.1.0
 * Author:      あなたの名前
 */

if ( ! defined( 'ABSPATH' ) ) { exit; }

// 1. 管理画面メニュー追加
function my_seasonal_gallery_menu() {
    add_menu_page( '季節別画像設定', '季節別画像設定', 'manage_options', 'my-default-thumbnail-gallery', 'my_seasonal_gallery_page', 'dashicons-images-alt2', 90 );
}
add_action( 'admin_menu', 'my_seasonal_gallery_menu' );

// 2. メディアライブラリ用アセット読み込み
function my_seasonal_gallery_assets( $hook ) {
    if ( 'toplevel_page_my-default-thumbnail-gallery' === $hook ) { wp_enqueue_media(); }
}
add_action( 'admin_enqueue_scripts', 'my_seasonal_gallery_assets' );

// 3. 設定画面のHTMLと保存処理
function my_seasonal_gallery_page() {
    if ( ! current_user_can( 'manage_options' ) ) { return; }
    $seasons = array( 'all_season' => 'オールシーズン用', 'spring' => '春(Spring)', 'summer' => '夏(Summer)', 'autumn' => '秋(Autumn)', 'winter' => '冬(Winter)' );

    if ( isset( $_POST['my_seasonal_nonce'] ) && wp_verify_nonce( $_POST['my_seasonal_nonce'], 'my_seasonal_action' ) ) {
        foreach ( $seasons as $key => $label ) {
            $field_name = 'my_plugin_image_ids_' . $key;
            update_option( $field_name, isset( $_POST[$field_name] ) ? sanitize_text_field( $_POST[$field_name] ) : '' );
        }
        update_option( 'my_plugin_select_mode', isset( $_POST['my_plugin_select_mode'] ) ? sanitize_text_field( $_POST['my_plugin_select_mode'] ) : 'auto' );
        $active_seasons = isset( $_POST['my_plugin_active_seasons'] ) ? array_map( 'sanitize_text_field', $_POST['my_plugin_active_seasons'] ) : array();
        update_option( 'my_plugin_active_seasons', $active_seasons );
        echo '<div class="updated"><p>すべての設定を保存しました。</p></div>';
    }

    $saved_mode = get_option( 'my_plugin_select_mode', 'auto' );
    $saved_active_seasons = get_option( 'my_plugin_active_seasons', array() );
    ?>
    <div class="wrap">
        <h1>季節別デフォルトアイキャッチ設定</h1>
        <form method="post" action="">
            <?php wp_nonce_field( 'my_seasonal_action', 'my_seasonal_nonce' ); ?>
            
            <div class="card" style="max-width: 100%; margin-bottom: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
                <h2 style="margin-top:0; font-size: 1.2em;">🎯 画像の選出モード設定</h2>
                <p>
                    <label style="font-weight: bold; font-size: 1.1em; cursor: pointer; margin-right: 20px;">
                        <input type="radio" name="my_plugin_select_mode" value="auto" <?php checked( $saved_mode, 'auto' ); ?> /> 現在の月から自動判定モード
                    </label>
                </p>
                <hr style="border:none; border-top:1px solid #eee; margin:15px 0;" />
                <p>
                    <label style="font-weight: bold; font-size: 1.1em; cursor: pointer;">
                        <input type="radio" name="my_plugin_select_mode" value="manual" <?php checked( $saved_mode, 'manual' ); ?> /> 手動カスタム選択モード
                    </label>
                </p>
                <div id="manual-checkbox-area" style="display: flex; gap: 20px; flex-wrap: wrap; margin-top: 10px; padding-left: 25px; <?php echo ($saved_mode === 'manual') ? '' : 'opacity: 0.5; pointer-events: none;'; ?>">
                    <?php foreach ( $seasons as $key => $label ) : ?>
                        <label style="cursor: pointer;"><input type="checkbox" name="my_plugin_active_seasons[]" value="<?php echo esc_attr( $key ); ?>" <?php checked( in_array( $key, $saved_active_seasons, true ) ); ?> /> <?php echo esc_html( $label ); ?></label>
                    <?php endforeach; ?>
                </div>
            </div>
            <table class="form-table">
                <?php foreach ( $seasons as $key => $label ) : 
                    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $key, '' );
                    $image_ids = ! empty( $saved_ids_str ) ? explode( ',', $saved_ids_str ) : array(); ?>
                <tr style="border-bottom: 1px solid #ccc;">
                    <th scope="row" style="width: 150px; font-weight: bold; font-size: 1.1em; padding: 20px 0;"><?php echo esc_html( $label ); ?></th>
                    <td style="padding: 20px 0;">
                        <div id="preview-<?php echo esc_attr( $key ); ?>" class="gallery-preview-box" style="display: flex; flex-wrap: wrap; gap: 15px; margin-bottom: 15px;">
                            <?php if ( ! empty( $image_ids ) ) {
                                foreach ( $image_ids as $id ) {
                                    $id = intval( $id );
                                    $img_src = wp_get_attachment_image_url( $id, 'thumbnail' );
                                    if ( $img_src ) {
                                        echo '<div class="gallery-item" data-id="' . esc_attr( $id ) . '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;">';
                                        echo '<img src="' . esc_url( $img_src ) . '" style="width: 100%; height: 100%; object-fit: cover;" />';
                                        echo '<button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button>';
                                        echo '</div>';
                                    }
                                }
                            } ?>
                        </div>
                        <input type="text" name="my_plugin_image_ids_<?php echo esc_attr( $key ); ?>" id="input-<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $saved_ids_str ); ?>" style="display:none;" />
                        <button type="button" class="button button-secondary upload-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>">画像を追加</button>
                        <button type="button" class="button clear-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>" style="<?php echo ! empty( $image_ids ) ? '' : 'display:none;'; ?>">すべてクリア</button>
                    </td>
                </tr>
                <?php endforeach; ?>
            </table>
            <?php submit_button( 'すべての設定を保存' ); ?>
        </form>
    </div>
    <script>
    jQuery(document).ready(function($){
        $('input[name="my_plugin_select_mode"]').change(function() {
            if ($(this).val() === 'manual') { $('#manual-checkbox-area').css({'opacity': '1', 'pointer-events': 'auto'}); }
            else { $('#manual-checkbox-area').css({'opacity': '0.5', 'pointer-events': 'none'}); }
        });
        var gallery_uploader; var active_season = '';
        $('.upload-seasonal-btn').click(function(e) {
            e.preventDefault(); active_season = $(this).data('season');
            if (!gallery_uploader) {
                gallery_uploader = wp.media({ title: '画像を選択・追加してください', button: { text: 'ギャラリーに追加' }, multiple: true });
                gallery_uploader.on('select', function() {
                    var selection = gallery_uploader.state().get('selection');
                    var $input = $('#input-' + active_season);
                    var current_ids = $input.val() ? $input.val().split(',') : [];
                    selection.each(function(attachment) {
                        var file = attachment.toJSON(); var id_str = file.id.toString();
                        if (current_ids.indexOf(id_str) === -1) {
                            current_ids.push(id_str);
                            var img_url = file.sizes.thumbnail ? file.sizes.thumbnail.url : file.url;
                            var html = '<div class="gallery-item" data-id="' + file.id + '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;"><img src="' + img_url + '" style="width: 100%; height: 100%; object-fit: cover;" /><button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button></div>';
                            $('#preview-' + active_season).append(html);
                        }
                    });
                    $input.val(current_ids.join(',')); $('.clear-seasonal-btn[data-season="' + active_season + '"]').show();
                });
            }
            gallery_uploader.open();
        });
        $('.gallery-preview-box').on('click', '.remove-item-btn', function() {
            var $item = $(this).closest('.gallery-item'); var remove_id = $item.data('id').toString();
            var season = $(this).closest('.gallery-preview-box').attr('id').replace('preview-', ''); var $input = $('#input-' + season);
            var current_ids = $input.val().split(',').filter(function(id) { return id !== remove_id; });
            $input.val(current_ids.join(',')); $item.remove();
            if (current_ids.length === 0) { $('.clear-seasonal-btn[data-season="' + season + '"]').hide(); $input.val(''); }
        });
        $('.clear-seasonal-btn').click(function() {
            var season = $(this).data('season');
            if (confirm('この季節の画像一覧をクリアしますか?')) { $('#preview-' + season).empty(); $('#input-' + season).val(''); $(this).hide(); }
        });
    });
    </script>
    <?php
}
// 4. 自動適用・固定化・無限ループ防止・ハイブリッド選出処理
function my_seasonal_default_thumbnail_id( $value, $post_id, $meta_key, $single ) {
    if ( is_admin() || '_thumbnail_id' !== $meta_key ) { return $value; }

    static $is_filtering = false;
    if ( $is_filtering ) { return $value; }

    $is_filtering = true;
    $db_thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true );
    $is_auto_saved = get_post_meta( $post_id, '_my_seasonal_is_auto_saved', true );

    if ( ! empty( $db_thumbnail_id ) && ! $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    if ( ! empty( $db_thumbnail_id ) && $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    $mode = get_option( 'my_plugin_select_mode', 'auto' );
    $target_seasons = array();

    if ( 'auto' === $mode ) {
        $month = intval( current_time( 'm' ) );
        if ( $month >= 3 && $month <= 5 ) { $target_seasons[] = 'spring'; }
        elseif ( $month >= 6 && $month <= 8 ) { $target_seasons[] = 'summer'; }
        elseif ( $month >= 9 && $month <= 11 ) { $target_seasons[] = 'autumn'; }
        else { $target_seasons[] = 'winter'; }
    } else {
        $target_seasons = get_option( 'my_plugin_active_seasons', array() );
    }

    $merged_image_ids = array();
    if ( ! empty( $target_seasons ) ) {
        foreach ( $target_seasons as $season_key ) {
            $saved_ids_str = get_option( 'my_plugin_image_ids_' . $season_key, '' );
            if ( ! empty( $saved_ids_str ) ) {
                $ids_array = explode( ',', $saved_ids_str );
                $merged_image_ids = array_merge( $merged_image_ids, $ids_array );
            }
        }
    }

    $merged_image_ids = array_filter( array_unique( array_map( 'intval', $merged_image_ids ) ) );

    if ( empty( $merged_image_ids ) ) {
        $fallback_str = get_option( 'my_plugin_image_ids_all_season', '' );
        if ( ! empty( $fallback_str ) ) {
            $merged_image_ids = array_filter( array_map( 'intval', explode( ',', $fallback_str ) ) );
        }
    }

    if ( empty( $merged_image_ids ) ) { 
        $is_filtering = false;
        return $value; 
    }

    $selected_thumb_id = $merged_image_ids[ array_rand( $merged_image_ids ) ];

    if ( $selected_thumb_id ) {
        update_post_meta( $post_id, '_thumbnail_id', $selected_thumb_id );
        update_post_meta( $post_id, '_my_seasonal_is_auto_saved', '1' );
        $is_filtering = false;
        return $single ? $selected_thumb_id : array( $selected_thumb_id );
    }

    $is_filtering = false;
    return $value;
}
add_filter( 'get_post_metadata', 'my_seasonal_default_thumbnail_id', 10, 4 );

// 5. 手動変更された場合のフラグクリア
function my_seasonal_clear_auto_save_flag( $post_id, $post, $update ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( isset( $_POST['_thumbnail_id'] ) ) {
        delete_post_meta( $post_id, '_my_seasonal_is_auto_saved' );
    }
}
add_action( 'save_post', 'my_seasonal_clear_auto_save_flag', 10, 3 );

4以下を入れ替えたコード
新規に入れたページは表示される。

以下のコード結局だめだった。
後で検証した結果、自動判別がそのシーズンの分が表示さているようでオールシーズンの分が表示されていないようだ、手動設定は完璧に機能しているように見える。

<?php
/**
 * Plugin Name: マイ季節別デフォルトアイキャッチプラグイン
 * Description: アイキャッチ未設定の投稿に対して、登録画像から1枚をランダム自動適用します(自動・手動切り替え・画像プレビュー完全両立版)。
 * Version:     7.1.0
 * Author:      あなたの名前
 */

if ( ! defined( 'ABSPATH' ) ) { exit; }

// 1. 管理画面メニュー追加
function my_seasonal_gallery_menu() {
    add_menu_page( '季節別画像設定', '季節別画像設定', 'manage_options', 'my-default-thumbnail-gallery', 'my_seasonal_gallery_page', 'dashicons-images-alt2', 90 );
}
add_action( 'admin_menu', 'my_seasonal_gallery_menu' );

// 2. メディアライブラリ用アセット読み込み
function my_seasonal_gallery_assets( $hook ) {
    if ( 'toplevel_page_my-default-thumbnail-gallery' === $hook ) { wp_enqueue_media(); }
}
add_action( 'admin_enqueue_scripts', 'my_seasonal_gallery_assets' );

// 3. 設定画面のHTMLと保存処理
function my_seasonal_gallery_page() {
    if ( ! current_user_can( 'manage_options' ) ) { return; }
    $seasons = array( 'all_season' => 'オールシーズン用', 'spring' => '春(Spring)', 'summer' => '夏(Summer)', 'autumn' => '秋(Autumn)', 'winter' => '冬(Winter)' );

    if ( isset( $_POST['my_seasonal_nonce'] ) && wp_verify_nonce( $_POST['my_seasonal_nonce'], 'my_seasonal_action' ) ) {
        foreach ( $seasons as $key => $label ) {
            $field_name = 'my_plugin_image_ids_' . $key;
            update_option( $field_name, isset( $_POST[$field_name] ) ? sanitize_text_field( $_POST[$field_name] ) : '' );
        }
        update_option( 'my_plugin_select_mode', isset( $_POST['my_plugin_select_mode'] ) ? sanitize_text_field( $_POST['my_plugin_select_mode'] ) : 'auto' );
        $active_seasons = isset( $_POST['my_plugin_active_seasons'] ) ? array_map( 'sanitize_text_field', $_POST['my_plugin_active_seasons'] ) : array();
        update_option( 'my_plugin_active_seasons', $active_seasons );
        echo '<div class="updated"><p>すべての設定を保存しました。</p></div>';
    }

    $saved_mode = get_option( 'my_plugin_select_mode', 'auto' );
    $saved_active_seasons = get_option( 'my_plugin_active_seasons', array() );
    ?>
    <div class="wrap">
        <h1>季節別デフォルトアイキャッチ設定</h1>
        <form method="post" action="">
            <?php wp_nonce_field( 'my_seasonal_action', 'my_seasonal_nonce' ); ?>
            
            <div class="card" style="max-width: 100%; margin-bottom: 20px; padding: 20px; background: #fff; border: 1px solid #ccd0d4; box-shadow: 0 1px 1px rgba(0,0,0,.04);">
                <h2 style="margin-top:0; font-size: 1.2em;">🎯 画像の選出モード設定</h2>
                <p>
                    <label style="font-weight: bold; font-size: 1.1em; cursor: pointer; margin-right: 20px;">
                        <input type="radio" name="my_plugin_select_mode" value="auto" <?php checked( $saved_mode, 'auto' ); ?> /> 現在の月から自動判定モード
                    </label>
                </p>
                <hr style="border:none; border-top:1px solid #eee; margin:15px 0;" />
                <p>
                    <label style="font-weight: bold; font-size: 1.1em; cursor: pointer;">
                        <input type="radio" name="my_plugin_select_mode" value="manual" <?php checked( $saved_mode, 'manual' ); ?> /> 手動カスタム選択モード
                    </label>
                </p>
                <div id="manual-checkbox-area" style="display: flex; gap: 20px; flex-wrap: wrap; margin-top: 10px; padding-left: 25px; <?php echo ($saved_mode === 'manual') ? '' : 'opacity: 0.5; pointer-events: none;'; ?>">
                    <?php foreach ( $seasons as $key => $label ) : ?>
                        <label style="cursor: pointer;"><input type="checkbox" name="my_plugin_active_seasons[]" value="<?php echo esc_attr( $key ); ?>" <?php checked( in_array( $key, $saved_active_seasons, true ) ); ?> /> <?php echo esc_html( $label ); ?></label>
                    <?php endforeach; ?>
                </div>
            </div>
            <table class="form-table">
                <?php foreach ( $seasons as $key => $label ) : 
                    $saved_ids_str = get_option( 'my_plugin_image_ids_' . $key, '' );
                    $image_ids = ! empty( $saved_ids_str ) ? explode( ',', $saved_ids_str ) : array(); ?>
                <tr style="border-bottom: 1px solid #ccc;">
                    <th scope="row" style="width: 150px; font-weight: bold; font-size: 1.1em; padding: 20px 0;"><?php echo esc_html( $label ); ?></th>
                    <td style="padding: 20px 0;">
                        <div id="preview-<?php echo esc_attr( $key ); ?>" class="gallery-preview-box" style="display: flex; flex-wrap: wrap; gap: 15px; margin-bottom: 15px;">
                            <?php if ( ! empty( $image_ids ) ) {
                                foreach ( $image_ids as $id ) {
                                    $id = intval( $id );
                                    $img_src = wp_get_attachment_image_url( $id, 'thumbnail' );
                                    if ( $img_src ) {
                                        echo '<div class="gallery-item" data-id="' . esc_attr( $id ) . '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;">';
                                        echo '<img src="' . esc_url( $img_src ) . '" style="width: 100%; height: 100%; object-fit: cover;" />';
                                        echo '<button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button>';
                                        echo '</div>';
                                    }
                                }
                            } ?>
                        </div>
                        <input type="text" name="my_plugin_image_ids_<?php echo esc_attr( $key ); ?>" id="input-<?php echo esc_attr( $key ); ?>" value="<?php echo esc_attr( $saved_ids_str ); ?>" style="display:none;" />
                        <button type="button" class="button button-secondary upload-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>">画像を追加</button>
                        <button type="button" class="button clear-seasonal-btn" data-season="<?php echo esc_attr( $key ); ?>" style="<?php echo ! empty( $image_ids ) ? '' : 'display:none;'; ?>">すべてクリア</button>
                    </td>
                </tr>
                <?php endforeach; ?>
            </table>
            <?php submit_button( 'すべての設定を保存' ); ?>
        </form>
    </div>
    <script>
    jQuery(document).ready(function($){
        $('input[name="my_plugin_select_mode"]').change(function() {
            if ($(this).val() === 'manual') { $('#manual-checkbox-area').css({'opacity': '1', 'pointer-events': 'auto'}); }
            else { $('#manual-checkbox-area').css({'opacity': '0.5', 'pointer-events': 'none'}); }
        });
        var gallery_uploader; var active_season = '';
        $('.upload-seasonal-btn').click(function(e) {
            e.preventDefault(); active_season = $(this).data('season');
            if (!gallery_uploader) {
                gallery_uploader = wp.media({ title: '画像を選択・追加してください', button: { text: 'ギャラリーに追加' }, multiple: true });
                gallery_uploader.on('select', function() {
                    var selection = gallery_uploader.state().get('selection');
                    var $input = $('#input-' + active_season);
                    var current_ids = $input.val() ? $input.val().split(',') : [];
                    selection.each(function(attachment) {
                        var file = attachment.toJSON(); var id_str = file.id.toString();
                        if (current_ids.indexOf(id_str) === -1) {
                            current_ids.push(id_str);
                            var img_url = file.sizes.thumbnail ? file.sizes.thumbnail.url : file.url;
                            var html = '<div class="gallery-item" data-id="' + file.id + '" style="position: relative; width: 100px; height: 100px; border: 1px solid #ccc; padding: 4px; background: #fff;"><img src="' + img_url + '" style="width: 100%; height: 100%; object-fit: cover;" /><button type="button" class="remove-item-btn" style="position: absolute; top: -8px; right: -8px; background: #ef4444; color: #fff; border: none; border-radius: 50%; width: 20px; height: 20px; cursor: pointer; font-size: 11px; line-height: 18px; text-align: center; font-weight: bold; padding:0;">×</button></div>';
                            $('#preview-' + active_season).append(html);
                        }
                    });
                    $input.val(current_ids.join(',')); $('.clear-seasonal-btn[data-season="' + active_season + '"]').show();
                });
            }
            gallery_uploader.open();
        });
        $('.gallery-preview-box').on('click', '.remove-item-btn', function() {
            var $item = $(this).closest('.gallery-item'); var remove_id = $item.data('id').toString();
            var season = $(this).closest('.gallery-preview-box').attr('id').replace('preview-', ''); var $input = $('#input-' + season);
            var current_ids = $input.val().split(',').filter(function(id) { return id !== remove_id; });
            $input.val(current_ids.join(',')); $item.remove();
            if (current_ids.length === 0) { $('.clear-seasonal-btn[data-season="' + season + '"]').hide(); $input.val(''); }
        });
        $('.clear-seasonal-btn').click(function() {
            var season = $(this).data('season');
            if (confirm('この季節の画像一覧をクリアしますか?')) { $('#preview-' + season).empty(); $('#input-' + season).val(''); $(this).hide(); }
        });
    });
    </script>
    <?php
}

// 4. 自動適用・固定化・無限ループ防止・ハイブリッド選出処理(デバッグ版)
function my_seasonal_default_thumbnail_id( $value, $post_id, $meta_key, $single ) {
    if ( is_admin() || '_thumbnail_id' !== $meta_key ) { return $value; }

    static $is_filtering = false;
    if ( $is_filtering ) { return $value; }

    $is_filtering = true;
    $db_thumbnail_id = get_post_meta( $post_id, '_thumbnail_id', true );
    $is_auto_saved = get_post_meta( $post_id, '_my_seasonal_is_auto_saved', true );

    if ( ! empty( $db_thumbnail_id ) && ! $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    if ( ! empty( $db_thumbnail_id ) && $is_auto_saved ) {
        $is_filtering = false;
        return $single ? $db_thumbnail_id : array( $db_thumbnail_id );
    }

    // --- ここから検証用ログ収集 ---
    $mode = get_option( 'my_plugin_select_mode', 'auto' );
    $target_seasons = array();

    if ( 'auto' === $mode ) {
        $month = intval( current_time( 'm' ) );
        if ( $month >= 3 && $month <= 5 ) { $target_seasons[] = 'spring'; }
        elseif ( $month >= 6 && $month <= 8 ) { $target_seasons[] = 'summer'; }
        elseif ( $month >= 9 && $month <= 11 ) { $target_seasons[] = 'autumn'; }
        else { $target_seasons[] = 'winter'; }
    } else {
        $target_seasons = get_option( 'my_plugin_active_seasons', array() );
    }

    $merged_image_ids = array();
    if ( ! empty( $target_seasons ) ) {
        foreach ( $target_seasons as $season_key ) {
            $saved_ids_str = get_option( 'my_plugin_image_ids_' . $season_key, '' );
            if ( ! empty( $saved_ids_str ) ) {
                $ids_array = explode( ',', $saved_ids_str );
                $merged_image_ids = array_merge( $merged_image_ids, $ids_array );
            }
        }
    }

    $merged_image_ids = array_filter( array_unique( array_map( 'intval', $merged_image_ids ) ) );
    $is_fallback = 'No';

    if ( empty( $merged_image_ids ) ) {
        $is_fallback = 'Yes';
        $fallback_str = get_option( 'my_plugin_image_ids_all_season', '' );
        if ( ! empty( $fallback_str ) ) {
            $merged_image_ids = array_filter( array_map( 'intval', explode( ',', $fallback_str ) ) );
        }
    }

    // 画面にデバッグ情報をこっそり出力(管理者のみ)
    if ( current_user_can( 'manage_options' ) ) {
        echo '<div style="display:none;" data-plugin-debug="1">';
        echo '【プラグイン診断】';
        echo ' 保存モード: ' . esc_html($mode);
        echo ' / 対象シーズン: ' . esc_html(implode(',', $target_seasons));
        echo ' / 最終画像プールID: ' . esc_html(implode(',', $merged_image_ids));
        echo ' / 最終フォールバック発生: ' . esc_html($is_fallback);
        echo '</div>';
    }
    // --- 検証用ログ収集ここまで ---

    if ( empty( $merged_image_ids ) ) { 
        $is_filtering = false;
        return $value; 
    }

    $selected_thumb_id = $merged_image_ids[ array_rand( $merged_image_ids ) ];

    if ( $selected_thumb_id ) {
        update_post_meta( $post_id, '_thumbnail_id', $selected_thumb_id );
        update_post_meta( $post_id, '_my_seasonal_is_auto_saved', '1' );
        $is_filtering = false;
        return $single ? $selected_thumb_id : array( $selected_thumb_id );
    }

    $is_filtering = false;
    return $value;
}
add_filter( 'get_post_metadata', 'my_seasonal_default_thumbnail_id', 10, 4 );

function my_seasonal_clear_auto_save_flag( $post_id, $post, $update ) {
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( isset( $_POST['_thumbnail_id'] ) ) {
        delete_post_meta( $post_id, '_my_seasonal_is_auto_saved' );
    }
}
add_action( 'save_post', 'my_seasonal_clear_auto_save_flag', 10, 3 );

たくさん画像があるバックアップ用のWebサイトに移動して再度やってみました。

自動判別モード:秋の画像が表示される。
全てのチェックを外した状態:秋の画像が表示される。
オールシーズンだけをチェックを入れる:

自動判別モード:どのボタンを設定しても同じ画面になる。リロードするたびに入れかわるということがない。

続きは以下のところkら

続きのサイト:https://www.google.com/search?client=safari&rls=en&q=昨日作成した「マイ季節別デフォルトアイキャッチプラグイン」の機能拡張の続きをお願いします%E3%80%82++【現在の前提条件と仕様】+・「オールシーズン」「春」「夏」「秋」「冬」の5パターン別に画像を複数登録できる管理画面が完成している%E3%80%82+・画像データはデータベースにカンマ区切りの画像ID(例%3A+12%2C45%2C78)として保存されている%E3%80%82+・アイキャッチ画像が設定されていない記事に対して、現在の月から判断した季節(またはオールシーズン用)の登録画像から、1枚をランダムに選んで自動適用する仕組み(get_post_metadataフィルター)が完璧に動作している%E3%80%82++ここからさらに機能を拡張していきたいです%E3%80%82&ie=UTF-8&oe=UTF-8&fbs=ACAhTvwYeyvPEtyt1PqrtP1hztNrcxN_EOE0rh9zA20_11aLairmGSJgcvk6ppC3OmwZn4MKd5y7Rd4vMWvNIA86ZvZ0gFIH2COh9hlZbF7-GBDMOqp62WCuOoxTvUyC2kiHAOOBEveDCGsDNQDJODGGeozawRKKe-CcJ5RHaHdK9MCmu3ayL85aFZE-3uuqnM5TT0ysIlDETDZm7s_J9S50DAi6gXv0CdEXEQB7BUDj_GY9BtY8WYk&aep=10&ntc=1&sxsrf=AKL5yDgtvfI8bciFR79kQ3x37CHHy3KUiw%3A1794267930341&mstk=AUtExfBSB3r_s0kChhbGJ-xWUB0mKLuUl7dGvRCz4kAmP5jnZG9abLaqEIf07wK0WynRj9W4lJYwW8WS9gceHvDXrwMX-UDYEhkFDcujkEGcAmD6xxdzmuq9Mzueu6AqPQHHqaaQeoDvfLowZeAJ04OfgExGRQJiZFdc7WI&aioh=3&csuir=1&mtid=GlvyaoyFLoLi2roPj7yv8Aw&lns_mode=cvst&udm=50