Atribuir em massa imagens em destaque em falta no WordPress

No comments

05.09.2026|

No comments

Tiempo de lectura Lectura: 13 min, 37 s
Número de palabras Palabras: 2521
Número de visitas Visitas: 11
Icono de traducción
Atribuir em massa as imagens em destaque que faltam no WordPress. Uma lista que mostra tanto as que faltam como as que já existem.

Há alguns dias, terminei uma tarefa que já devia ter sido feita há muito tempo, mas que andava a adiar há imenso tempo.Recuperei todas asimagens em destaque que faltavam e adicionei todo o texto alternativo que faltava às imagens. Também terminei de escrever todas as meta-descrições que faltavam. No total, adicionei ou editei mais de 15 000 registos utilizando três dos meus próprios snippets personalizados. Hoje, vou partilhar aqui o snippet para recuperar as imagens em destaque que faltavam, que também utilizei para realizar esta tarefa noutros sites.

Se já escreves no blogue há algum tempo, é bastante provável que tenhas várias publicações mais antigas sem uma imagem em destaque atribuída. Isto costumava acontecer com frequência na época do editor clássico, quando inseríamos a imagem diretamente no corpo da publicação, mas nos esquecíamos de a selecionar na caixa «Imagem em destaque».

Publicar artigos sem uma imagem em destaque não é apenas uma questão estética, entre outras coisas; afeta diretamente a otimização do seu site e a experiência do utilizador:

  1. SEO nas redes sociais e Open Graph: Ao partilhar a publicação nas redes sociais, em aplicações de mensagens ou em agregadores de conteúdos, as etiquetas Open Graph (og:image) não conseguem encontrar um recurso claro para apresentar, o que reduz drasticamente a CTR (taxa de cliques).
  2. Consistência visual no tema: os modelos modernos (como os criados com o GeneratePress ou o GenerateBlocks) dependem da imagem em destaque para criar grelhas de arquivo, listas de publicações relacionadas ou cabeçalhos. Sem ela, o layout fica desestruturado ou apresenta espaços desalinhados.
  3. Descoberta e feeds (RSS / Google Discover): Ferramentas como o Google Discover ou os leitores de RSS dão prioridade ou exigem conteúdos com uma miniatura de alta resolução associada, para melhorar a apresentação do artigo.

Para resolver isto sem recorrer a plugins (como este) ou a processos lentos, criei este trecho de código PHP simples e leve que define automaticamente a primeira imagem de cada publicação como imagem em destaque, diretamente a partir do painel de controlo do WordPress. Se a sua publicação não tiver imagens, pode atribuir uma imagem por predefinição adicionando o respetivo URL ao código.

O que é que este trecho de código faz, exatamente?

O código adiciona uma ferramenta inteligente e integrada de processamento em lote à lista de publicações do WordPress (wp-admin/edit.php):

  • Adicionar uma coluna personalizada: Crie a coluna «Imagemem destaque em falta » na lista de publicações para ver rapidamente quais as publicações que não têm uma miniatura.
  • Processamento em 3 etapas: Quando ativas a atribuição para uma publicação, o sistema procura a imagem exatamente nesta ordem:
    1. Verifique se existem imagens anexadas diretamente à publicação na Biblioteca de Multimédia.
    2. Se não houver anexos diretos (por exemplo, se tiverem sido inseridos através de um bloco de imagem ou de código HTML), analise o conteúdo à procura da primeira tag <img> para extrair o seu ID utilizando a função attachment_url_to_postid().
    3. Se a entrada não contiver absolutamente nenhuma imagem, é atribuída uma imagem predefinida (de substituição) especificada na configuração.
  • Processamento em massa com AJAX (processamento em lote): Inclui um botão no cabeçalho («⚡ Atribuir tudo nesta página») que processa todas as entradas visíveis no ecrã em sequência, utilizando pedidos assíncronos consecutivos. Também é possível fazer isto manualmente, utilizando o botão individual para cada publicação da lista.
  • Filtrar rascunhos: exclui automaticamente as entradas com o estado «rascunho», para que se possa concentrar exclusivamente no conteúdo publicado.
  • Coluna ordenável: Permite ordenar a lista de forma a que todas as entradas sem imagem em destaque fiquem agrupadas no topo.

Porque é que é tão leve e isso não afeta o desempenho do servidor?

Uma preocupação comum ao utilizar este tipo de ferramenta automatizada é o receio de bloquear a base de dados ou sobrecarregar a memória do PHP em sites com milhares de artigos. Este fragmento de código foi concebido de acordo com os seguintes critérios de otimização:

1. Só funciona na secção de administração (is_admin())

O código foi concebido exclusivamente para o ecrã de introdução de dados do painel de administração (edit.php). Não acrescenta uma única linha de sobrecarga às solicitações no site público. Os seus utilizadores e os indicadores de velocidade não serão afetados de forma alguma.

2. Enviar consultas diretamente para o Meta Cache

Para determinar se uma publicação contém ou não uma imagem, o snippet não realiza pesquisas complexas na base de dados para cada linha. Utiliza a chave de metadados _thumbnail_id, que o WordPress carrega na memória de forma nativa através da cache de metadados ao apresentar a lista. A tabela carrega quase instantaneamente.

3. Processamento assíncrono em cascata (ciclo AJAX sequencial)

Em vez de executar uma consulta de grande dimensão na base de dados para atualizar 700 ou 1 000 entradas de uma só vez (o que provocaria um tempo limite ou esgotaria toda a memória do servidor), o botão «Atribuir tudo» processa as entradas uma a uma utilizando promessas JavaScript:

POST 1 (AJAX)⟶Resposta OK⟶POST 2 (AJAX)⟶Resposta OK…

Isto garante uma utilização estável e consistente dos recursos, permitindo-lhe acompanhar o progresso em tempo real, linha a linha.

4. Sem duplicação de ficheiros

O snippet não descarrega, não recombina nem duplica imagens no seu disco rígido. Limita-se a obter o ID da imagem que já se encontra na sua Biblioteca Multimédia e a associá-la à publicação, atribuindo o meta_value correspondente na tabela wp_postmeta.

O código (PHP + JavaScript)

Pode adicionar este código ao ficheiro functions.php do seu tema filho, a um plugin personalizado ou através de um plugin de funções personalizadas, como o Code Snippets ou similar.

Nota: Lembre-se de definir a variável $default_image_url, na linha 56, com o URL completo da imagem genérica que pretende atribuir às publicações que não contenham imagens no texto.

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
}

Como é que se usa?

  • Aceda à lista «Publicações» no seu painel de administração.
  • Abra o separador «Opções de visualização» na parte superior e altere o número de itens a apresentar para 50 ou 100 por página. (Comece por experimentar números mais baixos e aumente-os gradualmente se o servidor responder bem.)

Atribuir em massa imagens em destaque em falta no WordPress. Opções de visualização

  • Clique no cabeçalho da coluna «Destaques em falta» para ordenar e agrupar as entradas pendentes. Nos filtros, pode escolher entre «Tem», «Em falta» ou «Todos»
  • Quando tiver a certeza de que está pronto para começar a atribuir as imagens em destaque em falta em lotes, clique no botão azul « » com a indicação «Atribuir todas nesta página» e deixe que o processo em cascata conclua a atribuição das miniaturas desse lote. Se preferir, pode atribuí-las uma a uma.
  • Passe para a página seguinte e repita o processo até ter terminado de organizar a sua biblioteca.

Opcional: trecho de código para atribuição automática

Para evitar ter de repetir esta tarefa no futuro, pode adicionar este pequeno trecho de código. Este código é executado em segundo plano apenas quando guardas ou publicas um artigo: se detetar que não selecionaste manualmente uma imagem em destaque, atribui automaticamente a primeira imagem do conteúdo (ou a imagem de reserva predefinida, que terás de adicionar em $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 );
        }
    }
}

Deixe um comentário

Há alguma coisa a dizer?

Este blog se aloja en LucusHost

LucusHost, el mejor hosting