start_controls_section('slides_section', ['label' => __('Slides', 'agy-slider')]); $r = new \Elementor\Repeater(); $r->start_controls_tabs('slide_tabs'); $r->start_controls_tab('background_tab', ['label' => __('Slide background', 'agy-slider')]); $r->add_control('background_color', ['label' => __('Background color', 'agy-slider'), 'type' => C::COLOR, 'default' => '#193742', 'selectors' => ['{{WRAPPER}} {{CURRENT_ITEM}}' => '--ags-background: {{VALUE}};']]); $r->add_control('image', ['label' => __('Image', 'agy-slider'), 'type' => C::MEDIA, 'media_types' => ['image']]); $r->add_control('mobile_image', ['label' => __('Separate mobile image (optional)', 'agy-slider'), 'type' => C::MEDIA, 'media_types' => ['image'], 'description' => __('Leave empty to use the main image. The browser selects the appropriate source.', 'agy-slider')]); $r->add_control('decorative', ['label' => __('Decorative background image', 'agy-slider'), 'type' => C::SWITCHER, 'default' => 'yes', 'description' => __('Leave enabled for images already described by the heading.', 'agy-slider')]); $r->add_control('image_alt', ['label' => __('Image alternative text', 'agy-slider'), 'type' => C::TEXT, 'condition' => ['decorative!' => 'yes'], 'description' => __('Leave empty to use the alternative text from the Media Library.', 'agy-slider')]); $r->add_control('fit', ['label' => __('Image fit', 'agy-slider'), 'type' => C::SELECT, 'default' => 'cover', 'options' => ['cover' => __('Cover', 'agy-slider'), 'contain' => __('Contain', 'agy-slider'), 'none' => __('Original', 'agy-slider')], 'selectors' => ['{{WRAPPER}} {{CURRENT_ITEM}}' => '--ags-fit: {{VALUE}};']]); $r->add_responsive_control('position', ['label' => __('Image focal point', 'agy-slider'), 'type' => C::SELECT, 'default' => 'center center', 'options' => ['left top'=>__('Top left', 'agy-slider'),'center top'=>__('Top center', 'agy-slider'),'right top'=>__('Top right', 'agy-slider'),'left center'=>__('Center left', 'agy-slider'),'center center'=>__('Center', 'agy-slider'),'right center'=>__('Center right', 'agy-slider'),'left bottom'=>__('Bottom left', 'agy-slider'),'center bottom'=>__('Bottom center', 'agy-slider'),'right bottom'=>__('Bottom right', 'agy-slider')], 'selectors' => ['{{WRAPPER}} {{CURRENT_ITEM}}' => '--ags-position: {{VALUE}};']]); $r->add_control('overlay_type', ['label' => __('Overlay type', 'agy-slider'), 'type' => C::SELECT, 'default' => 'color', 'options' => ['none'=>__('None', 'agy-slider'),'color'=>__('Solid color', 'agy-slider'),'gradient'=>__('Gradient', 'agy-slider')]]); // Keep this key, default and selector intact for saved 1.0.x widgets/CSS. $r->add_control('overlay_color', ['label' => __('Color overlay', 'agy-slider'), 'type' => C::COLOR, 'default' => '#00000055', 'alpha' => true, 'condition'=>['overlay_type'=>'color'], 'selectors' => ['{{WRAPPER}} {{CURRENT_ITEM}}' => '--ags-overlay: {{VALUE}};']]); $r->add_group_control(\Elementor\Group_Control_Background::get_type(), [ 'name'=>'overlay_gradient', 'types'=>['gradient'], 'condition'=>['overlay_type'=>'gradient'], 'selector'=>'{{WRAPPER}} {{CURRENT_ITEM}} .ags__overlay', 'fields_options'=>[ 'background'=>['type'=>C::HIDDEN, 'default'=>'gradient'], 'color'=>['default'=>'#000000aa'], 'color_b'=>['default'=>'#00000000'], ], ]); $r->add_control('ken_burns', ['label' => __('Slow zoom in / out', 'agy-slider'), 'type' => C::SELECT, 'default' => 'none', 'options' => ['none'=>__('Off', 'agy-slider'),'in'=>__('Zoom in', 'agy-slider'),'out'=>__('Zoom out', 'agy-slider')]]); $r->end_controls_tab(); $r->start_controls_tab('content_tab', ['label' => __('Content', 'agy-slider')]); $r->add_control('kicker', ['label'=>__('Kicker / Eyebrow', 'agy-slider'), 'type'=>C::TEXT, 'default'=>'', 'description'=>__('Appears above the heading. No output is generated when empty.', 'agy-slider')]); $r->add_control('title', ['label' => __('Heading', 'agy-slider'), 'type' => C::TEXTAREA, 'rows' => 2, 'default' => __('Slide heading', 'agy-slider'), 'description' => __('You can use <br> for a line break.', 'agy-slider')]); $r->add_control('description', ['label' => __('Description', 'agy-slider'), 'type' => C::TEXTAREA, 'rows' => 4]); $r->add_control('button_text', ['label' => __('Button text', 'agy-slider'), 'type' => C::TEXT, 'default' => __('Explore the details', 'agy-slider')]); $r->add_control('button_icon', ['label'=>__('Button icon', 'agy-slider'), 'type'=>C::ICONS, 'default'=>['value'=>'','library'=>''], 'condition'=>['button_text!'=>'']]); $r->add_control('icon_position', ['label'=>__('Icon position', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'right', 'options'=>['left'=>__('Left', 'agy-slider'),'right'=>__('Right', 'agy-slider')], 'condition'=>['button_text!'=>'','button_icon[value]!'=>'']]); foreach (['icon_gap'=>[__('Icon spacing', 'agy-slider'),10,60,'--ags-icon-gap'], 'icon_size'=>[__('Icon size', 'agy-slider'),18,64,'--ags-icon-size']] as $key=>$control) { $r->add_responsive_control($key, ['label'=>$control[0], 'type'=>C::SLIDER, 'size_units'=>['px'], 'range'=>['px'=>['min'=>$key==='icon_size'?8:0,'max'=>$control[2]]], 'default'=>['unit'=>'px','size'=>$control[1]], 'condition'=>['button_text!'=>'','button_icon[value]!'=>''], 'selectors'=>['{{WRAPPER}} {{CURRENT_ITEM}}'=>$control[3].': {{SIZE}}{{UNIT}};']]); } $r->add_control('link', ['label' => __('Link', 'agy-slider'), 'type' => C::URL, 'options' => ['url','is_external','nofollow'], 'placeholder' => 'https://']); $r->add_control('link_on', ['label' => __('Apply link to', 'agy-slider'), 'type' => C::SELECT, 'default' => 'button', 'options' => ['button'=>__('Button only', 'agy-slider'),'slide'=>__('Entire slide', 'agy-slider')]]); $r->end_controls_tab(); $r->start_controls_tab('style_tab', ['label' => __('Slide-specific style', 'agy-slider')]); $r->add_control('custom_style', ['label' => __('Use custom style', 'agy-slider'), 'type' => C::SWITCHER, 'description' => __('When disabled, the widget\'s global style settings are used.', 'agy-slider')]); foreach (['horizontal' => [__('Horizontal position', 'agy-slider'),['flex-start'=>__('Left', 'agy-slider'),'center'=>__('Center', 'agy-slider'),'flex-end'=>__('Right', 'agy-slider')],'--ags-horizontal'], 'vertical' => [__('Vertical position', 'agy-slider'),['flex-start'=>__('Top', 'agy-slider'),'center'=>__('Center', 'agy-slider'),'flex-end'=>__('Bottom', 'agy-slider')],'--ags-vertical'], 'align' => [__('Text alignment', 'agy-slider'),['left'=>__('Left', 'agy-slider'),'center'=>__('Center', 'agy-slider'),'right'=>__('Right', 'agy-slider')],'--ags-align']] as $key => $control) { $r->add_responsive_control('custom_' . $key, ['label' => $control[0], 'type' => C::SELECT, 'options' => $control[1], 'condition' => ['custom_style'=>'yes'], 'selectors' => ['{{WRAPPER}} {{CURRENT_ITEM}}' => $control[2] . ': {{VALUE}};']]); } foreach (['title_color'=>[__('Heading color', 'agy-slider'),'--ags-title-color'],'description_color'=>[__('Description color', 'agy-slider'),'--ags-description-color'],'button_color'=>[__('Button text color', 'agy-slider'),'--ags-button-color'],'button_background'=>[__('Button background', 'agy-slider'),'--ags-button-bg']] as $key=>$control) { $r->add_control('custom_' . $key, ['label'=>$control[0], 'type'=>C::COLOR, 'condition'=>['custom_style'=>'yes'], 'selectors'=>['{{WRAPPER}} {{CURRENT_ITEM}}'=>$control[1].': {{VALUE}};']]); } $r->end_controls_tab(); $r->end_controls_tabs(); $this->add_control('slides', ['type'=>C::REPEATER, 'fields'=>$r->get_controls(), 'title_field'=>'{{{ title }}}', 'default'=>[ ['title'=>__('Less weight.
More freedom.', 'agy-slider'), 'description'=>__('Add your image, write your message, and create your own design.', 'agy-slider'), 'button_text'=>'', 'background_color'=>'#193742'], ['title'=>__('Your design. Your control.', 'agy-slider'), 'description'=>__('Adjust images, text, and layout separately for each screen size.', 'agy-slider'), 'button_text'=>'', 'background_color'=>'#123B63'], ]]); $this->end_controls_section(); $this->start_controls_section('behavior_section', ['label'=>__('Slider settings', 'agy-slider')]); $this->add_control('accessible_label', ['label'=>__('Slider name', 'agy-slider'), 'type'=>C::TEXT, 'default'=>__('Featured content', 'agy-slider'), 'description'=>__('A short, distinct name for screen readers.', 'agy-slider')]); $this->add_responsive_control('height', ['label'=>__('Minimum height', 'agy-slider'), 'type'=>C::SLIDER, 'size_units'=>['px','vh'], 'range'=>['px'=>['min'=>180,'max'=>1200], 'vh'=>['min'=>20,'max'=>100]], 'default'=>['unit'=>'px','size'=>520], 'tablet_default'=>['unit'=>'px','size'=>460], 'mobile_default'=>['unit'=>'px','size'=>420], 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-height: {{SIZE}}{{UNIT}};'], 'description'=>__('Long content is not clipped; the height grows when needed.', 'agy-slider')]); $this->add_control('navigation', ['label'=>__('Navigation', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'both', 'options'=>['both'=>__('Arrows and dots', 'agy-slider'),'arrows'=>__('Arrows only', 'agy-slider'),'dots'=>__('Dots only', 'agy-slider'),'none'=>__('Hidden', 'agy-slider')]]); $this->add_control('effect', ['label'=>__('Transition', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'fade', 'options'=>['fade'=>__('Fade', 'agy-slider'),'slide'=>__('Horizontal slide', 'agy-slider'),'scale'=>__('Scale — subtle zoom', 'agy-slider')]]); $this->add_control('duration', ['label'=>__('Transition duration (ms)', 'agy-slider'), 'type'=>C::NUMBER, 'default'=>450, 'min'=>0, 'max'=>1600, 'step'=>50]); $this->add_control('content_animation', ['label'=>__('Content entrance animation', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'none', 'options'=>['none'=>__('None', 'agy-slider'),'fade'=>__('Fade', 'agy-slider'),'up'=>__('From bottom', 'agy-slider'),'down'=>__('From top', 'agy-slider'),'left'=>__('From right', 'agy-slider'),'right'=>__('From left', 'agy-slider')]]); $this->add_control('loop', ['label'=>__('Loop back to the first slide', 'agy-slider'), 'type'=>C::SWITCHER, 'default'=>'yes']); $this->add_control('swipe', ['label'=>__('Swipe navigation', 'agy-slider'), 'type'=>C::SWITCHER, 'default'=>'yes']); $this->add_control('autoplay', ['label'=>__('Autoplay', 'agy-slider'), 'type'=>C::SWITCHER, 'default'=>'', 'description'=>__('Adds a visible pause/play button. Stops on keyboard focus and does not start with reduced motion enabled. Always disabled in the editor.', 'agy-slider')]); $this->add_control('interval', ['label'=>__('Slide interval (ms)', 'agy-slider'), 'type'=>C::NUMBER, 'default'=>6000, 'min'=>3000, 'max'=>30000, 'step'=>500, 'condition'=>['autoplay'=>'yes']]); $this->add_control('heading_tag', ['label'=>__('Heading HTML tag', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'h2', 'options'=>['h2'=>__('H2', 'agy-slider'),'h3'=>__('H3', 'agy-slider'),'h4'=>__('H4', 'agy-slider'),'div'=>__('DIV', 'agy-slider')]]); $this->add_control('first_h1', ['label'=>__('Use H1 for the first slide only', 'agy-slider'), 'type'=>C::SWITCHER, 'description'=>__('Enable only if this slider contains the page\'s main heading. Other slides keep the tag selected above.', 'agy-slider')]); $this->add_control('image_size', ['label'=>__('Image source size', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'large', 'options'=>['medium_large'=>__('Medium large', 'agy-slider'),'large'=>__('Large (recommended)', 'agy-slider'),'full'=>__('Full size', 'agy-slider')], 'description'=>__('Uses existing WordPress srcset sources; no new image sizes are generated.', 'agy-slider')]); $this->add_control('hero_priority', ['label'=>__('Above-the-fold / hero image', 'agy-slider'), 'type'=>C::SWITCHER, 'default'=>'yes', 'description'=>__('Prioritizes the first image. Disable for sliders below the fold; other images load when needed.', 'agy-slider')]); $this->end_controls_section(); $this->start_controls_section('layout_style', ['label'=>__('Content layout', 'agy-slider'), 'tab'=>C::TAB_STYLE]); $this->add_responsive_control('inner_width', ['label'=>__('Inner width', 'agy-slider'), 'type'=>C::SLIDER, 'size_units'=>['px','%'], 'range'=>['px'=>['min'=>300,'max'=>1800],'%'=>['min'=>30,'max'=>100]], 'default'=>['unit'=>'px','size'=>1200], 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-inner-width: {{SIZE}}{{UNIT}};']]); $this->add_responsive_control('content_width', ['label'=>__('Text area width', 'agy-slider'), 'type'=>C::SLIDER, 'size_units'=>['px','%'], 'range'=>['px'=>['min'=>150,'max'=>1600],'%'=>['min'=>20,'max'=>100]], 'default'=>['unit'=>'px','size'=>640], 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-content-width: {{SIZE}}{{UNIT}};']]); foreach (['horizontal'=>[__('Horizontal position', 'agy-slider'),['flex-start'=>__('Left', 'agy-slider'),'center'=>__('Center', 'agy-slider'),'flex-end'=>__('Right', 'agy-slider')],'--ags-horizontal','flex-start'],'vertical'=>[__('Vertical position', 'agy-slider'),['flex-start'=>__('Top', 'agy-slider'),'center'=>__('Center', 'agy-slider'),'flex-end'=>__('Bottom', 'agy-slider')],'--ags-vertical','center'],'align'=>[__('Text alignment', 'agy-slider'),['left'=>__('Left', 'agy-slider'),'center'=>__('Center', 'agy-slider'),'right'=>__('Right', 'agy-slider')],'--ags-align','left']] as $key=>$control) { $this->add_responsive_control($key, ['label'=>$control[0], 'type'=>C::SELECT, 'options'=>$control[1], 'default'=>$control[3], 'selectors'=>['{{WRAPPER}} .ags'=>$control[2].': {{VALUE}};']]); } $this->add_responsive_control('padding', ['label'=>__('Padding', 'agy-slider'), 'type'=>C::DIMENSIONS, 'size_units'=>['px','%'], 'default'=>['unit'=>'px','top'=>72,'right'=>72,'bottom'=>80,'left'=>72,'isLinked'=>false], 'mobile_default'=>['unit'=>'px','top'=>60,'right'=>56,'bottom'=>72,'left'=>56,'isLinked'=>false], 'selectors'=>['{{WRAPPER}} .ags__inner'=>'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};']]); $this->end_controls_section(); foreach (['kicker'=>[__('Kicker / Eyebrow', 'agy-slider'),'.ags__kicker','--ags-kicker-color'], 'title'=>[__('Heading', 'agy-slider'),'.ags__title','--ags-title-color'], 'description'=>[__('Description', 'agy-slider'),'.ags__description','--ags-description-color']] as $key=>$control) { $this->start_controls_section($key.'_style', ['label'=>$control[0], 'tab'=>C::TAB_STYLE]); $this->add_control($key.'_color', ['label'=>__('Color', 'agy-slider'), 'type'=>C::COLOR, 'default'=>'#ffffff', 'selectors'=>['{{WRAPPER}} .ags'=>$control[2].': {{VALUE}};']]); $this->add_group_control(Typography::get_type(), ['name'=>$key.'_typography', 'selector'=>'{{WRAPPER}} '.$control[1]]); $this->add_responsive_control($key.'_space', ['label'=>__('Bottom spacing', 'agy-slider'), 'type'=>C::SLIDER, 'range'=>['px'=>['min'=>0,'max'=>100]], 'default'=>['unit'=>'px','size'=>$key==='kicker'?12:20], 'selectors'=>['{{WRAPPER}} '.$control[1]=>'margin-bottom: {{SIZE}}{{UNIT}};']]); if ($key==='title') { $this->add_group_control(\Elementor\Group_Control_Text_Shadow::get_type(), ['name'=>'title_shadow', 'selector'=>'{{WRAPPER}} .ags__title']); } $this->end_controls_section(); } $this->start_controls_section('button_style', ['label'=>__('Button', 'agy-slider'), 'tab'=>C::TAB_STYLE]); $this->add_group_control(Typography::get_type(), ['name'=>'button_typography', 'selector'=>'{{WRAPPER}} .ags__button']); foreach (['button_color'=>[__('Text color', 'agy-slider'),'--ags-button-color','#193742'],'button_bg'=>[__('Background', 'agy-slider'),'--ags-button-bg','#ffffff'],'button_hover_color'=>[__('Hover text color', 'agy-slider'),'--ags-button-hover-color','#ffffff'],'button_hover_bg'=>[__('Hover background', 'agy-slider'),'--ags-button-hover-bg','#075475'],'button_border'=>[__('Border color', 'agy-slider'),'--ags-button-border','#ffffff']] as $key=>$control) { $this->add_control($key, ['label'=>$control[0], 'type'=>C::COLOR, 'default'=>$control[2], 'selectors'=>['{{WRAPPER}} .ags'=>$control[1].': {{VALUE}};']]); } // Reuse the existing border color control; add only type/width from the native group. // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude -- Elementor control-field exclusion, not a WP_Query/get_posts argument. $this->add_group_control(\Elementor\Group_Control_Border::get_type(), ['name'=>'button_outline', 'exclude'=>['color'], 'selector'=>'{{WRAPPER}} .ags__button']); $this->add_control('button_hover_border', ['label'=>__('Hover border color', 'agy-slider'), 'type'=>C::COLOR, 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-button-hover-border: {{VALUE}};']]); $this->add_control('button_transition', ['label'=>__('Button transition duration (ms)', 'agy-slider'), 'type'=>C::NUMBER, 'default'=>200, 'min'=>0, 'max'=>1600, 'step'=>50, 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-button-transition: {{VALUE}}ms;']]); $this->add_responsive_control('button_radius', ['label'=>__('Border radius', 'agy-slider'), 'type'=>C::SLIDER, 'range'=>['px'=>['min'=>0,'max'=>60]], 'default'=>['unit'=>'px','size'=>4], 'selectors'=>['{{WRAPPER}} .ags__button'=>'border-radius: {{SIZE}}{{UNIT}};']]); $this->add_responsive_control('button_padding', ['label'=>__('Padding', 'agy-slider'), 'type'=>C::DIMENSIONS, 'size_units'=>['px'], 'selectors'=>['{{WRAPPER}} .ags__button'=>'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};']]); $this->end_controls_section(); $this->start_controls_section('navigation_style', ['label'=>__('Navigation', 'agy-slider'), 'tab'=>C::TAB_STYLE]); foreach (['control_color'=>[__('Arrow / control color', 'agy-slider'),'--ags-control-color','#ffffff'],'control_bg'=>[__('Control background', 'agy-slider'),'--ags-control-bg','#193742'],'dot_color'=>[__('Dot color', 'agy-slider'),'--ags-dot-color','#ffffff80'],'dot_active'=>[__('Active dot', 'agy-slider'),'--ags-dot-active','#ffffff']] as $key=>$control) { $this->add_control($key, ['label'=>$control[0], 'type'=>C::COLOR, 'default'=>$control[2], 'selectors'=>['{{WRAPPER}} .ags'=>$control[1].': {{VALUE}};']]); } $this->add_responsive_control('arrow_size', ['label'=>__('Arrow icon size', 'agy-slider'), 'type'=>C::SLIDER, 'range'=>['px'=>['min'=>16,'max'=>36]], 'default'=>['unit'=>'px','size'=>24], 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-arrow-size: {{SIZE}}{{UNIT}};']]); $this->add_responsive_control('arrow_offset', ['label'=>__('Arrow distance from edge', 'agy-slider'), 'type'=>C::SLIDER, 'range'=>['px'=>['min'=>0,'max'=>120]], 'default'=>['unit'=>'px','size'=>14], 'mobile_default'=>['unit'=>'px','size'=>4], 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-arrow-offset: {{SIZE}}{{UNIT}};']]); $this->add_control('dots_position', ['label'=>__('Dot position', 'agy-slider'), 'type'=>C::SELECT, 'default'=>'inside', 'options'=>['inside'=>__('Inside', 'agy-slider'),'outside'=>__('Below', 'agy-slider')], 'prefix_class'=>'ags-dots-']); $this->add_responsive_control('dot_size', ['label'=>__('Dot diameter', 'agy-slider'), 'type'=>C::SLIDER, 'range'=>['px'=>['min'=>6,'max'=>18]], 'default'=>['unit'=>'px','size'=>8], 'selectors'=>['{{WRAPPER}} .ags'=>'--ags-dot-size: {{SIZE}}{{UNIT}};']]); $this->end_controls_section(); } protected function render() { $editor = \Elementor\Plugin::instance()->editor->is_edit_mode(); // render.php context-escapes text, attributes and URLs, restricts rich text // with wp_kses(), and delegates icons to Elementor's native SVG renderer. // A second generic HTML filter would strip SVG/picture/inert markup. // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Audited HTML renderer; regression coverage in tests/render-security.php. echo render($this->get_settings_for_display(), $editor); } }