Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

**Features**

- Added link click conversion tracking for external and special links (mailto:, tel:, etc.) within popups. Clicks are tracked via analytics beacon and categorized by link type for conversion reporting.
- Added [Beaver Builder Forms integration](https://wppopupmaker.com/form-integrations/beaver-builder/) for form submission tracking and conversion analytics. Supports Contact, Subscribe, and Login form modules.
- Added [Bit Form integration](https://wppopupmaker.com/form-integrations/bit-form/) for form submission tracking and conversion analytics.
- Added [Elementor Pro Forms integration](https://wppopupmaker.com/form-integrations/elementor-forms/) for form submission tracking and conversion analytics with support for targeting specific forms.
Expand All @@ -15,12 +16,14 @@

**Improvements**

- Improved PID tracking reliability by firing template_redirect at priority 0, ensuring tracking occurs before other plugins that might redirect.
- Enhanced all Popup list views with sortable Enabled column and bulk enable/disable actions for easier management of multiple popups.
- Block library assets (CSS) loading unnecessarily on all front-end pages. WordPress now automatically loads these styles only when Popup Maker blocks are actually rendered.
- Enhanced ad-blocker bypass feature to obfuscate script and style element IDs (in addition to filenames) for improved bypass reliability. IDs now consistently use per site settings using either MD5 hashing or custom prefixes.

**Fixes**

- Fixed mailto: and tel: links inside popups being incorrectly modified with tracking parameters, which broke email and phone links.
- Fixed Fluent Forms integration fatal error when using double opt-in. Closes #1094.
- Fixed Time Delay trigger settings tab displaying blank when switching from Click Trigger advanced tab. Closes #1109.
- Fixed trigger modal "Add" button label not displaying due to incorrect i18n function usage. Props to @DAnn2012.
Expand Down
115 changes: 113 additions & 2 deletions assets/js/src/site/plugins/pum-url-tracking.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*
* Handles:
* - Appending pid (popup ID) to internal links within popups
* - Firing click conversion beacons for external/special links (mailto, tel, etc.)
*/
window.PUM_URLTracking = {
/**
Expand Down Expand Up @@ -44,6 +45,9 @@
/**
* Process all links within a popup to add tracking parameters.
*
* Internal links get ?pid= appended (tracked via server redirect).
* External/special links get click handlers for beacon tracking.
*
* @param {jQuery} $popup The popup element.
* @param {number} pid The popup ID.
*/
Expand All @@ -54,9 +58,8 @@
var $link = $( this ),
href = $link.attr( 'href' );

// Only process internal URLs.
if ( self.isInternalUrl( href ) ) {
// Start with base URL parameters.
// Internal URLs: Append PID parameter (tracked via server redirect).
var urlParams = { pid: pid };

// Allow extensions to add additional parameters.
Expand All @@ -71,10 +74,110 @@

var newHref = self.appendParamsToUrl( href, urlParams );
$link.attr( 'href', newHref );
} else if ( self.shouldTrackClick( href ) ) {
// External/special links: Attach click handler for beacon tracking.
self.attachClickTracking( $link, pid, href );
}
} );
},

/**
* Determine if a link should have click tracking attached.
*
* @param {string} url The URL to check.
* @return {boolean} True if click should be tracked.
*/
shouldTrackClick: function ( url ) {
// Skip empty URLs.
if ( ! url ) {
return false;
}

// Skip links already tracked via CTA system.
if ( url.indexOf( 'cta=' ) !== -1 ) {
return false;
}

return true;
},
Comment thread
danieliser marked this conversation as resolved.

/**
* Get the link type for analytics segmentation.
*
* @param {string} url The URL to categorize.
* @return {string} Link type: 'external', 'mailto', 'tel', or 'other'.
*/
getLinkType: function ( url ) {
if ( url.indexOf( 'mailto:' ) === 0 ) {
return 'mailto';
}
if ( url.indexOf( 'tel:' ) === 0 ) {
return 'tel';
}
if ( url.indexOf( 'javascript:' ) === 0 ) {
return 'javascript';
}
if ( url === '#' || url.indexOf( '#' ) === 0 ) {
return 'anchor';
}
if ( url.indexOf( 'http' ) === 0 || url.indexOf( '//' ) === 0 ) {
return 'external';
}
return 'other';
},

/**
* Attach click tracking to a link element.
*
* Fires a conversion beacon when the link is clicked.
*
* @param {jQuery} $link The link element.
* @param {number} pid The popup ID.
* @param {string} href The link URL.
*/
attachClickTracking: function ( $link, pid, href ) {
var self = this;

// Prevent duplicate handlers.
if ( $link.data( 'pum-click-tracked' ) ) {
return;
}
$link.data( 'pum-click-tracked', true );

$link.on( 'click.pum_tracking', function () {
// Only track if analytics is available and enabled.
if (
! window.PUM_Analytics ||
! window.pum_vars ||
! window.pum_vars.analytics_enabled
) {
return;
}

var data = {
pid: pid,
event: 'conversion',
eventData: {
type: 'link_click',
url: href,
linkType: self.getLinkType( href ),
},
};

// Allow extensions to modify click tracking data.
if ( window.PUM && window.PUM.hooks ) {
data = window.PUM.hooks.applyFilters(
'popupMaker.popup.linkClickData',
data,
$link
);
}

// Fire beacon (sendBeacon queues even during navigation).
window.PUM_Analytics.beacon( data );
} );
},
Comment thread
danieliser marked this conversation as resolved.

/**
* Check if URL is internal to the current site.
*
Expand All @@ -86,6 +189,14 @@
return false;
}

// Skip non-HTTP protocols (mailto:, tel:, javascript:, etc.).
if (
/^[a-z][a-z0-9+.-]*:/i.test( url ) &&
! /^https?:/i.test( url )
) {
return false;
}

// Handle relative URLs.
if ( url.indexOf( '/' ) === 0 && url.indexOf( '//' ) !== 0 ) {
return true;
Expand Down
3 changes: 2 additions & 1 deletion classes/Controllers/CallToActions.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ class CallToActions extends Controller {
* Initialize cta actions
*/
public function init() {
add_action( 'template_redirect', [ $this, 'template_redirect' ] );
// Priority 0 ensures PID tracking fires before other plugins that might redirect.
add_action( 'template_redirect', [ $this, 'template_redirect' ], 0 );
add_action( 'popup_maker/cta_conversion', [ $this, 'track_cta_conversion' ], 10, 2 );
}

Expand Down
16 changes: 16 additions & 0 deletions classes/Plugin/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,18 @@ function () {
}
);

$this->set(
'link_click_tracking',
/**
* Get link click tracking service.
*
* @return \PopupMaker\Services\LinkClickTracking
*/
function ( $container ) {
return new \PopupMaker\Services\LinkClickTracking( $container );
}
);

do_action( 'popup_maker/register_services', $this );
}

Expand All @@ -302,6 +314,10 @@ function () {
*/
protected function init_services() {
$license = $this->get( 'license' );

// Initialize link click tracking.
$link_click_tracking = $this->get( 'link_click_tracking' );
$link_click_tracking->init();
}

/**
Expand Down
Loading
Loading