
Mõni päev tagasi viisin lõpule ühe ammu tegemist vajava ülesande, mida olin juba kaua edasi lükanud.Täiendasin kõikpuuduvad esilehe pildid ja lisasin piltidele kõik puuduvad alt-tekstid. Samuti kirjutasin valmis kõik puuduvad meta-kirjeldused. Kokku lisasin või muutsin üle 15 000 kirje, kasutades kolme enda loodud ühekordset koodijuppi. Täna jagan siin koodijuppi puuduvate esilehe piltide taastamiseks, mida kasutasin ka selle ülesande täitmiseks teistel veebisaitidel.
Kui oled juba mõnda aega bloginud, on üsna tõenäoline, et sul on päris palju vanemaid postitusi, millele pole esilehepilti määratud. Seda juhtus varem klassikalise toimetaja ajal tihti, kui lisasime pildi otse postituse teksti sisse, kuid unustasime selle „Esilehe pilt” lahtris valida.
Postituste avaldamine ilma esilehe pildita ei ole muu hulgas mitte ainult esteetiline probleem, vaid see mõjutab otseselt ka teie veebisaidi optimeerimist ja kasutajakogemust:
- Sotsiaalmeedia-SEO ja Open Graph: kui postitust jagatakse sotsiaalmeedias, sõnumirakendustes või sisu koondajates, ei leia Open Graph’i sildid (
og:image) kuvamiseks sobivat allikat, mis vähendab oluliselt klõpsamismäära (CTR). - Teema visuaalne ühtsus: kaasaegsed mallid (näiteks GeneratePressi või GenerateBlocki abil loodud mallid) tuginevad esile tõstetud pildile arhiivivõrgustike, seotud postituste nimekirjade või pealkirjade koostamisel. Ilma selle pildita läheb paigutus sassi või tekivad valesti paigutatud tühikud.
- Avastamine ja uudisvood (RSS / Google Discover): Sellised tööriistad nagu Google Discover või RSS-lugejad eelistavad või nõuavad sisu, millele on lisatud kõrge resolutsiooniga pisipilt, et artikli kaarti paremini esile tuua.
Et seda probleemi lahendada ilma pistikprogrammide (nagu näiteks see) või aeglaste protsessideta, olen loonud selle lihtsa ja kerge PHP-koodijupi, mis määrab iga postituse esimese pildi automaatselt esilehe pildiks otse WordPressi juhtpaneelist. Kui su postitusel pole ühtegi pilti, saad määrata vaikimisi pildi, lisades selle URL-i koodi.
Mida see koodilõik täpselt teeb?
Kood lisab WordPressi postituste nimekirja (wp-admin/edit.php) nutika sisseehitatud partii-töötlemise tööriista:
- Kohandatud veeru lisamine: Loo postituste loendis veerg „Puuduv esilehe pilt”, et näha ühe pilguga, millistel postitustel puudub pisipilt.
- 3-astmeline töötlemine: kui lülitad postituse jaoks ülesande sisse, otsitakse pilti just selles järjekorras:
- Kontrollige, kas meediakogus on postitusele otse lisatud pilte.
- Kui otseseid manuseid pole (näiteks kui need lisati pildibloki või HTML-i kaudu), otsi sisust esimest
<img>-märget, et eraldada selle ID funktsiooniattachment_url_to_postid()abil. - Kui kirje ei sisalda ühtegi pilti, määratakse sellele konfiguratsioonis määratud vaikimisi (asenduspilt).
- AJAXi hulgitöötlus (partiitöötlus): Pealkirjas on nupp („⚡ Määra kõik sellel lehel”), mis töötleb järjest kõik ekraanil nähtavad kanded järjestikuste asünkroonsete päringute abil. Seda saab teha ka käsitsi, kasutades nimekirjas iga postituse juures olevat eraldi nuppu.
- Eelvaadete filtreerimine: välistab automaatselt eelnõu staatuses olevad kirjed, et saaksid keskenduda ainult avaldatud sisule.
- Sorteeritav veerg: võimaldab nimekirja sorteerida nii, et kõik kirjed, millel puudub esilehe pilt, rühmitatakse ülesossa.
Miks on see nii kerge ja kas see ei mõjuta serveri jõudlust?
Sellise automatiseeritud tööriista kasutamisel tekitab sageli muret hirm, et andmebaas võib ummistuda või PHP-mälu ülekoormuda veebisaitidel, kus on tuhandeid artikleid. See koodilõik on koostatud järgmiste optimeerimiskriteeriumide alusel:
1. See töötab ainult haldusosas (is_admin())
Kood on loodud eranditult halduspaneli sisestusekraani (edit.php) jaoks. See ei lisa avalikule veebisaidile saadetavatele päringutele ühtegi liigset rida. See ei mõjuta mingil viisil teie kasutajaid ega kiirusnäitajaid.
2. Suunake päringud Meta Cache’i
Selleks et kindlaks teha, kas postitus sisaldab pilti või mitte, ei tee koodijupp iga rea puhul keerukaid andmebaasiotsinguid. Selle asemel kasutatakse metaandmete võtit _thumbnail_id, mille WordPress laadib nimekirja kuvamisel vahetult mällu metaandmete vahemälu kaudu. Tabel laaditakse peaaegu koheselt.
3. Kaskadiline asünkroonne töötlemine (järjestikune AJAX-tsükkel)
Selle asemel, et teha andmebaasis mahukas päring 700 või 1000 kirje ühekorraga uuendamiseks (mis põhjustaks ajalõpu või tarbiks ära kogu serveri mälu), töötleb nupp „Assign All” kirjed ükshaaval, kasutades JavaScripti lubadusi:
POST 1 (AJAX)⟶OK-vastus⟶POST 2 (AJAX)⟶OK-vastus…
See tagab ressursside stabiilse ja järjepideva kasutamise, võimaldades teil jälgida edusamme reaalajas, rida-realt.
4. Failide dubleerimist ei toimu
See koodilõik ei lae alla, ei ühenda ega kopeeri pilte teie kõvakettale. See võtab lihtsalt teie meediakogus juba oleva pildi ID ja seob selle postitusega, määrates vastava meta_value väärtuse tabelisse wp_postmeta.
Kood (PHP + JavaScript)
Võid lisada selle koodi oma alateema faili functions.php, kohandatud pistikprogrammi või kasutada selleks mõnda kohandatud funktsioonide pistikprogrammi, näiteks Code Snippets või mõnda sarnast.
Märkus: Ära unusta määrata 56. real muutuja
$default_image_urlväärtuseks selle üldpildi täielik URL-aadress, mida soovid määrata postitustele, mille tekstis pole ühtegi pilti.
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
}
Kuidas seda kasutada?
- Mine oma halduspanelis loendisse „Postitused ”.
- Ava ülaosas asuv vahekaart „Kuvamisvalikud” ja muuda leheküljel kuvatavate kirjetearv 50-le või 100-le. (Alusta väiksemate arvudega ja suurenda neid järk-järgult, kui server reageerib hästi.)

- Klõpsake veeru pealkirjal „Puuduvad tähtsündmused”, et sorteerida ja rühmitada veel käsitlemata kirjed. Filtrites saate valida valikute „On”, „Puudub” või „Kõik” vahel.
- Kui oled kindel, et oled valmis puuduvate esilehe piltide määramist partiidena alustama, klõpsa sinist nuppu „ ”, millel on märge „Assign all on this page”, ja lase kaskaadprotsessil lõpetada selle partii pisipiltide määramine. Kui soovid, võid neid määrata ka ükshaaval.
- Mine järgmisele lehele ja korda seda, kuni oled raamatukogu korrastamise lõpetanud.
Valikuline: automaatne määramise koodijupp
Et vältida selle ülesande kordamist tulevikus, võid lisada selle lühikese koodijupi. See töötab taustal ainult siis, kui salvestate või avaldate postituse: kui see tuvastab, et te pole käsitsi esile tõstetud pilti valinud, määrab see automaatselt sisu esimese pildi (või vaikimisi asenduspildi, mille peate lisama $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 );
}
}
}






