
For noen dager siden fullførte jeg en oppgave som burde vært gjort for lenge siden, men som jeg hadde utsatt i evigheter. Jeghentet inn allede manglende utvalgte bildene og la til all den manglende alt-teksten til bildene. Jeg skrev også ferdig alle de manglende metabeskrivelsene. Totalt la jeg til eller redigerte over 15 000 oppføringer ved hjelp av tre av mine egne engangs-snippets. I dag deler jeg snippetet for å hente de manglende utvalgte bildene her, som jeg også brukte til å utføre denne oppgaven på andre nettsteder.
Hvis du har blogget en stund, er det ganske sannsynlig at du har en del eldre innlegg som ikke har et utvalgt bilde tilordnet seg. Dette skjedde ofte i tiden med den klassiske redigereren, da vi satte inn bildet direkte i selve innlegget, men glemte å velge det i «Utvalgt bilde»-boksen.
Å publisere innlegg uten et utvalgt bilde er ikke bare et estetisk problem, blant annet; det påvirker direkte nettstedets søkemotoroptimalisering og brukeropplevelsen:
- Sosial SEO og Open Graph: Når innlegget deles på sosiale medier, i meldingsapper eller på innholdsaggregatorer, klarer ikke Open Graph-taggene (
og:image) å finne en tydelig kilde å vise, noe som reduserer CTR (klikkfrekvensen) drastisk. - Visuell konsistens i temaet: Moderne maler (for eksempel de som er laget med GeneratePress eller GenerateBlocks) er avhengige av utvalgt bilde for å lage arkivrutenett, lister over relaterte innlegg eller overskrifter. Uten dette bildet blir oppsettet ødelagt, eller det oppstår feiljusterte mellomrom.
- Oppdagelse og nyhetsfeeder (RSS / Google Discover): Verktøy som Google Discover eller RSS-lesere prioriterer eller krever innhold med et tilhørende miniatyrbilde i høy oppløsning for å forbedre artikkelkortet.
For å løse dette uten å måtte ty til plugins (som denne) eller tregtgående prosesser, har jeg laget dette enkle og lette PHP-kodesnippet som automatisk angir det første bildet i hvert innlegg som utvalgt bilde, direkte fra WordPress-dashbordet. Hvis innlegget ditt ikke har noen bilder, kan du angi et standardbilde ved å legge til URL-en til det i koden.
Hva gjør egentlig dette kodestykket?
Koden legger til et smart, innebygd verktøy for batchbehandling i WordPress-innleggslisten (wp-admin/edit.php):
- Legg til en egendefinert kolonne: Opprett kolonnen «Mangler utvalgt bilde» i listen over innlegg for å se med ett blikk hvilke innlegg som mangler et miniatyrbilde.
- 3-trinns behandling: Når du aktiverer oppgaven for et innlegg, søker systemet etter bildet i akkurat denne rekkefølgen:
- Sjekk om det er noen bilder som er lagt ved direkte til innlegget i mediebiblioteket.
- Hvis det ikke finnes noen direkte vedlegg (for eksempel hvis de ble lagt inn via en bildeblokk eller HTML), må du søke gjennom innholdet etter den første
<img>-taggen for å hente ut ID-en ved hjelp avattachment_url_to_postid(). - Hvis oppføringen ikke inneholder noen bilder i det hele tatt, tildeles et standardbilde (reservebilde) som er angitt i konfigurasjonen.
- AJAX-massebehandling (batchbehandling): Inkluderer en knapp i toppteksten («⚡ Tilordne alle på denne siden») som behandler alle oppføringene som er synlige på skjermen i rekkefølge ved hjelp av påfølgende asynkrone forespørsler. Du kan også gjøre dette manuelt ved å bruke den enkelte knappen for hvert innlegg i listen.
- Filtrer utkast: Ekskluderer automatisk innlegg med status «utkast», slik at du kan konsentrere deg utelukkende om publisert innhold.
- Sorterbar kolonne: Lar deg sortere listen slik at alle oppføringer uten utvalgt bilde grupperes sammen øverst.
Hvorfor er den så lett, og påvirker det ikke serverens ytelse?
En vanlig bekymring ved bruk av denne typen automatiserte verktøy er frykten for at databasen skal låse seg eller at PHP-minnet skal bli overbelastet på nettsteder med tusenvis av artikler. Dette kodestykket er utformet i tråd med følgende optimaliseringskriterier:
1. Den kjører kun i administrasjonsdelen (is_admin())
Koden er utelukkende tilpasset innleggsskjermen i administrasjonspanelet (edit.php). Den legger ikke til en eneste linje med ekstra belastning på forespørsler på det offentlige nettstedet. Dette vil ikke påvirke brukerne eller hastighetsmålingene på noen måte.
2. Send forespørsler til Meta Cache
For å avgjøre om et innlegg inneholder et bilde eller ikke, utfører kodebiten ikke komplekse databasesøk for hver enkelt rad. Den bruker metadatanykkelen _thumbnail_id, som WordPress laster inn i minnet direkte via metadatacachen når listen vises. Tabellen lastes inn nesten umiddelbart.
3. Kaskadebasert asynkron behandling (sekvensiell AJAX-sløyfe)
I stedet for å kjøre en omfattende spørring mot databasen for å oppdatere 700 eller 1 000 oppføringer på én gang (noe som ville føre til tidsavbrudd eller tømme serverens minne), behandler «Assign All»-knappen oppføringene én etter én ved hjelp av JavaScript-promises:
POST 1 (AJAX)⟶OK-svar⟶POST 2 (AJAX)⟶OK-svar…
Dette sikrer en stabil og jevn ressursbruk, slik at du kan følge fremdriften i sanntid, rad for rad.
4. Ingen dupliserte filer
Dette kodestykket laster ikke ned, setter sammen på nytt eller dupliserer bilder på harddisken din. Det henter ganske enkelt ID-en til bildet som allerede finnes i mediebiblioteket ditt, og kobler det til innlegget ved å tilordne den tilhørende meta_value-verdien i tabellen wp_postmeta.
Koden (PHP + JavaScript)
Du kan legge til denne koden i filen functions.php i underordnede temaet ditt, i et egendefinert plugin eller via et plugin for egendefinerte funksjoner, for eksempel Code Snippets eller lignende.
Merk: Husk å angi variabelen
$default_image_urlpå linje 56 til den fullstendige URL-adressen til det generiske bildet du ønsker å tilordne til innlegg som ikke inneholder bilder 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 bruker man den?
- Gå til listen «Innlegg» i administrasjonspanelet.
- Åpne fanen «Visningsalternativer» øverst og endre antall elementer som skal vises til 50 eller 100 per side. (Begynn med å prøve lavere tall, og øk dem gradvis hvis serveren din reagerer bra.)

- Klikk på kolonneoverskriften «Manglende høydepunkter» for å sortere og gruppere de utestående oppføringene. I filtrene kan du velge mellom «Har», «Mangler» eller «Alle»
- Når du er sikker på at du er klar til å begynne å tilordne manglende utvalgte bilder i grupper, klikker du på den blå « »- knappen merket «Tilordne alle på denne siden» og lar prosessen fullføre tilordningen av miniatyrbildene for den aktuelle gruppen. Hvis du foretrekker det, kan du tilordne dem ett etter ett.
- Gå til neste side og gjenta dette til du er ferdig med å rydde opp i biblioteket ditt.
Valgfritt: kodebit for automatisk tildeling
For å unngå å måtte gjenta denne oppgaven i fremtiden, kan du legge til dette korte kodestykket. Det kjører i bakgrunnen bare når du lagrer eller publiserer et innlegg: hvis det oppdager at du ikke har valgt et utvalgt bilde manuelt, tilordner det automatisk det første bildet i innholdet (eller standardbilde, som du må legge til 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 );
}
}
}






