Masslägg till saknade utvalda bilder i WordPress

Inga kommentarer

05.09.2026|

Inga kommentarer

Tiempo de lectura Lectura: 13 min, 27 s
Número de palabras Palabras: 2491
Número de visitas Visitas: 11
Icono de traducción
Lägg till saknade utvalda bilder i bulk i WordPress. En lista som visar både de som saknas och de som redan finns.

För några dagar sedan avslutade jag en uppgift som jag borde ha gjort för länge sedan, men som jag hade skjutit upp i evigheter. Jaghämtade allasaknade utvalda bilder och lade till all saknad alt-text till bilderna. Jag skrev också klart alla saknade metabeskrivningar. Totalt lade jag till eller redigerade över 15 000 poster med hjälp av tre av mina egna engångs-snippets. Idag delar jag med mig av snippet för att hämta de saknade utvalda bilderna här, vilket jag också använde för att utföra denna uppgift på andra webbplatser.

Om du har bloggat ett tag är det ganska troligt att du har en hel del äldre inlägg som saknar en utvald bild. Det här hände ofta förr i tiden med den klassiska redigeraren, när vi infogade bilden direkt i själva inlägget men glömde att markera den i rutan ”Utvalda bilder”.

Att publicera inlägg utan en utvald bild är inte bara en estetisk fråga, bland annat; det påverkar direkt din webbplats optimering och användarupplevelsen:

  1. Social SEO och Open Graph: När inlägget delas på sociala medier, i meddelandeappar eller på innehållsaggregatorer kan Open Graph-taggarna (og:image) inte hitta någon tydlig källa att visa, vilket drastiskt minskar CTR (klickfrekvensen).
  2. Visuell enhetlighet i temat: Moderna mallar (t.ex. sådana som skapats med GeneratePress eller GenerateBlocks) är beroende av den utvalda bilden för att skapa arkivrutnät, listor över relaterade inlägg eller rubriker. Utan den blir layouten felaktig eller uppstår feljusterade mellanrum.
  3. Upptäckt och flöden (RSS / Google Discover): Verktyg som Google Discover eller RSS-läsare prioriterar eller kräver innehåll med en tillhörande högupplöst miniatyrbild för att förbättra artikelkortet.

För att lösa detta utan att behöva använda plugins (som till exempel det här) eller långsamma processer har jag skapat detta enkla och smidiga PHP-kodavsnitt som automatiskt ställer in den första bilden i varje inlägg som utvald bild, direkt från WordPress-instrumentpanelen. Om ditt inlägg inte innehåller några bilder kan du ange en standardbild genom att lägga till dess URL i koden.

Vad gör egentligen den här kodsnuttan?

Koden lägger till ett smart, inbyggt verktyg för batchbearbetning i WordPress-inläggslistan (wp-admin/edit.php):

  • Lägg till en anpassad kolumn: Skapa kolumnen ”Saknad utvald bild” i listan över inlägg för att snabbt kunna se vilka inlägg som saknar en miniatyrbild.
  • 3-stegsbehandling: När du aktiverar tilldelningen för ett inlägg söker systemet efter bilden i exakt följande ordning:
    1. Kontrollera om det finns några bilder som är direkt bifogade till inlägget i mediebiblioteket.
    2. Om det inte finns några direkta bilagor (till exempel om de har infogats via ett bildblock eller HTML), sök igenom innehållet efter den första <img> -taggen för att hämta dess ID med hjälp av attachment_url_to_postid().
    3. Om posten inte innehåller några bilder alls tilldelas den en standardbild (reservbild) som anges i konfigurationen.
  • AJAX-massbearbetning (batchbearbetning): Innehåller en knapp i sidhuvudet (”⚡ Tilldela alla på denna sida”) som bearbetar alla poster som syns på skärmen i tur och ordning med hjälp av på varandra följande asynkrona förfrågningar. Du kan också göra detta manuellt med hjälp av den enskilda knappen för varje inlägg i listan.
  • Filtrera utkast: Utesluter automatiskt inlägg som har statusen ”utkast”, så att du kan fokusera enbart på publicerat innehåll.
  • Sorterbar kolumn: Gör det möjligt att sortera listan så att alla poster utan utvald bild grupperas tillsammans högst upp.

Varför är den så lättviktig, och påverkar det inte serverns prestanda?

En vanlig oro när man använder den här typen av automatiserade verktyg är rädslan för att databasen ska låsa sig eller att PHP-minnet ska överbelastas på webbplatser med tusentals artiklar. Det här kodavsnittet har utformats i enlighet med följande optimeringskriterier:

1. Den körs endast i administratörsdelen (is_admin())

Koden är utformad enbart för inmatningssidan i administrationspanelen (edit.php). Den lägger inte till en enda rad extra kod i förfrågningarna på den offentliga webbplatsen. Dina användare och hastighetsmätningarna påverkas inte på något sätt.

2. Skicka förfrågningar direkt till metacachen

För att avgöra om ett inlägg innehåller en bild eller inte utför kodsnuttet inga komplexa databassökningar för varje rad. Det använder metadatanyckeln _thumbnail_id, som WordPress laddar in i minnet direkt via metadatacachen när listan renderas. Tabellen laddas nästan omedelbart.

3. Kaskadformad asynkron bearbetning (sekventiell AJAX-slinga)

I stället för att köra en omfattande sökning i databasen för att uppdatera 700 eller 1 000 poster på en gång (vilket skulle leda till att tidsgränsen överskrids eller att serverns minne tar slut) bearbetar knappen ”Tilldela alla” posterna en efter en med hjälp av JavaScript-promises:

POST 1 (AJAX)⟶Svar: OK⟶POST 2 (AJAX)⟶Svar: OK…

Detta säkerställer en stabil och konsekvent resursanvändning, vilket gör att du kan följa framstegen i realtid, rad för rad.

4. Inga dubbletter av filer

Plugin-koden laddar inte ner, sammanfogar eller duplicerar bilder på din hårddisk. Den hämtar helt enkelt ID-numret för den bild som redan finns i ditt mediebibliotek och länkar den till inlägget genom att tilldela motsvarande meta_value i tabellen wp_postmeta.

Koden (PHP + JavaScript)

Du kan lägga till den här koden i filen functions.php i ditt barntema, i ett anpassat plugin eller via ett plugin för anpassade funktioner, till exempel Code Snippets eller något liknande.

Obs! Kom ihåg att ställa in variabeln $default_image_url på rad 56 till den fullständiga webbadressen till den generiska bilden som du vill tilldela inlägg som inte innehåller några bilder i texten.

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
}

Hur använder man den?

  • Gå till listan ”Inlägg” i din administratörspanel.
  • Öppna fliken ”Visningsalternativ” högst upp och ändra antalet objekt som ska visas till 50 eller 100 per sida. (Börja med att prova lägre siffror och öka dem gradvis om servern svarar bra.)

Massläggning av saknade utvalda bilder i WordPress. Visningsalternativ

  • Klicka på kolumnrubriken ”Saknade höjdpunkter” för att sortera och gruppera de utestående posterna. I filtren kan du välja mellan ”Har”, ”Saknas” eller ”Alla”.
  • När du är säker på att du är redo att börja tilldela saknade utvalda bilder i omgångar, klickar du på den blå knappen med texten ”Tilldela alla på denna sida” och låter processen slutföra tilldelningen av miniatyrbilderna för den omgången. Om du föredrar det kan du tilldela dem en efter en.
  • Gå till nästa sida och upprepa tills du har städat klart i ditt bibliotek.

Valfritt: kodsnutt för automatisk tilldelning

För att slippa upprepa den här åtgärden i framtiden kan du lägga till det här korta kodavsnittet. Det körs i bakgrunden endast när du sparar eller publicerar ett inlägg: om det upptäcker att du inte manuellt har valt en utvald bild, tilldelar det automatiskt den första bilden i innehållet (eller standardbilden, som du måste lägga till 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 );
        }
    }
}

Lämna en kommentar

Har du något att säga?

Este blog se aloja en LucusHost

LucusHost, el mejor hosting