Fehlende Titelbilder in WordPress stapelweise zuweisen

Keine Kommentare

05.09.2026|

Keine Kommentare

Tiempo de lectura Lectura: 13 min, 1 s
Número de palabras Palabras: 2410
Número de visitas Visitas: 11
Icono de traducción
Fehlende Titelbilder in WordPress stapelweise zuweisen. Eine Liste, in der sowohl die fehlenden als auch die vorhandenen Bilder angezeigt werden.

Vor ein paar Tagen habe ich eine längst überfällige Aufgabe erledigt, die schon lange anstand, die ich aber schon seit Ewigkeiten vor mir hergeschoben hatte. Ichhabe allefehlenden Titelbilderwiederhergestelltund den fehlenden Alt-Text zu den Bildern hinzugefügt. Außerdem habe ich alle fehlenden Meta-Beschreibungen fertiggestellt. Insgesamt habe ich mithilfe von drei meiner eigenen, eigens dafür erstellten Snippets über 15.000 Datensätze hinzugefügt oder bearbeitet. Heute stelle ich hier das Snippet zum Abrufen der fehlenden Titelbilder vor, das ich auch verwendet habe, um diese Aufgabe auf anderen Websites zu erledigen.

Wenn Sie schon eine Weile bloggen, ist es sehr wahrscheinlich, dass Sie einige ältere Beiträge haben, denen kein Titelbild zugewiesen ist. Das kam früher in den Zeiten des klassischen Editors häufig vor, als wir das Bild direkt in den Text des Beitrags einfügten, aber vergaßen, es im Feld „Beitragsbild“ auszuwählen.

Beiträge ohne Titelbild zu veröffentlichen, ist nicht nur unter anderem ein ästhetisches Problem, sondern wirkt sich auch direkt auf die Suchmaschinenoptimierung Ihrer Website und die Benutzererfahrung aus:

  1. Social SEO und Open Graph: Beim Teilen des Beitrags in sozialen Medien, Messaging-Apps oder Content-Aggregatoren können die Open-Graph-Tags (og:image) keine eindeutige Ressource zur Anzeige finden, was die Klickrate (CTR) drastisch senkt.
  2. Visuelle Einheitlichkeit im Theme: Moderne Vorlagen (wie beispielsweise solche, die mit GeneratePress oder GenerateBlocks erstellt wurden) sind auf das Titelbild angewiesen, um Archivraster, Listen mit verwandten Beiträgen oder Kopfzeilen zu erstellen. Ohne dieses Bild kommt es zu Layoutfehlern oder zu ungleichmäßigen Abständen.
  3. Entdeckung und Feeds (RSS / Google Discover): Tools wie Google Discover oder RSS-Reader bevorzugen oder erfordern Inhalte mit einem zugehörigen hochauflösenden Vorschaubild, um die Artikelkarte optisch aufzuwerten.

Um dieses Problem zu lösen, ohne auf Plugins (wie dieses hier) oder langsame Prozesse zurückgreifen zu müssen, habe ich dieses einfache, kompakte PHP-Snippet erstellt, das das erste Bild in jedem Beitrag automatisch als Beitragsbild festlegt – direkt über das WordPress-Dashboard. Falls Ihr Beitrag keine Bilder enthält, können Sie ein Standardbild zuweisen, indem Sie dessen URL in den Code einfügen.

Was genau bewirkt dieser Codeausschnitt?

Der Code erweitert die WordPress-Beitragsliste (wp-admin/edit.php) um ein intelligentes, integriertes Tool zur Stapelverarbeitung:

  • Eine benutzerdefinierte Spalte hinzufügen: Erstellen Sie in der Liste der Beiträge die Spalte „Fehlendes Vorschaubild, um auf einen Blick zu erkennen, bei welchen Beiträgen ein Vorschaubild fehlt.
  • 3-stufige Verarbeitung: Wenn Sie die Zuordnung für einen Beitrag aktivieren, wird das Bild in genau dieser Reihenfolge gesucht:
    1. Überprüfen Sie, ob in der Medienbibliothek Bilder vorhanden sind, die direkt an den Beitrag angehängt sind.
    2. Wenn keine direkten Anhänge vorhanden sind (z. B. wenn sie über einen Bildblock oder HTML eingefügt wurden), durchsuche den Inhalt nach dem ersten <img> -Tag, um dessen ID mithilfe von attachment_url_to_postid() zu extrahieren.
    3. Wenn der Eintrag überhaupt keine Bilder enthält, wird ein in der Konfiguration festgelegtes Standardbild (Fallback-Bild) zugewiesen.
  • AJAX-Massenverarbeitung (Stapelverarbeitung): Enthält eine Schaltfläche in der Kopfzeile („⚡ Alle auf dieser Seite zuweisen“), die alle auf dem Bildschirm sichtbaren Einträge nacheinander mithilfe aufeinanderfolgender asynchroner Anfragen verarbeitet. Sie können dies auch manuell über die jeweilige Schaltfläche für jeden Beitrag in der Liste tun.
  • Entwürfe filtern: Schließt Einträge mit dem Status „Entwurf“ automatisch aus, sodass Sie sich ausschließlich auf veröffentlichte Inhalte konzentrieren können.
  • Sortierbare Spalte: Damit können Sie die Liste so sortieren, dass alle Einträge ohne Ausgewähltes Bild oben zusammengefasst werden.

Warum ist es so ressourcenschonend und beeinträchtigt es nicht die Serverleistung?

Eine häufige Sorge bei der Verwendung solcher automatisierter Tools ist die Befürchtung, dass die Datenbank blockiert oder der PHP-Speicher auf Websites mit Tausenden von Artikeln überlastet wird. Dieser Codeausschnitt wurde unter Berücksichtigung der folgenden Optimierungskriterien entwickelt:

1. Es läuft nur im Admin-Bereich (is_admin())

Der Code ist ausschließlich für den Eingabebildschirm des Administrationsbereichs (edit.php) vorgesehen. Er verursacht keinerlei zusätzliche Belastung für Anfragen auf der öffentlichen Website. Ihre Nutzer und die Geschwindigkeitswerte werden in keiner Weise beeinträchtigt.

2. Abfragen an den Meta-Cache richten

Um festzustellen, ob ein Beitrag ein Bild enthält oder nicht, führt das Snippet nicht für jede Zeile komplexe Datenbankabfragen durch. Es nutzt den Metadaten-Schlüssel _thumbnail_id, den WordPress beim Rendern der Liste standardmäßig über den Metadaten-Cache in den Arbeitsspeicher lädt. Die Tabelle wird nahezu sofort geladen.

3. Kaskadierende asynchrone Verarbeitung (sequenzielle AJAX-Schleife)

Anstatt eine umfangreiche Abfrage in der Datenbank auszuführen, um 700 oder 1.000 Einträge auf einmal zu aktualisieren (was zu einem Timeout führen oder den gesamten Arbeitsspeicher des Servers belasten würde), verarbeitet die Schaltfläche „Alle zuweisen“ die Einträge nacheinander mithilfe von JavaScript-Promises:

POST 1 (AJAX)⟶OK-Antwort⟶POST 2 (AJAX)⟶OK-Antwort…

Dadurch wird eine stabile und konsistente Ressourcennutzung gewährleistet, sodass Sie den Fortschritt in Echtzeit Zeile für Zeile verfolgen können.

4. Keine Dateiduplikate

Das Snippet lädt keine Bilder herunter, fügt sie nicht neu zusammen und dupliziert sie auch nicht auf Ihrer Festplatte. Es übernimmt lediglich die ID des Bildes, das sich bereits in Ihrer Medienbibliothek befindet, und verknüpft es mit dem Beitrag, indem es den entsprechenden „meta_value“ in der Tabelle „wp_postmeta“ zuweist.

Der Code (PHP + JavaScript)

Sie können diesen Code in die Datei „functions.php“ Ihres Child-Themes, in ein benutzerdefiniertes Plugin oder über ein Plugin für benutzerdefinierte Funktionen wie „Code Snippets“ oder ein ähnliches Plugin einfügen.

Hinweis: Denken Sie daran, die Variable $default_image_url in Zeile 56 auf die vollständige URL des Standardbildes zu setzen, das Sie Beiträgen zuweisen möchten, deren Text keine Bilder enthält.

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
}

Wie benutzt man es?

  • Rufen Sie die Liste „Beiträge“ in Ihrem Admin-Bereich auf.
  • Öffnen Sie oben die Registerkarte „Anzeigeoptionen“ und ändern Sie die Anzahl der anzuzeigenden Elemente auf 50 oder 100 pro Seite. (Beginnen Sie mit kleineren Zahlen und erhöhen Sie diese schrittweise, wenn Ihr Server gut darauf reagiert.)

Fehlende Titelbilder in WordPress stapelweise zuweisen. Anzeigeoptionen

  • Klicken Sie auf die Spaltenüberschrift „Fehlende Highlights“, um die ausstehenden Einträge zu sortieren und zu gruppieren. In den Filtern können Sie zwischen „Hat“, „Fehlt“ oder „Alle“ wählen.
  • Sobald Sie sicher sind, dass Sie bereit sind, fehlende Vorschaubilder stapelweise zuzuweisen, klicken Sie auf die blaue Schaltfläche mit der Beschriftung „Alle auf dieser Seite zuweisen“ und lassen Sie den kaskadierenden Vorgang die Zuweisung der Vorschaubilder für diesen Stapel abschließen. Wenn Sie möchten, können Sie die Vorschaubilder auch einzeln zuweisen.
  • Gehen Sie zur nächsten Seite und wiederholen Sie den Vorgang, bis Sie mit dem Aufräumen Ihrer Bibliothek fertig sind.

Optional: Snippet für die automatische Zuweisung

Um diese Aufgabe in Zukunft nicht wiederholen zu müssen, können Sie diesen kurzen Code-Schnipsel hinzufügen. Es läuft im Hintergrund nur dann, wenn du einen Beitrag speicherst oder veröffentlichst: Wenn es feststellt, dass du kein Titelbild manuell ausgewählt hast, weist es automatisch das erste Bild im Inhalt zu (oder das Standard-Ersatzbild, das du unter $default_image_url = hinzufügen musst).

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 );
        }
    }
}

Schreibe einen Kommentar

Haben Sie etwas zu sagen?

Este blog se aloja en LucusHost

LucusHost, el mejor hosting