Uname: Linux p3plzcpnl499967.prod.phx3.secureserver.net 4.18.0-553.54.1.lve.el8.x86_64 #1 SMP Wed Jun 4 13:01:13 UTC 2025 x86_64
Software: Apache
PHP version: 8.2.30 [ PHP INFO ] PHP os: Linux
Server Ip: 208.109.40.231
Your Ip: 216.73.216.26
User: nayff91c5tsx (10005085) | Group: nayff91c5tsx (10005085)
Safe Mode: OFF
Disable Function:
NONE

name : module.php
<?php
/**
 * Pro Free Trial Popup Module
 *
 * @package Elementor\Modules\ProFreeTrialPopup
 * @since 3.32.0
 */

namespace Elementor\Modules\ProFreeTrialPopup;

use Elementor\Core\Base\Module as BaseModule;
use Elementor\Core\Experiments\Manager as Experiments_Manager;
use Elementor\Core\Utils\Ab_Test;
use Elementor\Core\Isolation\Elementor_Adapter;
use Elementor\Core\Isolation\Elementor_Adapter_Interface;
use Elementor\Includes\EditorAssetsAPI;
use Elementor\Modules\ElementorCounter\Module as Elementor_Counter;
use Elementor\Utils;
use Elementor\Plugin;


if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

class Module extends BaseModule {

	const EXPERIMENT_NAME = 'e_pro_free_trial_popup';
	const MODULE_NAME = 'pro-free-trial-popup';
	const POPUP_DISPLAYED_OPTION = '_e_pro_free_trial_popup_displayed';
	const AB_TEST_NAME = 'pro_free_trial_popup';
	const REQUIRED_VISIT_COUNT = 4;
	const EXTERNAL_DATA_URL = 'https://assets.elementor.com/pro-free-trial-popup/v1/pro-free-trial-popup.json';
	const ACTIVE = 'active';

	private Elementor_Adapter_Interface $elementor_adapter;
	private array $external_data;

	public function __construct() {
		parent::__construct();

		if ( ! current_user_can( 'manage_options' ) ) {
			return;
		}

		if ( ! Plugin::$instance->experiments->is_feature_active( self::EXPERIMENT_NAME ) ) {
			return;
		}

		if ( Utils::has_pro() ) {
			return;
		}

		$this->external_data = $this->get_external_data();

		if ( ! EditorAssetsAPI::has_valid_nested_array( $this->external_data, [ self::MODULE_NAME, 0 ] ) ) {
			return false;
		}

		$this->elementor_adapter = new Elementor_Adapter();

		add_action( 'elementor/editor/before_enqueue_scripts', [ $this, 'maybe_enqueue_popup' ] );
	}

	public function get_name() {
		return self::MODULE_NAME;
	}

	public static function get_experimental_data(): array {
		return [
			'name' => self::EXPERIMENT_NAME,
			'title' => esc_html__( 'Pro Free Trial Popup', 'elementor' ),
			'description' => esc_html__( 'Show Pro free trial popup on 4th editor visit', 'elementor' ),
			'hidden' => true,
			'default' => Experiments_Manager::STATE_INACTIVE,
			'new_site' => [
				'default_active' => true,
				'minimum_installation_version' => '3.32.0',
			],
		];
	}

	/**
	 * Check if popup should be enqueued and enqueue if needed
	 */
	public function maybe_enqueue_popup(): void {
		if ( ! $this->should_show_popup() ) {
			return;
		}

		$this->enqueue_scripts();
		$this->set_popup_as_displayed();
	}

	/**
	 * Determine if popup should be shown
	 *
	 * @return bool True if popup should be shown
	 */
	private function should_show_popup(): bool {

		if ( ! $this->is_feature_enabled() ) {
			return false;
		}

		if ( $this->is_before_fourth_visit() ) {
			return false;
		}

		if ( $this->has_popup_been_displayed() ) {
			return false;
		}

		$result = Ab_Test::should_show_feature( self::AB_TEST_NAME );

		return $result;
	}

	/**
	 * Check if feature is enabled via external JSON
	 *
	 * @return bool True if feature is enabled
	 */
	private function is_feature_enabled(): bool {
		$popup_data = $this->extract_popup_data( $this->external_data );

		$status = $popup_data['status'] ?? '';
		return ! empty( $status ) && self::ACTIVE === $status;
	}

	/**
	 * Get external JSON data
	 *
	 * @return array External data or empty array on failure
	 */
	private function get_external_data(): array {
		$editor_assets_api = new EditorAssetsAPI( $this->get_api_config() );
		return $editor_assets_api->get_assets_data();
	}

	private function get_api_config(): array {
		return [
			EditorAssetsAPI::ASSETS_DATA_URL => self::EXTERNAL_DATA_URL,
			EditorAssetsAPI::ASSETS_DATA_TRANSIENT_KEY => '_elementor_pro_free_trial_data',
			EditorAssetsAPI::ASSETS_DATA_KEY => self::MODULE_NAME,
		];
	}

	/**
	 * Check if current visit is before the 4th visit
	 *
	 * @return bool True if before 4th visit
	 */
	private function is_before_fourth_visit(): bool {
		if ( ! $this->elementor_adapter ) {
			return true;
		}

		$editor_visit_count = $this->elementor_adapter->get_count( Elementor_Counter::EDITOR_COUNTER_KEY );
		return $editor_visit_count < self::REQUIRED_VISIT_COUNT;
	}

	/**
	 * Check if popup has already been displayed to this user
	 *
	 * @return bool True if already displayed
	 */
	private function has_popup_been_displayed(): bool {
		return (bool) get_user_meta( $this->get_current_user_id(), self::POPUP_DISPLAYED_OPTION, true );
	}

	/**
	 * Mark popup as displayed for current user
	 */
	private function set_popup_as_displayed(): void {
		$user_id = $this->get_current_user_id();
		update_user_meta( $user_id, self::POPUP_DISPLAYED_OPTION, true );
	}

	/**
	 * Enqueue popup scripts
	 */
	private function enqueue_scripts(): void {
		$min_suffix = Utils::is_script_debug() ? '' : '.min';
		$script_url = ELEMENTOR_ASSETS_URL . 'js/pro-free-trial-popup' . $min_suffix . '.js';

		wp_enqueue_script(
			self::MODULE_NAME,
			$script_url,
			[
				'react',
				'react-dom',
				'elementor-common',
				'elementor-v2-ui',
			],
			ELEMENTOR_VERSION,
			true
		);

		$popup_data = $this->extract_popup_data( $this->external_data );

		wp_localize_script( self::MODULE_NAME, 'elementorProFreeTrialData', $popup_data );

		wp_set_script_translations( self::MODULE_NAME, 'elementor' );
	}

	/**
	 * Extract popup data from external data
	 *
	 * @param array $external_data The full external data array
	 * @return array Popup data or empty array if not found
	 */
	private function extract_popup_data( array $external_data ): array {
		return $external_data[ self::MODULE_NAME ][0];
	}

	/**
	 * Get current user ID
	 *
	 * @return int Current user ID
	 */
	private function get_current_user_id(): int {
		$current_user = wp_get_current_user();
		return $current_user->ID ?? 0;
	}
}
© 2026 GrazzMean