
Acum câteva zile, am finalizat o sarcină pe care trebuia să o fac de mult, dar pe care o amânam de multă vreme. Amrecuperat toateimaginile de prezentare care lipseau și am adăugat textul alternativ care lipsea la toate imaginile. De asemenea, am terminat de scris toate meta-descrierile care lipseau. În total, am adăugat sau editat peste 15.000 de înregistrări folosind trei dintre propriile mele fragmente de cod unice. Astăzi, vă prezint aici fragmentul de cod pentru recuperarea imaginilor de prezentare lipsă, pe care l-am folosit și pentru a realiza această sarcină pe alte site-uri.
Dacă scrii pe blog de ceva vreme, este foarte probabil să ai destul de multe postări mai vechi cărora nu le-a fost atribuită o imagine reprezentativă. Acest lucru se întâmpla destul de des pe vremea editorului clasic, când inseram imaginea direct în corpul postării, dar uitam să o selectăm în caseta „Imagine reprezentativă”.
Publicarea articolelor fără o imagine reprezentativă nu este doar o chestiune de estetică, printre altele; aceasta afectează în mod direct optimizarea site-ului tău și experiența utilizatorului:
- SEO social și Open Graph: Atunci când se distribuie o postare pe rețelele sociale, în aplicațiile de mesagerie sau pe agregatoarele de conținut, etichetele Open Graph (
og:image) nu găsesc o resursă clară pe care să o afișeze, ceea ce reduce drastic rata de clic (CTR). - Coerența vizuală a temei: șabloanele moderne (cum ar fi cele create cu GeneratePress sau GenerateBlocks) se bazează pe imaginea principală pentru a genera grile de arhivă, liste de articole conexe sau anteturi. În absența acesteia, aspectul paginii se dereglează sau apar spații nealiniate.
- Descoperire și fluxuri (RSS / Google Discover): Instrumente precum Google Discover sau cititoarele RSS acordă prioritate sau solicită conținut care are asociată o miniatură de înaltă rezoluție pentru a îmbunătăți aspectul fișei articolului.
Pentru a rezolva această problemă fără a apela la pluginuri (cum ar fi acesta) sau la procese lente, am creat acest fragment de cod PHP simplu și ușor, care setează automat prima imagine din fiecare articol ca imagine reprezentativă, direct din panoul de control WordPress. Dacă articolul tău nu conține nicio imagine, poți atribui una implicită adăugând adresa URL a acesteia în cod.
Ce face mai exact acest fragment de cod?
Codul adaugă un instrument inteligent și integrat de procesare în lot la lista de articole din WordPress (wp-admin/edit.php):
- Adăugați o coloană personalizată: creați coloana „Lipsesc imagini de prezentare ” în lista de articole pentru a vedea dintr-o privire care articole nu au o imagine de prezentare.
- Procesare în 3 etape: Când activezi atribuirea pentru o postare, sistemul caută imaginea exact în această ordine:
- Verifică dacă există imagini atașate direct la postare în Biblioteca media.
- Dacă nu există atașamente directe (de exemplu, dacă au fost inserate printr-un bloc de imagine sau cod HTML), scanează conținutul până la prima etichetă
<img>pentru a-i extrage ID-ul folosindfuncția attachment_url_to_postid(). - Dacă intrarea nu conține absolut nicio imagine, se atribuie o imagine implicită (de rezervă) specificată în configurație.
- Prelucrarea în bloc cu AJAX (prelucrare în lot): Include un buton în antet („⚡ Atribuie toate din această pagină”) care prelucrează toate înregistrările vizibile pe ecran în ordine, folosind solicitări asincrone consecutive. De asemenea, poți face acest lucru manual, folosind butonul individual pentru fiecare postare din listă.
- Filtrare schițe: Exclude automat articolele aflate în stadiul de schiță, astfel încât să te poți concentra exclusiv pe conținutul publicat.
- Coloană sortabilă: vă permite să sortați lista astfel încât toate intrările fără imagine de evidențiere să fie grupate împreună în partea de sus.
De ce este atât de ușor și nu afectează performanța serverului?
O preocupare frecventă atunci când se utilizează acest tip de instrument automatizat este teama de a bloca baza de date sau de a supraîncărca memoria PHP pe site-urile care conțin mii de articole. Acest fragment de cod a fost conceput în conformitate cu următoarele criterii de optimizare:
1. Funcționează numai în secțiunea de administrare (is_admin())
Codul este integrat exclusiv în ecranul de introducere a datelor din panoul de administrare (edit.php). Acesta nu adaugă nicio linie de cod suplimentară la solicitările adresate site-ului public. Utilizatorii dumneavoastră și indicatorii de viteză nu vor fi afectați în niciun fel.
2. Trimiterea interogărilor către Meta Cache
Pentru a stabili dacă o postare conține sau nu o imagine, fragmentul de cod nu efectuează căutări complexe în baza de date pentru fiecare rând. Acesta utilizează cheia de metadate _thumbnail_id, pe care WordPress o încarcă nativ în memorie prin intermediul cache-ului de metadate atunci când afișează lista. Tabelul se încarcă aproape instantaneu.
3. Procesare asincronă în cascadă (buclă AJAX secvențială)
În loc să execute o interogare de amploare în baza de date pentru a actualiza 700 sau 1.000 de înregistrări dintr-o singură mișcare (ceea ce ar provoca depășirea timpului de așteptare sau ar epuiza toată memoria serverului), butonul „Assign All” procesează înregistrările una câte una folosind promisiunile JavaScript:
POST 1 (AJAX)⟶Răspuns OK⟶POST 2 (AJAX)⟶Răspuns OK…
Acest lucru asigură o utilizare stabilă și consecventă a resurselor, permițându-vă să urmăriți progresul în timp real, rând cu rând.
4. Fără duplicarea fișierelor
Acest fragment de cod nu descarcă, nu recombinează și nu duplică imaginile de pe hard disk-ul tău. Pur și simplu preia ID-ul imaginii care se află deja în biblioteca ta media și o leagă de articol prin atribuirea valorii meta_value corespunzătoare în tabelul wp_postmeta.
Codul (PHP + JavaScript)
Puteți adăuga acest cod în fișierul functions.php al temei dvs. derivate, într-un plugin personalizat sau prin intermediul unui plugin de funcții personalizate, cum ar fi Code Snippets sau altele similare.
Notă: Nu uitați să setați variabila
$default_image_urlde la rândul 56 cu adresa URL completă a imaginii generice pe care doriți să o atribuiți postărilor care nu conțin imagini în text.
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
}
Cum se folosește?
- Accesați lista „Postări” din panoul de administrare.
- Deschideți fila „Opțiuni de afișare” din partea de sus și modificați numărul de elemente afișate la 50 sau 100 pe pagină. (Începeți cu numere mai mici și măriți-le treptat dacă serverul răspunde bine.)

- Faceți clic pe antetul coloanei „Elementele marcate ca lipsă” pentru a sorta și a grupa înregistrările restante. În filtre, puteți alege între „Are”, „Lipsă” sau „Toate”
- Odată ce ești sigur că ești pregătit să începi să aloci în bloc imaginile de prezentare lipsă, dă clic pe butonul albastru „ ” ( Alocă toate imaginile de prezentare) intitulat „Assign all on this page” (Alocă toate de pe această pag ină ) și lasă procesul în cascadă să finalizeze alocarea miniaturilor pentru acel lot. Dacă preferi, le poți aloca una câte una.
- Treceți la pagina următoare și repetați procedura până când terminați de organizat biblioteca.
Opțional: fragment de cod pentru atribuire automată
Pentru a evita repetarea acestei operațiuni în viitor, poți adăuga acest fragment scurt de cod. Acesta rulează în fundal doar atunci când salvați sau publicați o postare: dacă detectează că nu ați selectat manual o imagine reprezentativă, atribuie automat prima imagine din conținut (sau imaginea implicită de rezervă, pe care va trebui să o adăugați în $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 );
}
}
}






