: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
* @copyright Copyright (c) 2023, Code Atlantic LLC
if ( ! defined( 'ABSPATH' ) ) {
* Controls the basic analytics methods for Popup Maker
* Initializes analytics endpoints and data
public static function init() {
if ( ! self::analytics_enabled() ) {
add_action( 'rest_api_init', [ __CLASS__, 'register_endpoints' ] );
add_action( 'wp_ajax_pum_analytics', [ __CLASS__, 'ajax_request' ] );
add_action( 'wp_ajax_nopriv_pum_analytics', [ __CLASS__, 'ajax_request' ] );
add_filter( 'pum_vars', [ __CLASS__, 'pum_vars' ] );
* Checks whether analytics is enabled.
public static function analytics_enabled() {
$disabled = pum_get_option( 'disable_analytics' ) || popmake_get_option( 'disable_popup_open_tracking' );
return (bool) apply_filters( 'pum_analytics_enabled', ! $disabled );
* Get a list of key pairs for each event type.
* Internally used only for meta keys.
* Example returns [[open,opened],[conversion,conversion]].
* - popup_open_count, popup_last_opened
* - popup_conversion_count, popup_last_conversion
* @param string $event Event key.
public static function event_keys( $event ) {
$keys = [ $event, rtrim( $event, 'e' ) . 'ed' ];
if ( 'conversion' === $event ) {
return apply_filters( 'pum_analytics_event_keys', $keys, $event );
* Returns an array of valid event types.
public static function valid_events() {
return apply_filters( 'pum_analytics_valid_events', [ 'open', 'conversion' ] );
* This is called by various methods including the ajax & rest api requests.
* Can be used externally such as after purchase tracking.
public static function track( $args = [] ) {
if ( empty( $args['pid'] ) || $args['pid'] <= 0 ) {
// $uuid = isset( $_COOKIE['__pum'] ) ? sanitize_text_field( $_COOKIE['__pum'] ) : false;
// $session = $uuid && isset( $_COOKIE[ $uuid ] ) ? PUM_Utils_Array::safe_json_decode( $_COOKIE[ $uuid ] ) : false;
$event = sanitize_text_field( $args['event'] );
$popup = pum_get_popup( $args['pid'] );
if ( ! pum_is_popup( $popup ) || ! in_array( $event, self::valid_events(), true ) ) {
$popup->increase_event_count( $event );
if ( has_action( 'pum_analytics_' . $event ) ) {
do_action( 'pum_analytics_' . $event, $popup->ID, $args );
do_action( 'pum_analytics_event', $args );
* Only used when WP-JSON Restful API is not available.
public static function ajax_request() {
switch ( $args['method'] ) {
self::serve_no_content();
* @param WP_REST_Request $request
public static function analytics_endpoint( WP_REST_Request $request ) {
$args = $request->get_params();
if ( ! $args || empty( $args['pid'] ) ) {
return new WP_Error( 'missing_params', __( 'Missing Parameters.' ), [ 'status' => 404 ] );
self::serve_no_content();
public static function endpoint_absint( $param ) {
return is_numeric( $param );
* Registers the analytics endpoints
public static function register_endpoints() {
self::get_analytics_namespace(),
self::get_analytics_route(),
'pum_analytics_rest_route_args',
'callback' => [ __CLASS__, 'analytics_endpoint' ],
'permission_callback' => '__return_true',
'description' => __( 'Event Type', 'popup-maker' ),
'description' => __( 'Popup ID', 'popup-maker' ),
'validation_callback' => [ __CLASS__, 'endpoint_absint' ],
'sanitize_callback' => 'absint',
* Adds our analytics endpoint to pum_vars
* @param array $vars The current pum_vars.
* @return array The updates pum_vars
public static function pum_vars( $vars = [] ) {
$vars['analytics_route'] = self::get_analytics_route();
if ( function_exists( 'rest_url' ) ) {
$vars['analytics_api'] = esc_url_raw( rest_url( self::get_analytics_namespace() ) );
$vars['analytics_api'] = false;
* Gets the analytics namespace
* If bypass adblockers is enabled, will return random or custom string. If not, returns 'pum/v1'.
* @return string The analytics namespce
public static function get_analytics_namespace() {
$namespace = self::customize_endpoint_value( 'pum' );
return "$namespace/v$version";
* Gets the analytics route
* If bypass adblockers is enabled, will return random or custom string. If not, returns 'analytics'.
* @return string The analytics route
public static function get_analytics_route() {
return self::customize_endpoint_value( $route );
* Customizes the endpoint value given to it
* If bypass adblockers is enabled, will return random or custom string. If not, returns the value given to it.
* @param string $value The value to, potentially, customize.
public static function customize_endpoint_value( $value = '' ) {
$bypass_adblockers = pum_get_option( 'bypass_adblockers', false );
if ( true === $bypass_adblockers || 1 === intval( $bypass_adblockers ) ) {
switch ( pum_get_option( 'adblock_bypass_url_method', 'random' ) ) {
$value = preg_replace( '/[^a-z0-9]+/', '-', pum_get_option( 'adblock_bypass_custom_filename', $value ) );
$site_url = get_site_url();
$value = md5( $site_url . $value );
* Creates and returns a 1x1 tracking gif to the browser.
public static function serve_pixel() {
$gif = self::get_file( Popup_Maker::$DIR . 'assets/images/beacon.gif' );
header( 'Content-Type: image/gif' );
header( 'Content-Length: ' . strlen( $gif ) );
public static function get_file( $path ) {
if ( function_exists( 'realpath' ) ) {
$path = realpath( $path );
if ( ! $path || ! @is_file( $path ) ) {
return @file_get_contents( $path );
* Returns a 204 no content header.
public static function serve_no_content() {
header( 'HTTP/1.0 204 No Content' );
header( 'Content-Type: image/gif' );
header( 'Content-Length: 0' );
* Serves a proper json response.
public static function serve_json( $data = 0 ) {
header( 'Content-Type: application/json' );
echo PUM_Utils_Array::safe_json_encode( $data );