Event Filters
Version 1.51.0 of the Pixel Manager
Customize event tracking data for all pixels using JavaScript (front-end) and PHP (server-side) filters.
Why Use the Command Queue?
Always wrap your filters in the Pixel Manager command queue:
window._pmwq = window._pmwq || [];
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_pixel_data_facebook', 'my-plugin', function(pixelData) {
pixelData.custom_data.custom_field = 'my_value';
return pixelData;
});
});
Why? Caching systems and JavaScript optimizers may shuffle, combine, or delay script loading. The command queue provides a 100% reliable way to ensure your filters register after Pixel Manager loads, preventing race conditions and initialization errors. Without it, pmw.hooks may not exist yet, causing your code to fail silently.
Adding to WordPress:
add_action('wp_head', function() {
?>
<script>
window._pmwq = window._pmwq || [];
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_pixel_data_facebook', 'my-plugin', function(pixelData) {
pixelData.custom_data.custom_field = 'my_value';
return pixelData;
});
});
</script>
<?php
}, 1); // Priority 1 to load early in <head>
Planning Your Filters
Before implementing filters, consider where your events are processed:
Front-End vs. Server-Side Events
Front-end events (processed in the browser):
- All events when server-to-server tracking is disabled
- Events like
add_to_cart,view_item,begin_checkout, etc. - Purchase events only if processed through the browser
Server-side events (processed on the server):
- Purchase events when server-to-server tracking is enabled (Facebook CAPI, TikTok EAPI, Pinterest APIC, Snapchat CAPI)
- Google Analytics purchase events when Measurement Protocol is enabled
- These are always sent from the server, never through the browser
Why server-side purchase events? Browser-based tracking can be blocked by ad blockers, browser extensions, privacy settings, or network-level filters. When server-to-server tracking is enabled, purchase events are compiled and sent directly from your server to the advertising platforms, completely bypassing the browser. This makes them immune to client-side blocking, ensuring 100% reliable conversion tracking. The tradeoff is that these events are processed in a completely independent pipeline, which means they require separate filters.
When server-to-server tracking is active, purchase events are compiled and sent exclusively from the server. This means:
- Front-end filters will NOT affect these purchase events
- You must implement PHP server-side filters to modify purchase event data
Example: To filter purchase events with server-to-server tracking enabled, you need both:
// Front-end (for any browser-based purchase events)
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_event_payload_purchase', 'my-filter', function(payload) {
payload.event_data.custom_field = 'value';
return payload;
});
});
// Server-side (REQUIRED for server-to-server purchase events)
add_filter('pmw_server_event_payload_event_purchase', function($pixel_data, $pixel_name, $event_name) {
$pixel_data['custom_data']['custom_field'] = 'value';
return $pixel_data;
}, 10, 3);
Always implement server-side filters when working with purchase events if you have server-to-server tracking enabled.
Front-End Filters (JavaScript)
Filter Pipeline
Events flow through 4 stages. Each filter must return the modified data:
pmw_event_payload_pre- Before pixel transformations (modify core event data)pmw_pixel_data_{pixel}- Per-pixel transformations (e.g.,pmw_pixel_data_facebook)pmw_event_payload_{event}- Per-event type (e.g.,pmw_event_payload_purchase)pmw_event_payload_post- Final stage (logging, debugging)
Supported pixels: facebook, google_ads, google_analytics, tiktok, pinterest, snapchat, linkedin, microsoft_ads, twitter, reddit, taboola, outbrain
Supported events: page_view, add_to_cart, view_item, view_item_list, begin_checkout, add_payment_info, add_to_wishlist, search, purchase
API
pmw.hooks.addFilter(hookName, namespace, callback, priority)
pmw.hooks.removeFilter(hookName, namespace)
pmw.hooks.hasFilter(hookName, namespace)
- namespace - Unique identifier to prevent conflicts (e.g.,
'my-plugin/feature') - priority - Execution order (default: 10, lower runs first)
- Return
nullto block an event from firing
Examples
Add Custom Facebook Parameters
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_pixel_data_facebook', 'my-store', function(pixelData) {
pixelData.custom_data = pixelData.custom_data || {};
pixelData.custom_data.store_location = 'NYC';
pixelData.custom_data.user_segment = 'premium';
return pixelData;
});
});
Adjust Prices Globally
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_event_payload_pre', 'price-modifier', function(payload) {
if (payload.event_data?.product?.price) {
payload.event_data.product.price *= 1.15; // +15% markup
}
return payload;
});
});
Filter by Event Type
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_event_payload_purchase', 'purchase-tags', function(payload) {
if (payload.event_data?.order_total > 500) {
payload.event_data.high_value = true;
}
return payload;
});
});
Block Events Conditionally
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_pixel_data_facebook', 'admin-filter', function(pixelData) {
if (window.userIsAdmin) {
return null; // Block event
}
return pixelData;
});
});
Use Priority for Execution Order
window._pmwq.push(function() {
// Runs first (priority 5)
pmw.hooks.addFilter('pmw_event_payload_pre', 'early-filter', function(payload) {
payload.event_data.processed_by = ['early-filter'];
return payload;
}, 5);
// Runs second (priority 10)
pmw.hooks.addFilter('pmw_event_payload_pre', 'late-filter', function(payload) {
payload.event_data.processed_by.push('late-filter');
return payload;
}, 10);
});
Server-Side Filters (PHP)
Filter Pipeline
Server-side events (Facebook CAPI, TikTok EAPI, Pinterest APIC, Snapchat CAPI) flow through 5 stages:
pmw_server_event_payload_pre- Before pixel processing (all pixels at once)pmw_server_event_payload_{pixel}- Per-pixel, all events (e.g.,facebook)pmw_server_event_payload_event_{event}- Per-event, all pixels (e.g.,purchase)pmw_server_event_payload_{pixel}_{event}- Specific pixel + event (e.g.,facebook_purchase)pmw_server_event_payload_post- Final stage before API transmission
Examples
Modify All Purchase Events (All Pixels)
add_filter('pmw_server_event_payload_event_purchase', function($pixel_data, $pixel_name, $event_name) {
// Add timestamp to all purchase events across all pixels
$pixel_data['custom_data']['order_timestamp'] = time();
// Categorize by value
if (isset($pixel_data['custom_data']['value'])) {
$value = $pixel_data['custom_data']['value'];
$pixel_data['custom_data']['value_tier'] = $value < 50 ? 'low' : ($value < 200 ? 'medium' : 'high');
}
return $pixel_data;
}, 10, 3);
Add Custom Data to Facebook Only
add_filter('pmw_server_event_payload_facebook', function($pixel_data, $pixel_name) {
$pixel_data['user_data']['subscription_status'] = 'premium';
return $pixel_data;
}, 10, 2);
Target Specific Pixel + Event
add_filter('pmw_server_event_payload_facebook_purchase', function($pixel_data, $pixel_name, $event_name) {
$user_id = get_current_user_id();
if ($user_id) {
$ltv = get_user_meta($user_id, 'customer_ltv', true);
if ($ltv > 1000 && isset($pixel_data['custom_data']['value'])) {
$pixel_data['custom_data']['value'] *= 1.2; // Boost value for high-LTV customers
}
}
return $pixel_data;
}, 10, 3);
Block Events Conditionally
// Block low-value purchases from all pixels
add_filter('pmw_server_event_payload_event_purchase', function($pixel_data, $pixel_name, $event_name) {
if (isset($pixel_data['custom_data']['value']) && $pixel_data['custom_data']['value'] < 10) {
return null; // Blocks event for all pixels
}
return $pixel_data;
}, 10, 3);
// Block only from Facebook
add_filter('pmw_server_event_payload_facebook', function($pixel_data) {
if (some_condition()) {
return null;
}
return $pixel_data;
});
Event Payload Structure
{
event: 'add_to_cart',
event_data: {
product: {
id: 123,
name: 'Product Name',
price: 99.99,
quantity: 1,
currency: 'USD',
categories: ['Electronics']
}
},
pixels: {
facebook: {
event_name: 'AddToCart',
event_id: 'unique-id',
custom_data: { /* pixel-specific data */ }
},
google_analytics: {
event_name: 'add_to_cart',
event_data: { /* pixel-specific data */ }
}
}
}
Best Practices
- Always return the value - Filters must return the modified data or
nullto block - Use unique namespaces - Format:
'plugin-name/feature'or'company-name/modifier' - Wrap in
_pmwq- Ensures Pixel Manager loads before your filters - Check data exists - Use optional chaining:
payload.event_data?.product?.price - Use appropriate priority - Default is 10; lower numbers run first
- Test thoroughly - Check browser console for filter execution logs
Debugging
Console Logging
Filter execution is logged to the browser console:
🔍 Pre-processing filter called: add_to_cart
📊 GA pixel data filter called: add_to_cart
Inspect Payloads
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_event_payload_post', 'debugger', function(payload, eventName) {
console.log(`Event: ${eventName}`, payload);
return payload;
}, 999); // High priority to run last
});
PHP Debugging
add_filter('pmw_server_event_payload_post', function($pixel_data, $pixel_name) {
if (defined('WP_DEBUG') && WP_DEBUG) {
error_log("Sending {$pixel_data['event_name']} to {$pixel_name}: " . json_encode($pixel_data));
}
return $pixel_data;
}, 10, 2);
Migration from Old System
If you were using jQuery event listeners:
Before:
jQuery(document).on("pmw:add-to-cart", function(event, product) {
product.price = product.price * 1.1;
});
After (Recommended - Using Filters):
window._pmwq.push(function() {
pmw.hooks.addFilter('pmw_event_payload_add_to_cart', 'namespace', function(payload) {
payload.event_data.product.price *= 1.1;
return payload;
});
});
Alternative - Using Public API Events:
If you only need to listen to events (not modify them), you can use the new public API events instead of filters.
window._pmwq.push(function() {
// Listen to the official public API event
jQuery(document).on('pmw:event:add-to-cart', function(event, payload) {
// payload contains fully processed event data
console.log('Product added:', payload.event_data.product);
console.log('Pixel-specific data:', payload.pixels);
// You can trigger your own tracking here
myCustomTracker.track('add_to_cart', payload.event_data);
});
});
The pmw:event:* events provide the complete processed payload including all pixel adaptations. See the Command Queue documentation for the full list of available events.
Event Name Mapping
The Pixel Manager uses internal snake_case event names which each pixel adapter transforms to the vendor-specific format.
Internal Event Names
| Internal Event | Description |
|---|---|
page_view | User views any page |
view_item | User views a single product |
view_category | User views a product category |
add_to_cart | User adds product to cart |
begin_checkout | User begins checkout process |
add_payment_info | User adds payment information |
purchase | Purchase completed |
add_to_wishlist | User adds product to wishlist |
search | User performs a search |
login | User logs in |
Vendor Event Name Mappings
Each pixel adapter transforms the internal event name to the vendor's format:
| Internal Event | TikTok | Snapchat | ||
|---|---|---|---|---|
page_view | PageView | — | PAGE_VIEW | — |
view_item | ViewContent | ViewContent | VIEW_CONTENT | pagevisit |
add_to_cart | AddToCart | AddToCart | ADD_CART | addtocart |
purchase | Purchase | CompletePayment | PURCHASE | checkout |
Note: A "—" indicates the pixel doesn't support this event (the adapter returns null and the event is skipped for that pixel).
Modifying Vendor-Specific Data
Use pmw_pixel_data_{pixel} filters to modify data after it's been transformed to the vendor format:
window._pmwq.push(function() {
// Modify Facebook-specific data structure
pmw.hooks.addFilter('pmw_pixel_data_facebook', 'my-plugin', function(pixelData, eventName) {
// pixelData.event_name is already "AddToCart" (Facebook format)
if (eventName === 'add_to_cart') {
pixelData.custom_data.source = 'mobile_app';
}
return pixelData;
});
});