
For et par dage siden fik jeg endelig afsluttet en opgave, der længe havde trængt sig på, men som jeg havde udskudt i en evighed. Jeghentede alle demanglende fremhævede billeder og tilføjede al den manglende alt-tekst til billederne. Jeg fik også skrevet alle de manglende metabeskrivelser. I alt tilføjede eller redigerede jeg over 15.000 poster ved hjælp af tre af mine egne engangs-snippets. I dag deler jeg her snippet'et til at hente de manglende featured images, som jeg også har brugt til at udføre denne opgave på andre hjemmesider.
Hvis du har blogget i et stykke tid, er det meget sandsynligt, at du har en del ældre indlæg, hvor der ikke er tildelt et fremhævet billede. Det skete tit i den tid, hvor den klassiske editor var i brug, hvor vi indsatte billedet direkte i selve indlægsteksten, men glemte at markere det i feltet »Fremhævet billede«.
At offentliggøre indlæg uden et fremhævet billede er ikke blot et æstetisk problem, blandt andet; det har direkte indflydelse på din hjemmesides søgemaskineoptimering og brugeroplevelsen:
- Social SEO og Open Graph: Når indlægget deles på sociale medier, i messaging-apps eller på indholdsaggregatorer, kan Open Graph-tags (
og:image) ikke finde en entydig ressource at vise, hvilket reducerer CTR (klikfrekvensen) markant. - Visuelt ensartet udseende i temaet: Moderne skabeloner (f.eks. dem, der er designet med GeneratePress eller GenerateBlocks) er afhængige af det fremhævede billede til at opbygge arkivgitter, lister over relaterede indlæg eller overskrifter. Uden det går layoutet i stykker, eller der opstår uregelmæssige mellemrum.
- Søgning og nyhedsfeeds (RSS / Google Discover): Værktøjer som Google Discover eller RSS-læsere prioriterer eller kræver indhold med en tilhørende miniaturebillede i høj opløsning for at forbedre artikelkortet.
For at løse dette uden at ty til plugins (som f.eks. dette) eller langsomme processer har jeg lavet dette enkle, letvægts PHP-kodestykke, der automatisk indstiller det første billede i hvert indlæg som det fremhævede billede – direkte fra WordPress-kontrolpanelet. Hvis dit indlæg ikke indeholder nogen billeder, kan du tildele et standardbillede ved at tilføje dets URL til koden.
Hvad gør dette kodestykke egentlig?
Koden tilføjer et smart, indbygget værktøj til batchbehandling til WordPress-indlægsoversigten (wp-admin/edit.php):
- Tilføj en brugerdefineret kolonne: Opret kolonnen »Manglende fremhævet billede« i listen over indlæg, så du med et blik kan se, hvilke indlæg der mangler et miniaturebillede.
- 3-trins behandling: Når du aktiverer tildelingen for et indlæg, søger systemet efter billedet i netop denne rækkefølge:
- Kontroller, om der er billeder, der er vedhæftet direkte til indlægget i mediebiblioteket.
- Hvis der ikke er nogen direkte vedhæftede filer (for eksempel hvis de er indsat via en billedblok eller HTML), skal du gennemsøge indholdet efter den første
<img>-tag for at udtrække dens ID ved hjælp afattachment_url_to_postid(). - Hvis indlægget slet ikke indeholder nogen billeder, indsætter den et standardbillede (reservebillede), der er angivet i konfigurationen.
- AJAX-massebehandling (batchbehandling): Indeholder en knap i overskriften („⚡ Tildel alle på denne side“), som behandler alle poster, der er synlige på skærmen, i rækkefølge ved hjælp af på hinanden følgende asynkrone anmodninger. Du kan også gøre dette manuelt ved hjælp af den enkelte knap for hvert indlæg på listen.
- Filtrer udkast: Udelukker automatisk indlæg med status som udkast, så du udelukkende kan fokusere på offentliggjort indhold.
- Sorterbar kolonne: Giver dig mulighed for at sortere listen, så alle poster uden et fremhævet billede samles øverst.
Hvorfor er den så let, og påvirker det ikke serverens ydeevne?
En almindelig bekymring ved brug af denne type automatiserede værktøjer er frygten for, at databasen går i baglås, eller at PHP-hukommelsen bliver overbelastet på hjemmesider med tusindvis af artikler. Dette kodestykke er udformet i overensstemmelse med følgende optimeringskriterier:
1. Det kører kun i administrationsområdet (is_admin())
Koden er udelukkende udviklet til administrationspanelets indtastningsside (edit.php). Den tilføjer ikke en eneste linje ekstra belastning til anmodninger på det offentlige websted. Det vil på ingen måde påvirke dine brugere eller hastighedsmålingerne.
2. Ret forespørgsler til Meta Cache
For at afgøre, om et indlæg indeholder et billede eller ej, foretager uddraget ikke komplekse databasesøgninger for hver enkelt række. Det bruger metadatanøglen _thumbnail_id, som WordPress indlæser direkte i hukommelsen via metadatacachen, når listen vises. Tabellen indlæses næsten øjeblikkeligt.
3. Kaskadebaseret asynkron behandling (sekventiel AJAX-loop)
I stedet for at køre en omfattende forespørgsel i databasen for at opdatere 700 eller 1.000 poster på én gang (hvilket ville medføre en timeout eller opbruge al serverens hukommelse), behandler knappen »Tildel alle« posterne én efter én ved hjælp af JavaScript-promises:
POST 1 (AJAX)⟶OK-svar⟶POST 2 (AJAX)⟶OK-svar…
Dette sikrer en stabil og ensartet udnyttelse af ressourcerne, så du kan følge fremskridtet i realtid, række for række.
4. Ingen dobbeltfiler
Udsnittet henter, sammenfletter eller duplikerer ikke billeder på din harddisk. Det henter blot ID’et for det billede, der allerede findes i dit mediebibliotek, og knytter det til indlægget ved at tildele den tilhørende meta_value i tabellen wp_postmeta.
Koden (PHP + JavaScript)
Du kan indsætte denne kode i filen functions.php i dit underordnet tema, i et brugerdefineret plugin eller via et plugin til brugerdefinerede funktioner, såsom Code Snippets eller lignende.
Bemærk: Husk at indstille variablen
$default_image_urlpå linje 56 til den fulde URL til det generiske billede, som du ønsker at tildele indlæg, der ikke indeholder billeder i teksten.
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
}
Hvordan bruger man det?
- Gå til listen »Indlæg« i dit adminpanel.
- Åbn fanen »Visningsindstillinger« øverst og ændr antallet af elementer, der skal vises, til 50 eller 100 pr. side. (Prøv først med lavere tal, og øg dem gradvist, hvis din server reagerer godt.)

- Klik på kolonneoverskriften »Manglende højdepunkter« for at sortere og gruppere de udestående poster. I filtrene kan du vælge mellem »Har«, »Mangler« eller »Alle«
- Når du er sikker på, at du er klar til at begynde at tildele manglende fremhævede billeder i grupper, skal du klikke på den blå knap med teksten » « (Tildel alle på denne side) og lade den automatiske proces færdiggøre tildelingen af miniaturebillederne for den pågældende gruppe. Hvis du foretrækker det, kan du også tildele dem ét ad gangen.
- Gå til næste side, og gentag, indtil du er færdig med at rydde op i dit bibliotek.
Valgfrit: kodestykke til automatisk tildeling
For at undgå at skulle gentage denne opgave i fremtiden kan du tilføje dette korte kodestykke. Det kører i baggrunden, kun når du gemmer eller offentliggør et indlæg: hvis det registrerer, at du ikke manuelt har valgt et fremhævet billede, tildeler det automatisk det første billede i indholdet (eller standardbilledet, som du skal tilføje i $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 );
}
}
}






