
Há alguns dias, concluí uma tarefa que já estava muito atrasada e precisava ser feita, mas que eu vinha adiando há muito tempo.Recuperei todas asimagens em destaque que estavam faltando e adicionei todo o texto alternativo que faltava às imagens. Também terminei de escrever todas as meta descrições que estavam faltando. No total, adicionei ou editei mais de 15.000 registros usando três dos meus próprios snippets exclusivos. Hoje, estou compartilhando aqui o snippet para recuperar as imagens em destaque que estavam faltando, que também usei para realizar essa tarefa em outros sites.
Se você já tem um blog há algum tempo, é bem provável que tenha várias postagens antigas sem uma imagem em destaque atribuída a elas. Isso costumava acontecer bastante na época do editor clássico, quando inseríamos a imagem diretamente no corpo da postagem, mas nos esquecíamos de selecioná-la na caixa “Imagem em destaque”.
Publicar posts sem uma imagem em destaque não é apenas uma questão estética, entre outras coisas; isso afeta diretamente a otimização do seu site e a experiência do usuário:
- SEO nas redes sociais e Open Graph: Ao compartilhar a publicação nas redes sociais, em aplicativos de mensagens ou em agregadores de conteúdo, as tags do Open Graph (
og:image) não conseguem encontrar um recurso claro para exibir, reduzindo drasticamente a CTR (taxa de cliques). - Consistência visual no tema: os modelos modernos (como aqueles criados com o GeneratePress ou o GenerateBlocks) dependem da imagem em destaque para criar grades de arquivo, listas de posts relacionados ou cabeçalhos. Sem ela, o layout fica desestruturado ou apresenta espaços desalinhados.
- Descoberta e feeds (RSS / Google Discover): Ferramentas como o Google Discover ou leitores de RSS priorizam ou exigem que o conteúdo tenha uma miniatura de alta resolução associada para aprimorar o cartão do artigo.
Para resolver isso sem precisar 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 postagem como imagem em destaque, diretamente do painel do WordPress. Se a sua postagem não tiver nenhuma imagem, você pode atribuir uma imagem padrão adicionando a URL dela ao código.
O que exatamente esse trecho de código faz?
O código adiciona uma ferramenta inteligente e integrada de processamento em lote à lista de posts do WordPress (wp-admin/edit.php):
- Adicionar uma coluna personalizada: crie a coluna “Imagemem destaque ausente ” na lista de posts para ver rapidamente quais posts não têm uma miniatura.
- Processamento em três etapas: quando você ativa a atribuição para uma publicação, o sistema procura a imagem exatamente nesta ordem:
- Verifique se há alguma imagem anexada diretamente à postagem na Biblioteca de Mídia.
- Se não houver anexos diretos (por exemplo, se eles tiverem sido inseridos por meio de um bloco de imagem ou HTML), verifique o conteúdo em busca da primeira tag
<img>para extrair seu ID usandoa função attachment_url_to_postid(). - Se a entrada não contiver absolutamente nenhuma imagem, será atribuída uma imagem padrão (de substituição) especificada na configuração.
- Processamento em massa via AJAX (processamento em lote): inclui um botão no cabeçalho (“⚡ Atribuir tudo nesta página”) que processa todas as entradas visíveis na tela em sequência, por meio de solicitações assíncronas consecutivas. Você também pode fazer isso manualmente, usando o botão individual de cada postagem da lista.
- Filtrar rascunhos: exclui automaticamente as entradas com status de rascunho para que você possa se concentrar exclusivamente no conteúdo publicado.
- Coluna classificável: permite classificar a lista de forma que todas as entradas sem imagem em destaque fiquem agrupadas juntas na parte superior.
Por que ele é tão leve e isso não afeta o desempenho do servidor?
Uma preocupação comum ao usar esse tipo de ferramenta automatizada é o receio de bloquear o banco de dados ou sobrecarregar a memória do PHP em sites com milhares de artigos. Este trecho de código foi projetado de acordo com os seguintes critérios de otimização:
1. Só é executado na seção de administração (is_admin())
O código foi desenvolvido exclusivamente para a tela de entrada do painel de administração (edit.php). Ele não adiciona nem mesmo uma linha de sobrecarga às solicitações no site público. Seus usuários e os indicadores de velocidade não serão afetados de forma alguma.
2. Encaminhar consultas ao Meta Cache
Para determinar se uma postagem contém ou não uma imagem, o snippet não realiza pesquisas complexas no banco de dados para cada linha. Ele utiliza a chave de metadados _thumbnail_id, que o WordPress carrega na memória de forma nativa por meio do cache de metadados ao renderizar a lista. A tabela é carregada quase instantaneamente.
3. Processamento assíncrono em cascata (ciclo AJAX sequencial)
Em vez de executar uma consulta massiva no banco de dados para atualizar 700 ou 1.000 entradas de uma só vez (o que causaria um tempo limite excedido ou esgotaria toda a memória do servidor), o botão “Atribuir tudo” processa as entradas uma a uma usando promessas do JavaScript:
POST 1 (AJAX)⟶Resposta OK⟶POST 2 (AJAX)⟶Resposta OK…
Isso garante um uso estável e consistente dos recursos, permitindo que você acompanhe o progresso em tempo real, linha por linha.
4. Sem duplicação de arquivos
O snippet não baixa, não recombina nem duplica imagens no seu disco rígido. Ele simplesmente pega o ID da imagem que já está na sua Biblioteca de Mídia e a vincula à publicação, atribuindo o meta_value correspondente na tabela wp_postmeta.
O código (PHP + JavaScript)
Você pode adicionar esse código ao arquivo functions.php do seu tema filho, a um plugin personalizado ou por meio de um plugin de funções personalizadas, como o Code Snippets ou similar.
Observação: Lembre-se de definir a variável
$default_image_urlna linha 56 com a URL completa da imagem genérica que você deseja atribuir às postagens que não contenham nenhuma imagem 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 se usa isso?
- Acesse a lista “Postagens” no seu painel de administração.
- Abra a guia “Opções de exibição” na parte superior e altere o número de itens a serem exibidos para 50 ou 100 por página. (Comece experimentando números menores e aumente-os gradualmente se o servidor responder bem.)

- Clique no cabeçalho da coluna “Destaques ausentes” para classificar e agrupar os itens pendentes. Nos filtros, você pode escolher entre “Tem”, “Ausente” ou “Todos”
- Quando tiver certeza de que está pronto para começar a atribuir as imagens em destaque que faltam em lotes, clique no botão azul “ ” ( Atribuir todas as imagens em destaque ) com a legenda “Atribuir todas nesta página” e aguarde até que o processo em cascata conclua a atribuição das miniaturas para esse lote. Se preferir, você pode atribuí-las uma a uma.
- Vá para a próxima página e repita o processo até terminar de organizar sua biblioteca.
Opcional: trecho de código para atribuição automática
Para evitar ter que repetir essa tarefa no futuro, você pode adicionar este pequeno trecho de código. Ele é executado em segundo plano apenas quando você salva ou publica um post: se detectar que você não selecionou manualmente uma imagem em destaque, ele atribui automaticamente a primeira imagem do conteúdo (ou a imagem padrão, que você precisará 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 );
}
}
}







