Editar miles de productos de WooCommerce en masa: velocidad, memoria y timeouts
Para editar miles de productos de WooCommerce en masa, el número de productos rara vez es el problema. BEAR muestra una página de la tabla cada vez y escribe en lotes pequeños, así que un catálogo de 60.000 productos se abre casi tan rápido como uno de 600. Lo que hace que el editor vaya lento, se quede sin memoria o se detenga con un 504 es otra cosa: cuántas taxonomías y términos tiene que dibujar, cuántas variaciones acaban en una misma página, cuánta memoria PHP y cuánto tiempo concede el servidor a cada petición, y lo que hacen los demás plugins cada vez que se guarda un producto. A continuación se explica cada uno de estos puntos, cómo reconocerlo y qué cambiar.
Qué consume realmente tiempo en el editor masivo
- Taxonomías y términos. Al abrir la página del editor, los paneles Filtros y Edición masiva se construyen con un desplegable por cada taxonomía de producto (categorías, etiquetas, cada atributo, taxonomías personalizadas) que contiene todos sus términos, también los que no se usan. La lista de campos carga además cada atributo con todos sus términos. Diez mil términos son diez mil opciones que construir en el servidor y dibujar en el navegador.
- Filas en la página. La tabla carga solo la página actual, pero cada fila es un objeto de producto completo, y con el interruptor de variaciones (variations) activado, cada variación de cada producto variable de la página se convierte también en una fila.
- Cada escritura. Una edición masiva guarda los productos a través de WooCommerce, y cada plugin enganchado al guardado de productos se ejecuta una vez por producto.
- Los límites del servidor. La memoria PHP por petición, el tiempo que puede ejecutarse una petición y el número de campos de formulario que acepta PHP.
El número total de productos solo afecta a cuántos lotes necesita una ejecución masiva, no a la rapidez con que se abre la página.
Demasiadas taxonomías, atributos o términos
Una tienda con unos cientos de categorías y unas decenas de atributos funciona bien. Los problemas empiezan con miles de términos, y suelen tener uno de tres orígenes: un atributo o una taxonomía que contiene un valor único por producto (un UPC, un código de modelo, una referencia de proveedor), atributos duplicados por importaciones (Color, Colour, color-2), o un árbol de categorías enorme. Las señales son una página que tarda un minuto en abrirse, una pestaña del navegador que se congela en la ventana emergente de categorías, o Maximum call stack size exceeded en la consola.
Qué cambiar, empezando por lo más eficaz:
- Saca los valores únicos de las taxonomías. Un valor que pertenece a un solo producto es un campo, no un término. Guárdalo en un campo meta y edítalo desde la pestaña Campos meta (Meta Fields); después elimina la taxonomía o el atributo.
- Limpia los atributos. Fusiona los duplicados y elimina los términos que nada usa en Productos → Atributos (Products > Attributes). El editor carga también los términos vacíos.
- Mantén las taxonomías pesadas fuera de los paneles. Estos filtros quitan taxonomías de los paneles Filtros y Edición masiva; los productos conservan sus términos.
// 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' );
Para dejar fuera de los dos paneles todos los atributos a la vez:
// 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' );
Desactiva también en la pestaña Ajustes (Settings) las columnas de taxonomía que no editas: una columna desactivada no se dibuja en ninguna fila. Con miles de categorías, cambia las categorías en la pestaña Edición masiva (Bulk Edit) en lugar de hacerlo en la ventana emergente de una celda de la tabla, que tiene que dibujar el árbol completo en el navegador cada vez que se abre; el artículo sobre edición masiva de categorías muestra cómo.
Las variaciones multiplican las filas
El interruptor de variaciones del panel de herramientas añade a la tabla las variaciones de cada producto variable de la página. Diez productos con 300 variaciones cada uno son 3.000 filas: 3.000 objetos de producto en la memoria PHP para una sola petición y 3.000 filas que el navegador debe dibujar. Los productos con cientos de variaciones son la causa más común de un error de memoria en la petición de la tabla.
- Antes de activar las variaciones, filtra por tipo de producto = variable y reduce las filas por página a 10 o 5 con el selector situado bajo la tabla. La documentación de variaciones recomienda lo mismo.
- No edites las variaciones fila por fila. En la pestaña Edición masiva, con el interruptor activado, elige las combinaciones de atributos que quieres cambiar y la operación se ejecuta por lotes sobre las variaciones de todos los productos filtrados.
- Fija Número predeterminado de productos por página (Default products count per page) en Ajustes en un valor moderado para que el editor no se abra en una página pesada.
Memoria PHP y ajustes que no se guardan
Allowed memory size of 134217728 bytes exhausted en el registro de depuración, un error 500 al abrir el editor o su pestaña Ajustes, o una petición de la tabla que falla mientras otras páginas funcionan: la petición necesitó más memoria de la que permite PHP. Sube el límite en wp-config.php, por encima de la línea que indica que se deje de editar:
define( 'WP_MEMORY_LIMIT', '256M' );
define( 'WP_MAX_MEMORY_LIMIT', '512M' );
WordPress solo puede subir la memoria hasta el memory_limit propio de PHP, que fija el hosting. Si el error sigue mostrando la cifra antigua, pide al hosting que suba memory_limit o cámbialo en el panel de hosting. En catálogos grandes, 256 MB es un mínimo razonable; reduce las taxonomías y las variaciones en lugar de subirlo sin fin.
Un límite distinto provoca que los Ajustes se guarden solo en parte. Cada atributo es un campo en la pestaña Ajustes, y cada campo envía varios valores, de modo que una tienda con cientos de atributos envía miles de valores en un solo guardado. PHP conserva los primeros max_input_vars (1000 por defecto) y descarta el resto en silencio, así que se pierden los cambios del final de la lista. Sube max_input_vars a 5000 o más en el panel de hosting o en php.ini, o arrastra los campos con los que trabajas al principio de la lista.
Ejecuciones masivas largas y timeouts 502 o 504
Una edición masiva no se ejecuta como una única petición larga. El servidor devuelve primero los ID de los productos que hay que cambiar, y después el navegador los reenvía por lotes, una petición cada uno, y la barra de progreso avanza por lote. Un 502 o un 504 a mitad de una ejecución significa que un lote tardó más de lo que permite el servidor.
- Reduce el tamaño del lote. Número de entradas procesadas a la vez (Number of posts processed at a time) en la pestaña Ajustes va desde 10 (para hosting compartido débil) hasta 100, con 30 (óptimo) como valor por defecto. Divídelo a la mitad y ejecuta de nuevo. Los lotes más pequeños tardan más en total, pero cada petición se mantiene corta.
- Divide el trabajo. Ejecuta la misma operación por categoría o por rango de precios. El Historial (History) registra cada ejecución, de modo que cada una se puede revertir por separado.
- Límites de tiempo del servidor. El
max_execution_timede PHP y los timeouts del servidor web (ApacheTimeout, nginxfastcgi_read_timeoutoproxy_read_timeout) deciden cuánto puede tardar un lote. Muchos hostings gestionados tienen un límite de pasarela fijo; en ese caso, el tamaño del lote es el ajuste que hay que cambiar. - Plugins enganchados al guardado de productos. Si diez productos tardan hasta un minuto, el tiempo se va en otros plugins: índices de búsqueda, feeds, conectores de sincronización, constructores de páginas, vaciados de caché. Aislar plugins durante las ediciones masivas muestra cómo mantenerlos fuera de las peticiones de BEAR.
Una ejecución que se detiene a la mitad deja escritos los primeros lotes. Su registro en el Historial mantiene el estado terminado (terminated) en lugar de completado (completed) y cuenta los productos escritos hasta ese momento; revierte la ejecución, o vuelve a ejecutar la operación sobre el mismo filtro si es seguro aplicarla dos veces (un valor establecer nuevo (set new) lo es, un aumentar en % (increase by %) no).
Otras cosas que ralentizan la página del editor
El desplegable de autores en tiendas con muchos usuarios
Cuando el editor se abre, construye la lista de autores para los paneles de filtro y de edición masiva pidiendo a WordPress todos los usuarios cuyo rol puede publicar. En un sitio con una tabla de usuarios muy grande, o con un plugin que reescribe las consultas de usuarios, esa consulta por sí sola puede tardar minutos y acabar en un 504 antes de que aparezca la página. El filtro woobe_users_args sustituye la consulta, por ejemplo por los usuarios que realmente son autores de productos:
// 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 usuario que todavía no es autor de ningún producto no aparecerá en la lista hasta que caduque la lista en caché un día después; elimina el transient bear_product_author_ids para actualizarla de inmediato.
Vaciados de la caché de objetos y optimización del administrador
En sitios con Redis o Memcached, BEAR vacía la caché de objetos antes de dibujar la tabla, de modo que todo el sitio reconstruye su caché cada vez que se carga la tabla. En una tienda grande con mucho tráfico se nota; el filtro woobe_use_cache_flush lo desactiva, con la contrapartida explicada en el filtro del editor masivo no funciona. Los plugins de caché de páginas y de optimización que minifican, combinan o retrasan scripts en wp-admin ralentizan todas las peticiones del editor; excluye /wp-admin/ de esas funciones.
Lista de comprobación para un catálogo grande
- Ninguna taxonomía contiene un término por producto; los atributos duplicados están fusionados y los términos sin uso, eliminados.
- Las taxonomías por las que nunca filtras ni editas en masa se han quitado de los paneles con
woobe_filter_taxonomiesywoobe_bulkedit_taxonomies. - Las filas por página son 10 o menos mientras el interruptor de variaciones está activado.
- El
memory_limitde PHP es de 256 MB o más ymax_input_varses lo bastante alto para tu pestaña Ajustes. - Número de entradas procesadas a la vez es lo bastante bajo como para que ningún lote llegue al timeout del servidor.
- No hay nada que hacer con las filas de BEAR en
wp_options: las que pueden crecer, los ajustes por usuario (woobe_options_más el ID de usuario) y la memoria por usuario (woobe_memory_más el ID de usuario), se escriben sin autoload, así que las páginas de la tienda nunca las cargan, y las filas de memoria guardan solo el filtro actual y los datos de la edición masiva, que caducan al cabo de un día.
Si el editor sigue lento después de estos cambios, abre un tema en el foro de soporte de BEAR con el número de productos, las variaciones por producto, las taxonomías y los términos, y el error que muestre el servidor o la consola del navegador.