Attribuer en masse les images mises en avant manquantes dans WordPress

Aucun commentaire

05.09.2026|

Aucun commentaire

Tiempo de lectura Lectura: 14 min, 11 s
Número de palabras Palabras: 2624
Número de visitas Visitas: 22
Icono de traducción
Attribuer en masse les images mises en avant manquantes dans WordPress. Une liste indiquant à la fois celles qui manquent et celles qui existent déjà.

Il y a quelques jours, j’ai enfin terminé une tâche que j’aurais dû faire depuis longtemps, mais que je repoussais depuis une éternité. J’ai récupéré toutesles images mises en avant manquantes et ajouté les textes alternatifs manquants à toutes les images. J’ai également rédigé toutes les méta-descriptions manquantes. Au total, j’ai ajouté ou modifié plus de 15 000 entrées à l’aide de trois de mes propres snippets personnalisés. Aujourd’hui, je partage ici le snippet permettant de récupérer les images mises en avant manquantes, que j’ai également utilisé pour effectuer cette tâche sur d’autres sites.

Si vous tenez un blog depuis un certain temps, il y a de fortes chances que vous ayez pas mal d'anciens articles auxquels aucune image mise en avant n'a été attribuée. Cela arrivait souvent à l'époque de l'éditeur classique, lorsque l'on insérait l'image directement dans le corps de l'article sans penser à la sélectionner dans le champ « Image mise en avant ».

Publier des articles sans image mise en avant n'est pas seulement un problème esthétique, entre autres ; cela a un impact direct sur le référencement de votre site et sur l'expérience utilisateur :

  1. Référencement social et Open Graph : lorsque l'on partage un article sur les réseaux sociaux, les applications de messagerie ou les agrégateurs de contenu, les balises Open Graph (og:image) ne parviennent pas à identifier une ressource claire à afficher, ce qui réduit considérablement le CTR (taux de clics).
  2. Cohérence visuelle du thème : les modèles modernes (tels que ceux conçus à l'aide de GeneratePress ou GenerateBlocks) s'appuient sur l'image mise en avant pour créer des grilles d'archives, des listes d'articles connexes ou des en-têtes. Sans celle-ci, la mise en page est perturbée ou présente des espaces mal alignés.
  3. Découverte et flux (RSS / Google Discover) : des outils tels que Google Discover ou les lecteurs RSS privilégient, voire exigent, que le contenu soit accompagné d'une vignette haute résolution afin d'améliorer la présentation de la fiche d'article.

Pour résoudre ce problème sans avoir recours à des plugins (comme celui-ci) ni à des processus lents, j'ai créé cet extrait de code PHP simple et léger qui définit automatiquement la première image de chaque article comme image mise en avant, directement depuis le tableau de bord WordPress. Si votre article ne contient aucune image, vous pouvez en attribuer une par défaut en ajoutant son URL au code.

À quoi sert exactement ce bout de code ?

Ce code ajoute un outil de traitement par lots intelligent et intégré à la liste des articles de WordPress (wp-admin/edit.php) :

  • Ajouter une colonne personnalisée : créez la colonne « Imagemise en avant manquante » dans la liste des articles pour voir d'un seul coup d'œil quels articles ne disposent pas de vignette.
  • Traitement en 3 étapes : lorsque vous activez l'attribution pour une publication, le système recherche l'image dans cet ordre précis :
    1. Vérifiez s'il y a des images jointes directement à l'article dans la bibliothèque multimédia.
    2. S'il n'y a pas de pièces jointes directes (par exemple, si elles ont été insérées via un bloc d'image ou du code HTML), parcourez le contenu à la recherche de la première balise <img> afin d'extraire son identifiant à l'aide de la fonction attachment_url_to_postid().
    3. Si l'entrée ne contient absolument aucune image, le système attribue une image par défaut (de secours) spécifiée dans la configuration.
  • Traitement en masse AJAX (traitement par lots) : comprend un bouton dans l'en-tête ( «Attribuer tout sur cette page ») qui traite toutes les entrées visibles à l'écran les unes après les autres à l'aide de requêtes asynchrones successives. Vous pouvez également effectuer cette opération manuellement à l'aide du bouton individuel correspondant à chaque publication de la liste.
  • Filtrer les brouillons : exclut automatiquement les entrées ayant le statut « brouillon » afin que vous puissiez vous concentrer uniquement sur le contenu publié.
  • Colonne triable : vous permet de trier la liste de manière à ce que toutes les entrées ne comportant pas d'image mise en avant soient regroupées en haut.

Pourquoi est-il si léger et cela n'affecte-t-il pas les performances du serveur ?

L'une des préoccupations courantes liées à l'utilisation de ce type d'outil automatisé est la crainte de bloquer la base de données ou de surcharger la mémoire PHP sur les sites comptant des milliers d'articles. Cet extrait de code a été conçu en respectant les critères d'optimisation suivants :

1. Il ne s'exécute que dans la section « Admin » (is_admin())

Le code est conçu exclusivement pour la page de saisie du panneau d'administration (edit.php). Il n'ajoute aucune surcharge aux requêtes sur le site public. Vos utilisateurs et vos indicateurs de vitesse n'en seront en aucun cas affectés.

2. Diriger les requêtes vers le méta-cache

Pour déterminer si un article contient ou non une image, l'extrait de code n'effectue pas de recherches complexes dans la base de données pour chaque ligne. Il utilise la clé de métadonnées _thumbnail_id, que WordPress charge en mémoire de manière native via le cache de métadonnées lors du rendu de la liste. Le tableau se charge presque instantanément.

3. Traitement asynchrone en cascade (boucle AJAX séquentielle)

Plutôt que d'exécuter une requête volumineuse sur la base de données pour mettre à jour 700 ou 1 000 entrées d'un seul coup (ce qui entraînerait un délai d'expiration ou épuiserait toute la mémoire du serveur), le bouton « Tout attribuer » traite les entrées une par une à l'aide de promesses JavaScript:

POST 1 (AJAX)⟶Réponse OK⟶POST 2 (AJAX)⟶Réponse OK…

Cela garantit une utilisation stable et cohérente des ressources, ce qui vous permet de suivre la progression en temps réel, ligne par ligne.

4. Pas de doublons dans les fichiers

Cet extrait de code ne télécharge pas, ne recombine pas et ne duplique pas les images sur votre disque dur. Il se contente de récupérer l’identifiant de l’image déjà présente dans votre bibliothèque multimédia et de l’associer à l’article en attribuant la valeur « meta_value » correspondante dans la table « wp_postmeta ».

Le code (PHP + JavaScript)

Vous pouvez ajouter ce code au fichier functions.php de votre thème enfant, à un plugin personnalisé, ou via un plugin de fonctions personnalisées tel que Code Snippets ou un plugin similaire.

Remarque : n'oubliez pas de définir la variable $default_image_url à la ligne 56 en indiquant l'URL complète de l'image générique que vous souhaitez attribuer aux articles ne contenant aucune image dans leur corps de texte.

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
}

Comment ça marche ?

  • Accédez à la liste « Articles » dans votre panneau d'administration.
  • Ouvrez l'onglet « Options d'affichage » en haut de la page et réglez le nombre d'éléments à afficher sur 50 ou 100 par page. (Commencez par essayer des nombres plus petits, puis augmentez-les progressivement si votre serveur réagit bien.)

Attribuer en masse les images mises en avant manquantes dans WordPress. Options d'affichage

  • Cliquez sur l'en-tête de la colonne « Éléments manquants » pour trier et regrouper les entrées en attente. Dans les filtres, vous pouvez choisir entre « Contient », « Manquant » ou « Tout ».
  • Une fois que vous êtes certain d’être prêt à attribuer en masse les images mises en avant manquantes, cliquez sur le bouton bleu « » intitulé « Attribuer toutes celles de cette page » et laissez le processus en cascade terminer l’attribution des vignettes pour ce lot. Si vous préférez, vous pouvez les attribuer une par une.
  • Passez à la page suivante et répétez l'opération jusqu'à ce que vous ayez fini de mettre de l'ordre dans votre bibliothèque.

Facultatif : extrait de code d'affectation automatique

Pour éviter d'avoir à répéter cette tâche à l'avenir, vous pouvez ajouter ce petit bout de code. Il s'exécute en arrière-plan uniquement lorsque vous enregistrez ou publiez un article : s'il détecte que vous n'avez pas sélectionné manuellement d'image mise en avant, il attribue automatiquement la première image du contenu (ou l'image de secours par défaut, que vous devrez ajouter dans $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 );
        }
    }
}

Laisser un commentaire

Vous avez quelque chose à dire ?

Este blog se aloja en LucusHost

LucusHost, el mejor hosting