wake-up-neo.net

Schnellerer Weg zu wp_insert_post & add_post_meta in loser Schüttung

Ich habe eine CSV-Datei, die ich einfügen möchte, die aus ~ 1.500 Zeilen und 97 Spalten besteht. Ein vollständiger Import dauert ca. 2-3 Stunden und ich würde dies gerne verbessern, wenn es einen Weg gibt. Derzeit führe ich für jede Zeile ein $ post_id = wp_insert_post und dann ein add_post_meta für die 97 zugeordneten Spalten mit jeder Zeile aus. Das ist ziemlich ineffizient ...

Gibt es eine bessere Möglichkeit, dies so zu tun, dass eine post_id die Beziehung zwischen post und seinen post_meta-Werten beibehält?

Im Moment versuche ich dies auf meinem lokalen Computer mit Wamp, aber ich werde es auf einem VPS laufen lassen

13
Corey Rowell

Ich hatte vor einiger Zeit ähnliche Probleme mit einem benutzerdefinierten CSV-Import, habe jedoch letztendlich einige benutzerdefinierte SQL-Anweisungen für die Masseneinfügung verwendet. Aber ich hatte diese Antwort bis dahin noch nicht gesehen:

Post einfügen und löschen für Massenoperationen optimieren?

verwenden Sie wp_defer_term_counting() , um die Zählung von Begriffen zu aktivieren oder zu deaktivieren.

Auch wenn Sie das source für das WordPress-Import-Plugin auschecken, sehen Sie diese Funktionen unmittelbar vor dem Massenimport:

wp_defer_term_counting( true );
wp_defer_comment_counting( true );

und dann nach dem Bulk Insert:

wp_defer_term_counting( false );
wp_defer_comment_counting( false );

Das könnte man also ausprobieren ;-)

Das Importieren von Posts als Entwurf anstelle von Veröffentlichen beschleunigt ebenfalls die Suche, da der langsame Prozess des Findens eines eindeutigen Slugs für jeden einzelnen übersprungen wird. Man könnte z.B. Veröffentlichen Sie sie später in kleineren Schritten. Beachten Sie jedoch, dass diese Methode die importierten Posts irgendwie markieren müsste, damit wir später nicht nur Entwürfe veröffentlichen! Dies würde eine sorgfältige Planung und höchstwahrscheinlich eine benutzerdefinierte Codierung erfordern.

Wenn es z.B. Viele ähnliche Post-Titel (derselbe post_name) müssen importiert werden, dann kann wp_unique_post_slug() aufgrund der Schleifenabfrage-Iteration langsam werden, um einen verfügbaren Slug zu finden. Dies kann möglicherweise eine große Anzahl von Datenbankabfragen erzeugen.

Seit WordPress 5.1 ist der pre_wp_unique_post_slug-Filter verfügbar, um die Schleifeniteration für den Slug zu vermeiden. Siehe Core Ticket # 21112 . Hier ist ein Beispiel:

add_filter( 'pre_wp_unique_post_slug', 
    function( $override_slug, $slug, $post_id, $post_status, $post_type, $post_parent ) {
        // Set a unique slug value to shortcircuit the slug iteration loop.
        // $override_slug = ...

        return $override_slug;
    }, 10, 6
);

Wenn man es versucht, z. $override_slug = _truncate_post_slug( $slug, 200 - ( strlen( $suffix ) + 1 ) ) . "-$suffix" mit $suffix als $post_id, dann würden wir bemerken, dass $post_id für neue Beiträge immer 0 ist, wie erwartet. Es gibt jedoch verschiedene Möglichkeiten, eindeutige Zahlen in PHP zu generieren, wie zum Beispiel uniqid( '', true ). Verwenden Sie diesen Filter jedoch mit Sorgfalt, um sicherzustellen, dass Sie eindeutige Schnecken haben. Wir könnten z. Führen Sie anschließend eine Gruppenzählungsabfrage für post_name aus, um sicherzugehen.

Eine andere Möglichkeit wäre, WP-CLI zu verwenden, um eine Zeitüberschreitung zu vermeiden. Siehe z. Meine Antwort wurde gepostet für Erstellen von 20.000 Posts oder Seiten mit einer CSV-Datei?

Dann können wir unser benutzerdefiniertes PHP -Importskript import.php mit dem WP-CLI-Befehl ausführen:

wp eval-file import.php

Vermeiden Sie außerdem den Import einer großen Anzahl hierarchischer Beitragstypen, da die aktuelle Benutzeroberfläche von wp-admin damit nicht gut zurechtkommt. Siehe z. Benutzerdefinierter Beitragstyp - Liste der Beiträge - weißer Bildschirm des Todes

Hier ist der großartige Tipp von @otto:

Deaktivieren Sie vor Masseneinfügungen den Modus autocommit explizit:

$wpdb->query( 'SET autocommit = 0;' );

Führen Sie nach den Masseneinfügungen Folgendes aus:

$wpdb->query( 'COMMIT;' );

Ich denke auch, dass es eine gute Idee wäre, ein bisschen Haushalt zu führen wie:

$wpdb->query( 'SET autocommit = 1;' );

Ich habe dies nicht auf MyISAM getestet, aber dies sollte auf InnoDB funktionieren.

Wie schon erwähnt von @kovshenin, würde dieser Tipp für MyISAM nicht funktionieren.

18
birgire

Sie müssen den Beitrag einfügen, um Ihre ID zu erhalten, aber die $wpdb->postmeta-Tabelle ist sehr einfach aufgebaut. Sie könnten wahrscheinlich eine direkte INSERT INTO -Anweisung verwenden, wie folgt aus den MySQL-Dokumenten: INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

In Ihrem Fall...

$ID = 1; // from your wp_insert_post
$values = '($ID,2,3),($ID,5,6),($ID,8,9)'; // build from your 97 columns; I'd use a loop of some kind
$wpdb->query("INSERT INTO {$wpdb->postmeta} (post_id,meta_key,meta_value) VALUES {$values}");

Das wird nichts mit Kodierung, Serialisierung, Escape, Fehlerprüfung, Vervielfältigung oder anderem zu tun haben, aber ich würde erwarten, dass es schneller ist (obwohl ich es nicht versucht habe).

Ich würde dies auf einer Produktionsstätte nicht ohne gründliche Tests tun, und wenn ich es nur ein- oder zweimal tun müsste, würde ich die Kernfunktionen nutzen und ein langes Mittagessen einnehmen, während Dinge importieren.

5
s_ha_dum

Ich musste folgendes hinzufügen:

    remove_action('do_pings', 'do_all_pings', 10, 1);

Beachten Sie, dass dabei do_all_pings übersprungen wird, der Pingbacks, Enclosures, Trackbacks und andere Pings verarbeitet (Link: https://developer.wordpress.org/reference/functions/do_all_pings/ ). Mein Verständnis beim Betrachten des Codes ist, dass ausstehende Pingbacks/Trackbacks/Enclosures weiterhin verarbeitet werden, nachdem Sie diese remove_action-Zeile entfernt haben, aber ich bin nicht ganz sicher.

Update: habe ich auch hinzugefügt

    define( 'WP_IMPORTING', true );

Darüber hinaus benutze ich:

    ini_set("memory_limit",-1);
    set_time_limit(0);
    ignore_user_abort(true);

    wp_defer_term_counting( true );
    wp_defer_comment_counting( true );
    $wpdb->query( 'SET autocommit = 0;' );

    /* Inserting 100,000 posts at a time
       including assigning a taxonomy term and adding meta keys
       (i.e. a `foreach` loop with each loop containing:
       `wp_insert_post`, `wp_set_object_terms`, `add_post_meta`.)
    */

    $wpdb->query( 'COMMIT;' );
    wp_defer_term_counting( false );
    wp_defer_comment_counting( false );
3
firasd

Wichtiger Hinweis zu 'SET autocommit = 0;'

nach dem Setzen von autocommit = 0 wird die Ausführung des Skripts nicht mehr gespeichert (aus irgendeinem Grund, z. B. exit, schwerwiegender Fehler usw.). Ihre Änderungen WERDEN NICHT IN DB GESPEICHERT.

$wpdb->query( 'SET autocommit = 0;' );

update_option("something", "value");     

exit; //lets say, here happens error or anything...

$wpdb->query( 'COMMIT;' );

In diesem Fall wird update_option nicht in der DB gespeichert!

Daher ist es am besten, COMMIT in shutdown als Vorsichtsmaßnahme registrieren zu lassen (für den Fall, dass ein unerwartetes Beenden eintritt).

register_shutdown_function( function(){
    $GLOBALS['wpdb']->query( 'COMMIT;' );
} );
0
T.Todua