GTM4WP中排除指定产品ID的WooCommerce购买收入datalayer上报
需求背景
- 当WooCommerce订单包含产品ID为224112或159324的商品时,需将对应收入从Google Analytics购买事件中剔除,不上报至GA4。
- 此前尝试过通过GTM排除触发器、GA4后台内置过滤器实现数据拦截,最终判定从数据源头阻止对应值进入datalayer是最优实现方案。
- 站点基于WordPress+WooCommerce搭建,使用GTM4WP插件向GTM datalayer推送站点行为数据,已定位到插件中负责生成购买事件datalayer数据的
gtm4wp_get_purchase_datalayer函数,原函数代码如下:
function gtm4wp_get_purchase_datalayer( $order, $order_items ) { global $gtm4wp_options, $gtm4wp_is_woocommerce3_7; $dataLayer = array(); if ( $order instanceof WC_Order ) { $woo = WC(); // 用于Google智能购物活动新客户上报的变量 if ( $woo->customer instanceof WC_Customer ) { // 直接从数据库读取用户订单数据,避免会话数据不准 $woo_customer = new WC_Customer( $woo->customer->get_id() ); $dataLayer['new_customer'] = $woo_customer->get_order_count() === 1; } if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEXCLUDETAX ] ) { $order_revenue = (float)( $order->get_total() - $order->get_total_tax() ); } else { $order_revenue = (float) $order->get_total(); } $order_shipping_cost = (float) $order->get_shipping_total(); if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCEXCLUDESHIPPING ] ) { $order_revenue -= $order_shipping_cost; } $order_currency = $order->get_currency(); if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) { $dataLayer['event'] = 'gtm4wp.orderCompleted'; $dataLayer['transactionId'] = $order->get_order_number(); $dataLayer['transactionAffiliation'] = ''; $dataLayer['transactionTotal'] = $order_revenue; $dataLayer['transactionShipping'] = $order_shipping_cost; $dataLayer['transactionTax'] = (float) $order->get_total_tax(); $dataLayer['transactionCurrency'] = $order_currency; } if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) { $dataLayer['event'] = 'gtm4wp.orderCompletedEEC'; $dataLayer['ecommerce'] = array( 'currencyCode' => $order_currency, 'purchase' => array( 'actionField' => array( 'id' => $order->get_order_number(), 'affiliation' => '', 'revenue' => $order_revenue, 'tax' => (float) $order->get_total_tax(), 'shipping' => (float)( $order->get_shipping_total() ), 'coupon' => implode( ', ', ( $gtm4wp_is_woocommerce3_7 ? $order->get_coupon_codes() : $order->get_used_coupons() ) ), ) ) ); } if ( isset( $order_items ) ) { $_order_items = $order_items; } else { $_order_items = gtm4wp_process_order_items( $order ); } if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKCLASSICEC ] ) { $dataLayer['transactionProducts'] = $_order_items['products']; } if ( true === $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCTRACKENHANCEDEC ] ) { $dataLayer['ecommerce']['purchase']['products'] = $_order_items['products']; } if ( $gtm4wp_options[ GTM4WP_OPTION_INTEGRATE_WCREMARKETING ] ) { $dataLayer['ecomm_prodid'] = $_order_items['product_ids']; $dataLayer['ecomm_pagetype'] = 'purchase'; $dataLayer['ecomm_totalvalue'] = (float) $_order_items['sumprice']; } } return $dataLayer; }
初步尝试与待解问题
- 因不熟悉该段插件代码逻辑,且GA4数据回传存在24小时延迟,为避免站点配置出错,暂未直接修改代码。初步设想在excludeTAX判断逻辑前添加条件判断,命中目标产品ID时将
$order_revenue设为0,预想代码如下:
If ($productID = array (224112, 159324)) { $order_revenue = 0; } else { $order_revenue = (float) $order->get_total(); }
- 待解决的两个核心问题:
- 代码中获取订单内产品ID对应的正确变量是什么
- 上述修改逻辑是否可正常实现需求,求正确的代码修改方案
问题解答
两个疑问的结论先给清楚:
- 你写的预想代码跑不通:一是PHP语法错误,判断元素是否在数组内要用
in_array(),你写的是直接给变量赋值数组,逻辑完全不对;二是直接把整单收入设为0的逻辑太粗,如果订单同时有要排除的商品和其他正常商品,会把正常商品的收入也一起抹掉,数据不准;三是只改总营收不改商品列表的话,GA4里商品维度的收入加起来和总营收对不上,数据会乱。 - 这个函数里没有提前存好的订单商品ID变量,要自己通过
$order->get_items()遍历拿,判断的时候记得取商品父ID,兼容可变商品,不要拿可变商品的变体ID判断,会漏判。
正确实现方案
重要提醒:别直接改GTM4WP插件的原文件,插件更个新你的修改就没了,把逻辑写到子主题的functions.php里,或者用插件提供的filter钩子挂载是稳妥做法
1. 先加订单遍历逻辑
在原函数里计算$order_revenue的代码之前,加下面这段,先判断订单里有没有要排除的商品,同时算好要扣掉的金额:
// 要排除上报的商品ID列表 $exclude_pids = [224112, 159324]; $hit_exclude = false; $deduct_revenue = 0; // 遍历订单下所有商品 foreach ( $order->get_items() as $item ) { $pid = $item->get_product_id(); // 这个方法会自动返回可变商品的父ID,不用单独判断变体 if ( in_array($pid, $exclude_pids) ) { $hit_exclude = true; // 累加要排除的商品实际金额(算上分摊的折扣、税费) $deduct_revenue += (float)$item->get_total() + (float)$item->get_total_tax(); } }
2. 调整营收计算逻辑
根据你的实际需求选对应逻辑:
- 如果要求只要订单包含目标商品,整单收入都不上报:就在原代码算完
$order_revenue(扣完税、扣完运费之后)加判断,if($hit_exclude) { $order_revenue = 0; }就行 - 如果要求只剔除目标商品对应的收入,同单其他正常商品收入正常上报:就在原代码算完
$order_revenue之后,执行$order_revenue = max(0, $order_revenue - $deduct_revenue);,避免出现负数。
3. 同步过滤商品维度数据
原代码里拿到$_order_items之后,加下面这段过滤逻辑,把要排除的商品从上报列表里删掉,重算商品总价值,保证数据前后一致:
// 过滤商品列表 if ( !empty($_order_items['products']) ) { $clean_products = []; $clean_total = 0; $clean_pids = []; foreach ( $_order_items['products'] as $prod ) { if ( !in_array($prod['id'], $exclude_pids) ) { $clean_products[] = $prod; $clean_total += (float)$prod['price'] * (int)$prod['quantity']; $clean_pids[] = $prod['id']; } } // 替换原数据 $_order_items['products'] = $clean_products; $_order_items['sumprice'] = $clean_total; $_order_items['product_ids'] = $clean_pids; }
上线前校验
改完先开GTM的预览模式,下测试单分别验证三种场景:只有目标商品、只有普通商品、同时包含目标商品和普通商品,看datalayer里的revenue、商品列表、ecomm_totalvalue是不是符合预期,确认没问题再正式上线,避免GA4数据出错。
内容的提问来源于stack exchange,提问作者J.K.
相关产品推荐
相关产品推荐

