
本文介绍在 WooCommerce 后台更新商品(尤其是变体产品)时,准确捕获价格变更前旧值与变更后新值的可靠方法,解决 save_post_product 钩子无法获取原始价格的常见痛点。
本文介绍在 woocommerce 后台更新商品(尤其是变体产品)时,准确捕获价格变更前旧值与变更后新值的可靠方法,解决 `save_post_product` 钩子无法获取原始价格的常见痛点。
在 WooCommerce 中,当编辑一个可变商品(Variable Product)并点击“更新”时,系统会先通过 Ajax 单独保存所有变体(variations),再保存父级商品。这意味着:变体的价格变更早已在 save_post_product 触发前完成写入数据库——因此你在该钩子中调用 $variation->get_price() 得到的始终是“新价格”,无法获取变更前的原始值。
✅ 正确时机:使用 woocommerce_admin_process_variation_object 钩子
该动作在 WooCommerce 后台处理每个变体对象(即提交变体表单时)立即触发,且在数据库持久化之前执行。此时变体对象仍保留原始数据(包括旧价格),同时已加载用户提交的新值,因此可通过对比 get_dirty_data() 或直接访问原始属性实现前后值捕获。
但需注意:$variation->get_price() 在此钩子中返回的是提交后的新价格(因为对象已被更新)。要获取旧价格,必须在数据库写入前主动查询历史值:
add_action('woocommerce_admin_process_variation_object', 'log_variation_price_change', 10, 1);
function log_variation_price_change($variation) {
$variation_id = $variation->get_id();
// 获取变更前价格(从数据库读取当前存储值)
$old_price = get_post_meta($variation_id, '_price', true);
$old_regular_price = get_post_meta($variation_id, '_regular_price', true);
$old_sale_price = get_post_meta($variation_id, '_sale_price', true);
// 获取变更后价格(已应用到对象,但尚未写入 DB)
$new_price = $variation->get_price();
$new_regular_price = $variation->get_regular_price();
$new_sale_price = $variation->get_sale_price();
// 记录日志(示例:写入 debug.log)
error_log(sprintf(
'[Variation #%d] Price: %s → %s | Regular: %s → %s | Sale: %s → %s',
$variation_id,
$old_price ?: 'N/A',
$new_price ?: 'N/A',
$old_regular_price ?: 'N/A',
$new_regular_price ?: 'N/A',
$old_sale_price ?: 'N/A',
$new_sale_price ?: 'N/A'
));
// ✅ 此处可安全执行自定义逻辑:如写入审计表、发送通知、触发同步等
}
⚠️ 关键注意事项:
- 不要依赖
save_post_product或wp_insert_post_data捕获变体旧价格——它们触发太晚; -
woocommerce_admin_process_variation_object是唯一能稳定介入变体保存流程的早期钩子; - 使用
get_post_meta()直接读取当前数据库值,是获取“旧价”的最可靠方式(因对象尚未 flush 到 DB); - 若需区分是否为真实变更,建议增加判断:
if ($old_price !== $new_price); - 该钩子对每个变体单独触发,无需手动遍历
$product->get_children()。
? 扩展建议:如需完整审计(含操作人、时间、IP),可结合 wp_get_current_user() 和 $_SERVER['REMOTE_ADDR'] 增强日志信息,并将记录存入自定义数据库表而非仅 error_log。
掌握这一机制,即可精准构建价格变更监控、自动化定价策略或第三方系统价格同步等专业功能。










