start_controls_section( 'content_type_section', [ 'label' => __('Images', 'marqueex'), 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_control( 'content_type', [ 'label' => __('Content Type', 'marqueex'), 'type' => Controls_Manager::SELECT, 'default' => 'custom', 'options' => [ 'posts' => __('Dynamic Posts', 'marqueex'), 'custom' => __('Custom Images', 'marqueex'), ], 'condition' => [ 'content_type' => 'never_display', ], ] ); $this->add_control( 'image_content_custom', [ 'label' => __('Image Content', 'marqueex'), 'type' => Controls_Manager::REPEATER, 'condition' => [ 'content_type' => 'custom', ], 'fields' => [ [ 'name' => 'image', 'label' => __('Image', 'marqueex'), 'type' => Controls_Manager::MEDIA, 'default' => [ 'url' => Utils::get_placeholder_image_src(), ], 'description' => __('Choose an image for the marquee.', 'marqueex'), ], [ 'name' => 'alt_text', 'label' => __('Alt Text', 'marqueex'), 'type' => Controls_Manager::TEXT, 'default' => __('Image', 'marqueex'), 'description' => __('Enter alt text for accessibility.', 'marqueex'), ], [ 'name' => 'link', 'label' => __('Link', 'marqueex'), 'type' => Controls_Manager::URL, 'default' => [ 'url' => '', 'is_external' => '', 'nofollow' => '', ], 'description' => __('Enter the link for the image.', 'marqueex'), ], ], 'condition' => [ 'content_type' => 'custom', ], 'title_field' => '{{{ alt_text }}}', 'default' => [ [ 'image' => [ 'url' => Utils::get_placeholder_image_src(), ], 'alt_text' => __('Sample Image 1', 'marqueex'), 'link' => [ 'url' => '', 'is_external' => '', 'nofollow' => '', ], ], [ 'image' => [ 'url' => Utils::get_placeholder_image_src(), ], 'alt_text' => __('Sample Image 2', 'marqueex'), 'link' => [ 'url' => '', 'is_external' => '', 'nofollow' => '', ], ], [ 'image' => [ 'url' => Utils::get_placeholder_image_src(), ], 'alt_text' => __('Sample Image 3', 'marqueex'), 'link' => [ 'url' => '', 'is_external' => '', 'nofollow' => '', ], ], ], ] ); $this->add_responsive_control( 'item_spacing', [ 'label' => __('Item Spacing', 'marqueex'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px', 'em', 'rem'], 'range' => [ 'px' => [ 'min' => 0, 'max' => 100, 'step' => 1, ], 'em' => [ 'min' => 0, 'max' => 10, 'step' => 0.1, ], 'rem' => [ 'min' => 0, 'max' => 10, 'step' => 0.1, ], ], 'default' => [ 'unit' => 'rem', 'size' => 2, ], 'selectors' => [ '{{WRAPPER}} .marqueex-marquee-track-wrapper' => 'gap: {{SIZE}}{{UNIT}};', '{{WRAPPER}} .marqueex-marquee-track' => 'gap: {{SIZE}}{{UNIT}};', '{{WRAPPER}} .marqueex-marquee-wrapper' => 'gap: {{SIZE}}{{UNIT}};', ], 'separator' => 'before', // 'condition' => [ // 'content_type' => 'never_display', // ], ] ); $this->end_controls_section(); // Query Section $this->start_controls_section( 'query_section', [ 'label' => __('Query', 'marqueex'), 'tab' => Controls_Manager::TAB_CONTENT, 'condition' => [ 'content_type' => 'posts', ], ] ); $this->add_control( 'post_type', [ 'label' => __('Post Type', 'marqueex'), 'type' => Controls_Manager::SELECT, 'default' => 'post', 'options' => $this->get_post_types(), ] ); $this->add_control( 'posts_per_page', [ 'label' => __('Number of Posts', 'marqueex'), 'type' => Controls_Manager::NUMBER, 'default' => 6, 'min' => 1, 'max' => 50, ] ); $this->add_control( 'orderby', [ 'label' => __('Order By', 'marqueex'), 'type' => Controls_Manager::SELECT, 'default' => 'date', 'options' => [ 'date' => __('Date', 'marqueex'), 'title' => __('Title', 'marqueex'), 'rand' => __('Random', 'marqueex'), 'menu_order' => __('Menu Order', 'marqueex'), ], ] ); $this->add_control( 'order', [ 'label' => __('Order', 'marqueex'), 'type' => Controls_Manager::SELECT, 'default' => 'desc', 'options' => [ 'asc' => __('ASC', 'marqueex'), 'desc' => __('DESC', 'marqueex'), ], 'condition' => [ 'orderby!' => 'rand', ], ] ); $this->add_control( 'category_ids', [ 'label' => __('Categories', 'marqueex'), 'type' => Controls_Manager::SELECT2, 'multiple' => true, 'options' => $this->get_post_categories(), 'condition' => [ 'post_type' => 'post', ], ] ); $this->end_controls_section(); // Marquee Settings Section $this->start_controls_section( 'marquee_settings_section', [ 'label' => __('Marquee Settings', 'marqueex'), 'tab' => Controls_Manager::TAB_CONTENT, ] ); $this->add_control( 'speed', [ 'label' => __('Speed', 'marqueex'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px/s'], 'range' => [ 'px' => [ 'min' => 10, 'max' => 100, 'step' => 1, ], ], 'default' => [ 'unit' => 'px', 'size' => 10, ], ] ); $this->add_control( 'direction_vertical', [ 'label' => __('Direction Vertical', 'marqueex'), 'type' => Controls_Manager::SWITCHER, 'default' => 'no', 'options' => [ 'no' => __('Horizontal', 'marqueex'), 'yes' => __('Vertical', 'marqueex'), ], ] ); $this->add_control( 'pause_on_hover', [ 'label' => __('Pause on Hover', 'marqueex'), 'type' => Controls_Manager::SWITCHER, 'label_on' => __('Yes', 'marqueex'), 'label_off' => __('No', 'marqueex'), 'return_value' => 'yes', 'default' => 'yes', ] ); $this->add_control( 'reverse_direction', [ 'label' => __('Reverse Direction', 'marqueex'), 'type' => Controls_Manager::SWITCHER, 'label_on' => __('Yes', 'marqueex'), 'label_off' => __('No', 'marqueex'), 'return_value' => 'yes', 'default' => 'no', ] ); $this->end_controls_section(); // Image Settings Section $this->start_controls_section( 'image_settings_section', [ 'label' => __('Image', 'marqueex'), 'tab' => Controls_Manager::TAB_STYLE, 'condition' => [ 'content_type' => 'custom', ], ] ); $this->add_responsive_control( 'image_width', [ 'label' => __('Image Width', 'marqueex'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px', '%', 'em', 'rem', 'vw'], 'range' => [ 'px' => [ 'min' => 50, 'max' => 500, 'step' => 1, ], '%' => [ 'min' => 10, 'max' => 100, 'step' => 1, ], ], 'default' => [ 'unit' => 'px', 'size' => 150, ], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'width: {{SIZE}}{{UNIT}};', ], ] ); $this->add_responsive_control( 'image_height', [ 'label' => __('Image Height', 'marqueex'), 'type' => Controls_Manager::SLIDER, 'size_units' => ['px', '%', 'em', 'rem', 'vh'], 'range' => [ 'px' => [ 'min' => 50, 'max' => 500, 'step' => 1, ], '%' => [ 'min' => 10, 'max' => 100, 'step' => 1, ], ], 'default' => [ 'unit' => 'px', 'size' => 150, ], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'height: {{SIZE}}{{UNIT}};', ], ] ); //border control $this->add_group_control( Group_Control_Border::get_type(), [ 'name' => 'image_border', 'label' => __('Border', 'marqueex'), 'selector' => '{{WRAPPER}} .marqueex-image-item', ] ); $this->add_responsive_control( 'image_border_radius', [ 'label' => __('Border Radius', 'marqueex'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', '%', 'em'], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], ] ); $this->add_group_control( Group_Control_Box_Shadow::get_type(), [ 'name' => 'image_box_shadow', 'label' => __('Box Shadow', 'marqueex'), 'selector' => '{{WRAPPER}} .marqueex-image-item', ] ); $this->add_responsive_control( 'image_padding', [ 'label' => __('Padding', 'marqueex'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', 'em', '%'], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], ] ); $this->add_responsive_control( 'image_margin', [ 'label' => __('Margin', 'marqueex'), 'type' => Controls_Manager::DIMENSIONS, 'size_units' => ['px', 'em', '%'], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'margin: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', ], ] ); $this->add_control( 'image_object_fit', [ 'label' => __('Object Fit', 'marqueex'), 'type' => Controls_Manager::SELECT, 'default' => 'cover', 'options' => [ 'fill' => __('Fill', 'marqueex'), 'contain' => __('Contain', 'marqueex'), 'cover' => __('Cover', 'marqueex'), 'none' => __('None', 'marqueex'), 'scale-down' => __('Scale Down', 'marqueex'), ], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'object-fit: {{VALUE}};', ], ] ); $this->add_control( 'image_object_position', [ 'label' => __('Object Position', 'marqueex'), 'type' => Controls_Manager::SELECT, 'default' => 'center center', 'options' => [ 'center center' => __('Center Center', 'marqueex'), 'center left' => __('Center Left', 'marqueex'), 'center right' => __('Center Right', 'marqueex'), 'top center' => __('Top Center', 'marqueex'), 'top left' => __('Top Left', 'marqueex'), 'top right' => __('Top Right', 'marqueex'), 'bottom center' => __('Bottom Center', 'marqueex'), 'bottom left' => __('Bottom Left', 'marqueex'), 'bottom right' => __('Bottom Right', 'marqueex'), ], 'selectors' => [ '{{WRAPPER}} .marqueex-image-item' => 'object-position: {{VALUE}};', ], 'condition' => [ 'image_object_fit!' => 'fill', ], ] ); $this->end_controls_section(); } /** * Prepare widget configuration from settings * * Extracts and processes all widget settings into a clean configuration array. * * @param array $settings Widget settings from Elementor * @return array Processed configuration array */ private function prepare_widget_config($settings) { return [ 'unique_id' => 'marqueex-ticker-' . $this->get_id(), 'speed' => max(10, min(100, intval($settings['speed']['size'] ?? 10))), // Security: Clamp speed values 'marquee_direction' => $settings['marquee_direction'] ?? 'horizontal', 'pause_on_hover' => $settings['pause_on_hover'] === 'yes' ? 'true' : 'false', 'reverse_direction' => $settings['reverse_direction'] === 'yes', 'content_type' => in_array($settings['content_type'] ?? 'posts', ['posts', 'custom']) ? $settings['content_type'] : 'posts', ]; } /** * Render ticker content based on content type * * @param array $settings Widget settings * @param array $config Widget configuration */ private function render_ticker_content_by_type($settings, $config) { if ($config['content_type'] === 'posts') { $this->render_dynamic_posts_content($settings); } else { $this->render_custom_image_content($settings); } } /** * Render dynamic posts content * * @param array $settings Widget settings */ private function render_dynamic_posts_content($settings) { $query_args = $this->get_query_args($settings); $posts = get_posts($query_args); $this->render_ticker_content($settings, $posts); } /** * Render custom image content * * @param array $settings Widget settings */ private function render_custom_image_content($settings) { $image_content = $settings['image_content_custom'] ?? []; if (empty($image_content)) { return; } echo '