WordPress多站点产品同步脚本优化请求:解决4000+产品同步时500内部服务器错误
WordPress多站点产品同步脚本优化方案
针对你在4000+产品的多站点环境中同步时出现的500内部服务器错误,我帮你梳理几个关键优化方向,结合你的代码逐一调整:
1. 修复WP_Query分页逻辑(核心性能问题)
你当前同时使用了paged和offset,这会导致WP_Query额外查询大量冗余数据,严重拖慢性能甚至耗尽内存。去掉offset参数,paged已经能正确处理分页,同时添加几个参数减少不必要的查询开销:
$args = array( 'post_type' => 'product', 'posts_per_page' => $post_per_page, 'post_status' => array('publish', 'draft', 'private'), 'paged' => $paged, 'no_found_rows' => true, // 不需要计算总页数时开启,大幅减少SQL查询时间 'update_post_meta_cache' => false, // 后续批量获取元数据,关闭自动缓存 'update_post_term_cache' => false // 后续批量处理分类,关闭自动缓存 );
2. 批量获取产品元数据与分类
不要在循环中逐个调用get_post_meta,改用$wpdb批量查询,减少数据库请求次数:
// 在产品循环前批量获取所有产品的SKU和库存 $product_ids = wp_list_pluck($products->posts, 'ID'); $meta_query = $wpdb->get_results( $wpdb->prepare( "SELECT post_id, meta_key, meta_value FROM {$wpdb->postmeta} WHERE post_id IN (" . implode(',', array_fill(0, count($product_ids), '%d')) . ") AND meta_key IN ('_sku', '_stock')", $product_ids ) ); // 整理成便于查询的数组 $product_meta = array(); foreach ($meta_query as $meta) { $product_meta[$meta->post_id][$meta->meta_key] = $meta->meta_value; } // 批量获取atum_location分类 $location_terms = wp_get_object_terms($product_ids, 'atum_location', array('fields' => 'all_with_object_id')); $product_locations = array(); foreach ($location_terms as $term) { $product_locations[$term->object_id] = $term->slug; // 根据实际需求调整为ID或slug }
3. 按站点分组处理,减少switch_to_blog开销
每次switch_to_blog和restore_current_blog都有性能开销,不要在每个产品循环里切换站点,改为先按站点分组要同步的数据,每个站点只切换一次:
// 先整理每个站点需要同步的产品数据 $site_sync_data = array(); $current_blog_id = get_current_blog_id(); $sites = array(1, 26, 27, 28); foreach ($products->posts as $product) { $product_id = (int)$product->ID; $sku = $product_meta[$product_id]['_sku'] ?? ''; $stock = $product_meta[$product_id]['_stock'] ?? ''; $location = $product_locations[$product_id] ?? ''; if (empty($sku)) continue; // 跳过无SKU产品 foreach ($sites as $site) { if ($site == $current_blog_id) continue; if (!isset($site_sync_data[$site])) { $site_sync_data[$site] = array(); } $site_sync_data[$site][] = array( 'sku' => $sku, 'stock' => $stock, 'location' => $location ); } } // 按站点批量同步 $total_synced_products = array(); $d_sites = array(); foreach ($site_sync_data as $site => $sync_items) { switch_to_blog($site); // 批量获取站点内SKU对应的产品ID $skus = wp_list_pluck($sync_items, 'sku'); $site_product_ids = $wpdb->get_results( $wpdb->prepare( "SELECT ID, meta_value FROM {$wpdb->postmeta} pm JOIN {$wpdb->posts} p ON pm.post_id = p.ID WHERE pm.meta_key = '_sku' AND pm.meta_value IN (" . implode(',', array_fill(0, count($skus), '%s')) . ") AND p.post_type = 'product'", $skus ) ); // 整理SKU到产品ID的映射 $sku_to_pid = array(); foreach ($site_product_ids as $item) { $sku_to_pid[$item->meta_value] = $item->ID; } // 批量更新库存和分类 foreach ($sync_items as $item) { if (!isset($sku_to_pid[$item['sku']])) continue; $p_id = $sku_to_pid[$item['sku']]; wp_set_object_terms($p_id, $item['location'], 'atum_location'); update_post_meta($p_id, '_stock', $item['stock']); $total_synced_products[] = $p_id; } $d_sites[] = $site; restore_current_blog(); }
4. 增加内存与超时限制
在脚本开头添加以下代码,避免因内存不足或执行超时导致500错误:
ini_set('max_execution_time', 300); // 设置为300秒,可根据服务器配置调整 wp_memory_limit('256M'); // 提升内存限制,按需调整
5. 添加错误处理与日志记录
500错误往往是未捕获的异常导致,添加错误捕获和日志记录便于排查:
function sync_stock_action_fn() { try { // 这里放入上述优化后的所有逻辑 } catch (Exception $e) { error_log('产品同步错误: ' . $e->getMessage() . ' 行号: ' . $e->getLine()); echo json_encode(array('error' => $e->getMessage())); exit; } }
6. 移除无用的生成器函数
你当前的get_query_data生成器只是遍历数组,没有起到分批加载的作用,完全可以移除,直接遍历$products->posts即可。
内容的提问来源于stack exchange,提问作者Mohammad Umer
相关产品推荐
相关产品推荐

