Caminho mais rápido para wp_insert_post e add_post_meta em massa

12

Eu tenho um arquivo csv que quero inserir que consiste em ~ 1.500 linhas e 97 colunas. Demora cerca de 2-3 horas para fazer uma importação completa e eu gostaria de melhorar isso se houver uma maneira. Atualmente para cada linha estou fazendo um $ post_id = wp_insert_post e, em seguida, um add_post_meta para as 97 colunas associadas a cada linha. Isso é muito ineficiente ...

Existe uma maneira melhor de fazer isso de uma maneira que um post_id possa manter a relação entre post e seus valores post_meta?

Agora eu estou tentando isso na minha máquina local com o wamp mas ele está rodando em um VPS

    
por Corey Rowell 08.06.2013 / 18:37

4 respostas

16

Eu tive problemas semelhantes há algum tempo com uma importação de CSV personalizada, mas acabei usando algum SQL personalizado para a inserção em massa. Mas eu não tinha visto essa resposta até então:

Otimize a inserção de postagens e exclua operações em massa?

para usar wp_defer_term_counting() para ativar ou desativar a contagem de termos.

Além disso, se você verificar a fonte para o WordPress importador plugin, você verá essas funções pouco antes da importação em massa:

wp_defer_term_counting( true );
wp_defer_comment_counting( true );

e depois da inserção em massa:

wp_defer_term_counting( false );
wp_defer_comment_counting( false );

Então, isso pode ser algo para experimentar; -)

A importação de posts como rascunho ao invés de publicar , também acelera as coisas, pois o processo lento de encontrar um slug exclusivo para cada um é ignorado. Um poderia, e. publique-os posteriormente em etapas menores, mas observe que esse tipo de abordagem precisaria marcar as postagens importadas de alguma forma, portanto, não publicamos mais rascunhos depois! Isso precisaria de um planejamento cuidadoso e, provavelmente, de alguma codificação personalizada.

Outra opção seria usar WP-CLI para evitar o tempo limite. Veja por exemplo minha resposta postada para Criando 20.000 postagens ou páginas usando um arquivo .csv?

Além disso, evite importar um grande número de tipos de postagens hierárquicas, já que a interface do usuário atual do wp-admin não lida bem com isso. Veja por exemplo Lista de postagens de postagens personalizadas - tela branca da morte

Esta é a ótima dica do @otto:

Antes de inserções em massa , desative o modo autocommit explicitamente:

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

Após as inserções em massa, execute:

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

Eu também acho que seria uma boa ideia fazer algumas tarefas domésticas como:

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

Eu não testei isso em MyISAM mas isso deve funcionar em InnoDB .

Como mencionado por @kovshenin, esta dica não funcionaria para MyISAM .

    
por birgire 08.06.2013 / 21:36
5

Você precisará inserir a postagem para obter seu ID, mas a tabela $wpdb->postmeta é muito simples na estrutura. Provavelmente você poderia usar uma instrução INSERT INTO direta, como esta nos documentos do MySQL: INSERT INTO tbl_name (a,b,c) VALUES(1,2,3),(4,5,6),(7,8,9);

No seu caso ...

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

Isso não lidará com nenhuma codificação, serialização, escape, verificação de erros, duplicações ou qualquer outra coisa, mas esperaria que fosse mais rápido (embora eu não tenha tentado).

Eu não faria isso em um site de produção sem testes completos, e se eu tivesse que fazer isso apenas uma ou duas vezes, usaria as funções principais e faria um longo almoço enquanto as coisas importavam.

    
por s_ha_dum 08.06.2013 / 19:13
3

Eu tive que adicionar isso:

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

Lembre-se de que isso ignorará do_all_pings , que processa pingbacks, anexos, trackbacks e outros pings (link: enlace . Meu entendimento de olhar para o código é que pingbacks / trackbacks / enclosures pendentes ainda serão processados depois que você remover essa linha remove_action , mas não tenho certeza absoluta.

Atualização: também adicionei

    define( 'WP_IMPORTING', true );

Além disso, estou usando:

    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 );
    
por firasd 01.08.2016 / 23:41
0

Nota importante sobre 'SET autocommit = 0;'

depois de definir autocommit = 0 se o script parar a execução (por algum motivo, como exit , erro fatal ou etc ...), suas alterações NÃO SERÃO SALVADAS NA BD!

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

update_option("something", "value");     

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

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

Nesse caso, update_option não será salvo no banco de dados!

Portanto, o melhor conselho é ter COMMIT registrada em shutdown como uma precação (no caso de ocorrer uma saída inesperada).

register_shutdown_function( function(){
    $GLOBALS['wpdb']->query( 'COMMIT;' );
} );
    
por T.Todua 14.09.2018 / 19:04