Μαζική αντιστοίχιση ελλειπουσών επιλεγμένων εικόνων στο WordPress

No comments

05.09.2026|

No comments

Tiempo de lectura Lectura: 7 min, 8 s
Número de palabras Palabras: 1320
Número de visitas Visitas: 22
Icono de traducción
Μαζική προσθήκη εικόνων προβολής που λείπουν στο WordPress. Μια λίστα που εμφανίζει τόσο τις εικόνες που λείπουν όσο και τις υπάρχουσες.

Πριν από λίγες μέρες, ολοκλήρωσα μια εργασία που έπρεπε να είχα κάνει εδώ και καιρό, αλλά την ανέβαλλα για πολύ καιρό.Ανέκτησα όλες τιςεικόνες που έλειπαν και πρόσθεσα το κείμενο εναλλακτικής περιγραφής σε όλες τις εικόνες. Επίσης, ολοκλήρωσα τη σύνταξη όλων των περιγραφών meta που έλειπαν. Συνολικά, πρόσθεσα ή επεξεργάστηκα πάνω από 15.000 εγγραφές χρησιμοποιώντας τρία δικά μου εφάπαξ snippets. Σήμερα, μοιράζομαι εδώ το snippet για την ανάκτηση των εικόνων που έλειπαν, το οποίο χρησιμοποίησα επίσης για να ολοκληρώσω αυτή την εργασία σε άλλους ιστότοπους.

Αν γράφετε στο blog σας εδώ και αρκετό καιρό, είναι πολύ πιθανό να έχετε αρκετές παλαιότερες αναρτήσεις στις οποίες δεν έχει οριστεί εικόνα προβολής. Αυτό συνέβαινε συχνά την εποχή του κλασικού επεξεργαστή, όταν εισάγαμε την εικόνα απευθείας στο κύριο κείμενο της ανάρτησης, αλλά ξεχνούσαμε να την επιλέξουμε στο πλαίσιο «Επιλεγμένη εικόνα».

Η δημοσίευση άρθρων χωρίς επιλεγμένη εικόνα δεν αποτελεί απλώς ένα αισθητικό ζήτημα, μεταξύ άλλων· επηρεάζει άμεσα τη βελτιστοποίηση του ιστότοπού σας και την εμπειρία του χρήστη:

  1. Κοινωνικό SEO και Open Graph: Όταν μοιράζεστε μια ανάρτηση στα κοινωνικά δίκτυα, σε εφαρμογές ανταλλαγής μηνυμάτων ή σε ιστότοπους συγκέντρωσης περιεχομένου, οι ετικέτες Open Graph (og:image) δεν μπορούν να εντοπίσουν έναν σαφή πόρο για εμφάνιση, με αποτέλεσμα να μειώνεται δραστικά το CTR (ποσοστό κλικ).
  2. Οπτική συνοχή στο θέμα: Τα μοντέρνα πρότυπα (όπως αυτά που έχουν σχεδιαστεί με το GeneratePress ή το GenerateBlocks) βασίζονται στην επιλεγμένη εικόνα για τη δημιουργία πλεγμάτων αρχείων, λιστών σχετικών αναρτήσεων ή κεφαλίδων. Χωρίς αυτήν, η διάταξη καταστρέφεται ή δημιουργούνται κενά που δεν είναι ευθυγραμμισμένα.
  3. Αναζήτηση και ροές (RSS / Google Discover): Εργαλεία όπως το Google Discover ή οι αναγνώστες RSS δίνουν προτεραιότητα ή απαιτούν περιεχόμενο που συνοδεύεται από μικρογραφία υψηλής ανάλυσης, προκειμένου να βελτιώσουν την εμφάνιση της κάρτας του άρθρου.

Για να το επιλύσω αυτό χωρίς να καταφύγω σε προσθήκες (όπως αυτή εδώ) ή σε αργές διαδικασίες, δημιούργησα αυτό το απλό και ελαφρύ απόσπασμα κώδικα PHP που ορίζει αυτόματα την πρώτη εικόνα σε κάθε ανάρτηση ως επιλεγμένη εικόνα, απευθείας από τον πίνακα ελέγχου του WordPress. Αν η ανάρτησή σας δεν περιέχει εικόνες, μπορείτε να ορίσετε μια προεπιλεγμένη εικόνα προσθέτοντας τη διεύθυνση URL της στον κώδικα.

Τι ακριβώς κάνει αυτό το απόσπασμα κώδικα;

Ο κώδικας προσθέτει ένα έξυπνο, ενσωματωμένο εργαλείο μαζικής επεξεργασίας στη λίστα αναρτήσεων του WordPress (wp-admin/edit.php):

  • Προσθήκη προσαρμοσμένης στήλης: Δημιουργήστε τη στήλη «Λείπει η επιλεγμένη εικόνα» στη λίστα των αναρτήσεων, για να βλέπετε με μια ματιά ποιες αναρτήσεις δεν έχουν μικρογραφία.
  • Επεξεργασία σε 3 στάδια: Όταν ενεργοποιείτε την αντιστοίχιση για μια ανάρτηση, η αναζήτηση της εικόνας πραγματοποιείται με την ακόλουθη ακριβή σειρά:
    1. Ελέγξτε αν υπάρχουν εικόνες που έχουν επισυναφθεί απευθείας στην ανάρτηση στη Βιβλιοθήκη πολυμέσων.
    2. Εάν δεν υπάρχουν άμεσα συνημμένα (για παράδειγμα, εάν έχουν εισαχθεί μέσω ενός μπλοκ εικόνας ή κώδικα HTML), αναζητήστε στο περιεχόμενο την πρώτη ετικέτα <img> για να εξαγάγετε το αναγνωριστικό της χρησιμοποιώντας τη συνάρτηση attachment_url_to_postid().
    3. Εάν η καταχώριση δεν περιέχει καμία εικόνα, τότε χρησιμοποιείται μια προεπιλεγμένη (εφεδρική) εικόνα που καθορίζεται στη διαμόρφωση.
  • Μαζική επεξεργασία AJAX (επεξεργασία κατά παρτίδες): Περιλαμβάνει ένα κουμπί στην κεφαλίδα («⚡ Ανάθεση όλων σε αυτή τη σελίδα»), το οποίο επεξεργάζεται διαδοχικά όλες τις εγγραφές που εμφανίζονται στην οθόνη, χρησιμοποιώντας διαδοχικά ασύγχρονα αιτήματα. Μπορείτε επίσης να το κάνετε αυτό χειροκίνητα, χρησιμοποιώντας το ξεχωριστό κουμπί για κάθε ανάρτηση στη λίστα.
  • Φίλτρο προσχεδίων: Εξαιρεί αυτόματα τις καταχωρήσεις που βρίσκονται σε κατάσταση προσχεδίου, ώστε να μπορείτε να επικεντρωθείτε αποκλειστικά στο δημοσιευμένο περιεχόμενο.
  • Στήλη με δυνατότητα ταξινόμησης: Σας επιτρέπει να ταξινομήσετε τη λίστα έτσι ώστε όλες οι καταχωρήσεις που δεν διαθέτουν επιλεγμένη εικόνα να ομαδοποιούνται μαζί στην κορυφή.

Γιατί είναι τόσο ελαφρύ και δεν επηρεάζει την απόδοση του διακομιστή;

Μια συχνή ανησυχία κατά τη χρήση αυτού του είδους αυτοματοποιημένων εργαλείων είναι ο φόβος να «κλειδωθεί» η βάση δεδομένων ή να υπερφορτωθεί η μνήμη PHP σε ιστότοπους με χιλιάδες άρθρα. Αυτό το απόσπασμα κώδικα έχει σχεδιαστεί σύμφωνα με τα ακόλουθα κριτήρια βελτιστοποίησης:

1. Λειτουργεί μόνο στην ενότητα «Διαχείριση» (is_admin())

Ο κώδικας έχει σχεδιαστεί αποκλειστικά για την οθόνη εισαγωγής δεδομένων του πίνακα διαχείρισης (edit.php). Δεν προσθέτει ούτε μία γραμμή επιπλέον φόρτου στις αιτήσεις του δημόσιου ιστότοπου. Οι χρήστες σας και οι δείκτες ταχύτητας δεν θα επηρεαστούν με κανέναν τρόπο.

2. Απευθύνετε τα ερωτήματά σας στο Meta Cache

Για να προσδιοριστεί αν μια ανάρτηση περιέχει εικόνα ή όχι, το απόσπασμα κώδικα δεν πραγματοποιεί πολύπλοκες αναζητήσεις στη βάση δεδομένων για κάθε σειρά. Χρησιμοποιεί το κλειδί μεταδεδομένων _thumbnail_id, το οποίο το WordPress φορτώνει στη μνήμη εγγενώς μέσω της προσωρινής μνήμης μεταδεδομένων κατά την απεικόνιση της λίστας. Ο πίνακας φορτώνεται σχεδόν αμέσως.

3. Ασύγχρονη επεξεργασία σε σειρά (διαδοχικός βρόχος AJAX)

Αντί να εκτελείται μια τεράστια ερώτηση στη βάση δεδομένων για την ενημέρωση 700 ή 1.000 εγγραφών με μία κίνηση (κάτι που θα προκαλούσε χρονικό όριο ή θα εξαντλούσε όλη τη μνήμη του διακομιστή), το κουμπί «Assign All» επεξεργάζεται τις εγγραφές μία προς μία χρησιμοποιώντας «promises» της JavaScript:

POST 1 (AJAX)⟶Απάντηση «OK»⟶POST 2 (AJAX)⟶Απάντηση «OK»…

Αυτό εξασφαλίζει μια σταθερή και συνεπή χρήση των πόρων, επιτρέποντάς σας να παρακολουθείτε την πρόοδο σε πραγματικό χρόνο, σειρά προς σειρά.

4. Χωρίς διπλότυπα αρχεία

Το σνιπέτ δεν κατεβάζει, δεν ανασυνθέτει ούτε αντιγράφει εικόνες στον σκληρό σας δίσκο. Απλώς λαμβάνει τον κωδικό αναγνώρισης της εικόνας που βρίσκεται ήδη στη Βιβλιοθήκη πολυμέσων σας και τη συνδέει με την ανάρτηση, εκχωρώντας την αντίστοιχη τιμή meta_value στον πίνακα wp_postmeta.

Ο κώδικας (PHP + JavaScript)

Μπορείτε να προσθέσετε αυτόν τον κώδικα στο αρχείο functions.php του υπο-θέματός σας, σε ένα προσαρμοσμένο πρόσθετο ή μέσω ενός πρόσθετου προσαρμοσμένων συναρτήσεων, όπως το Code Snippets ή κάποιο παρόμοιο.

Σημείωση: Μην ξεχάσετε να ορίσετε τη μεταβλητή $default_image_url στη γραμμή 56 με τη πλήρη διεύθυνση URL της γενικής εικόνας που θέλετε να αντιστοιχίσετε σε αναρτήσεις που δεν περιέχουν εικόνες στο κείμενο.

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
}

Πώς το χρησιμοποιείς;

  • Μεταβείτε στη λίστα «Αναρτήσεις» στον πίνακα διαχείρισης.
  • Ανοίξτε την καρτέλα «Επιλογές εμφάνισης» στην κορυφή της σελίδας και αλλάξτε τον αριθμό των στοιχείων που θα εμφανίζονται σε 50 ή 100 ανά σελίδα. (Ξεκινήστε δοκιμάζοντας μικρότερους αριθμούς και αυξήστε τους σταδιακά, αν ο διακομιστής σας ανταποκρίνεται καλά.)

Μαζική ανάθεση ελλειπουσών επιλεγμένων εικόνων στο WordPress. Επιλογές εμφάνισης

  • Κάντε κλικ στην επικεφαλίδα της στήλης «Λείπουν επισημάνσεις» για να ταξινομήσετε και να ομαδοποιήσετε τις εκκρεμείς εγγραφές. Στα φίλτρα, μπορείτε να επιλέξετε μεταξύ «Έχει», «Λείπει» ή «Όλα»
  • Μόλις βεβαιωθείτε ότι είστε έτοιμοι να ξεκινήσετε την ανάθεση των ελλειπουσών επιλεγμένων εικόνων κατά ομάδες, κάντε κλικ στο μπλε κουμπί « » με την ένδειξη «Assign all on this page» και αφήστε τη διαδικασία να ολοκληρώσει την ανάθεση των μικρογραφιών για τη συγκεκριμένη ομάδα. Αν προτιμάτε, μπορείτε να τις αναθέσετε μία προς μία.
  • Πήγαινε στην επόμενη σελίδα και επανέλαβε τη διαδικασία μέχρι να ολοκληρώσεις την τακτοποίηση της βιβλιοθήκης σου.

Προαιρετικό: απόσπασμα αυτόματης ανάθεσης

Για να μην χρειαστεί να επαναλάβετε αυτή τη διαδικασία στο μέλλον, μπορείτε να προσθέσετε αυτό το σύντομο κομμάτι κώδικα. Εκτελείται στο παρασκήνιο μόνο όταν αποθηκεύετε ή δημοσιεύετε μια ανάρτηση: αν διαπιστώσει ότι δεν έχετε επιλέξει χειροκίνητα μια επιλεγμένη εικόνα, ορίζει αυτόματα την πρώτη εικόνα του περιεχομένου (ή την προεπιλεγμένη εφεδρική εικόνα, την οποία θα πρέπει να προσθέσετε στο $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 );
        }
    }
}

Σχολιάστε

Έχεις τίποτα να πεις;

Este blog se aloja en LucusHost

LucusHost, el mejor hosting