投稿内の最初の画像をアイキャッチ画像(Featured Image)として自動設定するWordPressプラグインを作成する

アイキャッチがとが設定されていない投稿が複数あって、まとめて投稿の最初の画像をアイキャッチ画像に設定したいと思ったことはありませんか?以下は、投稿内の最初の画像をアイキャッチ画像(Featured Image)として自動設定するWordPressプラグインのサンプルコードです。functions.phpに直接書くのではなく、独立したプラグインとして作成できます。


プラグイン用のファイルを作成

  1. コードを auto-featured-image.php という名前で保存します。
  2. WordPressの /wp-content/plugins/ フォルダにアップロードします。
  3. 管理画面からプラグインを有効化します。

基本機能:

  • 投稿の本文から最初の画像を自動的に検出し、アイキャッチ画像として設定
  • アイキャッチ画像が未設定の投稿を一括で処理可能
  • シンプルで使いやすい管理画面

主な機能の詳細:

a) 自動アイキャッチ画像設定:

  • 投稿保存時に自動的に本文から最初の画像を検出
  • 検出した画像をメディアライブラリに追加
  • 追加した画像をアイキャッチ画像として設定

b) 一括処理機能:

  • 既存の投稿に対して一括でアイキャッチ画像を設定可能
  • 進捗状況をリアルタイムで表示
  • エラー発生時の詳細なログ表示

c) 設定オプション:

  • 処理対象の投稿タイプを選択可能(投稿、固定ページなど)
  • 管理画面から簡単に設定可能

技術的な特徴:

  • PHP 7.4以上が必要
  • WordPress 5.8以上に対応
  • モダンなオブジェクト指向プログラミングを採用
  • セキュリティ対策(nonce、権限チェックなど)を実装

管理画面の機能:

  • 進捗バーの表示
  • エラーメッセージの表示
  • 処理状況のリアルタイム更新
  • レスポンシブなデザイン

セキュリティ機能:

  • 管理者権限のチェック
  • データのサニタイズ処理
  • セキュアなAJAX処理

設定セクションの説明

アイキャッチ画像の自動設定に関する基本設定を行います。

 /**
* 設定セクションの説明
*/
public function settings_section_callback() {
echo '<p>アイキャッチ画像の自動設定に関する基本設定を行います。</p>';
}

設定値のサニタイズ

    public function sanitize_options($input) {
        $sanitized = array();

        // 投稿タイプのサニタイズ
        if (isset($input['post_types']) && is_array($input['post_types'])) {
            $sanitized['post_types'] = array_map('sanitize_text_field', $input['post_types']);
        } else {
            $sanitized['post_types'] = array('post');
        }

        return $sanitized;
    }

投稿タイプ選択のコールバック

    public function post_types_callback() {
        $post_types = get_post_types(array(
            'public' => true,
            'show_in_menu' => true
        ), 'objects');

        // メディアを除外
        unset($post_types['attachment']);

        $selected = isset($this->options['post_types']) ? $this->options['post_types'] : array('post');

        echo '<div class="post-type-list">';
        foreach ($post_types as $post_type) {
            ?>
            <label>
                <input type="checkbox"
                       name="eguweb_auto_featured_image_options[post_types][]"
                       value="<?php echo esc_attr($post_type->name); ?>"
                       <?php checked(in_array($post_type->name, $selected)); ?>>
                <?php echo esc_html($post_type->label); ?>
                <span class="description">(<?php echo esc_html($post_type->name); ?>)</span>
            </label>
            <?php
        }
        echo '</div>';
        echo '<p class="description">アイキャッチ画像を自動設定する投稿タイプを選択してください。</p>';
    }

管理メニューに設定ページを追加

    public function add_admin_menu() {
        // メインメニューを追加
        $menu_page = add_menu_page(
            '自動アイキャッチ画像設定',
            '自動アイキャッチ画像',
            'manage_options',
            'eguweb-auto-featured-image',
            array($this, 'admin_page'),
            'dashicons-images-alt2',
            30
        );

        // 管理画面のスタイルを追加
        add_action('admin_print_styles-' . $menu_page, array($this, 'admin_styles'));
    }

管理画面のスタイル

    public function admin_styles() {
        ?>
        <style>
            .eguweb-settings-wrap {
                margin: 20px;
                max-width: 800px;
            }
            .eguweb-settings-wrap h1 {
                margin-bottom: 20px;
                padding-bottom: 10px;
                border-bottom: 1px solid #ccc;
            }
            .eguweb-settings-wrap .form-table {
                margin-top: 20px;
                background: #fff;
                padding: 20px;
            }
            .eguweb-settings-wrap .form-table th {
                width: 200px;
                padding: 20px 10px 20px 0;
            }
            .eguweb-settings-wrap .form-table td {
                padding: 15px 10px;
            }
            .eguweb-settings-wrap .submit {
                margin-top: 20px;
                padding: 20px;
                background: #fff;
            }
            .eguweb-settings-wrap .notice {
                margin: 20px 0;
            }
            .eguweb-settings-wrap .post-type-list {
                margin: 10px 0;
            }
            .eguweb-settings-wrap .post-type-list label {
                display: block;
                margin: 5px 0;
                padding: 8px 12px;
                background: #f9f9f9;
                border: 1px solid #e5e5e5;
                border-radius: 4px;
            }
            .eguweb-settings-wrap .post-type-list label:hover {
                background: #f0f0f0;
            }
            .eguweb-settings-wrap .post-type-list input[type="checkbox"] {
                margin-right: 8px;
            }
            .eguweb-settings-wrap .post-type-list .description {
                margin-left: 8px;
                color: #666;
            }
            .eguweb-settings-wrap select {
                min-width: 200px;
            }
            .eguweb-settings-wrap .bulk-process-section {
                margin-top: 30px;
                padding: 20px;
                background: #fff;
                border: 1px solid #ccd0d4;
                box-shadow: 0 1px 1px rgba(0,0,0,.04);
            }
            .eguweb-settings-wrap .bulk-process-section h2 {
                margin-top: 0;
                padding-bottom: 10px;
                border-bottom: 1px solid #eee;
            }
            .eguweb-settings-wrap .bulk-process-section p {
                margin: 10px 0;
            }
            .eguweb-settings-wrap .button-primary {
                margin-top: 10px;
            }
            /* 設定画面の背景を白く囲む */
            .eguweb-settings-wrap form {
                background: #fff;
                padding: 20px;
            }
            /* 説明文のスタイル調整 */
            .eguweb-settings-wrap .description {
                color: #666;
                font-style: italic;
                margin-top: 5px;
            }
        </style>
        <?php
    }

管理画面用のスクリプトとスタイルを読み込み

    public function enqueue_admin_scripts($hook) {
        if ('toplevel_page_eguweb-auto-featured-image' !== $hook) {
            return;
        }

        wp_enqueue_style(
            'eguweb-auto-featured-image-admin',
            plugins_url('css/admin.css', __FILE__),
            array(),
            '1.0.0'
        );

        wp_enqueue_script(
            'eguweb-auto-featured-image-admin',
            plugins_url('js/admin.js', __FILE__),
            array('jquery'),
            '1.0.0',
            true
        );

    }

管理画面の表示

   public function admin_page() {
        // 現在の処理対象件数を取得
        $current_args = array(
            'post_type' => $this->options['post_types'],
            'posts_per_page' => -1,
            'post_status' => array('publish', 'private', 'future'),
            'meta_query' => array(
                'relation' => 'OR',
                array(
                    'key' => '_thumbnail_id',
                    'compare' => 'NOT EXISTS'
                ),
                array(
                    'key' => '_thumbnail_id',
                    'value' => '0',
                    'compare' => '='
                )
            )
        );
        $current_query = new WP_Query($current_args);
        $current_total = $current_query->found_posts;
        wp_reset_postdata();

        // デバッグ情報
        $debug_info = array(
            'total_posts' => $current_total,
            'post_types' => $this->options['post_types'],
            'query_args' => $current_args
        );

        ?>
        <div class="wrap eguweb-settings-wrap">
            <h1>自動アイキャッチ画像設定</h1>

            <form method="post" action="options.php">
                <?php
                settings_fields('eguweb_auto_featured_image_options');
                do_settings_sections('eguweb_auto_featured_image_options');
                submit_button('設定を保存');
                ?>
            </form>

            <div class="bulk-process-section">
                <h2>一括処理</h2>
                <form method="post" action="" id="eguweb-bulk-process-form">
                    <?php wp_nonce_field('eguweb_auto_featured_image_bulk', 'eguweb_auto_featured_image_nonce'); ?>
                    <p>アイキャッチ画像が未設定の投稿に、最初の画像を自動的に設定します。</p>
                    <p>処理対象の投稿タイプ: <?php echo esc_html(implode(', ', array_map(function($type) {
                        $post_type = get_post_type_object($type);
                        return $post_type ? $post_type->label : $type;
                    }, $this->options['post_types']))); ?></p>
                    <p>アイキャッチ未設定件数: <strong><?php echo esc_html($current_total); ?></strong>件</p>

                    <div id="eguweb-progress-container" style="display: none;">
                        <div class="progress-bar">
                            <div class="progress-bar-fill"></div>
                        </div>
                        <div class="progress-status">
                            <span class="current-count">0</span> / <span class="total-count"><?php echo esc_html($current_total); ?></span> 件処理完了
                        </div>
                        <div class="progress-message"></div>
                    </div>

                    <div id="eguweb-error-container" style="display: none;">
                        <h3>エラーが発生しました</h3>
                        <ul class="error-list"></ul>
                    </div>

                    <input type="submit" name="eguweb_auto_featured_image_bulk" class="button button-primary" value="一括処理を実行">
                </form>
            </div>
        </div>
        <?php
    }

プラグインのポイント

  • 投稿の保存時(save_post)に処理を実行します。
  • すでにアイキャッチがある投稿には何もしません。
  • 投稿内の画像URLからメディアIDを逆引きしてアイキャッチに設定します。

まとめ

希望によっては、「投稿更新時にもアイキャッチを更新」「自動でメディアに追加」などの機能も拡張可能です。

このプラグインは、WordPressサイトのアイキャッチ画像管理を自動化し、効率的なコンテンツ管理を実現するのに役立ちます。特に、多数の投稿を持つサイトや、定期的にコンテンツを更新するサイトで有用です。