Modifier en masse des milliers de produits WooCommerce : vitesse, mémoire, délais
Pour modifier en masse des milliers de produits WooCommerce, le nombre de produits est rarement le problème. BEAR affiche une page du tableau à la fois et écrit par petits lots, si bien qu'un catalogue de 60 000 produits s'ouvre presque aussi vite qu'un catalogue de 600. Ce qui rend l'éditeur lent, le fait manquer de mémoire ou l'arrête avec une erreur 504 est autre chose : le nombre de taxonomies et de termes à afficher, le nombre de variations qui se retrouvent sur une même page, la mémoire PHP et le temps que le serveur accorde à chaque requête, et ce que font les autres extensions chaque fois qu'un produit est enregistré. Voici chacun de ces points, comment le reconnaître et quoi changer.
Ce qui coûte réellement du temps dans l'éditeur en masse
- Les taxonomies et les termes. À l'ouverture de la page de l'éditeur, les panneaux Filtres et Modifier en bloc (Bulk Edit) sont construits avec une liste déroulante pour chaque taxonomie de produit (catégories, étiquettes, chaque attribut, taxonomies personnalisées) contenant tous les termes, y compris ceux qui ne sont pas utilisés. La liste des champs charge aussi chaque attribut avec tous ses termes. Dix mille termes, ce sont dix mille options à construire sur le serveur et à afficher dans le navigateur.
- Les lignes de la page. Le tableau ne charge que la page en cours, mais chaque ligne est un objet produit complet, et avec l'interrupteur variations activé, chaque variation de chaque produit variable de la page devient elle aussi une ligne.
- Chaque écriture. Une modification en masse enregistre les produits via WooCommerce, et chaque extension branchée sur l'enregistrement des produits s'exécute une fois par produit.
- Les limites du serveur. La mémoire PHP par requête, la durée pendant laquelle une requête peut s'exécuter, et le nombre de champs de formulaire que PHP accepte.
Le nombre total de produits n'influe que sur le nombre de lots d'un traitement en masse, pas sur la vitesse d'ouverture de la page.
Trop de taxonomies, d'attributs ou de termes
Une boutique avec quelques centaines de catégories et quelques dizaines d'attributs fonctionne très bien. Les ennuis commencent avec des milliers de termes, et ils ont en général l'une de trois origines : un attribut ou une taxonomie contenant une valeur unique par produit (un code UPC, un code de modèle, une référence fournisseur), des attributs dupliqués par des imports (Couleur, Couleurs, couleur-2), ou une arborescence de catégories immense. Les signes sont une page qui met une minute à s'ouvrir, un onglet du navigateur qui se fige sur la fenêtre des catégories, ou Maximum call stack size exceeded dans la console.
Ce qu'il faut changer, du plus efficace au moins efficace :
- Sortez les valeurs uniques des taxonomies. Une valeur qui appartient à un seul produit est un champ, pas un terme. Conservez-la dans un champ méta et modifiez-la via l'onglet Champs méta (Meta Fields) ; supprimez ensuite la taxonomie ou l'attribut.
- Nettoyez les attributs. Fusionnez les doublons et supprimez les termes que rien n'utilise sous Produits > Attributs (Products > Attributes). L'éditeur charge aussi les termes vides.
- Gardez les taxonomies lourdes hors des panneaux. Ces filtres retirent des taxonomies des panneaux Filtres et Modifier en bloc ; les produits conservent leurs termes.
// Child theme functions.php or a code snippets plugin.
// BEAR: do not draw these taxonomies in the Filters and Bulk Edit panels.
function bear_skip_heavy_taxonomies( $taxonomies ) {
foreach ( array( 'pa_model-code', 'product_tag' ) as $slug ) { // your taxonomy slugs
unset( $taxonomies[ $slug ] );
}
return $taxonomies;
}
add_filter( 'woobe_filter_taxonomies', 'bear_skip_heavy_taxonomies' );
add_filter( 'woobe_bulkedit_taxonomies', 'bear_skip_heavy_taxonomies' );
Pour exclure d'un coup tous les attributs des deux panneaux :
// BEAR: no attribute (pa_) drop-downs in the Filters and Bulk Edit panels.
add_filter( 'woobe_hide_filters_by_attribute', '__return_true' );
add_filter( 'woobe_hide_bulk_by_attribute', '__return_true' );
Désactivez aussi, dans l'onglet Paramètres (Settings), les colonnes de taxonomie que vous ne modifiez pas : une colonne désactivée n'est dessinée pour aucune ligne. Avec des milliers de catégories, changez les catégories dans l'onglet Modifier en bloc plutôt que dans la fenêtre d'une cellule du tableau, qui doit dessiner toute l'arborescence dans le navigateur à chaque ouverture ; l'article sur l'édition en masse des catégories montre comment.
Les variations multiplient les lignes
L'interrupteur variations du panneau d'outils ajoute au tableau les variations de chaque produit variable de la page. Dix produits de 300 variations chacun font 3 000 lignes : 3 000 objets produit dans la mémoire PHP pour une seule requête et 3 000 lignes à dessiner pour le navigateur. Les produits qui ont des centaines de variations sont la cause la plus fréquente d'une erreur de mémoire sur la requête du tableau.
- Avant d'activer les variations, filtrez par type de produit = variable et réduisez le nombre de lignes par page à 10 ou 5 avec le sélecteur sous le tableau. La documentation sur les variations recommande la même chose.
- Ne modifiez pas les variations ligne par ligne. Dans l'onglet Modifier en bloc, interrupteur activé, choisissez les combinaisons d'attributs à modifier et l'opération s'exécute par lots sur les variations de tous les produits filtrés.
- Réglez Nombre de produits par page par défaut (Default products count per page) dans les Paramètres sur une valeur modérée afin que l'éditeur ne s'ouvre pas sur une page trop lourde.
Mémoire PHP et réglages qui ne s'enregistrent pas
Allowed memory size of 134217728 bytes exhausted dans le journal de débogage, une erreur 500 à l'ouverture de l'éditeur ou de son onglet Paramètres, ou une requête du tableau qui échoue alors que les autres pages fonctionnent : la requête a eu besoin de plus de mémoire que PHP n'en autorise. Augmentez la limite dans wp-config.php, au-dessus de la ligne qui indique de ne plus rien modifier :
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
WordPress ne peut augmenter la mémoire que jusqu'à la valeur de memory_limit de PHP, que fixe l'hébergeur. Si l'erreur mentionne toujours l'ancien nombre, demandez à l'hébergeur d'augmenter memory_limit ou modifiez-le dans le panneau d'hébergement. Sur de grands catalogues, 256 Mo est un minimum raisonnable ; réduisez les taxonomies et les variations plutôt que d'augmenter la limite sans fin.
Une autre limite fait que les Paramètres ne s'enregistrent que partiellement. Chaque attribut est un champ de l'onglet Paramètres, et chaque champ envoie plusieurs valeurs, si bien qu'une boutique avec des centaines d'attributs envoie des milliers de valeurs en un seul enregistrement. PHP conserve les max_input_vars premières (1000 par défaut) et ignore silencieusement le reste, de sorte que les modifications situées en bas de la liste sont perdues. Augmentez max_input_vars à 5000 ou plus dans le panneau d'hébergement ou dans php.ini, ou faites glisser en haut de la liste les champs avec lesquels vous travaillez.
Longs traitements en masse et délais dépassés 502 ou 504
Une modification en masse ne s'exécute pas comme une seule longue requête. Le serveur renvoie d'abord les ID des produits à modifier, puis le navigateur les renvoie par lots, une requête chacun, et la barre de progression avance à chaque lot. Une erreur 502 ou 504 au milieu d'un traitement signifie qu'un lot a pris plus de temps que le serveur ne le permet.
- Réduisez la taille des lots. Nombre d'éléments traités à la fois (Number of posts processed at a time) dans l'onglet Paramètres va de 10 (pour hébergement mutualisé faible) (10 (for weak shared hosting)) à 100, avec 30 (optimal) par défaut. Divisez la valeur par deux et relancez. Des lots plus petits prennent plus de temps au total, mais chaque requête reste courte.
- Découpez le travail. Lancez la même opération par catégorie ou par tranche de prix. L'Historique enregistre chaque exécution, et chacune peut donc être annulée séparément.
- Les limites de temps du serveur.
max_execution_timede PHP et les délais du serveur web (Timeoutd'Apache,fastcgi_read_timeoutouproxy_read_timeoutde nginx) déterminent la durée maximale d'un lot. De nombreux hébergeurs gérés imposent une limite fixe sur la passerelle ; dans ce cas, la taille des lots est le réglage à modifier. - Les extensions branchées sur l'enregistrement des produits. Si dix produits prennent jusqu'à une minute, le temps est consommé par d'autres extensions : index de recherche, flux, connecteurs de synchronisation, constructeurs de pages, purges de cache. Isoler les extensions pendant les modifications en masse montre comment les tenir à l'écart des requêtes de BEAR.
Un traitement qui s'arrête en cours de route laisse les premiers lots écrits. Son enregistrement dans l'Historique garde l'état interrompu (terminated) au lieu de terminé (completed) et compte les produits écrits jusque-là ; annulez-le, ou relancez l'opération sur le même filtre si l'appliquer deux fois est sans risque (une valeur définir une nouvelle valeur (set new) l'est, une augmenter de % (increase by %) ne l'est pas).
Autres causes de lenteur de la page de l'éditeur
La liste déroulante des auteurs sur les boutiques comptant beaucoup d'utilisateurs
À l'ouverture, l'éditeur construit la liste des auteurs pour les panneaux de filtre et de modification en masse en demandant à WordPress tous les utilisateurs dont le rôle peut publier. Sur un site dont la table des utilisateurs est très grande, ou avec une extension qui réécrit les requêtes d'utilisateurs, cette seule requête peut durer plusieurs minutes et se terminer par une erreur 504 avant l'affichage de la page. Le filtre woobe_users_args remplace la requête, par exemple par les utilisateurs qui possèdent effectivement des produits :
// Child theme functions.php or a code snippets plugin.
// BEAR: list only users who already own products in the author drop-down.
add_filter( 'woobe_users_args', function ( $args ) {
global $wpdb;
$author_ids = get_transient( 'bear_product_author_ids' );
if ( false === $author_ids ) {
$author_ids = $wpdb->get_col( "SELECT DISTINCT post_author FROM {$wpdb->posts} WHERE post_type = 'product'" );
set_transient( 'bear_product_author_ids', $author_ids, DAY_IN_SECONDS );
}
return array(
'fields' => array( 'ID', 'display_name' ),
'include' => empty( $author_ids ) ? array( 0 ) : array_map( 'intval', $author_ids ),
'orderby' => 'display_name',
);
} );
Un utilisateur qui ne possède encore aucun produit n'apparaîtra pas dans la liste avant l'expiration de la liste en cache, un jour plus tard ; supprimez le transient bear_product_author_ids pour l'actualiser immédiatement.
Purges du cache d'objets et optimisation de l'administration
Sur les sites avec Redis ou Memcached, BEAR vide le cache d'objets avant de dessiner le tableau, si bien que tout le site reconstruit son cache chaque fois que le tableau se charge. Sur une grande boutique très fréquentée, cela se remarque ; le filtre woobe_use_cache_flush le désactive, avec le compromis expliqué dans le filtre de l'éditeur en masse ne fonctionne pas. Les extensions de cache de pages et d'optimisation qui minifient, combinent ou retardent les scripts dans wp-admin ralentissent chaque requête de l'éditeur ; excluez /wp-admin/ de ces fonctions.
Liste de contrôle pour un grand catalogue
- Aucune taxonomie ne contient un terme par produit ; les attributs en double sont fusionnés et les termes inutilisés supprimés.
- Les taxonomies par lesquelles vous ne filtrez ni ne modifiez jamais en masse sont retirées des panneaux avec
woobe_filter_taxonomiesetwoobe_bulkedit_taxonomies. - Le nombre de lignes par page est de 10 ou moins tant que l'interrupteur des variations est activé.
memory_limitde PHP est de 256 Mo ou plus etmax_input_varsest assez élevé pour votre onglet Paramètres.- Nombre d'éléments traités à la fois (Number of posts processed at a time) est assez bas pour qu'aucun lot n'atteigne le délai d'expiration du serveur.
- Rien à faire concernant les lignes de BEAR dans
wp_options: celles qui peuvent grossir, les réglages par utilisateur (woobe_options_suivi de l'ID de l'utilisateur) et la mémoire par utilisateur (woobe_memory_suivi de l'ID de l'utilisateur), sont écrites sans chargement automatique, de sorte que les pages de la boutique ne les chargent jamais, et les lignes de mémoire ne contiennent que le filtre et les données de modification en masse en cours, qui expirent au bout d'un jour.
Si l'éditeur reste lent après ces changements, ouvrez un sujet sur le forum d'assistance de BEAR en indiquant le nombre de produits, les variations par produit, les taxonomies et les termes, ainsi que l'erreur affichée par le serveur ou la console du navigateur.