Un moyen plus rapide de traiter en vrac wp_insert_post & add_post_meta

12

Je souhaite insérer un fichier csv comprenant environ 1 500 lignes et 97 colonnes. Il faut environ 2 à 3 heures pour effectuer une importation complète et j'aimerais l'améliorer s'il y a un moyen. Actuellement, pour chaque ligne, je fais un $ post_id = wp_insert_post puis un add_post_meta pour les 97 colonnes associées à chaque ligne. C'est assez inefficace ...

Existe-t-il une meilleure façon de s'y prendre pour pouvoir obtenir un post_id en conservant la relation entre post et ses valeurs post_meta?

En ce moment, j'essaie ceci sur ma machine locale avec wamp mais je vais le faire fonctionner sur un VPS

    
posée Corey Rowell 08.06.2013 - 18:37

4 réponses

16

J'ai eu des problèmes similaires il y a quelque temps avec une importation CSV personnalisée, mais j'ai fini par utiliser un code SQL personnalisé pour l'insertion en bloc. Mais je n'avais pas encore vu cette réponse:

Optimiser l'insertion et la suppression pour les opérations en bloc?

utiliser wp_defer_term_counting() pour activer ou désactiver le comptage de termes.

Aussi, si vous consultez la source pour la Plugin importateur WordPress, vous verrez ces fonctions juste avant l’importation en bloc:

wp_defer_term_counting( true );
wp_defer_comment_counting( true );

puis après l'insertion en bloc:

wp_defer_term_counting( false );
wp_defer_comment_counting( false );

Cela pourrait donc être quelque chose à essayer; -)

L'importation de publications sous forme de brouillon au lieu de publier accélérera également les choses, car le processus lent de recherche d'un slug unique pour chacun d'entre eux est ignoré. On pourrait par exemple publiez-les plus tard par petites étapes, mais notez que ce type d'approche devrait marquer les publications importées d'une manière ou d'une autre, de sorte que nous ne publions pas de brouillon plus tard! Cela nécessiterait une planification minutieuse et très probablement un code personnalisé.

Une autre option consisterait à utiliser la WP-CLI pour éviter l'expiration du délai. Voir par exemple Ma réponse a été postée pour Création de 20 000 articles ou pages à l'aide d'un fichier .csv?

Évitez également d'importer un grand nombre de types de publication hiérarchiques, car l'interface utilisateur actuelle de wp-admin ne la gère pas correctement. Voir par exemple Type de message personnalisé - Liste des messages - Écran blanc de la mort

Voici le bon conseil de @otto:

Avant les insertions en bloc , désactivez explicitement le mode autocommit :

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

Après avoir inséré en vrac, exécutez:

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

Je pense aussi que ce serait une bonne idée de faire un peu de ménage comme:

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

Je n'ai pas testé cela sur MyISAM mais cela devrait fonctionner sur InnoDB .

Comme mentionné par @kovshenin, ce conseil ne fonctionnerait pas pour MyISAM .

    
réponse donnée birgire 08.06.2013 - 21:36
5

Vous devrez insérer le message pour obtenir votre identifiant, mais la table $wpdb->postmeta a une structure très simple. Vous pourriez probablement utiliser une instruction INSERT INTO , comme ceci depuis les documents MySQL: INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

Dans votre cas ...

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

Cela ne traitera pas l'encodage, la sérialisation, l'échappement, la vérification des erreurs, les duplications ou toute autre chose, mais je m'attendrais à ce que ce soit plus rapide (bien que je n'aie pas essayé).

Je ne le ferais pas sur un site de production sans des tests approfondis. Si je devais le faire une ou deux fois seulement, j'utiliserais les fonctions principales et prendrais un long déjeuner pendant que les choses importaient.

    
réponse donnée s_ha_dum 08.06.2013 - 19:13
3

Je devais ajouter ceci:

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

Gardez à l'esprit que cela ignorera do_all_pings , qui traite les pingbacks, les enclos, les rétroliens et autres pings (lien: enlace ). D'après ce que j'ai compris en regardant le code, les pingbacks / rétroliens / enclos en attente seront toujours traités après la suppression de cette ligne remove_action , mais je ne suis pas tout à fait sûr.

Mise à jour: j'ai également ajouté

    define( 'WP_IMPORTING', true );

Au-delà de ce que j'utilise:

    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 );
    
réponse donnée firasd 01.08.2016 - 23:41
0

Note importante à propos de 'SET autocommit = 0;'

après avoir défini autocommit = 0 si le script arrête l'exécution (pour une raison quelconque, telle que exit , une erreur fatale ou etc ...), vos modifications ne seront pas sauvegardées dans la base de données!

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

update_option("something", "value");     

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

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

Dans ce cas, update_option ne sera pas enregistré dans la base de données!

Donc, le meilleur conseil est d’enregistrer COMMIT enregistré dans shutdown comme précaturation (au cas où une sortie inattendue se produirait).

register_shutdown_function( function(){
    $GLOBALS['wpdb']->query( 'COMMIT;' );
} );
    
réponse donnée T.Todua 14.09.2018 - 19:04

Lire d'autres questions sur les étiquettes