register_general_controls(); $this->register_overlay_controls(); $this->register_animation_controls(); $this->register_baseline_controls(); $this->register_style_container_controls(); $this->register_style_overlay_controls(); $this->register_pro_notice_controls(); } public function render(): void { $settings = $this->get_settings_for_display(); $this->render_output($settings); } protected function register_general_controls(): void { $this->start_controls_section( 'kng_mesh_general_section', [ 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('General', 'king-addons'), 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_control( 'kng_mesh_preset', [ 'label' => esc_html__('Preset', 'king-addons'), 'type' => Controls_Manager::SELECT, 'default' => 'aurora', 'options' => $this->get_preset_options(), ] ); $this->add_control( 'kng_mesh_base_color', [ 'label' => esc_html__('Base Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'description' => esc_html__('Overrides the preset base color.', 'king-addons'), ] ); $this->add_control( 'kng_mesh_engine', [ 'label' => esc_html__('Engine', 'king-addons'), 'type' => Controls_Manager::SELECT, 'default' => 'auto', 'options' => [ 'auto' => esc_html__('Auto', 'king-addons'), 'css' => esc_html__('CSS Gradients', 'king-addons'), 'canvas' => esc_html__('Canvas 2D', 'king-addons'), ], ] ); $this->add_responsive_control( 'kng_mesh_height', [ 'label' => esc_html__('Height', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px', 'vh'], 'range' => [ 'px' => ['min' => 120, 'max' => 1200], 'vh' => ['min' => 20, 'max' => 100], ], 'default' => [ 'size' => 420, 'unit' => 'px', ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => 'height: {{SIZE}}{{UNIT}};', ], ] ); $this->add_responsive_control( 'kng_mesh_radius', [ 'label' => esc_html__('Border Radius', 'king-addons'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', '%'], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], ] ); $this->add_control( 'kng_mesh_alignment', [ 'label' => esc_html__('Overlay Alignment', 'king-addons'), 'type' => Controls_Manager::CHOOSE, 'options' => [ 'left' => [ 'title' => esc_html__('Left', 'king-addons'), 'icon' => 'eicon-text-align-left', ], 'center' => [ 'title' => esc_html__('Center', 'king-addons'), 'icon' => 'eicon-text-align-center', ], 'right' => [ 'title' => esc_html__('Right', 'king-addons'), 'icon' => 'eicon-text-align-right', ], ], 'default' => 'center', 'toggle' => false, 'prefix_class' => 'king-addons-gradient-mesh--align-', ] ); $this->add_control( 'kng_mesh_vertical_align', [ 'label' => esc_html__('Overlay Vertical Align', 'king-addons'), 'type' => Controls_Manager::CHOOSE, 'options' => [ 'top' => [ 'title' => esc_html__('Top', 'king-addons'), 'icon' => 'eicon-v-align-top', ], 'center' => [ 'title' => esc_html__('Center', 'king-addons'), 'icon' => 'eicon-v-align-middle', ], 'bottom' => [ 'title' => esc_html__('Bottom', 'king-addons'), 'icon' => 'eicon-v-align-bottom', ], ], 'default' => 'center', 'toggle' => false, 'prefix_class' => 'king-addons-gradient-mesh--valign-', ] ); $this->add_responsive_control( 'kng_mesh_padding', [ 'label' => esc_html__('Padding', 'king-addons'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', 'em', '%'], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__overlay' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], ] ); $this->end_controls_section(); } protected function register_overlay_controls(): void { $this->start_controls_section( 'kng_mesh_overlay_section', [ 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Overlay Content', 'king-addons'), 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_control( 'kng_mesh_show_overlay', [ 'label' => esc_html__('Show Overlay', 'king-addons'), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', ] ); if ($this->is_pro()) { $this->add_control( 'kng_mesh_overlay_source', [ 'label' => esc_html__('Overlay Source', 'king-addons'), 'type' => Controls_Manager::SELECT, 'default' => 'basic', 'options' => [ 'basic' => esc_html__('Basic Content', 'king-addons'), 'template' => esc_html__('Elementor Template', 'king-addons'), ], 'condition' => [ 'kng_mesh_show_overlay' => 'yes', ], ] ); } else { $this->add_control( 'kng_mesh_overlay_source', [ 'type' => Controls_Manager::HIDDEN, 'default' => 'basic', ] ); } if ($this->is_pro()) { $this->add_control( 'kng_mesh_overlay_template', [ 'label' => esc_html__('Choose Template', 'king-addons'), 'type' => Controls_Manager::SELECT2, 'options' => $this->get_elementor_templates_options(), 'label_block' => true, 'condition' => [ 'kng_mesh_show_overlay' => 'yes', 'kng_mesh_overlay_source' => 'template', ], ] ); } $this->add_control( 'kng_mesh_title', [ 'label' => esc_html__('Title', 'king-addons'), 'type' => Controls_Manager::TEXT, 'default' => esc_html__('Interactive Gradient Mesh', 'king-addons'), 'label_block' => true, 'condition' => [ 'kng_mesh_show_overlay' => 'yes', 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_control( 'kng_mesh_subtitle', [ 'label' => esc_html__('Subtitle', 'king-addons'), 'type' => Controls_Manager::TEXT, 'default' => esc_html__('Soft motion, premium atmosphere.', 'king-addons'), 'label_block' => true, 'condition' => [ 'kng_mesh_show_overlay' => 'yes', 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_control( 'kng_mesh_text', [ 'label' => esc_html__('Text', 'king-addons'), 'type' => Controls_Manager::TEXTAREA, 'rows' => 3, 'default' => esc_html__('Use gradient meshes to add depth to heroes, highlights, and feature blocks.', 'king-addons'), 'condition' => [ 'kng_mesh_show_overlay' => 'yes', 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_control( 'kng_mesh_button_text', [ 'label' => esc_html__('Button Text', 'king-addons'), 'type' => Controls_Manager::TEXT, 'default' => esc_html__('Learn More', 'king-addons'), 'condition' => [ 'kng_mesh_show_overlay' => 'yes', 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_control( 'kng_mesh_button_url', [ 'label' => esc_html__('Button Link', 'king-addons'), 'type' => Controls_Manager::URL, 'placeholder' => esc_html__('https://', 'king-addons'), 'condition' => [ 'kng_mesh_show_overlay' => 'yes', 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->end_controls_section(); } protected function register_animation_controls(): void { $this->start_controls_section( 'kng_mesh_animation_section', [ 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Animation', 'king-addons'), 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_control( 'kng_mesh_enable_animation', [ 'label' => esc_html__('Enable Animation', 'king-addons'), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => 'yes', ] ); $this->add_responsive_control( 'kng_mesh_speed', [ 'label' => esc_html__('Speed', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['custom'], 'range' => [ 'custom' => [ 'min' => 0, 'max' => 100, 'step' => 1, ], ], 'default' => [ 'size' => 80, 'unit' => 'custom', ], 'condition' => [ 'kng_mesh_enable_animation' => 'yes', ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => '--kng-mesh-speed: {{SIZE}};', ], ] ); $this->add_control( 'kng_mesh_motion', [ 'label' => esc_html__('Motion Style', 'king-addons'), 'type' => Controls_Manager::SELECT, 'default' => 'drift', 'options' => [ 'drift' => esc_html__('Smooth Drift', 'king-addons'), 'pulse' => esc_html__('Slow Pulse', 'king-addons'), 'wave' => esc_html__('Calm Wave', 'king-addons'), ], 'condition' => [ 'kng_mesh_enable_animation' => 'yes', ], ] ); $this->end_controls_section(); } protected function register_baseline_controls(): void { $this->start_controls_section( 'kng_mesh_baseline_section', [ 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Baseline', 'king-addons'), 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_responsive_control( 'kng_mesh_saturation', [ 'label' => esc_html__('Saturation', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['%'], 'range' => [ '%' => ['min' => 50, 'max' => 160], ], 'default' => [ 'size' => 110, 'unit' => '%', ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => '--kng-mesh-saturate: {{SIZE}}{{UNIT}};', ], ] ); $this->add_responsive_control( 'kng_mesh_contrast', [ 'label' => esc_html__('Contrast', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['%'], 'range' => [ '%' => ['min' => 70, 'max' => 160], ], 'default' => [ 'size' => 105, 'unit' => '%', ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => '--kng-mesh-contrast: {{SIZE}}{{UNIT}};', ], ] ); $this->add_responsive_control( 'kng_mesh_blur', [ 'label' => esc_html__('Blur', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px'], 'range' => [ 'px' => ['min' => 0, 'max' => 60], ], 'default' => [ 'size' => 0, 'unit' => 'px', ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => '--kng-mesh-blur: {{SIZE}}{{UNIT}};', ], ] ); $this->add_control( 'kng_mesh_noise', [ 'label' => esc_html__('Noise Layer', 'king-addons'), 'type' => Controls_Manager::SWITCHER, 'return_value' => 'yes', 'default' => '', ] ); $this->add_control( 'kng_mesh_noise_opacity', [ 'label' => esc_html__('Noise Opacity', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['custom'], 'range' => [ 'custom' => ['min' => 0, 'max' => 0.4, 'step' => 0.02], ], 'default' => [ 'size' => 0.12, 'unit' => 'custom', ], 'condition' => [ 'kng_mesh_noise' => 'yes', ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh' => '--kng-mesh-noise-opacity: {{SIZE}};', ], ] ); $this->end_controls_section(); } protected function register_style_overlay_controls(): void { $this->start_controls_section( 'kng_mesh_style_overlay', [ 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Overlay Style', 'king-addons'), 'tab' => Controls_Manager::TAB_STYLE, 'condition' => [ 'kng_mesh_show_overlay' => 'yes', ], ] ); $this->add_control( 'kng_mesh_content_box_heading', [ 'label' => esc_html__('Content Box', 'king-addons'), 'type' => Controls_Manager::HEADING, 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_group_control( Group_Control_Background::get_type(), [ 'name' => 'kng_mesh_content_background', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__content', 'types' => ['classic', 'gradient'], 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_group_control( Group_Control_Border::get_type(), [ 'name' => 'kng_mesh_content_border', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__content', 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_group_control( Group_Control_Box_Shadow::get_type(), [ 'name' => 'kng_mesh_content_shadow', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__content', 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_responsive_control( 'kng_mesh_content_radius', [ 'label' => esc_html__('Content Radius', 'king-addons'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', '%'], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__content' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_responsive_control( 'kng_mesh_content_padding', [ 'label' => esc_html__('Content Padding', 'king-addons'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', 'em'], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_responsive_control( 'kng_mesh_content_width', [ 'label' => esc_html__('Content Width', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px', '%'], 'range' => [ 'px' => ['min' => 240, 'max' => 960], '%' => ['min' => 50, 'max' => 100], ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__content' => 'max-width: {{SIZE}}{{UNIT}};', ], 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_responsive_control( 'kng_mesh_content_gap', [ 'label' => esc_html__('Content Gap', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px'], 'range' => [ 'px' => ['min' => 0, 'max' => 40], ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__content' => 'gap: {{SIZE}}{{UNIT}};', ], 'condition' => [ 'kng_mesh_overlay_source' => 'basic', ], ] ); $this->add_group_control( Group_Control_Typography::get_type(), [ 'name' => 'kng_mesh_title_typography', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__title', ] ); $this->add_control( 'kng_mesh_title_color', [ 'label' => esc_html__('Title Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__title' => 'color: {{VALUE}};', ], ] ); $this->add_group_control( Group_Control_Typography::get_type(), [ 'name' => 'kng_mesh_subtitle_typography', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__subtitle', ] ); $this->add_control( 'kng_mesh_subtitle_color', [ 'label' => esc_html__('Subtitle Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__subtitle' => 'color: {{VALUE}};', ], ] ); $this->add_group_control( Group_Control_Typography::get_type(), [ 'name' => 'kng_mesh_text_typography', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__text', ] ); $this->add_control( 'kng_mesh_text_color', [ 'label' => esc_html__('Text Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__text' => 'color: {{VALUE}};', ], ] ); $this->add_control( 'kng_mesh_button_heading', [ 'label' => esc_html__('Button', 'king-addons'), 'type' => Controls_Manager::HEADING, 'separator' => 'before', ] ); $this->add_responsive_control( 'kng_mesh_button_padding', [ 'label' => esc_html__('Button Padding', 'king-addons'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', 'em'], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], ] ); $this->add_group_control( Group_Control_Typography::get_type(), [ 'name' => 'kng_mesh_button_typography', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__button', ] ); $this->add_control( 'kng_mesh_button_color', [ 'label' => esc_html__('Button Text Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button' => 'color: {{VALUE}};', ], ] ); $this->add_control( 'kng_mesh_button_background', [ 'label' => esc_html__('Button Background', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button' => 'background-color: {{VALUE}};', ], ] ); $this->add_group_control( Group_Control_Border::get_type(), [ 'name' => 'kng_mesh_button_border', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__button', ] ); $this->add_control( 'kng_mesh_button_hover_heading', [ 'label' => esc_html__('Button Hover', 'king-addons'), 'type' => Controls_Manager::HEADING, 'separator' => 'before', ] ); $this->add_control( 'kng_mesh_button_hover_color', [ 'label' => esc_html__('Hover Text Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button:hover' => 'color: {{VALUE}};', ], ] ); $this->add_control( 'kng_mesh_button_hover_background', [ 'label' => esc_html__('Hover Background', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button:hover' => 'background-color: {{VALUE}};', ], ] ); $this->add_control( 'kng_mesh_button_hover_border_color', [ 'label' => esc_html__('Hover Border Color', 'king-addons'), 'type' => Controls_Manager::COLOR, 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button:hover' => 'border-color: {{VALUE}};', ], ] ); $this->add_responsive_control( 'kng_mesh_button_radius', [ 'label' => esc_html__('Button Border Radius', 'king-addons'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px', '%'], 'range' => [ 'px' => ['min' => 0, 'max' => 50], '%' => ['min' => 0, 'max' => 100], ], 'selectors' => [ '{{WRAPPER}} .king-addons-gradient-mesh__button' => 'border-radius: {{SIZE}}{{UNIT}};', ], ] ); $this->add_group_control( Group_Control_Box_Shadow::get_type(), [ 'name' => 'kng_mesh_button_shadow', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh__button', ] ); $this->end_controls_section(); } protected function register_style_container_controls(): void { $this->start_controls_section( 'kng_mesh_style_container', [ 'label' => KING_ADDONS_ELEMENTOR_ICON . esc_html__('Container', 'king-addons'), 'tab' => Controls_Manager::TAB_STYLE, ] ); $this->add_group_control( Group_Control_Border::get_type(), [ 'name' => 'kng_mesh_container_border', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh', ] ); $this->add_group_control( Group_Control_Box_Shadow::get_type(), [ 'name' => 'kng_mesh_container_shadow', 'selector' => '{{WRAPPER}} .king-addons-gradient-mesh', ] ); $this->end_controls_section(); } protected function register_pro_notice_controls(): void { if (!king_addons_freemius()->can_use_premium_code__premium_only()) { Core::renderProFeaturesSection($this, '', Controls_Manager::RAW_HTML, 'interactive-gradient-mesh', [ 'Per-point controls (positions, colors, blend modes, motion)', 'Scroll-driven animation with easing', 'Export CSS (static or keyframes) with copy button', 'Fallback image options for legacy browsers', 'Performance modes and adaptive limits', ]); } } protected function render_output(array $settings): void { $preset = $this->get_preset($settings); $points = $this->get_points($settings, $preset); if (empty($points)) { return; } $mesh_payload = $this->build_mesh_payload($settings, $preset, $points); $mesh_data = esc_attr(wp_json_encode($mesh_payload)); $background_css = $this->build_gradient_css($points); $blend_modes = $this->build_blend_modes($points); $base_color = $this->get_base_color($settings, $preset); $wrapper_classes = [ 'king-addons-gradient-mesh', ($settings['kng_mesh_enable_animation'] ?? 'yes') === 'yes' ? 'is-animated' : 'is-static', ($settings['kng_mesh_noise'] ?? '') === 'yes' ? 'has-noise' : '', ]; $style_vars = $this->build_point_variables($points); $motion = $settings['kng_mesh_motion'] ?? 'drift'; $engine = $settings['kng_mesh_engine'] ?? 'auto'; $animate = ($settings['kng_mesh_enable_animation'] ?? 'yes') === 'yes' ? 'yes' : 'no'; $wrapper_attr = sprintf( 'class="%1$s" data-mesh="%2$s" data-motion="%3$s" data-engine="%4$s" data-animate="%5$s" style="%6$s"', esc_attr(trim(implode(' ', array_filter($wrapper_classes)))), $mesh_data, esc_attr($motion), esc_attr($engine), esc_attr($animate), esc_attr($style_vars) ); $bg_attr = sprintf( 'style="background-color:%1$s;background-image:%2$s;background-blend-mode:%3$s;"', esc_attr($base_color), esc_attr($background_css), esc_attr($blend_modes) ); $overlay_html = $this->get_overlay_content($settings); ?>