
Prieš keletą dienų baigiau seniai užstrigusią užduotį, kurią reikėjo atlikti, bet kurią atidėliojau amžinybę.Atkūriau visastrūkstamas pagrindines nuotraukas ir pridėjau trūkstamus alternatyvius tekstus prie nuotraukų. Taip pat baigiau rašyti visus trūkstamus metaprašymus. Iš viso, naudodamas tris savo pačio sukurtus vienkartinius kodų fragmentus, pridėjau arba redagavau daugiau nei 15 000 įrašų. Šiandien čia dalinuosi kodų fragmentu, skirtu trūkstamų išskirtinių paveikslėlių atkūrimui, kurį taip pat naudojau atlikdamas šią užduotį kitose svetainėse.
Jei jau kurį laiką rašote tinklaraštį, labai tikėtina, kad turite nemažai senesnių įrašų, kuriems nėra priskirtas pagrindinis paveikslėlis. Tai dažnai pasitaikydavo klasikinio redaktoriaus laikais, kai paveikslėlį įterpdavome tiesiai į įrašo tekstą, bet pamiršdavome jį pažymėti laukelyje „Pagrindinis paveikslėlis“.
Įrašų publikavimas be pagrindinio paveikslėlio yra ne tik estetinė problema, be kita ko; tai tiesiogiai veikia jūsų svetainės optimizavimą ir vartotojo patirtį:
- Socialinis SEO ir „Open Graph“: dalijantis įrašu socialiniuose tinkluose, žinučių programėlėse ar turinio agregatoriuose, „Open Graph“ žymės (
og:image) negali rasti aiškaus šaltinio, kurį būtų galima rodyti, todėl smarkiai sumažėja CTR (paspaudimų santykis). - Temos vizualinis nuoseklumas: Šiuolaikiniai šablonai (pavyzdžiui, sukurti naudojant „GeneratePress“ ar „GenerateBlocks“) remiasi pagrindiniu paveikslėliu, kurdami archyvų lenteles, susijusių įrašų sąrašus ar antraštes. Be jo išdėstymas sutrinka arba atsiranda netolygiai išdėstyti tarpai.
- Atradimas ir naujienų srautai (RSS / „Google Discover“): Tokios priemonės kaip „Google Discover“ ar RSS skaitytuvai teikia pirmenybę arba reikalauja, kad turinys būtų pateikiamas su susijusia aukštos raiškos miniatiūra, siekiant patobulinti straipsnio kortelę.
Norėdamas išspręsti šią problemą nenaudodamas papildinių (pavyzdžiui, šio) ar lėtai veikiančių procesų, sukūriau šį paprastą ir lengvą PHP kodą, kuris automatiškai nustato pirmąjį kiekvieno įrašo paveikslėlį kaip pagrindinį, tiesiogiai iš „WordPress“ valdymo skydo. Jei jūsų įraše nėra jokių paveikslėlių, galite paskirti numatytąjį, įterpdami jo URL adresą į kodą.
Ką tiksliai daro šis kodas?
Šis kodas į „WordPress“ įrašų sąrašą (wp-admin/edit.php) įtraukia išmanų, integruotą paketinio apdorojimo įrankį:
- Pridėti pasirinktinį stulpelį: įrašų sąraše sukurkite stulpelį „Trūksta pagrindinio paveikslėlio“, kad iš pirmo žvilgsnio matytumėte, kuriems įrašams trūksta miniatiūros.
- 3 pakopų apdorojimas: kai įjungiate užduotį įrašui, vaizdas ieškomas būtent tokia tvarka:
- Patikrinkite, ar medijos bibliotekoje yra kokių nors vaizdų, tiesiogiai pridėtų prie įrašo.
- Jei nėra tiesioginių priedų (pavyzdžiui, jei jie buvo įterpti per vaizdo bloką arba HTML), peržiūrėkite turinį, ieškant pirmosios žymės
<img>, kad išgautumėte jos ID naudodamifunkciją attachment_url_to_postid(). - Jei įraše nėra nė vieno paveikslėlio, sistema priskiria konfigūracijoje nurodytą numatytąjį (atsarginį) paveikslėlį.
- AJAX masinis apdorojimas (partijų apdorojimas): Antraštėje yra mygtukas („⚡ Priskirti viską šiame puslapyje“), kuris paeiliui apdoroja visus ekrane matomus įrašus, naudodamas paeiliui siunčiamus asinchroninius užklausimus. Tai taip pat galima padaryti rankiniu būdu, pasinaudojant atskiru mygtuku prie kiekvieno sąrašo įrašo.
- Filtruoti juodraščius: automatiškai pašalina įrašus, kurių būsena yra „juodraštis“, kad galėtumėte sutelkti dėmesį tik į paskelbtą turinį.
- Rūšiuojamas stulpelis: leidžia surūšiuoti sąrašą taip, kad visi įrašai be išskirtinio paveikslėlio būtų sugrupuoti kartu viršuje.
Kodėl jis toks lengvas ir ar tai neturi įtakos serverio našumui?
Dažnai kylantis susirūpinimas naudojant šios rūšies automatizuotas priemones – baimė, kad duomenų bazė gali užstrigti arba PHP atmintis gali būti perkrauta svetainėse, kuriose yra tūkstančiai straipsnių. Šis kodas buvo sukurtas laikantis šių optimizavimo kriterijų:
1. Ji veikia tik „Admin“ skyriuje (is_admin())
Šis kodas yra skirtas išskirtinai administravimo skydo įvesties ekranui (edit.php). Jis neprideda nė vienos papildomos eilutės prie viešosios svetainės užklausų. Tai jokiu būdu neturės įtakos jūsų vartotojams ir greičio rodikliams.
2. Užklausas siųsti į „Meta Cache“
Norėdamas nustatyti, ar įraše yra paveikslėlis, fragmentas neatlieka sudėtingų duomenų bazės paieškų kiekvienai eilutei. Jis naudoja metaduomenų raktą _thumbnail_id, kurį „WordPress“ iš karto įkelia į atmintį per metaduomenų talpyklą, kai atvaizduoja sąrašą. Lentelė įkeliama beveik akimirksniu.
3. Kaskadinis asinchroninis apdorojimas (sekvencinė AJAX kilpa)
Užuot vykdžius didžiulį užklausą duomenų bazėje, kad vienu kartu būtų atnaujinti 700 ar 1 000 įrašų (o tai sukeltų laiko limito pasibaigimą arba išeikvotų visą serverio atmintį), mygtukas „Paskirti visus“ apdoroja įrašus po vieną, naudodamas „JavaScript“ pažadus:
POST 1 (AJAX)⟶Atsakymas „OK“⟶POST 2 (AJAX)⟶Atsakymas „OK“…
Tai užtikrina stabilų ir nuoseklų išteklių naudojimą, leidžiantį stebėti pažangą realiuoju laiku, eilutė po eilutės.
4. Nėra failų dubliavimo
Šis kodas neatsisiunčia, nesujungia ir nekopijuoja vaizdų į jūsų kietąjį diską. Jis tiesiog paima jau jūsų medijų bibliotekoje esančio vaizdo identifikatorių ir susieja jį su įrašu, priskirdamas atitinkamą „meta_value“ reikšmę lentelėje „wp_postmeta“.
Kodas (PHP + JavaScript)
Šį kodą galite įterpti į savo vaiko temos „functions.php“ failą, į pasirinktinį įskiepį arba naudodami pasirinktinį funkcijų įskiepį, pavyzdžiui, „Code Snippets“ ar panašų.
Pastaba: Nepamirškite 56 eilutėje kintamajam
$default_image_urlnustatyti pilną bendrojo paveikslėlio URL adresą, kurį norite priskirti įrašams, kurių tekste nėra jokių paveikslėlių.
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
}
Kaip jį naudoti?
- Eikite į savo administratoriaus skydo sąrašą „Įrašai “.
- Atidarykite viršuje esantį skirtuką „Rodymo parinktys“ ir pakeiskite viename puslapyje rodomų elementų skaičių į 50 arba 100. (Pradėkite nuo mažesnių skaičių ir, jei serveris gerai reaguoja, palaipsniui juos didinkite.)

- Spustelėkite stulpelio „Trūkstami svarbiausi įvykiai“ antraštę, kad surūšiuotumėte ir sugrupuotumėte neapdorotus įrašus. Filtruose galite pasirinkti vieną iš variantų: „Yra“, „Trūksta“ arba „Visi“
- Kai būsite įsitikinę, kad esate pasirengę pradėti priskirti trūkstamus pagrindinius paveikslėlius partijomis, spustelėkite mėlyną mygtuką „ “ su užrašu „Priskirti visus šioje puslapyje“ ir leiskite kaskadiniam procesui užbaigti miniatiūrų priskyrimą tai partijai. Jei pageidaujate, galite juos priskirti po vieną.
- Eikite į kitą puslapį ir kartokite šį veiksmą, kol baigsite tvarkyti savo biblioteką.
Pasirinktinai: automatinio priskyrimo fragmentas
Kad ateityje nereikėtų kartoti šios užduoties, galite įterpti šį trumpą kodą. Jis veikia fone tik tada, kai išsaugote ar paskelbiate įrašą: jei nustato, kad rankiniu būdu nepasirinkote pagrindinio paveikslėlio, automatiškai priskiria pirmąjį paveikslėlį turinyje (arba numatytąjį atsarginį paveikslėlį, kurį turėsite įtraukti į $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 );
}
}
}






