Масово задаване на липсващи изображения за избрани публикации в WordPress

No comments

05.09.2026|

No comments

Tiempo de lectura Lectura: 7 min, 6 s
Número de palabras Palabras: 1315
Número de visitas Visitas: 22
Icono de traducción
Масово добавяне на липсващи избрани изображения в WordPress. Списък, в който се показват както липсващите, така и наличните изображения.

Преди няколко дни приключих с една отдавна закъсняла задача, която трябваше да изпълня, но я отлагах от векове.Възстанових всичкилипсващи избрани изображения и добавих липсващия алтернативен текст към тях. Също така завърших написването на всички липсващи метаописания. Общо добавих или редактирах над 15 000 записи, като използвах три от моите собствени еднократни скриптове. Днес споделям тук скрипта за възстановяване на липсващите избрани изображения, който използвах и за изпълнението на тази задача на други сайтове.

Ако вече от известно време пишете блог, много вероятно е да имате доста по-стари публикации, на които не е зададена избрана картинка. Това се случваше често по времето на класическия редактор, когато вмъквахме изображението директно в текста на публикацията, но забравяхме да го изберем в полето „Избрано изображение“.

Публикуването на статии без избрана картинка не е само естетически проблем, наред с други неща; то оказва пряко влияние върху оптимизацията на сайта ви и потребителското преживяване:

  1. Социално SEO и Open Graph: Когато публикацията се споделя в социалните медии, приложения за съобщения или агрегатори на съдържание, Open Graph таговете (og:image) не могат да намерят ясен ресурс, който да покажат, което значително намалява CTR (процент на кликванията).
  2. Визуална последователност в темата: Съвременните шаблони (като например тези, създадени с GeneratePress или GenerateBlocks) разчитат на избраната картинка за изграждането на мрежи в архива, списъци със свързани публикации или заглавни редове. Без нея оформлението се нарушава или се появяват неравномерно разпределени празнини.
  3. Откриване и емисии (RSS / Google Discover): Инструменти като Google Discover или RSS четците дават приоритет или изискват съдържание, придружено от миниатюра с висока резолюция, за да подобрят представянето на статията.

За да разреша този проблем, без да се налага да използвам плъгини (като този) или бавни процеси, създадох този прост и лек PHP фрагмент, който автоматично задава първата картинка във всяка публикация като избрана картинка – директно от таблото за управление на WordPress. Ако публикацията ви няма картинки, можете да зададете такава по подразбиране, като добавите нейния URL адрес към кода.

Какво точно прави този фрагмент от код?

Кодът добавя интелигентен, вграден инструмент за пакетна обработка към списъка с публикации в WordPress (wp-admin/edit.php):

  • Добавяне на персонализирана колона: Създайте колоната „Липсваща избрана картинка“ в списъка с публикации, за да виждате с един поглед кои публикации нямат миниатюра.
  • 3-етапна обработка: Когато активирате заданието за дадена публикация, то търси изображението точно в този ред:
    1. Проверете дали в медийната библиотека има изображения, прикачени директно към публикацията.
    2. Ако няма преки прикачени файлове (например, ако са били вмъкнати чрез блок с изображение или HTML), претърсете съдържанието за първия таг <img>, за да извлечете неговия идентификатор с помощта на attachment_url_to_postid().
    3. Ако записът не съдържа абсолютно никакви изображения, системата използва изображение по подразбиране (резервно), посочено в конфигурацията.
  • Масова обработка чрез AJAX (пакетна обработка): Включва бутон в горната част на екрана („⚡ Присвои всички на тази страница“), който обработва последователно всички записи, видими на екрана, чрез поредица от асинхронни заявки. Можете да направите това и ръчно, като използвате отделния бутон за всеки пост в списъка.
  • Филтриране на чернови: Автоматично изключва записите със статус „чернова“, за да можете да се съсредоточите изцяло върху публикуваното съдържание.
  • Колона за сортиране: Позволява ви да сортирате списъка така, че всички записи без избрана картинка да бъдат групирани заедно в горната част.

Защо е толкова лек и това не се отразява ли на производителността на сървъра?

Често срещано притеснение при използването на този тип автоматизирани инструменти е страхът от блокиране на базата данни или претоварване на PHP паметта в сайтове с хиляди статии. Този фрагмент от код е разработен в съответствие със следните критерии за оптимизация:

1. Работи само в раздела „Администратор“ (is_admin())

Кодът е предназначен изключително за екрана за въвеждане на данни в панела за администриране (edit.php). Той не добавя нито един ред допълнителен код към заявките към публичния сайт. Това няма да се отрази по никакъв начин на вашите потребители и показателите за скорост.

2. Изпращане на заявки към Meta Cache

За да се установи дали дадена публикация съдържа изображение, фрагментът не извършва сложни търсения в базата данни за всеки ред. Той използва ключа за метаданни _thumbnail_id, който WordPress зарежда в паметта по подразбиране чрез кеша за метаданни при визуализирането на списъка. Таблицата се зарежда почти мигновено.

3. Каскадна асинхронна обработка (последователен AJAX цикъл)

Вместо да се изпълнява масивен запит към базата данни за актуализиране на 700 или 1 000 записи наведнъж (което би довело до изтичане на времето за изчакване или изчерпване на цялата памет на сървъра), бутонът „Assign All“ обработва записите един по един, като използва обещания в JavaScript:

POST 1 (AJAX)⟶отговор „OK“⟶POST 2 (AJAX)⟶отговор „OK“…

Това гарантира стабилно и последователно използване на ресурсите, което ви позволява да наблюдавате напредъка в реално време, ред по ред.

4. Без дублиране на файлове

Добавката не изтегля, не комбинира и не дублира изображения на вашия твърд диск. Тя просто взема идентификатора на изображението, което вече се намира във вашата медийна библиотека, и го свързва с публикацията, като присвоява съответната стойност на метаданните в таблицата wp_postmeta.

Кодът (PHP + JavaScript)

Можете да добавите този код във файла functions.php на вашата подтема, в потребителски плъгин или чрез плъгин за потребителски функции, като например Code Snippets или подобен.

Забележка: Не забравяйте да зададете променливата $default_image_url в ред 56 на пълния URL адрес на общото изображение, което искате да присвоите на публикациите, чийто текст не съдържа никакви изображения.

PHP


// 1. Añadir columna personalizada en el listado de entradas
add_filter( 'manage_posts_columns', 'custom_featured_status_column' );
function custom_featured_status_column( $columns ) 
    $columns['featured_missing'] = 'Destacada Faltante';
    return $columns;
}

// 2. Hacer la columna ordenable al hacer clic en el encabezado
add_filter( 'manage_edit-post_sortable_columns', 'custom_featured_sortable_column' );
function custom_featured_sortable_column( $columns ) {
    $columns['featured_missing'] = 'featured_missing';
    return $columns;
}

// 3. Modificar la consulta para ordenar por presencia de _thumbnail_id
add_action( 'pre_get_posts', 'custom_featured_column_orderby' );
function custom_featured_column_orderby( $query ) {
    if ( ! is_admin() || ! $query->is_main_query() ) return;

    if ( $query->get( 'orderby' ) === 'featured_missing' ) {
        $query->set( 'meta_key', '_thumbnail_id' );
        $query->set( 'orderby', 'meta_value_num' );
        $query->set( 'meta_compare', 'NOT EXISTS' );
    }
}

// 3.1. Añadir desplegable de filtro nativo en el listado de entradas
add_action( 'restrict_manage_posts', 'custom_featured_filter_dropdown' );
function custom_featured_filter_dropdown( $post_type ) {
    if ( $post_type !== 'post' ) return;

    $selected = isset( $_GET['filter_featured_status'] ) ? sanitize_text_field( $_GET['filter_featured_status'] ) : '';
    ?>
    <select name="filter_featured_status" id="filter_featured_status">
        <option value=""><?php _e( 'Todas las destacadas', 'textdomain' ); ?></option>
        <option value="has_img" <?php selected( $selected, 'has_img' ); ?>>Tiene</option>
        <option value="missing_img" <?php selected( $selected, 'missing_img' ); ?>>Falta</option>
    </select>
    <?php
}

// 3.2. Aplicar el filtro del desplegable a la consulta de WP_Query
add_filter( 'parse_query', 'custom_featured_filter_apply' );
function custom_featured_filter_apply( $query ) {
    global $pagenow;
    if ( ! is_admin() || $pagenow !== 'edit.php' || ! $query->is_main_query() ) return;

    if ( isset( $_GET['filter_featured_status'] ) && $_GET['filter_featured_status'] !== '' ) {
        $filter_value = sanitize_text_field( $_GET['filter_featured_status'] );
        $meta_query   = (array) $query->get( 'meta_query' );

        if ( $filter_value === 'has_img' ) {
            $meta_query[] = array(
                'key'     => '_thumbnail_id',
                'compare' => 'EXISTS',
            );
        } elseif ( $filter_value === 'missing_img' ) {
            $meta_query[] = array(
                'key'     => '_thumbnail_id',
                'compare' => 'NOT EXISTS',
            );
        }

        $query->set( 'meta_query', $meta_query );
    }
}

// 4. Mostrar el estado y el botón rápido en la columna (Excluyendo borradores)
add_action( 'manage_posts_custom_column', 'custom_featured_status_column_content', 10, 2 );
function custom_featured_status_column_content( $column, $post_id ) {
    if ( $column === 'featured_missing' ) {
        if ( get_post_type( $post_id ) !== 'post' || get_post_status( $post_id ) === 'draft' ) {
            echo '<span style="color: #999;">—</span>';
            return;
        }

        $has_thumbnail = get_post_meta( $post_id, '_thumbnail_id', true );

        if ( $has_thumbnail ) {
            echo '<span style="color: #46b450; font-weight: bold;">✔ Tiene</span>';
        } else {
            echo '<span style="color: #dc3232; font-weight: bold;">❌ Falta</span> ';
            echo '<button type="button" class="button button-small set-first-img-btn" data-postid="' . esc_attr( $post_id ) . '">Asignar imagen</button>';
            echo '<span class="set-img-status" style="margin-left:5px;"></span>';
        }
    }
}

// 5. Procesar la asignación por AJAX (con fallback a la imagen por defecto)
add_action( 'wp_ajax_set_first_image_as_featured', 'ajax_set_first_image_as_featured' );
function ajax_set_first_image_as_featured() {
    check_ajax_referer( 'set_first_image_nonce', 'nonce' );

    $post_id = isset( $_POST['post_id'] ) ? intval( $_POST['post_id'] ) : 0;
    if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
        wp_send_json_error( 'Sin permisos o ID inválido' );
    }

    if ( get_post_status( $post_id ) === 'draft' ) {
        wp_send_json_error( 'La entrada es un borrador' );
    }

    // =========================================================================
    // CONFIGURACIÓN: Reemplaza esta URL por la URL completa de tu imagen por defecto
    // =========================================================================
    $default_image_url = 'https://tu-dominio.com/wp-content/uploads/imagen-por-defecto.jpg';

    // A. Buscar adjuntos directos al post
    $attachments = get_posts( array(
        'post_type'      => 'attachment',
        'posts_per_page' => 1,
        'post_parent'    => $post_id,
        'post_mime_type' => 'image',
        'orderby'        => 'menu_order',
        'order'          => 'ASC',
        'fields'         => 'ids'
    ) );

    if ( ! empty( $attachments ) ) {
        set_post_thumbnail( $post_id, $attachments[0] );
        wp_send_json_success( '¡Asignada primera!' );
    }

    // B. Si no hay adjuntos, buscar <img> en el contenido
    $post = get_post( $post_id );
    preg_match_all( '/<img.+?src=[\'"]([^\'"]+)[\'"]/i', $post->post_content, $matches );

    if ( isset( $matches[1][0] ) ) {
        $attachment_id = attachment_url_to_postid( $matches[1][0] );
        if ( $attachment_id ) {
            set_post_thumbnail( $post_id, $attachment_id );
            wp_send_json_success( '¡Asignada primera!' );
        }
    }

    // C. Si no hay ninguna imagen en el post, asignar la imagen por defecto
    if ( ! empty( $default_image_url ) ) {
        $default_id = attachment_url_to_postid( $default_image_url );

        if ( $default_id ) {
            set_post_thumbnail( $post_id, $default_id );
            wp_send_json_success( '¡Asignada por defecto!' );
        }
    }

    wp_send_json_error( 'No se encontró ninguna imagen en el post ni ID de fallback' );
}

// 6. Cargar JS y botón masivo en el admin (edit.php)
add_action( 'admin_footer-edit.php', 'custom_featured_ajax_script' );
function custom_featured_ajax_script() {
    $screen = get_current_screen();
    if ( $screen->post_type !== 'post' ) return;
    
    $nonce = wp_create_nonce( 'set_first_image_nonce' );
    ?>
    <script>
    jQuery(document).ready(function($) {
        $('<button type="button" id="process-all-page-btn" class="page-title-action" style="margin-left:10px; background:#2271b1; color:#fff; border-color:#2271b1;">⚡ Asignar todas en esta página</button>')
            .insertAfter('.wp-heading-inline');

        function processButton($btn) {
            return new Promise(function(resolve) {
                var $status = $btn.siblings('.set-img-status');
                var postId = $btn.data('postid');

                $btn.prop('disabled', true).text('Procesando...');

                $.post(ajaxurl, {
                    action: 'set_first_image_as_featured',
                    post_id: postId,
                    nonce: '<?php echo $nonce; ?>'
                }, function(response) {
                    if (response.success) {
                        $btn.parent().html('<span style="color: #46b450; font-weight: bold;">✔ ' + response.data + '</span>');
                    } else {
                        $status.css('color', '#dc3232').text(response.data);
                        $btn.prop('disabled', false).text('Asignar imagen');
                    }
                    resolve();
                }).fail(function() {
                    $btn.prop('disabled', false).text('Error');
                    resolve();
                });
            });
        }

        $(document).on('click', '.set-first-img-btn', function(e) {
            e.preventDefault();
            processButton($(this));
        });

        $('#process-all-page-btn').on('click', async function(e) {
            e.preventDefault();
            var $batchBtn = $(this);
            var $pendingButtons = $('.set-first-img-btn:not(:disabled)');

            if ($pendingButtons.length === 0) {
                alert('No hay entradas pendientes de asignar en esta página.');
                return;
            }

            $batchBtn.prop('disabled', true).text('Procesando por lote...');

            for (var i = 0; i < $pendingButtons.length; i++) {
                await processButton($($pendingButtons[i]));
            }

            $batchBtn.text('¡Lote completado!').css('background', '#46b450');
            setTimeout(function() {
                $batchBtn.prop('disabled', false).text('⚡ Asignar todas en esta página').css('background', '#2271b1');
            }, 3000);
        });
    });
    </script>
    <?php
}

Как се използва?

  • Отидете в списъка „Публикации“ в административния панел.
  • Отворете раздела „Опции за показване“ в горната част и променете броя на елементите, които да се показват, на 50 или 100 на страница. (Започнете с по-малки числа и ги увеличавайте постепенно, ако сървърът ви реагира добре.)

Масово задаване на липсващи избрани изображения в WordPress. Опции за показване

  • Кликнете върху заглавието на колоната „Липсващи отбелязани елементи“, за да сортирате и групирате неотбелязаните записи. Във филтрите можете да изберете между „Има“, „Липсва“ или „Всички“
  • След като сте сигурни, че сте готови да започнете да присвоявате липсващите избрани изображения на групи, кликнете върху синия бутон с надпис „Assign all on this page“ и изчакайте каскадният процес да завърши присвояването на миниатюрите за тази група. Ако предпочитате, можете да ги присвоявате една по една.
  • Преминете на следващата страница и повтаряйте, докато не приключите с подреждането на библиотеката си.

По избор: фрагмент за автоматично присвояване

За да не се налага да повтаряте тази задача в бъдеще, можете да добавите този кратък фрагмент код. Той се изпълнява във фонов режим само когато запазвате или публикувате публикация: ако установи, че не сте избрали ръчно избрана картинка, той автоматично присвоява първата картинка в съдържанието (или резервната картинка по подразбиране, която трябва да добавите в $default_image_url =).

PHP

// Asignar imagen destacada automáticamente al publicar/guardar nuevas entradas
add_action( 'save_post_post', 'auto_set_featured_image_on_save', 10, 3 );
function auto_set_featured_image_on_save( $post_id, $post, $update ) {
    // Evitar autoguardados, revisiones o peticiones AJAX/REST innecesarias
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return;
    if ( wp_is_post_revision( $post_id ) || $post->post_status === 'auto-draft' ) return;

    // Si la entrada ya tiene imagen destacada marcada, no hacemos nada
    if ( has_post_thumbnail( $post_id ) ) return;

    $default_image_url = 'https://tu-dominio.com/wp-content/uploads/imagen-por-defecto.jpg';

    // 1. Buscar primera imagen en el contenido
    preg_match_all( '/<img.+?src=[\'"]([^\'"]+)[\'"]/i', $post->post_content, $matches );

    if ( isset( $matches[1][0] ) ) {
        $attachment_id = attachment_url_to_postid( $matches[1][0] );
        if ( $attachment_id ) {
            set_post_thumbnail( $post_id, $attachment_id );
            return;
        }
    }

    // 2. Si el post no tiene imágenes, asignar la imagen por defecto
    if ( ! empty( $default_image_url ) ) {
        $default_id = attachment_url_to_postid( $default_image_url );
        if ( $default_id ) {
            set_post_thumbnail( $post_id, $default_id );
        }
    }
}

Вашият коментар

Имаш ли нещо да кажеш?

Este blog se aloja en LucusHost

LucusHost, el mejor hosting