HEX
Server: Apache/2.4.65 (Debian)
System: Linux 88f31f35b0b8 6.1.0-38-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.147-1 (2025-08-02) x86_64
User: www-data (33)
PHP: 8.2.29
Disabled: NONE
Upload Files
File: /var/www/html/wp-content/plugins/advanced-ads-tracking/includes/frontend/class-tracking-scripts.php
<?php
/**
 * Frontend Tracking Scripts.
 *
 * @package AdvancedAds\Tracking
 * @author  Advanced Ads <info@wpadvancedads.com>
 * @since   2.6.0
 */

namespace AdvancedAds\Tracking\Frontend;

use AdvancedAds\Abstracts\Ad;
use AdvancedAds\Tracking\Helpers;
use AdvancedAds\Tracking\Constants;
use AdvancedAds\Utilities\Conditional;
use AdvancedAds\Framework\Utilities\Str;
use AdvancedAds\Tracking\Utilities\Data;
use AdvancedAds\Tracking\Utilities\Tracking;
use AdvancedAds\Framework\Interfaces\Integration_Interface;

defined( 'ABSPATH' ) || exit;

/**
 * Frontend Tracking Scripts.
 */
class Tracking_Scripts implements Integration_Interface {

	/**
	 * Ads for which page query string should be transmitted.
	 *
	 * @var array
	 */
	protected $transmit_pageqs = [];

	/**
	 * Ad ids that should be tracked using JavaScript
	 *
	 * @var arr
	 */
	protected $ad_ids = [];

	/**
	 * Hook into WordPress.
	 *
	 * @return void
	 */
	public function hooks(): void {
		add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_scripts' ], 11 );
		add_action( 'advanced-ads-ad-output-ready', [ $this, 'collect_ad_id' ], 10, 3 );
		add_filter( 'advanced-ads-output-wrapper-options', [ $this, 'add_wrapper' ], 20, 2 );
		add_action( 'wp_footer', [ $this, 'output_ad_ids' ], PHP_INT_MAX - 1 );
	}

	/**
	 * Load header scripts (actually loads in footer).
	 *
	 * @since 1.0.0
	 *
	 * @return void
	 */
	public function enqueue_scripts(): void {
		if ( Conditional::is_amp() ) {
			return;
		}

		$deps           = [];
		$is_ga_tracking = Helpers::is_tracking_method( 'ga' ) || is_multisite() || Helpers::is_forced_analytics();

		if ( wp_script_is( 'advanced-ads-pro/cache_busting' ) ) {
			$deps[] = 'advanced-ads-pro/cache_busting';
		}

		wp_enqueue_script( 'advadsTrackingScript', AA_TRACKING_BASE_URL . 'assets/dist/tracking.js', $deps, AAT_VERSION, true );
		$deps[] = 'advadsTrackingScript';
		if ( $is_ga_tracking ) {
			wp_enqueue_script( 'advadsTrackingGAFront', AA_TRACKING_BASE_URL . 'assets/dist/ga-tracking.js', $deps, AAT_VERSION, true );
		}

		// Pass ajax_action name to script.
		wp_localize_script(
			'advadsTrackingScript',
			'advadsTracking',
			[
				'impressionActionName' => Constants::TRACK_IMPRESSION,
				'clickActionName'      => Constants::TRACK_CLICK,
				'targetClass'          => wp_advads()->get_frontend_prefix() . 'target',
				'blogId'               => get_current_blog_id(),
				'frontendPrefix'       => wp_advads()->get_frontend_prefix(),
			]
		);

		if ( $is_ga_tracking ) {
			wp_advads()->json->add(
				'tracking',
				[
					'googleEvents' => [
						/**
						 * Filters the Google Analytics 4 event name for ad impressions
						 *
						 * @param string $impression_name ad impression event name.
						 */
						'impression' => apply_filters( 'advanced-ads-tracking-ga-impression', 'advanced_ads_impression' ),

						/**
						 * Filters the Google Analytics 4 event name for clicks
						 *
						 * @param string $click_name ad click event name.
						 */
						'click'      => apply_filters( 'advanced-ads-tracking-ga-click', 'advanced_ads_click' ),
					],
				]
			);
		}

		// Delayed ads add-ons are available.
		if ( Helpers::has_delayed_ads() ) {
			wp_enqueue_script( 'advadsTrackingDelayed', AA_TRACKING_BASE_URL . 'assets/dist/delayed.js', array_merge( $deps, [ 'jquery' ] ), AAT_VERSION, true );
		}
	}

	/**
	 * Collect ad id, so that JavaScript can access it
	 *
	 * @param Ad     $ad     Ad instance.
	 * @param string $output The ad output string.
	 */
	public function collect_ad_id( Ad $ad, $output ) {
		if (
			empty( $ad->get_prop( 'global_output' ) ) ||
			empty( $output ) ||
			! Tracking::has_ad_tracking_enabled( $ad )
		) {
			return;
		}

		$blog_id = get_current_blog_id();

		if ( Helpers::is_tracking_method( 'ga' ) ) {
			$can_transmit_pageqs = apply_filters( 'advanced-ads-tracking-query-string', false, $ad->get_id() );
			if ( $can_transmit_pageqs ) {
				if ( ! isset( $this->transmit_pageqs[ $blog_id ] ) ) {
					$this->transmit_pageqs[ $blog_id ] = [];
				}
				$this->transmit_pageqs[ $blog_id ][ $ad->get_id() ] = true;
			}
		}

		if ( ! isset( $this->ad_ids[ $blog_id ] ) ) {
			$this->ad_ids[ $blog_id ] = [];
		}

		Data::collect_blog_data();
		$this->ad_ids[ $blog_id ][] = $ad->get_id();
	}

	/**
	 * Add a wrapper for the ad
	 *
	 * @param array $wrapper The wrapper object.
	 * @param Ad    $ad      The ad object.
	 *
	 * @return array
	 */
	public function add_wrapper( $wrapper, $ad ) {
		// If this ad should not be tracked, don't show wrapper.
		if ( ! Tracking::has_ad_tracking_enabled( $ad, 'min_one' ) ) {
			return $wrapper;
		}

		$frontend_prefix = wp_advads()->get_frontend_prefix();

		// Add the ad id to the wrapper.
		$wrapper[ 'data-' . $frontend_prefix . 'trackid' ]  = $ad->get_id();
		$wrapper[ 'data-' . $frontend_prefix . 'trackbid' ] = get_current_blog_id();
		$wrapper[ 'data-' . $frontend_prefix . 'redirect' ] = (bool) $ad->get_prop( 'tracking.cloaking' ) && ! empty( $ad->get_url() );

		// Add class to wrapper for click tracking, if ad is image or dummy only if it has a URL.
		if (
			Tracking::has_ad_tracking_enabled( $ad, 'click' )
			&& ! ( empty( $ad->get_url() ) && $ad->is_type( [ 'dummy', 'image' ] ) )
		) {
			$wrapper['class'][] = $frontend_prefix . 'target';
		}

		$is_peepso_stream = $ad->get_root_placement() && $ad->get_root_placement()->is_type( 'peepso_stream' );
		if (
			( ! $ad->get_root_placement() || ! Str::contains( 'sticky', $ad->get_root_placement()->get_type() ) || 'timeout' !== $ad->get_prop( 'sticky.trigger' ) ) &&
			empty( $ad->get_prop( 'layer_placement.trigger' ) ) && ! $is_peepso_stream
		) {

			// If not sticky, or sticky but no timeout, AND not layer ad or no trigger, AND not PeepSo abort.
			return $wrapper;
		}

		// Add data attribute if this ad's impressions should be tracked.
		if ( Tracking::has_ad_tracking_enabled( $ad ) ) {
			$wrapper[ 'data-' . $frontend_prefix . 'impression' ] = true;
		}

		// Add delayed marker.
		if ( ! $is_peepso_stream ) {
			$wrapper['data-delayed'] = 1;
		}

		return $wrapper;
	}

	/**
	 * Output ad ids
	 *
	 * @return void
	 */
	public function output_ad_ids(): void {
		if ( Conditional::is_amp() ) {
			return;
		}

		$blog_data = Data::collect_blog_data();
		$variables = [
			'advads_tracking_' => [
				'ads'       => $this->ad_ids,
				'urls'      => $blog_data['ajaxurls'],
				'methods'   => $blog_data['methods'],
				'parallel'  => $blog_data['parallelTracking'],
				'linkbases' => $blog_data['linkbases'],
			],
		];

		// Add Google Analytics specific variables.
		if ( is_multisite() || Helpers::is_tracking_method( 'ga' ) || Helpers::is_forced_analytics() ) {
			$variables['advads_gatracking_'] = [
				'uids'           => $blog_data['gaUIDs'],
				'allads'         => $blog_data['allads'],
				'anonym'         => defined( 'ADVANCED_ADS_DISABLE_ANALYTICS_ANONYMIZE_IP' ) && ADVANCED_ADS_DISABLE_ANALYTICS_ANONYMIZE_IP,
				'transmitpageqs' => $this->transmit_pageqs,
			];
		}

		// transpose variables into string.
		$output = '';
		foreach ( $variables as $dimension => $vars ) {
			foreach ( $vars as $var => $value ) {
				$output .= sprintf( 'var %s = %s;', $dimension . $var, wp_json_encode( $value, ( is_array( $value ) && empty( $value ) ) ? JSON_FORCE_OBJECT : 0 ) );
			}
		}

		printf( '<script id="%stracking">%s</script>', wp_advads()->get_frontend_prefix(), $output ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}
}