WordPress

php – Jak masowo aktualizować wartości taksonomii CPT za pomocą tabeli wyszukiwania CSV

  • 15 września, 2024
  • 4 min read
php – Jak masowo aktualizować wartości taksonomii CPT za pomocą tabeli wyszukiwania CSV


Mam CPT o nazwie Places na bardzo dużej stronie internetowej z kilkoma milionami postów. Każdy post ma wartość dla taksonomii States (np. FL). Zwykle używam WP All Import, ale jest bardzo wolny. Przetwarza około 10 tys. wierszy na godzinę, ale muszę zaktualizować 900 tys. postów.

Przyszło mi do głowy, żeby zrobić coś podobnego do vlookup. Gdyby WordPress pozwalał nam mieć jedną tabelę dla CPT, wtedy byłoby bardzo łatwo zbiorczo aktualizować wartości. Utworzyłem główną tabelę każdego pojedynczego CPT wraz ze wszystkimi terminami, taksonomiami itp. Zajęło mi to około 5 godzin, żeby zdobyć wszystko.

Wiem, że mogę zbiorczo aktualizować wartości, ponieważ robiłem to miesiącami dla innej taksonomii, używając kodu php. Problem w tym, że nie pamiętam, jak to zrobiłem, ponieważ miałem nadzieję znaleźć coś takiego jak Airtable bez ograniczenia 100 tys. wierszy na tabelę. Głupi ze mnie, że nie udokumentowałem procesu.

Kod, który wymyśliłem, działa w przypadku niektórych postów, ale nie wszystkich. Przeprowadziłem test 100 tys. aktualizacji, aby zastąpić wartość (pusta, null lub inna) taksonomii stanów wartościami w mojej tabeli testowej. Wygląda na to, że niektóre zostały zaktualizowane. Mnóstwo błędów.

WordPress database error Duplicate entry '983102-118270' for key 'wp_term_relationships.PRIMARY' for query UPDATE `wp_term_relationships` SET `term_taxonomy_id` = 118270 WHERE `object_id` = 983102
WordPress database error Duplicate entry '965290-118270' for key 'wp_term_relationships.PRIMARY' for query UPDATE `wp_term_relationships` SET `term_taxonomy_id` = 118270 WHERE `object_id` = 965290

Kod PHP

query("SET innodb_lock_wait_timeout = 120");

// Get total number of rows to process
$total_rows = $wpdb->get_var(
    "SELECT COUNT(*) 
     FROM domain.import_state_taxonomy_only_2 
     WHERE state IS NOT NULL 
     AND state <> ''"
);

// Calculate total number of batches
$total_batches = ceil($total_rows / $batch_size);

// Iterate through batches
for ($batch = 0; $batch < $total_batches; $batch++) {
    // Start transaction for data integrity
    $wpdb->query('START TRANSACTION');

    try {
        // Fetch a batch of data from the lookup table
        $lookup_data = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT wp_postid, state 
                 FROM domain.import_state_taxonomy_only_2 
                 WHERE state IS NOT NULL 
                 AND state <> ''
                 LIMIT %d OFFSET %d",
                $batch_size, $batch * $batch_size
            ),
            ARRAY_A
        );

        foreach ($lookup_data as $index => $row) {
            $post_id = $row['wp_postid'];
            $state_name = $row['state'];

            // Get the term ID for the new state name
            $term_id = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT term_id FROM {$wpdb->terms} WHERE name = %s",
                    $state_name
                )
            );

                                                            
            if (!$term_id) {
                $message = "State '$state_name' not found for post ID $post_id.\n";
                file_put_contents($log_file, $message, FILE_APPEND);
                continue;
            }

            // Get the term taxonomy ID for 'states'
            $term_taxonomy_id = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT term_taxonomy_id FROM {$wpdb->term_taxonomy} 
                     WHERE term_id = %d AND taxonomy = 'states'",
                    $term_id
                )
            );

                                                                     
            if (!$term_taxonomy_id) {
                $message = "Taxonomy 'states' not found for term ID $term_id and post ID $post_id.\n";
                file_put_contents($log_file, $message, FILE_APPEND);
                continue;
            }

            // Check if the row exists
            $row_exists = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT COUNT(*) FROM {$wpdb->term_relationships} 
                     WHERE object_id = %d AND term_taxonomy_id = %d",
                    $post_id, $term_taxonomy_id
                )
            );

            if ($row_exists) {
                // Row exists, update the existing row
                $wpdb->update(
                    $wpdb->term_relationships,
                    array('term_taxonomy_id' => $term_taxonomy_id),
                    array('object_id' => $post_id),
                    array('%d'), // Format for term_taxonomy_id
                    array('%d')  // Format for object_id
                );
                $message = "Updated row for post ID {$post_id}.\n";
            } else {
                // Row does not exist, insert a new row
                $wpdb->insert(
                    $wpdb->term_relationships,
                    array('object_id' => $post_id, 'term_taxonomy_id' => $term_taxonomy_id),
                    array('%d', '%d') // Format for object_id and term_taxonomy_id
                );

                                               
                                                                                    
                        
                $message = "Inserted new row for post ID {$post_id}.\n";
        }

            // Log the message
            file_put_contents($log_file, $message, FILE_APPEND);
        }

        // Commit the transaction
        $wpdb->query('COMMIT');
        file_put_contents($log_file, "Batch {$batch} processed successfully!\n", FILE_APPEND);

        // Display progress bar
        $progress = round((($batch + 1) / $total_batches) * 100);
        echo "\rProgress: [";
        echo str_repeat("=", $progress / 2) . str_repeat(" ", 50 - $progress / 2) . "] {$progress}%";
        ob_flush();
        flush();

    } catch (Exception $e) {
        // Rollback the transaction in case of an error
        $wpdb->query('ROLLBACK');
        $error_message = "Error in batch {$batch}: " . $e->getMessage() . "\n";
        file_put_contents($log_file, $error_message, FILE_APPEND);
        echo "\n" . $error_message;
    }
}

echo "\nBulk update complete!\n";
?>

Czy czegoś mi brakuje? NAPRAWDĘ wolałbym iść drogą bazy danych, ponieważ korzystanie z wtyczki zajmuje o wiele za dużo czasu.

Dzięki.


Źródło

Warto przeczytać!  Wygeneruj/zapisz plik JSON lub XML ze skryptu JSON