
Muutama päivä sitten sain valmiiksi tehtävän, joka oli jo kauan ollut tekemättä, mutta jota olin lykännyt ikuisuuden.Haitoin kaikkipuuttuvat esikuvakuvat ja lisäsin kuviin kaikki puuttuvat alt-tekstit. Kirjoitin myös valmiiksi kaikki puuttuvat metakuvaukset. Yhteensä lisäsin tai muokkasin yli 15 000 tietuetta käyttämällä kolmea omaa kertakäyttöistä koodinpätkääni. Tänään jaan täällä koodinpätkän, jolla haetaan puuttuvat esikuvat – käytin sitä myös tämän tehtävän suorittamiseen muilla sivustoilla.
Jos olet blogannut jo jonkin aikaa, on varsin todennäköistä, että sinulla on melko paljon vanhempia kirjoituksia, joille ei ole määritetty esikuvakuvaa. Tämä tapahtui usein klassisen editorin aikoina, kun lisäsimme kuvan suoraan kirjoituksen tekstiosaan, mutta unohdimme valita sen ”Esikuvakuvaksi” -kentässä.
Artikkelien julkaiseminen ilman esikatselukuvaa ei ole pelkästään esteettinen kysymys, vaan se vaikuttaa suoraan sivustosi hakukoneoptimointiin ja käyttökokemukseen:
- Sosiaalinen hakukoneoptimointi ja Open Graph: Kun julkaisua jaetaan sosiaalisessa mediassa, viestisovelluksissa tai sisältökokoajissa, Open Graph -tunnisteet (
og:image) eivät löydä selkeää lähdettä, jota voitaisiin näyttää, mikä laskee klikkausprosenttia (CTR) huomattavasti. - Teeman visuaalinen yhtenäisyys: Nykyaikaiset mallipohjat (kuten GeneratePress- tai GenerateBlocks-ohjelmilla suunnitellut) hyödyntävät esikuvakuvaa arkistoruudukkojen, aiheeseen liittyvien artikkeleiden luetteloiden tai otsikoiden muodostamisessa. Ilman sitä asettelu menee sekaisin tai siihen jää epätasaisia aukkoja.
- Löydettävyys ja syötteet (RSS / Google Discover): Google Discoverin tai RSS-lukijoiden kaltaiset työkalut suosivat tai edellyttävät, että sisältöön liitetään korkean resoluution pikkukuva artikkelikortin ulkoasun parantamiseksi.
Jotta tämä asia saataisiin hoidettua ilman lisäosia (kuten tätä) tai hitaita prosesseja, olen luonut tämän yksinkertaisen ja kevyen PHP-koodinpätkän, joka asettaa automaattisesti kunkin artikkelin ensimmäisen kuvan esikuvaksi suoraan WordPress-hallintapaneelista. Jos artikkelissasi ei ole kuvia, voit määrittää oletuskuvan lisäämällä sen URL-osoitteen koodiin.
Mitä tämä koodinpätkä tarkalleen ottaen tekee?
Koodi lisää WordPressin artikkeliluetteloon (wp-admin/edit.php) kätevän, sisäänrakennetun eräkäsittelytyökalun:
- Lisää mukautettu sarake: Luo ”Puuttuva esikatselukuva ” -sarake artikkeliluetteloon, jotta näet yhdellä silmäyksellä, mistä artikkeleista puuttuu esikatselukuva.
- 3-vaiheinen käsittely: Kun otat tehtävän käyttöön tietyn julkaisun kohdalla, se etsii kuvaa juuri tässä järjestyksessä:
- Tarkista, onko mediakirjastossa viestiin suoraan liitettyjä kuvia.
- Jos suoria liitteitä ei ole (esimerkiksi jos ne on lisätty kuvalohkon tai HTML-koodin kautta), etsi sisällöstä ensimmäinen
<img>-tagi ja poimi sen tunniste käyttämälläattachment_url_to_postid()-funktiota. - Jos merkinnässä ei ole lainkaan kuvia, järjestelmä käyttää määrityksissä määritettyä oletuskuvaa (varakuvaa).
- AJAX-joukkokäsittely (eräkäsittely): Otsikossa on painike (”⚡ Määritä kaikki tällä sivulla”), joka käsittelee kaikki näytöllä näkyvät merkinnät peräkkäin käyttämällä peräkkäisiä asynkronisia pyyntöjä. Voit tehdä tämän myös manuaalisesti käyttämällä luettelossa olevan kunkin viestin omaa painiketta.
- Suodata luonnokset: Poistaa automaattisesti luonnosvaiheessa olevat merkinnät, jotta voit keskittyä yksinomaan julkaistuun sisältöön.
- Lajiteltava sarake: Tämän avulla voit lajitella luettelon niin, että kaikki merkintät, joissa ei ole esikuvakuvaa, ryhmitellään yhteen luettelon yläosaan.
Miksi se on niin kevyt, eikä se vaikuta palvelimen suorituskykyyn?
Tämän tyyppisiä automatisoituja työkaluja käytettäessä yleinen huolenaihe on pelko siitä, että tietokanta jumiutuu tai PHP:n muisti ylikuormittuu sivustoilla, joilla on tuhansia artikkeleita. Tämä koodinpätkä on suunniteltu seuraavien optimointikriteerien mukaisesti:
1. Se toimii vain Admin-osiossa (is_admin())
Koodi on suunniteltu yksinomaan hallintapaneelin syöttöruudulle (edit.php). Se ei lisää yhtään ylimääräistä riviä julkisen sivuston pyyntöihin. Se ei vaikuta millään tavalla käyttäjiisi tai sivuston nopeusmittareihin.
2. Ohjaa kyselyt Meta-välimuistiin
Sen selvittämiseksi, sisältääkö viesti kuvan vai ei, koodinpätkä ei suorita monimutkaisia tietokantahakuja jokaiselle riville. Se käyttää _thumbnail_id-metatietoa, jonka WordPress lataa suoraan muistiin metatietovälimuistin kautta luetteloa renderöidessään. Taulukko latautuu lähes välittömästi.
3. Asynkronisen käsittelyn kaskadointi (peräkkäinen AJAX-silmukka)
Sen sijaan, että tietokannassa suoritettaisiin valtava kysely 700 tai 1 000 tietueen päivittämiseksi kerralla (mikä aiheuttaisi aikakatkaisun tai kuluttaisi kaiken palvelimen muistin), ”Assign All” -painike käsittelee tietueet yksi kerrallaan JavaScript-lupauksien avulla:
POST 1 (AJAX)⟶OK-vastaus⟶POST 2 (AJAX)⟶OK-vastaus…
Tämä takaa resurssien vakaan ja johdonmukaisen käytön, minkä ansiosta voit seurata edistymistä reaaliajassa rivi riviltä.
4. Tiedostoja ei saa olla kahdesti
Lisäosa ei lataa, yhdistä uudelleen tai kopioi kuvia kiintolevyllesi. Se vain poimii mediakirjastossasi jo olevan kuvan tunnisteen ja linkittää sen julkaisuun määrittämällä vastaavan meta_value-arvon wp_postmeta-taulukko on.
Koodi (PHP + JavaScript)
Voit lisätä tämän koodin child-teemasi functions.php-tiedostoon, mukautettuun laajennukseen tai mukautettujen toimintojen laajennuksen, kuten Code Snippetsin tai vastaavan, kautta.
Huomautus: Muista asettaa rivillä 56 oleva
$default_image_url-muuttujasen yleiskuvan täydelliseksi URL-osoitteeksi, jonka haluat liittää viesteihin, joiden tekstissä ei ole kuvia.
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
}
Miten sitä käytetään?
- Siir ry hallintapaneelin ”Julkaisut”-luetteloon.
- Avaa yläreunassa oleva ”Näytön asetukset” -välilehti ja muuta sivulla näytettävien kohteiden määräksi 50 tai 100. (Kokeile aluksi pienempiä lukuja ja lisää niitä vähitellen, jos palvelimesi toimii hyvin.)

- Napsauta ”Puuttuvat kohokohdat” -sarakkeen otsikkoa lajitellaksesi ja ryhmitelläksesi käsittelemättömät merkinnät. Suodattimissa voit valita vaihtoehdoista ”Sisältää”, ”Puuttuu” tai ”Kaikki”
- Kun olet varma, että olet valmis aloittamaan puuttuvien esikatselukuvien määrittämisen erissä, napsauta sinistä ” ” -painiketta, jossa lukee ”Määritä kaikki tällä sivulla”, ja anna prosessin suorittaa kyseisen erän esikatselukuvien määrittäminen loppuun. Halutessasi voit määrittää ne myös yksi kerrallaan.
- Siirry seuraavalle sivulle ja toista tätä, kunnes olet saanut kirjastosi siivouksen valmiiksi.
Valinnainen: automaattisen osoituksen koodinpätkä
Jotta sinun ei tarvitse toistaa tätä tehtävää tulevaisuudessa, voit lisätä tämän lyhyen koodinpätkän. Se toimii taustalla vain silloin, kun tallennat tai julkaiset artikkelin: jos se havaitsee, ettet ole valinnut esikuvakuvaksi mitään manuaalisesti, se määrittää automaattisesti sisällön ensimmäisen kuvan (tai oletuskuvan, jonka sinun on lisättävä kohtaan $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 );
}
}
}






