true ] ); } /** * Enqueue assets (safe to call multiple times). */ public function do_enqueue() { if ( ! wp_style_is( 'aafe-adv-backgrounds', 'registered' ) ) { $this->register_assets(); } wp_enqueue_style( 'aafe-adv-backgrounds' ); wp_enqueue_script( 'aafe-adv-backgrounds' ); } /** * Enqueue frontend scripts and styles. */ public function enqueue_assets() { // Editor preview or editor mode: always load so effects appear instantly while editing. if ( class_exists( '\Elementor\Plugin' ) ) { if ( \Elementor\Plugin::$instance->editor->is_edit_mode() || \Elementor\Plugin::$instance->preview->is_preview_mode() ) { $this->do_enqueue(); return; } } // Frontend: load in when the current document uses an effect $document = \Elementor\Plugin::$instance->documents->get( get_the_ID() ); if ( ! $document ) { return; } $data = $document->get_elements_data(); if ( empty( $data ) || ! is_array( $data ) ) { return; } $find = function ( $elements ) use ( &$find ) { foreach ( $elements as $element ) { $s = $element['settings'] ?? []; if ( ( ! empty( $s['aafe_bg_type'] ) && 'none' !== $s['aafe_bg_type'] ) || ( isset( $s['aafe_float_enable'] ) && 'yes' === $s['aafe_float_enable'] ) ) { return true; } if ( ! empty( $element['elements'] ) && $find( $element['elements'] ) ) { return true; } } return false; }; if ( $find( $data ) ) { $this->do_enqueue(); } } /** * Retrieve hex color value for an Elementor Global Color ID from the active Kit. * * @param string $color_id Global Color ID. * @return string|null */ public function get_kit_global_color( $color_id ) { if ( ! class_exists( '\Elementor\Plugin' ) || ! isset( \Elementor\Plugin::$instance->kits_manager ) ) { return null; } $km = \Elementor\Plugin::$instance->kits_manager; $kit = null; if ( method_exists( $km, 'get_active_kit_for_frontend' ) ) { $kit = $km->get_active_kit_for_frontend(); } if ( ( ! $kit || ! is_object( $kit ) ) && method_exists( $km, 'get_active_kit' ) ) { $kit = $km->get_active_kit(); } if ( ! $kit || ! is_object( $kit ) ) { return null; } // Check system colors $system = $kit->get_settings_for_display( 'system_colors' ); if ( empty( $system ) || ! is_array( $system ) ) { $system = $kit->get_settings( 'system_colors' ); } if ( is_array( $system ) ) { foreach ( $system as $sc ) { if ( isset( $sc['_id'] ) && $sc['_id'] === $color_id && ! empty( $sc['color'] ) ) { return $sc['color']; } } } // Check custom colors $custom = $kit->get_settings_for_display( 'custom_colors' ); if ( empty( $custom ) || ! is_array( $custom ) ) { $custom = $kit->get_settings( 'custom_colors' ); } if ( is_array( $custom ) ) { foreach ( $custom as $cc ) { if ( isset( $cc['_id'] ) && $cc['_id'] === $color_id && ! empty( $cc['color'] ) ) { return $cc['color']; } } } // Fallbacks for standard Elementor default system colors $default_system_colors = [ 'primary' => '#6EC1E4', 'secondary' => '#54595F', 'text' => '#7A7A7A', 'accent' => '#61CE70', ]; return $default_system_colors[ $color_id ] ?? null; } /** * Resolve color values with full support for Elementor Global Colors. * * @param array $settings Element settings. * @param string $key Setting key. * @param string $default Fallback color. * @return string */ public function resolve_color( $settings, $key, $default = '' ) { // 1. Check if Elementor Global Color is selected if ( ! empty( $settings['__globals__'][ $key ] ) ) { $global_key = $settings['__globals__'][ $key ]; if ( preg_match( '/id=([a-zA-Z0-9_-]+)/', $global_key, $matches ) ) { $color_id = $matches[1]; $resolved = $this->get_kit_global_color( $color_id ); if ( ! empty( $resolved ) ) { return $resolved; } return 'var(--e-global-color-' . $color_id . ')'; } } // 2. Direct custom color value if ( ! empty( $settings[ $key ] ) ) { return $settings[ $key ]; } return $default; } /** * Register Advanced Background controls. * * @param Element_Base $element Element instance. * @param array $args Control args. */ public function register_section_controls( Element_Base $element, $args ) { $element->start_controls_section( 'aafe_adv_bg_section', [ 'label' => ' ' . esc_html__( 'AAFE Advanced Background', 'addronix-addons-for-elementor' ), 'tab' => Controls_Manager::TAB_STYLE, ] ); $element->add_control( 'aafe_bg_type', [ 'label' => esc_html__( 'Background Effect', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SELECT, 'options' => [ 'none' => esc_html__( 'None', 'addronix-addons-for-elementor' ), 'particles' => esc_html__( 'Particles', 'addronix-addons-for-elementor' ), 'waves' => esc_html__( 'SVG Waves', 'addronix-addons-for-elementor' ), 'gradient' => esc_html__( 'Animated Gradient', 'addronix-addons-for-elementor' ), 'noise' => esc_html__( 'Noise / Grain', 'addronix-addons-for-elementor' ), ], 'default' => 'none', 'render_type' => 'template', ] ); // ─── Particles Settings ───────────────────────────────── $element->add_control( 'aafe_particles_count', [ 'label' => esc_html__( 'Particle Count', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 10, 'max' => 300, 'step' => 10 ] ], 'default' => [ 'size' => 80 ], 'condition' => [ 'aafe_bg_type' => 'particles' ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_particles_color', [ 'label' => esc_html__( 'Particle Color', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::COLOR, 'default' => '#ffffff', 'condition' => [ 'aafe_bg_type' => 'particles' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-particles-color: {{VALUE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_particles_size', [ 'label' => esc_html__( 'Particle Size', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 1, 'max' => 10, 'step' => 0.5 ] ], 'default' => [ 'size' => 3 ], 'condition' => [ 'aafe_bg_type' => 'particles' ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_particles_speed', [ 'label' => esc_html__( 'Animation Speed', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 0.5, 'max' => 10, 'step' => 0.5 ] ], 'default' => [ 'size' => 3 ], 'condition' => [ 'aafe_bg_type' => 'particles' ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_particles_lines', [ 'label' => esc_html__( 'Connect with Lines', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', 'condition' => [ 'aafe_bg_type' => 'particles' ], 'render_type' => 'template', ] ); // ─── SVG Waves Settings ───────────────────────────────── $element->add_control( 'aafe_waves_color', [ 'label' => esc_html__( 'Wave Color', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::COLOR, 'default' => 'rgba(255, 255, 255, 0.25)', 'condition' => [ 'aafe_bg_type' => 'waves' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-waves-color: {{VALUE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_waves_position', [ 'label' => esc_html__( 'Wave Position', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SELECT, 'options' => [ 'bottom' => esc_html__( 'Bottom', 'addronix-addons-for-elementor' ), 'top' => esc_html__( 'Top', 'addronix-addons-for-elementor' ), 'both' => esc_html__( 'Both', 'addronix-addons-for-elementor' ), ], 'default' => 'bottom', 'condition' => [ 'aafe_bg_type' => 'waves' ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_waves_height', [ 'label' => esc_html__( 'Wave Height (px)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 40, 'max' => 300, 'step' => 5 ] ], 'default' => [ 'size' => 100 ], 'condition' => [ 'aafe_bg_type' => 'waves' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-wave-height: {{SIZE}}px;', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_waves_animate', [ 'label' => esc_html__( 'Flowing Animation', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', 'condition' => [ 'aafe_bg_type' => 'waves' ], 'render_type' => 'template', ] ); // ─── Animated Gradient Settings ───────────────────────── $element->add_control( 'aafe_gradient_color1', [ 'label' => esc_html__( 'Gradient Color 1', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::COLOR, 'default' => '#667eea', 'condition' => [ 'aafe_bg_type' => 'gradient' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-gradient-color1: {{VALUE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_gradient_color2', [ 'label' => esc_html__( 'Gradient Color 2', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::COLOR, 'default' => '#764ba2', 'condition' => [ 'aafe_bg_type' => 'gradient' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-gradient-color2: {{VALUE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_gradient_color3', [ 'label' => esc_html__( 'Gradient Color 3', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::COLOR, 'default' => '#f093fb', 'condition' => [ 'aafe_bg_type' => 'gradient' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-gradient-color3: {{VALUE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_gradient_color4', [ 'label' => esc_html__( 'Gradient Color 4 (Optional)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::COLOR, 'default' => '', 'condition' => [ 'aafe_bg_type' => 'gradient' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-gradient-color4: {{VALUE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_gradient_angle', [ 'label' => esc_html__( 'Gradient Angle (deg)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 0, 'max' => 360, 'step' => 5 ] ], 'default' => [ 'size' => 135 ], 'condition' => [ 'aafe_bg_type' => 'gradient' ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_gradient_speed', [ 'label' => esc_html__( 'Animation Speed (s)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 2, 'max' => 30, 'step' => 1 ] ], 'default' => [ 'size' => 8 ], 'condition' => [ 'aafe_bg_type' => 'gradient' ], 'render_type' => 'template', ] ); // ─── Noise / Grain Settings ───────────────────────────── $element->add_control( 'aafe_noise_type', [ 'label' => esc_html__( 'Grain Tone', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SELECT, 'options' => [ 'dark' => esc_html__( 'Dark Grain (For Light BG)', 'addronix-addons-for-elementor' ), 'light' => esc_html__( 'Light Grain (For Dark BG)', 'addronix-addons-for-elementor' ), 'subtle' => esc_html__( 'Neutral Film Grain', 'addronix-addons-for-elementor' ), ], 'default' => 'dark', 'description' => esc_html__( 'Pure transparent grain overlay. Never changes or overrides your section background color.', 'addronix-addons-for-elementor' ), 'condition' => [ 'aafe_bg_type' => 'noise' ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_noise_opacity', [ 'label' => esc_html__( 'Grain Opacity', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 0.05, 'max' => 0.8, 'step' => 0.05 ] ], 'default' => [ 'size' => 0.15 ], 'condition' => [ 'aafe_bg_type' => 'noise' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-noise-opacity: {{SIZE}};', ], 'render_type' => 'template', ] ); $element->add_control( 'aafe_noise_size', [ 'label' => esc_html__( 'Grain Size (px)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 50, 'max' => 300, 'step' => 10 ] ], 'default' => [ 'size' => 120 ], 'condition' => [ 'aafe_bg_type' => 'noise' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-noise-size: {{SIZE}}px;', ], 'render_type' => 'template', ] ); $element->end_controls_section(); } /** * Register Floating Effects controls. * * @param Element_Base $element Element instance. * @param array $args Control args. */ public function register_floating_controls( Element_Base $element, $args ) { $element->start_controls_section( 'aafe_floating_section', [ 'label' => ' ' . esc_html__( 'AAFE Floating Effects', 'addronix-addons-for-elementor' ), 'tab' => Controls_Manager::TAB_ADVANCED, ] ); $element->add_control( 'aafe_float_enable', [ 'label' => esc_html__( 'Enable Floating', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => '', 'prefix_class' => 'aafe-floating-', 'render_type' => 'ui', ] ); $element->add_control( 'aafe_float_direction', [ 'label' => esc_html__( 'Direction', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SELECT, 'options' => [ 'up-down' => esc_html__( 'Up & Down', 'addronix-addons-for-elementor' ), 'left-right' => esc_html__( 'Left & Right', 'addronix-addons-for-elementor' ), 'rotate' => esc_html__( 'Rotate', 'addronix-addons-for-elementor' ), 'pulse' => esc_html__( 'Pulse / Scale', 'addronix-addons-for-elementor' ), 'shake' => esc_html__( 'Shake', 'addronix-addons-for-elementor' ), ], 'default' => 'up-down', 'condition' => [ 'aafe_float_enable' => 'yes' ], 'prefix_class' => 'aafe-float-dir-', 'render_type' => 'ui', ] ); $element->add_control( 'aafe_float_duration', [ 'label' => esc_html__( 'Duration (s)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 0.5, 'max' => 10, 'step' => 0.1 ] ], 'default' => [ 'size' => 3 ], 'condition' => [ 'aafe_float_enable' => 'yes' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-float-duration: {{SIZE}}s;', ], 'render_type' => 'ui', ] ); $element->add_control( 'aafe_float_delay', [ 'label' => esc_html__( 'Delay (s)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 0, 'max' => 5, 'step' => 0.1 ] ], 'default' => [ 'size' => 0 ], 'condition' => [ 'aafe_float_enable' => 'yes' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-float-delay: {{SIZE}}s;', ], 'render_type' => 'ui', ] ); $element->add_control( 'aafe_float_distance', [ 'label' => esc_html__( 'Distance (px)', 'addronix-addons-for-elementor' ), 'type' => Controls_Manager::SLIDER, 'range' => [ 'px' => [ 'min' => 2, 'max' => 80, 'step' => 1 ] ], 'default' => [ 'size' => 15 ], 'condition' => [ 'aafe_float_enable' => 'yes' ], 'selectors' => [ '{{WRAPPER}}' => '--aafe-float-distance: {{SIZE}}px;', ], 'render_type' => 'ui', ] ); $element->end_controls_section(); } /** * Inject background data attributes and inline styles before render. * * @param Element_Base $element Element instance. */ public function before_render( Element_Base $element ) { $settings = $element->get_settings_for_display(); $bg_type = $settings['aafe_bg_type'] ?? 'none'; $float = $settings['aafe_float_enable'] ?? ''; $has_bg = ! empty( $bg_type ) && 'none' !== $bg_type; $has_float = 'yes' === $float; if ( ! $has_bg && ! $has_float ) { return; } $this->do_enqueue(); if ( $has_bg ) { // Ensure __globals__ is preserved from raw settings and raw element data $globals = []; $raw_settings = $element->get_settings(); if ( ! empty( $raw_settings['__globals__'] ) && is_array( $raw_settings['__globals__'] ) ) { $globals = $raw_settings['__globals__']; } if ( empty( $globals ) ) { $raw_data = $element->get_data(); if ( ! empty( $raw_data['settings']['__globals__'] ) && is_array( $raw_data['settings']['__globals__'] ) ) { $globals = $raw_data['settings']['__globals__']; } } if ( empty( $globals ) && ! empty( $settings['__globals__'] ) && is_array( $settings['__globals__'] ) ) { $globals = $settings['__globals__']; } $settings['__globals__'] = $globals; $options = $this->get_bg_options( $settings, $bg_type ); $element->add_render_attribute( '_wrapper', [ 'data-aafe-bg' => $bg_type, 'data-aafe-bg-opts' => wp_json_encode( $options ), ] ); // CSS variables for gradient effect if ( 'gradient' === $bg_type ) { $speed = $options['speed'] ?? 8; $angle = $options['angle'] ?? 135; $gradient_vars = sprintf( '--aafe-gradient-speed: %ds; --aafe-gradient-angle: %ddeg;', $speed, $angle ); $element->add_render_attribute( '_wrapper', 'style', $gradient_vars ); } elseif ( 'noise' === $bg_type ) { // Pure grain overlay variables — never adds any background color! $opacity = $options['opacity'] ?? 0.15; $size = $options['size'] ?? 120; $noise_css = sprintf( '--aafe-noise-opacity: %s; --aafe-noise-size: %dpx;', $opacity, $size ); $element->add_render_attribute( '_wrapper', 'style', $noise_css ); } } } /** * Build options array for a given background type with resolved global colors. * * @param array $settings Element settings. * @param string $type Background type. * @return array */ private function get_bg_options( $settings, $type ) { switch ( $type ) { case 'particles': return [ 'count' => ! empty( $settings['aafe_particles_count']['size'] ) ? (int) $settings['aafe_particles_count']['size'] : 80, 'color' => $this->resolve_color( $settings, 'aafe_particles_color', '#ffffff' ), 'size' => ! empty( $settings['aafe_particles_size']['size'] ) ? (float) $settings['aafe_particles_size']['size'] : 3, 'speed' => isset( $settings['aafe_particles_speed']['size'] ) ? (float) $settings['aafe_particles_speed']['size'] : 3, 'lines' => ! empty( $settings['aafe_particles_lines'] ) && 'yes' === $settings['aafe_particles_lines'], ]; case 'waves': return [ 'color' => $this->resolve_color( $settings, 'aafe_waves_color', 'rgba(255, 255, 255, 0.25)' ), 'position' => ! empty( $settings['aafe_waves_position'] ) ? $settings['aafe_waves_position'] : 'bottom', 'height' => ! empty( $settings['aafe_waves_height']['size'] ) ? (int) $settings['aafe_waves_height']['size'] : 100, 'animate' => ! empty( $settings['aafe_waves_animate'] ) ? ( 'yes' === $settings['aafe_waves_animate'] ) : true, ]; case 'gradient': $c1 = $this->resolve_color( $settings, 'aafe_gradient_color1', '#667eea' ); $c2 = $this->resolve_color( $settings, 'aafe_gradient_color2', '#764ba2' ); $c3 = $this->resolve_color( $settings, 'aafe_gradient_color3', '#f093fb' ); $c4 = $this->resolve_color( $settings, 'aafe_gradient_color4', '' ); $colors = array_values( array_filter( [ $c1, $c2, $c3, $c4 ] ) ); if ( empty( $colors ) ) { $colors = [ '#667eea', '#764ba2', '#f093fb' ]; } return [ 'colors' => $colors, 'speed' => ! empty( $settings['aafe_gradient_speed']['size'] ) ? (int) $settings['aafe_gradient_speed']['size'] : 8, 'angle' => isset( $settings['aafe_gradient_angle']['size'] ) ? (int) $settings['aafe_gradient_angle']['size'] : 135, ]; case 'noise': return [ 'tone' => ! empty( $settings['aafe_noise_type'] ) ? $settings['aafe_noise_type'] : 'dark', 'opacity' => isset( $settings['aafe_noise_opacity']['size'] ) ? (float) $settings['aafe_noise_opacity']['size'] : 0.15, 'size' => ! empty( $settings['aafe_noise_size']['size'] ) ? (int) $settings['aafe_noise_size']['size'] : 120, ]; default: return []; } } }