use Elementor\Controls_Manager;
use WprAddons\Includes\Controls\WprAjaxSelect2\WPR_Control_Ajax_Select2;
use WprAddons\Includes\Controls\WPR_Control_Animations;
use WprAddons\Includes\Controls\WPR_Control_Animations_Alt;
use WprAddons\Includes\Controls\WPR_Control_Button_Animations;
use WprAddons\Includes\Controls\WPR_Control_Arrow_Icons;
use WprAddons\Classes\Utilities;
use Elementor\Core\App\App;
if ( ! defined( 'ABSPATH' ) ) { exit; } // Exit if accessed directly
private static $_instance;
private $_modules_manager;
private $_localize_settings = [];
public function get_version() {
return WPR_ADDONS_VERSION;
* Throw error on object clone
* The whole idea of the singleton design pattern is that there is a single
* object therefore, we don't want the object to be cloned.
public function __clone() {
// Cloning instances of the class is forbidden
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin huh?', 'wpr-addons' ), '1.0' );
* Disable unserializing of the class
public function __wakeup() {
// Unserializing instances of the class is forbidden
_doing_it_wrong( __FUNCTION__, esc_html__( 'Cheatin huh?', 'wpr-addons' ), '1.0' );
public static function instance() {
if ( is_null( self::$_instance ) ) {
self::$_instance = new self();
private function _includes() {
require WPR_ADDONS_PATH . 'includes/modules-manager.php';
require WPR_ADDONS_PATH . 'includes/controls/wpr-ajax-select2/wpr-control-ajax-select2.php';
require WPR_ADDONS_PATH . 'includes/controls/wpr-ajax-select2/wpr-control-ajax-select2-api.php';
require WPR_ADDONS_PATH . 'includes/controls/wpr-control-animations.php';
require WPR_ADDONS_PATH . 'includes/controls/wpr-control-icons.php';
require WPR_ADDONS_PATH . 'admin/includes/wpr-templates-library.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-post-likes.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-ajax-search.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-load-more-instagram-posts.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-load-more-tweets.php';
require WPR_ADDONS_PATH . 'classes/wpr-custom-meta-keys.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-filter-grid-posts.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-filter-grid-media.php';
require WPR_ADDONS_PATH . 'classes/modules/wpr-filter-woo-products.php';
if ( 'on' === get_option('wpr-particles', 'on') ) {//TODO: make this check automatic(loop through) for all extensions
require WPR_ADDONS_PATH . 'extensions/wpr-particles.php';
if ( 'on' === get_option('wpr-parallax-background', 'on') || 'on' === get_option('wpr-parallax-multi-layer', 'on') ) {
require WPR_ADDONS_PATH . 'extensions/wpr-parallax.php';
if ( 'on' === get_option('wpr-sticky-section', 'on') ) {
require WPR_ADDONS_PATH . 'extensions/wpr-sticky-section.php';
if ( 'on' === get_option('wpr-custom-css', 'on') ) {
require WPR_ADDONS_PATH . 'extensions/wpr-custom-css.php';
require WPR_ADDONS_PATH . 'admin/mega-menu.php';
// TODO:: ommit if form builder turned off if possible
require WPR_ADDONS_PATH . 'classes/modules/wpr-form-handlers.php';
require WPR_ADDONS_PATH . 'admin/plugin-options.php';
require WPR_ADDONS_PATH . 'admin/templates-kit.php';
require WPR_ADDONS_PATH . 'admin/theme-builder.php';
require WPR_ADDONS_PATH . 'admin/premade-blocks.php';
require WPR_ADDONS_PATH . 'admin/popups.php';
require WPR_ADDONS_PATH . 'admin/metabox/wpr-secondary-image.php';
// Dropdown Category Filter for Wpr Templates
require WPR_ADDONS_PATH . 'admin/includes/wpr-templates-category-filter.php';
// TODO: Remove this and fix with Transients
add_action( 'admin_enqueue_scripts', [ $this, 'hide_theme_notice' ] );
if ( class_exists('WooCommerce') ) {
if ( 'on' === get_option('wpr_override_woo_templates', 'on') ) {
require WPR_ADDONS_PATH . 'includes/woocommerce/woocommerce-config.php';
// Add Remove From Wishlist
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-add-remove-from-wishlist.php';
// Add Remove From Compare
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-add-remove-from-compare.php';
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-update-mini-wishlist.php';
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-compare-popup-action.php';
// Add Remove From Compare
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-update-mini-compare.php';
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-count-wishlist-compare-items.php';
require WPR_ADDONS_PATH . 'classes/woocommerce/wpr-check-product-in-wc.php';
public function autoload( $class ) {
if ( 0 !== strpos( $class, __NAMESPACE__ ) ) {
[ '/^' . __NAMESPACE__ . '\\\/', '/([a-z])([A-Z])/', '/_/', '/\\\/' ],
[ '', '$1-$2', '-', DIRECTORY_SEPARATOR ],
$filename = WPR_ADDONS_PATH . $filename . '.php';
if ( is_readable( $filename ) ) {
public function get_localize_settings() {
return $this->_localize_settings;
public function add_localize_settings( $setting_key, $setting_value = null ) {
if ( is_array( $setting_key ) ) {
$this->_localize_settings = array_replace_recursive( $this->_localize_settings, $setting_key );
if ( ! is_array( $setting_value ) || ! isset( $this->_localize_settings[ $setting_key ] ) || ! is_array( $this->_localize_settings[ $setting_key ] ) ) {
$this->_localize_settings[ $setting_key ] = $setting_value;
$this->_localize_settings[ $setting_key ] = array_replace_recursive( $this->_localize_settings[ $setting_key ], $setting_value );
public function script_suffix() {
// $dir = is_rtl() ? '-rtl' : '';
return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
public function register_ajax_hooks() {
add_action( 'wp_ajax_mailchimp_subscribe', [new Utilities, 'ajax_mailchimp_subscribe'] );
add_action( 'wp_ajax_nopriv_mailchimp_subscribe', [new Utilities, 'ajax_mailchimp_subscribe'] );
public function mega_menu_ajax_loading() {
$elementor = \Elementor\Plugin::instance();
$mega_id = get_post_meta( $_GET['item_id'], 'wpr-mega-menu-item', true);
$type = get_post_meta(get_the_ID(), '_wpr_template_type', true) || get_post_meta($mega_id, '_elementor_template_type', true);
$has_css = 'internal' === get_option( 'elementor_css_print_method' ) || '' !== $type;
$content = $elementor->frontend->get_builder_content_for_display($mega_id, $has_css);
wp_send_json( $content );
public function register_megamenu_route() {
add_action( 'rest_api_init', function() {
'callback' => [$this, 'mega_menu_ajax_loading'],
'permission_callback' => '__return_true'
public function register_custom_controls() {
$controls_manager = \Elementor\Plugin::$instance->controls_manager;
$controls_manager->register( new WPR_Control_Ajax_Select2() );
$controls_manager->register( new WPR_Control_Animations() );
$controls_manager->register( new WPR_Control_Animations_Alt() );
$controls_manager->register( new WPR_Control_Button_Animations() );
$controls_manager->register( new WPR_Control_Arrow_Icons() );
public function register_elementor_document_type( $documents_manager ) {
require WPR_ADDONS_PATH . 'modules/theme-builder/wpr-theme-builder.php';
$documents_manager->register_document_type( 'wpr-theme-builder', 'Wpr_Theme_Builder' );
require WPR_ADDONS_PATH . 'modules/popup/wpr-popup.php';
if ( defined('WPR_ADDONS_PRO_VERSION') && wpr_fs()->can_use_premium_code() ) {
require WPR_ADDONS_PRO_PATH . 'modules/popup-pro/wpr-popup-pro.php';
$documents_manager->register_document_type( 'wpr-popups', 'Wpr_Popup_Pro' );
$documents_manager->register_document_type( 'wpr-popups', 'Wpr_Popup' );
public function enqueue_styles() {
WPR_ADDONS_URL . 'assets/css/lib/animations/wpr-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-link-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/wpr-link-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-loading-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/loading-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-button-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/button-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
// GOGA - enqueue instead of register (because of animations)
'wpr-text-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/text-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
WPR_ADDONS_URL . 'assets/css/lib/lightgallery/lightgallery'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
WPR_ADDONS_URL . 'assets/css/lib/aos/aos.min.css',
WPR_ADDONS_URL . 'assets/css/lib/flipster/jquery.flipster.min.css',
Plugin::instance()->get_version()
WPR_ADDONS_URL . 'assets/css/frontend'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
// Load FontAwesome - TODO: Check if necessary (maybe elementor is already loading this)
ELEMENTOR_ASSETS_URL . 'lib/font-awesome/css/all'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
if ( \Elementor\Plugin::$instance->preview->is_preview_mode() ) {
'wpr-addons-library-frontend-css',
WPR_ADDONS_URL . 'assets/css/admin/library-frontend'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
public function enqueue_editor_styles() {
WPR_ADDONS_URL . 'assets/css/lib/animations/wpr-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-animations-link-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/wpr-link-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-loading-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/loading-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-button-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/button-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
'wpr-text-animations-css',
WPR_ADDONS_URL . 'assets/css/lib/animations/text-animations'. $this->script_suffix() .'.css',
Plugin::instance()->get_version()
WPR_ADDONS_URL . 'assets/css/lib/aos/aos.min.css',
WPR_ADDONS_URL . 'assets/css/lib/flipster/jquery.flipster.min.css',
Plugin::instance()->get_version()
public function wpr_some_init_actions() {
load_plugin_textdomain('wpr-addons', false, dirname(plugin_basename(__FILE__)) . '/languages/');
if ( get_option('wpr_hide_banners') !== 'on' ) {
require WPR_ADDONS_PATH . 'admin/notices/pro-features-notice.php';
require WPR_ADDONS_PATH . 'admin/notices/plugin-update-notice.php';
require WPR_ADDONS_PATH . 'admin/notices/plugin-sale-notice.php';
require WPR_ADDONS_PATH . 'admin/notices/rating-notice.php';
// if ( defined('REST_REQUEST') && REST_REQUEST ) {
// if ( ! isset( $_COOKIE['wpr_guest_token'] ) && !headers_sent() ) {
// // Generate a unique token and store it in a cookie
// $guest_id = bin2hex(random_bytes(32)); // Secure random string as guest "session"
// $secure = ( isset( $_SERVER['HTTPS'] ) && $_SERVER['HTTPS'] === 'on' );
// setcookie( 'wpr_guest_token', $guest_id, time() + 3600, '/', '', $secure, true ); // 1 hour expiration
// $_COOKIE['wpr_guest_token'] = $guest_id; // Ensure it's immediately available in PHP
public function wpr_generate_custom_token() {
if ( is_user_logged_in() ) {
// For logged-in users, use their user ID to store a token
$user_id = get_current_user_id();
$token = bin2hex(\random_bytes(32)); // Secure token generation
set_transient( 'wpr_custom_token_' . $user_id, $token, HOUR_IN_SECONDS ); // Store token for 1 hour
// For non-logged-in users, check if the guest token cookie exists
if ( isset( $_COOKIE['wpr_guest_token'] ) ) {
$guest_id = sanitize_text_field( $_COOKIE['wpr_guest_token'] );
// If somehow the cookie isn't set, handle appropriately
// Check if a token already exists for this guest
$existing_token = get_transient( 'wpr_custom_guest_token_' . $guest_id );
// Only create new token if one doesn't exist
$token = bin2hex(\random_bytes(32)); // Secure token generation
set_transient( 'wpr_custom_guest_token_' . $guest_id, $token, HOUR_IN_SECONDS ); // Store token for 1 hour
// Clean up old guest tokens periodically (1% chance)
if ( rand(1, 100) === 1 ) {
$this->cleanup_guest_tokens();
private function cleanup_guest_tokens() {