Create New Item
Item Type
File
Folder
Item Name
Search file in folder and subfolders...
Are you sure want to rename?
File Manager
/
wp-content
/
plugins
/
royal-elementor-addons
/
includes
/
display-conditions
:
class-conditions-manager.php
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php if ( ! defined( 'ABSPATH' ) ) { exit; } /** * Central manager for the Visibility tab. * Loads all sections, registers controls on all Elementor elements, evaluates conditions on render. */ class WPR_DC_Conditions_Manager { /** * Registered section instances, sorted by order. * * @var WPR_DC_Section_Base[] */ private $sections = []; /** * Cached user-agent parsing result. */ private $ua_parsed = null; public function __construct() { $this->load_sections(); $this->setup_hooks(); } /** * Load and register all section classes from the sections/ directory. */ private function load_sections() { $sections_dir = WPR_ADDONS_PATH . 'includes/display-conditions/sections/'; $files = glob( $sections_dir . 'class-*.php' ); if ( ! $files ) { return; } foreach ( $files as $file ) { require_once $file; } // All section classes follow naming: WPR_DC_Section_{PascalName} // We collect them by checking declared classes that extend WPR_DC_Section_Base $section_classes = [ 'WPR_DC_Section_General_Settings', 'WPR_DC_Section_Visitor_Roles', 'WPR_DC_Section_User_Profile', 'WPR_DC_Section_Page_Content', 'WPR_DC_Section_Archive', 'WPR_DC_Section_Date_Time', 'WPR_DC_Section_Device_Browser', 'WPR_DC_Section_Visitor_Location', 'WPR_DC_Section_Url_Parameters', 'WPR_DC_Section_Woocommerce', 'WPR_DC_Section_Language', 'WPR_DC_Section_Custom_Fields', 'WPR_DC_Section_Dynamic_Tags', 'WPR_DC_Section_Interaction', 'WPR_DC_Section_Random_Limits', 'WPR_DC_Section_Fallback_Content', 'WPR_DC_Section_Pro_Features', ]; foreach ( $section_classes as $class_name ) { // Use pro override class if available $pro_class = $class_name . '_Pro'; $use_class = class_exists( $pro_class ) ? $pro_class : $class_name; if ( class_exists( $use_class ) ) { $section = new $use_class(); if ( $section->is_available() ) { $this->sections[] = $section; } } } // Sort by order usort( $this->sections, function ( $a, $b ) { return $a->get_order() - $b->get_order(); } ); } /** * Hook into Elementor to register controls and intercept rendering. */ private function setup_hooks() { // Register controls on all element types $element_types = [ 'common', 'section', 'column', 'container' ]; foreach ( $element_types as $type ) { add_action( "elementor/element/{$type}/section_effects/after_section_end", [ $this, 'register_tab_sections' ], 10, 2 ); } // Frontend: intercept rendering to show/hide elements $render_types = [ 'widget', 'section', 'column', 'container' ]; foreach ( $render_types as $type ) { add_action( "elementor/frontend/{$type}/before_render", [ $this, 'before_render' ] ); add_action( "elementor/frontend/{$type}/after_render", [ $this, 'after_render' ] ); } // Prevent Elementor from caching elements that have visibility conditions. // Without this, the first render result gets cached and served to all users, // breaking role-based and other dynamic visibility logic. add_filter( 'elementor/element/is_dynamic_content', [ $this, 'disable_element_caching' ], 10, 2 ); } /** * Tell Elementor that elements with visibility conditions are dynamic * so they are never served from the element cache. * * @param bool $is_dynamic_content Current dynamic-content flag. * @param array $raw_data Raw element data including settings. * @return bool */ public function disable_element_caching( $is_dynamic_content, $raw_data ) { if ( ! empty( $raw_data['settings']['wpr_dc_enabled'] ) ) { return true; } return $is_dynamic_content; } /** * Register all visibility sections as collapsible panels in our custom tab. */ public function register_tab_sections( $element, $args ) { foreach ( $this->sections as $section ) { $section_args = [ 'tab' => 'wpr_display_conditions', 'label' => $section->get_label(), ]; // Hide all sections except General when visibility is not enabled if ( 'wpr_dc_general' !== $section->get_id() ) { $section_args['condition'] = [ 'wpr_dc_enabled' => 'yes', ]; } $element->start_controls_section( $section->get_id(), $section_args ); $section->register_controls( $element ); $element->end_controls_section(); } } /** * Before an element renders on the frontend — evaluate conditions and hide if needed. */ public function before_render( $element ) { // Never hide in editor if ( \Elementor\Plugin::$instance->editor->is_edit_mode() ) { return; } // Also skip preview mode so Elementor preview works if ( \Elementor\Plugin::$instance->preview->is_preview_mode() ) { return; } $settings = $element->get_settings_for_display(); // Check master toggle if ( empty( $settings['wpr_dc_enabled'] ) || 'yes' !== $settings['wpr_dc_enabled'] ) { return; } $mode = ! empty( $settings['wpr_dc_mode'] ) ? $settings['wpr_dc_mode'] : 'show'; $logic = ! empty( $settings['wpr_dc_logic'] ) ? $settings['wpr_dc_logic'] : 'any'; $css_only = ! empty( $settings['wpr_dc_css_only'] ) && 'yes' === $settings['wpr_dc_css_only']; // Collect results from evaluable sections (skip general, fallback, interaction) $skip_ids = [ 'wpr_dc_general', 'wpr_dc_fallback', 'wpr_dc_interaction' ]; $results = []; foreach ( $this->sections as $section ) { if ( in_array( $section->get_id(), $skip_ids, true ) ) { continue; } $result = $section->evaluate( $settings ); if ( null !== $result ) { $results[] = $result; } } // No conditions configured — always show if ( empty( $results ) ) { return; } // Apply logic if ( 'all' === $logic ) { $conditions_met = ! in_array( false, $results, true ); } else { $conditions_met = in_array( true, $results, true ); } // Determine if element should be shown $should_show = ( 'show' === $mode ) ? $conditions_met : ! $conditions_met; if ( ! $should_show ) { WPR_DC_Render_Handler::instance()->start_hiding( $element, $settings, $css_only ); } } /** * After an element renders — close output buffer if hiding. */ public function after_render( $element ) { if ( \Elementor\Plugin::$instance->editor->is_edit_mode() ) { return; } WPR_DC_Render_Handler::instance()->finish_hiding( $element ); } /** * Get parsed user-agent info (cached per request). */ public function get_user_agent_info() { if ( null !== $this->ua_parsed ) { return $this->ua_parsed; } $ua = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : ''; $this->ua_parsed = [ 'raw' => $ua, 'device' => $this->detect_device( $ua ), 'browser' => $this->detect_browser( $ua ), ]; return $this->ua_parsed; } /** * Detect device type from user-agent string. */ private function detect_device( $ua ) { if ( preg_match( '/iPad|Android(?!.*Mobile)|Tablet/i', $ua ) ) { return 'tablet'; } if ( preg_match( '/Mobile|iPhone|iPod|Android.*Mobile|webOS|BlackBerry|Opera Mini|IEMobile/i', $ua ) ) { return 'mobile'; } return 'desktop'; } /** * Detect browser from user-agent string. */ private function detect_browser( $ua ) { if ( preg_match( '/Edg\//i', $ua ) ) { return 'edge'; } if ( preg_match( '/OPR|Opera/i', $ua ) ) { return 'opera'; } if ( preg_match( '/Chrome/i', $ua ) && ! preg_match( '/Edg|OPR/i', $ua ) ) { return 'chrome'; } if ( preg_match( '/Safari/i', $ua ) && ! preg_match( '/Chrome|Edg|OPR/i', $ua ) ) { return 'safari'; } if ( preg_match( '/Firefox/i', $ua ) ) { return 'firefox'; } if ( preg_match( '/MSIE|Trident/i', $ua ) ) { return 'ie'; } return 'other'; } }