PageSourceSearch

https://sweetcode.com/assets/js/62e34844.0f3feb26.js

js sweetcode.com collected 2026-10-01 10:38:09 UTC 42,852 bytes, 1 lines download raw bytes

1"use strict";(globalThis.webpackChunkdocusaurus_test=globalThis.webpackChunkdocusaurus_test||[]).push([[21931],{94190(e,n,t){t.r(n),t.d(n,{assets:()=>c,contentTitle:()=>r,default:()=>h,frontMatter:()=>a,metadata:()=>o,toc:()=>d});let o=JSON.parse('{"id":"pmw/developers/tipps-and-tricks","title":"Tips and Tricks","description":"All the jQuery event listeners on this page will only work if jQuery has not been moved to the footer or delayed by a JavaScript optimizer. In case that happened use the following code to wait asynchronously (non page load blocking) until jQuery is loaded and then attach the event listeners.","source":"@site/docs/pmw/developers/tipps-and-tricks.md","sourceDirName":"pmw/developers","slug":"/pmw/developers/tipps-and-tricks","permalink":"/docs/pmw/developers/tipps-and-tricks","draft":false,"unlisted":false,"tags":[],"version":"current","lastUpdatedAt":1790234219000,"frontMatter":{},"sidebar":"pmwSidebar","previous":{"title":"Logs","permalink":"/docs/pmw/developers/logs"},"next":{"title":"Server-Side Proxy","permalink":"/docs/pmw/server-side-proxy/overview"}}');var i=t(74848),s=t(28453);let a={},r="Tips and Tricks",c={},d=[{value:"A way to always attach event listeners after jQuery has been loaded",id:"a-way-to-always-attach-event-listeners-after-jquery-has-been-loaded",level:2},{value:"Add the product name to add-to-cart events with a label",id:"add-the-product-name-to-add-to-cart-events-with-a-label",level:2},{value:"Add an event listener to any element on the website",id:"add-an-event-listener-to-any-element-on-the-website",level:2},{value:"Track custom events for Meta (Facebook)",id:"track-custom-events-for-meta-facebook",level:2},{value:"Limits of custom Meta events",id:"limits-of-custom-meta-events",level:3},{value:"Replicate PixelYourSite&#39;s Advanced Marketing Events",id:"replicate-pixelyoursites-advanced-marketing-events",level:2},{value:"Adjust pixel IDs and other settings per country domain",id:"adjust-pixel-ids-and-other-settings-per-country-domain",level:2},{value:"Fire the view_item event on variable products when no variation is pre-selected",id:"fire-the-view_item-event-on-variable-products-when-no-variation-is-pre-selected",level:2},{value:"Recommended: use the Variations Output setting",id:"recommended-use-the-variations-output-setting",level:3},{value:"Alternative: keep Variations Output enabled and fire a parent view_item on load",id:"alternative-keep-variations-output-enabled-and-fire-a-parent-view_item-on-load",level:3},{value:"Doing it in JavaScript instead",id:"doing-it-in-javascript-instead",level:4},{value:"Modify the page_title and page_location in GA4",id:"modify-the-page_title-and-page_location-in-ga4",level:2},{value:"Track custom Google Ads conversions",id:"track-custom-google-ads-conversions",level:2},{value:"Track mailto: links with Google Ads conversions",id:"track-mailto-links-with-google-ads-conversions",level:2},{value:"Track <code>add-to-cart</code> and <code>begin-checkout</code> events with Google Ads conversions",id:"track-add-to-cart-and-begin-checkout-events-with-google-ads-conversions",level:2}];function l(e){let n={a:"a",admonition:"admonition",code:"code",h1:"h1",h2:"h2",h3:"h3",h4:"h4",header:"header",li:"li",mdxAdmonitionTitle:"mdxAdmonitionTitle",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",ul:"ul",...(0,s.R)(),...e.components};return(0,i.jsxs)(i.Fragment,{children:[(0,i.jsx)(n.header,{children:(0,i.jsx)(n.h1,{id:"tips-and-tricks",children:"Tips and Tricks"})}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsx)(n.p,{children:"All the jQuery event listeners on this page will only work if jQuery has not been moved to the footer or delayed by a JavaScript optimizer. In case that happened use the following code to wait asynchronously (non page load blocking) until jQuery is loaded and then attach the event listeners."})}),"\n",(0,i.jsx)(n.admonition,{type:"tip",children:(0,i.jsxs)(n.p,{children:["Many examples on this page hook into the Pixel Manager's ",(0,i.jsx)(n.code,{children:"pmw:*"})," events. ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/javascript-events",children:"JavaScript Events"})," documents all of them, including the payloads and how to trigger events yourself."]}
1)}),"\n",(0,i.jsxs)(n.admonition,{type:"warning",children:[(0,i.jsxs)(n.mdxAdmonitionTitle,{children:["If you call ",(0,i.jsx)(n.code,{children:"gtag()"})," yourself"]}),(0,i.jsxs)(n.p,{children:["The Pixel Manager loads the Google tag itself, and on shops that defer or delay JavaScript it does so ",(0,i.jsx)(n.strong,{children:"after"})," the page's own inline scripts have run. Code of yours that calls ",(0,i.jsx)(n.code,{children:"gtag()"})," without waiting therefore fires nothing, and it does so reliably rather than occasionally, because the data layer is printed by PHP long before the tracking bundle executes."]}),(0,i.jsx)(n.p,{children:"Two guards fix it, the same two the Pixel Manager applies to its own Google conversions:"}),(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:'pmw.googleConfigConditionsMet({type: "marketing"})'})," (or ",(0,i.jsx)(n.code,{children:'"statistics"'})," for an analytics-only event) for consent,"]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.code,{children:"pmw.gtagLoaded().then(\u2026)"})," to wait until the Google tag is actually there."]}),"\n"]}),(0,i.jsxs)(n.p,{children:["Both belong inside a ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/command-queue",children:"command queue"})," command, which is what guarantees that ",(0,i.jsx)(n.code,{children:"pmw"})," exists at all. Do not wait for ",(0,i.jsx)(n.code,{children:"pmw:ready"})," instead: that event carries no payload and is never replayed, so a snippet that registers after it fired hears nothing."]}),(0,i.jsxs)(n.p,{children:["From version ",(0,i.jsx)(n.code,{children:"1.67.1"})," on, ",(0,i.jsx)(n.a,{href:"#track-custom-google-ads-conversions",children:(0,i.jsx)(n.code,{children:"pmw.trackCustomGoogleAdsConversion()"})})," applies both guards for you. Prefer it over a hand-written ",(0,i.jsx)(n.code,{children:"gtag()"})," call for anything that is a Google Ads conversion."]})]}),"\n",(0,i.jsx)(n.h2,{id:"a-way-to-always-attach-event-listeners-after-jquery-has-been-loaded",children:"A way to always attach event listeners after jQuery has been loaded"}),"\n",(0,i.jsx)(n.p,{children:"Some shop owners use JavaScript optimizers to delay or lazy load jQuery and tracking scripts, including Pixel Manager for WooCommerce."}),"\n",(0,i.jsx)(n.p,{children:"Pixel Manager for WooCommerce itself can handle this seamlessly. But if you want to track your own events using the Pixel Manager for WooCommerce API, handling delayed and lazy loaded scripts is a challenge because hooking into jQuery, only after it loaded, is not straight forward. So if jQuery gets delayed or lazy loaded we need a way to deal with this."}),"\n",(0,i.jsx)(n.p,{children:"The following code example will wait until jQuery is loaded. Once done it will attach an event listener to any element and execute the code each time the event is triggered."}),"\n",(0,i.jsx)(n.p,{children:"The advantage of the method is, that it won't block any other page loading execution, because it runs asynchronously."}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-js",children:'// This first part of the code waits until jQuery has been loaded\n// without blocking the main page loading thread\n\nnew Promise((resolve) => {\n    (function waitForjQuery() {\n        if (window.jQuery) return resolve()\n        setTimeout(waitForjQuery, 100)\n    })()\n}).then(() => {\n\n    // Replace the following code with your event listener\n    jQuery(document).on("SOME_EVENT", function () {\n        // Here is your custom code\n    })\n	// End replacement code\n})\n'})}),"\n",(0,i.jsx)(n.h2,{id:"add-the-product-name-to-add-to-cart-events-with-a-label",children:"Add the product name to add-to-cart events with a label"}),"\n",(0,i.jsxs)(n.p,{children:["Ever wanted to see which products are added to the cart in real-time? Then this filter is for you. Simply add the following code to ",(0,i.jsx)(n.code,{children:"functions.php"})," and from then on it will send the product name as the event label to Google Analytics"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:'add_action(\'wp_footer\', function () {\n	?>\n	<script>\n		window._pmwq = window._pmwq || [];\n		window._pmwq.push(function () {\n\n			pmw.bus.on("pmw:add-to-cart", function (product) {\n\n				if (!pmw.googleConfigConditionsMet({type: "statistics"})) return;
1\n\n				pmw.gtagLoaded().then(function () {\n					gtag("event", "add_to_cart", {\n						event_category: "add_to_cart",\n						event_label   : product.name,\n					})\n				}).catch(function () {\n					// The Google tag never became ready, so there is nothing to send.\n				})\n			})\n		})\n	<\/script>\n	<?php\n});\n'})}),"\n",(0,i.jsx)(n.h2,{id:"add-an-event-listener-to-any-element-on-the-website",children:"Add an event listener to any element on the website"}),"\n",(0,i.jsx)(n.p,{children:"You can use the following example to attach an event listener to any element on your website and trigger a tracking event."}),"\n",(0,i.jsx)(n.p,{children:"In the following example we're attaching an event listener to a contact form button and triggering a Google Ads conversion for every submit form click."}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsx)(n.p,{children:"This example is only to illustrate how this can be done."}),(0,i.jsxs)(n.p,{children:["To track contact form submissions we recommend to only track ",(0,i.jsx)(n.strong,{children:"successful"})," form submissions. This can be easily done by creating a redirect to a thank-you page after a successful form submission and place a ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/shortcodes",children:"tracking shortcode"})," on the thank-you page."]})]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:'add_action(\'wp_footer\', function () { ?>\n\n    <script>\n        window._pmwq = window._pmwq || [];\n        window._pmwq.push(function () {\n\n            // Attach the event to a button or any element on your page\n            jQuery(document).on("click", ".contact-form-button", function () {\n\n                if (!pmw.googleConfigConditionsMet({type: "marketing"})) return;\n\n                // Fire a tracking event like "gtag" for Google, "fbq" for Facebook, etc.\n                pmw.gtagLoaded().then(function () {\n                    gtag("event", "conversion", {\n                        send_to: "AW-123456789/AABBCCDDEEFFGG",\n                        value: 0.0,\n                        currency: "USD",\n                        transaction_id: "",\n                    });\n                }).catch(function () {\n                    // The Google tag never became ready, so there is nothing to send.\n                });\n            })\n        })\n    <\/script>\n\n<?php });\n'})}),"\n",(0,i.jsx)(n.h2,{id:"track-custom-events-for-meta-facebook",children:"Track custom events for Meta (Facebook)"}),"\n",(0,i.jsxs)(n.p,{children:["If for some reason you want to track ",(0,i.jsx)(n.a,{href:"https://developers.facebook.com/docs/meta-pixel/implementation/conversion-tracking/#custom-events",children:"custom events"})," in Meta (Facebook) there is a way to do this with Pixel Manager for WooCommerce."]}),"\n",(0,i.jsxs)(n.p,{children:["The Pixel Manager offers the function ",(0,i.jsx)(n.code,{children:'pmw.trackCustomFacebookEvent("CUSTOM_EVENT_NAME", OPTIONAL_CUSTOM_DATA_OBJECT)'}),". When you run this function it will send ",(0,i.jsx)(n.code,{children:"CUSTOM_EVENT_NAME"})," to Meta (Facebook), including the ",(0,i.jsx)(n.code,{children:"OPTIONAL_CUSTOM_DATA_OBJECT"})," if it is added. And if Meta (Facebook) CAPI is enabled in the pro version, it will also send it using Meta (Facebook) CAPI."]}),"\n",(0,i.jsxs)(n.p,{children:["For instance, if you want to track ",(0,i.jsx)(n.code,{children:"ViewCategory"})," events, which are not part of the ",(0,i.jsx)(n.a,{href:"https://developers.facebook.com/docs/meta-pixel/reference#standard-events",children:"standard events"})," in Meta (Facebook), you can do that. The Pixel Manager emits a ",(0,i.jsx)(n.code,{children:"pmw:view-category"})," event when a visitor visits a category page. We can track this event in Meta (Facebook) using the following code in ",(0,i.jsx)(n.code,{children:"functions.php"}),":"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:'add_action(\'wp_footer\', function () {\n	?>\n	<script>\n		jQuery(document).on("pmw:view-category", function () {\n			pmw.trackCustomFacebookEvent("ViewCategory", OPTIONAL_CUSTOM_DATA_OBJECT)\n		})\n	<\/script>\n	<?php\n});\n'})}),"\n",(0,i.jsx)(n.h3,{id:"limits-of-custom-meta-events",children:"Limits of custom Meta events"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"It needs the browser pixel."})," The function only runs when the Meta pixel is loaded and allowed to fire, which means after the visitor granted marketing consent. When it cannot fire in the browser, it sends nothing to the Conversions API either."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Each call is its own event."})," Every call generates its own event ID, which its browser event and its Conversions API copy share, so Meta deduplicates that pair. Two calls are two separate events for Meta, even with the same name and data."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Advanced matching cannot be switched off per event."})," The browser event uses the advanced matching data the pixel was initialized with, and the Conversions API copy carries the same customer data as every other event."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"The JavaScript payload filters do not run."}
1)," Custom events skip the event processor, so filters such as ",(0,i.jsx)(n.code,{children:"pmw_pixel_data_facebook"})," never see them. Pass everything you need in the custom data object. The Conversions API copy still passes through the ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/event-filters#server-side-filters-php",children:"server-side filters"}),"."]}),"\n"]}),"\n",(0,i.jsx)(n.h2,{id:"replicate-pixelyoursites-advanced-marketing-events",children:"Replicate PixelYourSite's Advanced Marketing Events"}),"\n",(0,i.jsxs)(n.p,{children:["PixelYourSite offers a set of ",(0,i.jsx)(n.a,{href:"https://www.pixelyoursite.com/docs/woocommerce-advanced-marketing-events",children:"Advanced Marketing Events"})," for WooCommerce: ",(0,i.jsx)(n.code,{children:"FirstTimeBuyer"}),", ",(0,i.jsx)(n.code,{children:"ReturningCustomer"}),", ",(0,i.jsx)(n.code,{children:"FrequentShopper"}),", ",(0,i.jsx)(n.code,{children:"VIPClient"})," and ",(0,i.jsx)(n.code,{children:"BigWhale"}),". Many shop owners use these events to build customer segments, audiences and lookalikes in Meta (Facebook)."]}),"\n",(0,i.jsxs)(n.p,{children:["Shop owners migrating from PixelYourSite to the Pixel Manager can replicate all of these events with one snippet, combining ",(0,i.jsx)(n.a,{href:"#track-custom-events-for-meta-facebook",children:(0,i.jsx)(n.code,{children:"pmw.trackCustomFacebookEvent()"})})," with the ",(0,i.jsx)(n.code,{children:"pmw:purchase"})," event and the ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/command-queue",children:"command queue"}),"."]}),"\n",(0,i.jsx)(n.p,{children:"The snippet calculates the customer's transaction count, average order value (AOV) and lifetime value (LTV) on the purchase confirmation page, and then fires each segment event the customer qualifies for:"}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:"add_action('wp_footer', function () {\n\n	if (!is_order_received_page()) {\n		return;\n	}\n\n	// Get the current order\n	global $wp;\n	$order_id = absint($wp->query_vars['order-received'] ?? 0);\n	if (!$order_id) {\n		return;\n	}\n\n	$order = wc_get_order($order_id);\n	if (!$order) {\n		return;\n	}\n\n	$customer_email = $order->get_billing_email();\n	if (!$customer_email) {\n		return;\n	}\n\n	// Thresholds (set these to the same values you used in PixelYourSite)\n	$frequent_shopper_min_tx = 2;\n	$vip_min_tx              = 2;\n	$vip_min_aov             = 200;\n	$big_whale_min_ltv       = 5000;\n\n	// Collect all paid orders for this customer.\n	// Matching by billing email also includes guest orders.\n	$customer_orders = wc_get_orders([\n		'billing_email' => $customer_email,\n		'status'        => ['wc-processing', 'wc-completed'],\n		'limit'         => -1,\n	]);\n\n	$transaction_count = count($customer_orders);\n	$ltv               = 0;\n	foreach ($customer_orders as $customer_order) {\n		$ltv += (float) $customer_order->get_total();\n	}\n	$aov = $transaction_count > 0 ? $ltv / $transaction_count : 0;\n\n	$is_first_time_buyer = $transaction_count <= 1;\n	$is_returning        = $transaction_count > 1;\n	$is_frequent_shopper = $transaction_count >= $frequent_shopper_min_tx;\n	$is_vip_client       = $transaction_count >= $vip_min_tx && $aov >= $vip_min_aov;\n	$is_big_whale        = $ltv >= $big_whale_min_ltv;\n\n	?>\n	<script>\n		window._pmwq = window._pmwq || [];\n		window._pmwq.push(function () {\n			jQuery(document).on('pmw:purchase', function () {\n\n				var custom_data = {\n					transaction_count: <?php echo (int) $transaction_count; ?>,\n					aov              : <?php echo round($aov, 2); ?>,\n					ltv              : <?php echo round($ltv, 2); ?>\n				};\n\n				<?php if ($is_first_time_buyer) : ?>\n				pmw.trackCustomFacebookEvent(\"FirstTimeBuyer\", custom_data);\n				<?php endif; ?>\n\n				<?php if ($is_returning) : ?>\n				pmw.trackCustomFacebookEvent(\"ReturningCustomer\", custom_data);\n				<?php endif; ?>\n\n				<?php if ($is_frequent_shopper) : ?>\n				pmw.trackCustomFacebookEvent(\"FrequentShopper\", custom_data);\n				<?php endif; ?>\n\n				<?php if ($is_vip_client) : ?>
1\n				pmw.trackCustomFacebookEvent(\"VIPClient\", custom_data);\n				<?php endif; ?>\n\n				<?php if ($is_big_whale) : ?>\n				pmw.trackCustomFacebookEvent(\"BigWhale\", custom_data);\n				<?php endif; ?>\n			});\n		});\n	<\/script>\n	<?php\n});\n"})}),"\n",(0,i.jsx)(n.p,{children:"A few notes:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:["Each event carries ",(0,i.jsx)(n.code,{children:"transaction_count"}),", ",(0,i.jsx)(n.code,{children:"aov"})," and ",(0,i.jsx)(n.code,{children:"ltv"})," as custom data, so you can also use those values in Meta audience rules (e.g. ",(0,i.jsx)(n.code,{children:"ltv > 10000"}),")."]}),"\n",(0,i.jsxs)(n.li,{children:["The events hook into ",(0,i.jsx)(n.code,{children:"pmw:purchase"}),", which respects the Pixel Manager's order duplication prevention. Reloading the purchase confirmation page won't re-fire the segment events."]}),"\n",(0,i.jsxs)(n.li,{children:["If Meta (Facebook) CAPI is enabled (pro version), ",(0,i.jsx)(n.code,{children:"pmw.trackCustomFacebookEvent()"})," automatically sends the events through CAPI too."]}),"\n",(0,i.jsx)(n.li,{children:"Audiences in Meta populate dynamically going forward, the same way they did with PixelYourSite. Past purchases can't be backfilled through pixel events."}),"\n",(0,i.jsx)(n.li,{children:"The customer's order history is queried once per purchase confirmation page load, which is negligible on virtually all shops."}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{title:"Let our chatbot write the code for you",type:"tip",children:(0,i.jsxs)(n.p,{children:["This snippet was generated by ",(0,i.jsx)(n.a,{href:"https://sweetcode.com/help",children:"our chatbot"}),". If you want different thresholds, additional segments, or the same events sent to GA4 or other platforms, paste the description of what you need (or the docs page of the plugin you're migrating from) into the chatbot and ask it to generate the code for you."]})}),"\n",(0,i.jsx)(n.h2,{id:"adjust-pixel-ids-and-other-settings-per-country-domain",children:"Adjust pixel IDs and other settings per country domain"}),"\n",(0,i.jsx)(n.p,{children:"There is a use case where shop owners want to run the same shop instance on different country domains (e.g. example.com, example.nl, example.br) and run paid ads traffic from different accounts to each of those domains."}),"\n",(0,i.jsx)(n.p,{children:"But the Pixel Manager for WooCommerce user interface only allows to set one pixel ID in the settings."}),"\n",(0,i.jsxs)(n.p,{children:["In this case you can use the ",(0,i.jsx)(n.code,{children:"pmw_options"})," filter to adjust the pixel IDs based on the domain.\nThe ",(0,i.jsx)(n.code,{children:"pmw_options"})," filter allows you to modify the options before they are processed by the Pixel Manager.\nThe ",(0,i.jsx)(n.code,{children:"$options"})," array contains all the options that are set in the Pixel Manager for WooCommerce settings."]}),"\n",(0,i.jsxs)(n.p,{children:["Use the ",(0,i.jsx)(n.code,{children:"error_log"})," function to output and see the structure of the ",(0,i.jsx)(n.code,{children:"$options"})," array to find out how the options for other pixels are structured."]}),"\n",(0,i.jsx)(n.admonition,{type:"warning",children:(0,i.jsxs)(n.p,{children:["The structure of the ",(0,i.jsx)(n.code,{children:"$options"})," array may change in future releases. It happens very rarely, but it can happen. Subscribe to our newsletter and read the changelogs to be informed about new releases and breaking changes."]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:" /**\n * Filter the Pixel Manager's options before it processes them.\n * \n * Place this code into functions.php of your child theme.\n * \n * This example shows how to set different GA4 and Google Ads conversion IDs and labels.\n * \n * Use the error_log function to output and see the structure of the $options array\n * if you want to see how the options for other pixels are structured.\n **/\nadd_filter('pmw_options', function ( $options ) {\n\n	// error_log('options: ' . print_r($options, true));\n\n	$host = $_SERVER['HTTP_HOST'];\n\n	if (preg_match(\"/.*example.nl/\", $host)) {\n		$options['google']['anal
1ytics']['ga4']['measurement_id'] = 'abc';\n		$options['google']['ads']['conversion_id']               = '1234567890';\n		$options['google']['ads']['conversion_label']            = 'abc123';\n	} elseif (preg_match(\"/.*example.fr/\", $host)) {\n		$options['google']['analytics']['ga4']['measurement_id'] = 'xyz';\n		$options['google']['ads']['conversion_id']               = '1122334455';\n		$options['google']['ads']['conversion_label']            = 'def123';\n	} elseif (preg_match(\"/.*example.us/\", $host)) {\n		$options['google']['analytics']['ga4']['measurement_id'] = 'def';\n		$options['google']['ads']['conversion_id']               = '9988776655';\n		$options['google']['ads']['conversion_label']            = 'ghi123';\n	}\n\n	return $options;\n});\n"})}),"\n",(0,i.jsx)(n.h2,{id:"fire-the-view_item-event-on-variable-products-when-no-variation-is-pre-selected",children:"Fire the view_item event on variable products when no variation is pre-selected"}),"\n",(0,i.jsxs)(n.admonition,{type:"info",children:[(0,i.jsxs)(n.p,{children:["By default, when ",(0,i.jsx)(n.a,{href:"/docs/pmw/plugin-configuration/shop-settings#variations-output",children:"Variations Output"})," is enabled, the Pixel Manager does not fire the ",(0,i.jsx)(n.code,{children:"view_item"})," event on a variable product page until a variation is selected."]}),(0,i.jsxs)(n.p,{children:["The reason is that for dynamic remarketing events like ",(0,i.jsx)(n.code,{children:"view_item"}),", the product information sent with the event must match a product in the uploaded catalog. When variations are uploaded to the catalog, the parent product is not. So when no variation is pre-selected on the product page, there is no reliable way for the Pixel Manager to know which variation ID to send. Sending the correct variation ID also yields much more precise ad sets."]})]}),"\n",(0,i.jsx)(n.h3,{id:"recommended-use-the-variations-output-setting",children:"Recommended: use the Variations Output setting"}),"\n",(0,i.jsxs)(n.p,{children:["If you are fine reporting the ",(0,i.jsx)(n.strong,{children:"parent product ID"})," for variable products, you do not need any custom code. Disable the ",(0,i.jsx)(n.a,{href:"/docs/pmw/plugin-configuration/shop-settings#variations-output",children:"Variations Output"})," setting in the Pixel Manager under ",(0,i.jsx)(n.strong,{children:"General \u2192 Product data"})," (the ",(0,i.jsx)(n.strong,{children:"Output product variations as separate items"})," toggle). With it disabled, the Pixel Manager automatically fires a ",(0,i.jsx)(n.code,{children:"view_item"})," event with the parent product data on page load for variable products, even when no variation is selected."]}),"\n",(0,i.jsxs)(n.p,{children:["Keep in mind this setting is global: it switches all product reporting (remarketing, ",(0,i.jsx)(n.code,{children:"add_to_cart"}),", ",(0,i.jsx)(n.code,{children:"purchase"}),", and so on) from variation-level IDs to parent-product IDs. Only disable it if your product feed is built around parent products. See ",(0,i.jsx)(n.a,{href:"/docs/pmw/plugin-configuration/shop-settings#variations-output",children:"Variations Output"})," for the full trade-offs."]}),"\n",(0,i.jsx)(n.h3,{id:"alternative-keep-variations-output-enabled-and-fire-a-parent-view_item-on-load",children:"Alternative: keep Variations Output enabled and fire a parent view_item on load"}),"\n",(0,i.jsxs)(n.p,{children:["If you want to keep variation-level reporting enabled but also fire a ",(0,i.jsx)(n.code,{children:"view_item"})," for the parent product on page load, use the ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/php-filters#fire-parent-view-item-on-variable-products",children:(0,i.jsx)(n.code,{children:"pmw_fire_parent_view_item_on_variable_products"})})," filter:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:"add_filter('pmw_fire_parent_view_item_on_variable_products', '__return_true');\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The variation's own ",(0,i.jsx)(n.code,{children:"view_item"})," still fires once the shopper picks a variation. The filter receives the product ID, so you can also decide per product. See the ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/php-filters#fire-parent-view-item-on-variable-products",children:"filter reference"})," for the trade-offs."]}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:["The filter is available as of version ",(0,i.jsx)(n.code,{children:"1.66.1"}),". On older versions, use the JavaScript snippet below."]})}),"\n",(0,i.jsx)(n.h4,{id:"doing-it-in-javascript-instead",children:"Doing it in JavaScript instead"}),"\n",(0,i.jsxs)(n.p,{children:["On versions older than ",(0,i.jsx)(n.code,{children:"1.66.1"}),", or when the decision depends on something only the browser knows, the same thing can be done from a snippet."]}),"\n",(0,i.jsx)(n.admonition,{type:"caution",children:(0,i.jsxs)(n.p,{children:["Do not use the ",(0,i.jsx)(n.code,{children:"hide_variation"})," event for this. That event fires only when a customer deselects a variation that was already selected, not on a fresh page load when nothing is selected. The snippet below hooks the Pixel Manager's own ",(0,i.jsx)(n.code,{children:"pmwLoad"})," event instead, which fires reliably on page load."]})}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:'add_action(\'wp_footer\', function () {\n\n	if (!function_exists(\'is_product\') || !is_product()) {\n		return;\n	}\n	?>\n	<script>\n		window._pmwq = window._pmwq || [];\n		window._pmwq.push(function () {\n			pmw.bus.on("pmwLoad", function () {\n				try {\n					if (pmwDataLayer?.shop?.page_type !== "product") return;\n					if (pmwDataLayer?.shop?.product_type !== "variable") return;\n\n					var parentId = pmw.getMainProductIdFromProductPage();\n					if (!parentId) return;\n\n					pmw.triggerViewItemEventPrep(parentId);\n				} catch (e) {\n					console.error(e);\n				}\n			});\n		});\n	<\/script>\n	<?php\n});\n'})}),"\n",(0,i.jsxs)(n.p,{children:["With Variations Output enabled, this fires a ",(0,i.jsx)(n.code,{children:"view_item"})," for the parent product on page load, and the Pixel Manager will still fire an additional ",(0,i.jsx)(n.code,{children:"view_item"})," for the specific variation once the customer selects one."]}),"\n",(0,i.jsxs)(n.admonition,{title:"Older versions of this snippet",type:"caution",children:[(0,i.jsxs)(n.p,{children:["Until August 2026 this 
1snippet used ",(0,i.jsx)(n.code,{children:'jQuery(document).on("pmwLoad", ...)'})," instead of ",(0,i.jsx)(n.code,{children:"_pmwq"})," and ",(0,i.jsx)(n.code,{children:"pmw.bus.on()"}),". If you still run the jQuery version, replace it with the filter above, or with this snippet."]}),(0,i.jsxs)(n.p,{children:["On Pixel Manager ",(0,i.jsx)(n.code,{children:"1.65.0"})," to ",(0,i.jsx)(n.code,{children:"1.66.0"})," the jQuery version ran twice per page load, and it could send the browser into an endless loop that ends in ",(0,i.jsx)(n.code,{children:"RangeError: Maximum call stack size exceeded"}),", freezing the page and firing thousands of requests. The cause was a defect in the plugin's jQuery compatibility layer, fixed in ",(0,i.jsx)(n.code,{children:"1.66.1"}),". ",(0,i.jsx)(n.code,{children:"pmw.bus.on()"})," is not affected on any version, and ",(0,i.jsx)(n.code,{children:"_pmwq"})," additionally makes the snippet independent of script load order."]})]}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"pmw.bus"})," is available from version ",(0,i.jsx)(n.code,{children:"1.65.0"}),". On older versions, use the ",(0,i.jsx)(n.code,{children:'jQuery(document).on("pmwLoad", ...)'})," form and make sure you are not running Pixel Manager ",(0,i.jsx)(n.code,{children:"1.65.0"})," to ",(0,i.jsx)(n.code,{children:"1.66.0"}),"."]}),"\n",(0,i.jsx)(n.h2,{id:"modify-the-page_title-and-page_location-in-ga4",children:"Modify the page_title and page_location in GA4"}),"\n",(0,i.jsxs)(n.p,{children:["The following code examples show how to modify the ",(0,i.jsx)(n.code,{children:"page_title"})," and ",(0,i.jsx)(n.code,{children:"page_location"})," in GA4 based on GA4's ",(0,i.jsx)(n.a,{href:"https://developers.google.com/analytics/devguides/collection/ga4/views?client_type=gtag#manual_pageviews",children:"documentation"}),"."]}),"\n",(0,i.jsxs)(n.p,{children:["The first code example disables the default ",(0,i.jsx)(n.code,{children:"page_view"})," event."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:"add_filter('pmw_ga_4_parameters', function ($analytics_parameters, $analytics_id) {\n	\n	$analytics_parameters['send_page_view'] = false;\n\n    return $analytics_parameters;\n}, 10, 2);\n"})}),"\n",(0,i.jsxs)(n.p,{children:["The second code example shows how to send a custom ",(0,i.jsx)(n.code,{children:"page_view"})," event with custom ",(0,i.jsx)(n.code,{children:"page_title"})," and ",(0,i.jsx)(n.code,{children:"page_location"})," parameters. Make sure to replace ",(0,i.jsx)(n.code,{children:"PAGE_TITLE"})," and ",(0,i.jsx)(n.code,{children:"PAGE_LOCATION"})," with your own values."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:"add_action('wp_footer', function(){\n    ?>\n    <script>\n        gtag('event', 'page_view', {\n            page_title: 'PAGE_TITLE',\n            page_location: 'PAGE_LOCATION'\n            });\n    <\/script>\n    <?php\n});\n"})}),"\n",(0,i.jsx)(n.h2,{id:"track-custom-google-ads-conversions",children:"Track custom Google Ads conversions"}),"\n",(0,i.jsx)(n.admonition,{type:"info",children:(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"pmw.trackCustomGoogleAdsConversion()"})," is available in version 1.67.1 and later. On older versions, write the ",(0,i.jsx)(n.code,{children:"gtag()"})," call out with both guards, as the examples further down do."]})}),"\n",(0,i.jsxs)(n.p,{children:[(0,i.jsx)(n.code,{children:"pmw.trackCustomGoogleAdsConversion(sendTo, data)"})," sends a conversion to a conversion action of your own. It is the Google counterpart of ",(0,i.jsx)(n.a,{href:"#track-custom-events-for-meta-facebook",children:(0,i.jsx)(n.code,{children:"pmw.trackCustomFacebookEvent()"})}),", and it applies the same two guards the Pixel Manager's own Google Ads conversions pass: the marketing consent gate, and the wait for the Google tag to actually be loaded."]}),"\n",(0,i.jsxs)(n.table,{children:[(0,i.jsx)(n.thead,{children:(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.th,{children:"Argument"}),(0,i.jsx)(n.th,{children:"Contents"})]})}),(0,i.jsxs)(n.tbody,{children:[(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"sendTo"})}),(0,i.jsxs)(n.td,{children:["The conversion identifier, ",(0,i.jsx)(n.code,{children:'"AW-CONVERSION_ID/CONVERSION_LABEL"'}),". Both halves are in the Google Ads conversion action's tag instructions."]})]}),(0,i.jsxs)(n.tr,{children:[(0,i.jsx)(n.td,{children:(0,i.jsx)(n.code,{children:"data"})}),(0,i.jsxs)(n.td,{children:["Optional. Any event parameters the conversion takes: ",(0,i.jsx)(n.code,{children:"value"}),", ",(0,i.jsx)(n.code,{children:"currency"}),", ",(0,i.jsx)(n.code,{children:"transaction_id"}),", and so on."]})]})]})]}),"\n",(0,i.jsxs)(n.p,{children:["It returns a promise that resolves once the conversion was sent, and ",(0,i.jsx)(n.code,{children:"undefined"})," when a guard declined it, so null-check before chaining."]}),"\n",(0,i.jsxs)(n.p,{children:["Reporting the ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/php-filters#profit-margin-api",children:"profit"})," of an order to a second Google Ads conversion action, next to the revenue action the Pixel Manager fires:"]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:'add_action(\'wp_head\', function () {\n	?>\n	<script>\n		window._pmwq = window._pmwq || [];\n\n		window._pmwq.push(function () {\n\n			pmw.bus.on("pmw:event:purchase", function () {\n\n				var order = window.pmwDataLayer && pmwDataLayer.order;\n				if (!order || !order.custom_parameters) return;\n\n				var profit = parseFloat(order.custom_parameters.profit);\n				if (!isFinite(profit)) return;
1\n\n				pmw.trackCustomGoogleAdsConversion("AW-CONVERSION_ID/CONVERSION_LABEL", {\n					value         : Math.max(0, profit),\n					currency      : order.currency,\n					transaction_id: String(order.number)\n				});\n			});\n		});\n	<\/script>\n	<?php\n});\n'})}),"\n",(0,i.jsx)(n.p,{children:"Four details in that snippet matter, and all four have cost shops a conversion at some point:"}),"\n",(0,i.jsxs)(n.ul,{children:["\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Print it on every page"}),", ",(0,i.jsx)(n.code,{children:"wp_head"})," with no page condition. The purchase event is the gate, and ",(0,i.jsx)(n.a,{href:"/docs/pmw/features/acr",children:"Automatic Conversion Recovery"})," fires it on an ordinary shop page when a customer returns with an order that was never tracked. A snippet scoped to the confirmation page misses exactly those orders."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsxs)(n.strong,{children:["Hang it on ",(0,i.jsx)(n.code,{children:"pmw:event:purchase"})]}),", not on ",(0,i.jsx)(n.code,{children:"pmw:ready"})," and not on a ",(0,i.jsx)(n.code,{children:"window.gtag"})," check. That event is ",(0,i.jsx)(n.a,{href:"/docs/pmw/developers/javascript-events#registration-timing",children:"replayed"}),", so registering late is safe."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsxs)(n.strong,{children:["Use ",(0,i.jsx)(n.code,{children:"order.number"})]})," for ",(0,i.jsx)(n.code,{children:"transaction_id"}),", which is what the Pixel Manager's own conversion sends, so both actions key on the same identifier."]}),"\n",(0,i.jsxs)(n.li,{children:[(0,i.jsx)(n.strong,{children:"Floor the value at zero."})," A profit figure can be negative on a heavily refunded order, and the ad platforms either reject a negative value or misread it."]}),"\n"]}),"\n",(0,i.jsx)(n.admonition,{title:"Counting the requests is not counting the conversions",type:"tip",children:(0,i.jsxs)(n.p,{children:["One conversion fans out over several Google endpoints, so a single ",(0,i.jsx)(n.code,{children:"gtag()"})," call produces more than one request in the Network panel. Confirm the count in Google Ads, not in the browser."]})}),"\n",(0,i.jsx)(n.h2,{id:"track-mailto-links-with-google-ads-conversions",children:"Track mailto: links with Google Ads conversions"}),"\n",(0,i.jsxs)(n.p,{children:["From version ",(0,i.jsx)(n.code,{children:"1.67.1"})," on, ",(0,i.jsx)(n.a,{href:"#track-custom-google-ads-conversions",children:(0,i.jsx)(n.code,{children:"pmw.trackCustomGoogleAdsConversion()"})})," applies both guards, so the body of the click handler is a single call. The version below spells them out and works on every version."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:'add_action(\'wp_footer\', function () {\n?>\n    <script>\n        window._pmwq = window._pmwq || [];\n        window._pmwq.push(function () {\n\n            jQuery(document).on("click", "a[href^=\'mailto:\']", function (event) {\n\n                if (!pmw.googleConfigConditionsMet({type: "marketing"})) return;\n\n                pmw.gtagLoaded().then(function () {\n                    gtag("event", "conversion", {\n                        // replace with own conversion ID and label\n                        "send_to": "AW-1000000000/0000000000",\n                    });\n                }).catch(function () {\n                    // The Google tag never became ready, so there is nothing to send.\n                });\n            });\n        });\n    <\/script>\n<?php\n});\n'})}),"\n",(0,i.jsxs)(n.h2,{id:"track-add-to-cart-and-begin-checkout-events-with-google-ads-conversions",children:["Track ",(0,i.jsx)(n.code,{children:"add-to-cart"})," and ",(0,i.jsx)(n.code,{children:"begin-checkout"})," events with Google Ads conversions"]}),"\n",(0,i.jsxs)(n.p,{children:["Google Ads offers conversion actions for ",(0,i.jsx)(n.code,{children:"add-to-cart"})," and ",(0,i.jsx)(n.code,{children:"begin-checkout"})," events. But we highly discourage tracking these events as conversions in Google Ads because they will be detrimental for optimizing campaigns for profitable revenue."]}),"\n",(0,i.jsxs)(n.p,{children:["If you chose to track these events as conversions in Google Ads, you can use the following code to track the ",(0,i.jsx)(n.code,{children:"add-to-cart"})," and ",(0,i.jsx)(n.code,{children:"begin-checkout"})," events with Google Ads as conversion actions. From version ",(0,i.jsx)(n.code,{children:"1.67.1"})," on, ",(0,i.jsx)(n.a,{href:"#track-custom-google-ads-conversions",children:(0,i.jsx)(n.code,{children:"pmw.trackCustomGoogleAdsConversion()"})})," replaces the consent check and the ",(0,i.jsx)(n.code,{children:"gtagLoaded()"})," wait in each handler with a single call."]}),"\n",(0,i.jsx)(n.pre,{children:(0,i.jsx)(n.code,{className:"language-php",metastring:'title="/wp-content/themes/child-theme/functions.php"',children:"/**\n * The following snippet allows you to track the add-to-cart\n * and begin-checkout events with Google Ads as conversion actions.\n *\n * We highly discourage tracking add-to-cart and begin-checkout events\n * as conversions in Google Ads because they will be detrimental\n * for optimizing campaigns for profitable revenue.\n *\n * Place this in your child theme's functions.php file and replace\n * the AW-CONVERSION_ID and CONVERSION_LABEL with your actual values.\
1n */\nadd_action('wp_footer', function () {\n	?>\n	<script>\n		window._pmwq = window._pmwq || [];\n		window._pmwq.push(function () {\n\n			pmw.bus.on(\"pmw:add-to-cart\", function (product) {\n\n				if (!pmw.googleConfigConditionsMet({type: \"marketing\"})) return;\n\n				pmw.gtagLoaded().then(function () {\n					gtag(\"event\", \"conversion\", {\n						\"send_to\" : \"AW-CONVERSION_ID/CONVERSION_LABEL\",\n						\"value\"   : product.price,\n						\"currency\": product.currency,\n					});\n				}).catch(function () {\n					// The Google tag never became ready, so there is nothing to send.\n				});\n			});\n\n			pmw.bus.on(\"pmw:begin-checkout\", function () {\n\n				if (!pmw.googleConfigConditionsMet({type: \"marketing\"})) return;\n\n				pmw.gtagLoaded().then(function () {\n					gtag(\"event\", \"conversion\", {\n						\"send_to\" : \"AW-CONVERSION_ID/CONVERSION_LABEL\",\n					});\n				}).catch(function () {\n					// The Google tag never became ready, so there is nothing to send.\n				});\n			});\n		});\n	<\/script>\n	<?php\n});\n```## Filter the Pixel Manager's options based on the WPML language\n\nIf you are using WPML and want to set different Pixel IDs or other settings based on the current language, you can use the `pmw_options` filter. This allows you to modify the options before they are processed by the Pixel Manager.\n\n```php title=\"/wp-content/themes/child-theme/functions.php\"\n/**\n * Change the Facebook Pixel ID based on the current WPML language.\n */\nadd_filter('pmw_options', function ( $options ) {\n\n	// Get the current WPML language (returns e.g. 'en', 'de', etc.)\n	$current_language = apply_filters('wpml_current_language', null);\n\n	// Modify options based on language\n	switch ($current_language) {\n		case 'de':\n			$options['facebook']['pixel_id'] = '123456789';\n			break;\n\n		case 'fr':\n			$options['facebook']['pixel_id'] = '1122334455';\n			break;\n\n		default: // Fallback (e.g. English or unknown)\n			$options['facebook']['pixel_id'] = '5544332211';\n			break;\n	}\n\n	return $options;\n});\n"})})]})}function h(e={}){let{wrapper:n}={...(0,s.R)(),...e.components};return n?(0,i.jsx)(n,{...e,children:(0,i.jsx)(l,{...e})}):l(e)}}}]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.