get_action_options(); // Content tab. $this->start_controls_section( 'content_section', array( 'label' => __( 'Content', 'selectika' ), 'tab' => Controls_Manager::TAB_CONTENT, ) ); $this->add_control( 'product', array( 'label' => __( 'Product', 'selectika' ), 'type' => Controls_Manager::TEXT, 'placeholder' => __( 'Product identity or leave empty for current product', 'selectika' ), 'description' => __( 'Leave empty on product pages to use the configured current product identity.', 'selectika' ), ) ); $this->add_control( 'control_type', array( 'label' => __( 'Control Type', 'selectika' ), 'type' => Controls_Manager::SELECT, 'default' => '', 'options' => array( '' => __( 'Use site default', 'selectika' ) ) + $action_options, ) ); $this->add_control( 'carousel_view_type', array( 'label' => __( 'Layout Type', 'selectika' ), 'type' => Controls_Manager::SELECT, 'default' => 'Carousel', 'options' => array( 'Carousel' => __( 'Carousel', 'selectika' ), 'grid' => __( 'Grid', 'selectika' ), ), ) ); $this->add_control( 'item_count', array( 'label' => __( 'Number of Items', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 10, 'min' => 1, 'max' => 30, ) ); $this->add_control( 'title_text', array( 'label' => __( 'Carousel Title', 'selectika' ), 'type' => Controls_Manager::TEXT, 'placeholder' => __( 'e.g. You May Also Like', 'selectika' ), ) ); $this->add_control( 'retailer', array( 'label' => __( 'Retailer ID', 'selectika' ), 'type' => Controls_Manager::TEXT, 'placeholder' => __( 'Leave empty to use site hostname', 'selectika' ), ) ); $this->add_control( 'lang', array( 'label' => __( 'Language', 'selectika' ), 'type' => Controls_Manager::TEXT, 'placeholder' => get_bloginfo( 'language' ), ) ); $this->end_controls_section(); // Style tab - Typography. $this->start_controls_section( 'style_typography', array( 'label' => __( 'Typography', 'selectika' ), 'tab' => Controls_Manager::TAB_STYLE, ) ); $this->add_control( 'title_size_desktop', array( 'label' => __( 'Title Size (Desktop)', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 24, 'min' => 10, 'max' => 72, ) ); $this->add_control( 'title_size_mobile', array( 'label' => __( 'Title Size (Mobile)', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 18, 'min' => 10, 'max' => 48, ) ); $this->add_control( 'product_name_size_desktop', array( 'label' => __( 'Product Name Size (Desktop)', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 12, 'min' => 8, 'max' => 24, ) ); $this->add_control( 'product_name_size_mobile', array( 'label' => __( 'Product Name Size (Mobile)', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 10, 'min' => 8, 'max' => 20, ) ); $this->add_control( 'normal_price_size_desktop', array( 'label' => __( 'Price Size (Desktop)', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 12, 'min' => 8, 'max' => 24, ) ); $this->add_control( 'normal_price_size_mobile', array( 'label' => __( 'Price Size (Mobile)', 'selectika' ), 'type' => Controls_Manager::NUMBER, 'default' => 10, 'min' => 8, 'max' => 20, ) ); $this->end_controls_section(); // Style tab - Colors. $this->start_controls_section( 'style_colors', array( 'label' => __( 'Colors', 'selectika' ), 'tab' => Controls_Manager::TAB_STYLE, ) ); $this->add_control( 'title_color', array( 'label' => __( 'Title Color', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => '#000000', ) ); $this->add_control( 'product_name_color', array( 'label' => __( 'Product Name Color', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => '#000000', ) ); $this->add_control( 'normal_price_color', array( 'label' => __( 'Price Color', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => '#000000', ) ); $this->add_control( 'discount_price_color', array( 'label' => __( 'Sale Price Color', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => '#e62e00', ) ); $this->add_control( 'prediscount_price_color', array( 'label' => __( 'Original Price Color', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => '#d3d3d3', ) ); $this->add_control( 'card_color', array( 'label' => __( 'Card Background', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => 'transparent', ) ); $this->end_controls_section(); // Style tab - Add to Cart Button. $this->start_controls_section( 'style_button', array( 'label' => __( 'Add to Cart Button', 'selectika' ), 'tab' => Controls_Manager::TAB_STYLE, ) ); $this->add_control( 'add_to_cart_allow_present', array( 'label' => __( 'Show Add to Cart', 'selectika' ), 'type' => Controls_Manager::SELECT, 'default' => 'No', 'options' => array( 'No' => __( 'No', 'selectika' ), 'Yes' => __( 'Yes', 'selectika' ), ), ) ); $this->add_control( 'add_to_cart_button_text', array( 'label' => __( 'Button Text', 'selectika' ), 'type' => Controls_Manager::TEXT, 'default' => __( 'Add to cart', 'selectika' ), 'condition' => array( 'add_to_cart_allow_present' => 'Yes', ), ) ); $this->add_control( 'add_to_cart_button_background_color', array( 'label' => __( 'Button Color', 'selectika' ), 'type' => Controls_Manager::COLOR, 'default' => '#000000', 'condition' => array( 'add_to_cart_allow_present' => 'Yes', ), ) ); $this->end_controls_section(); // Advanced tab. $this->start_controls_section( 'advanced_section', array( 'label' => __( 'Advanced', 'selectika' ), 'tab' => Controls_Manager::TAB_ADVANCED, ) ); $this->add_control( 'custom_css', array( 'label' => __( 'Custom CSS ID', 'selectika' ), 'type' => Controls_Manager::TEXT, 'placeholder' => __( 'e.g. dark-theme', 'selectika' ), 'description' => __( 'Custom stylesheet identifier from Selectika.', 'selectika' ), ) ); $this->add_control( 'mtop', array( 'label' => __( 'Margin Top', 'selectika' ), 'type' => Controls_Manager::TEXT, 'default' => '0', ) ); $this->add_control( 'mbottom', array( 'label' => __( 'Margin Bottom', 'selectika' ), 'type' => Controls_Manager::TEXT, 'default' => '80px', ) ); $this->end_controls_section(); } /** * Get action type options. * * @return array */ private function get_action_options() { $options = array( 'sbi' => __( 'Shop Similar (SBI)', 'selectika' ), 'ctl' => __( 'Complete the Look (CTL)', 'selectika' ), 'stl' => __( 'Shop the Look (STL)', 'selectika' ), 'mtl' => __( 'Maximize the Look (MTL)', 'selectika' ), 'rdc' => __( 'Retailer Defined Carousels (RDC)', 'selectika' ), 'ffs' => __( 'Find Fit for Shoes (FFS)', 'selectika' ), 'ffk' => __( 'Find Fit for Kids (FFK)', 'selectika' ), 'fit' => __( 'Find Your Fit (FIT)', 'selectika' ), 'sps' => __( 'Selectika Personal Shopper (SPS)', 'selectika' ), ); return $options; } /** * Build params JSON for selectika-wc. * * @return string */ private function build_params_json() { $settings = $this->get_settings_for_display(); $price_size_d = (int) ( $settings['normal_price_size_desktop'] ?? 12 ); $price_size_m = (int) ( $settings['normal_price_size_mobile'] ?? 10 ); $params = array( 'title_text' => $settings['title_text'] ?? '', 'title_size_desktop' => (int) ( $settings['title_size_desktop'] ?? 24 ), 'title_size_mobile' => (int) ( $settings['title_size_mobile'] ?? 18 ), 'title_color' => $settings['title_color'] ?? '#000000', 'normal_price_color' => $settings['normal_price_color'] ?? '#000000', 'normal_price_size_desktop' => $price_size_d, 'normal_price_size_mobile' => $price_size_m, 'discount_price_color' => $settings['discount_price_color'] ?? '#e62e00', 'discount_price_size_desktop' => $price_size_d, 'discount_price_size_mobile' => $price_size_m, 'prediscount_price_color' => $settings['prediscount_price_color'] ?? '#d3d3d3', 'prediscount_price_size_desktop' => $price_size_d, 'prediscount_price_size_mobile' => $price_size_m, 'carousel_view_type' => $settings['carousel_view_type'] ?? 'Carousel', 'item_count' => (int) ( $settings['item_count'] ?? 10 ), 'card_color' => $settings['card_color'] ?? 'transparent', 'product_name_size_desktop' => (int) ( $settings['product_name_size_desktop'] ?? 12 ), 'product_name_size_mobile' => (int) ( $settings['product_name_size_mobile'] ?? 10 ), 'product_name_color' => $settings['product_name_color'] ?? '#000000', 'add_to_cart_button_text' => $settings['add_to_cart_button_text'] ?? 'Add to cart', 'add_to_cart_button_background_color' => $settings['add_to_cart_button_background_color'] ?? '#000000', 'add_to_cart_allow_present' => $settings['add_to_cart_allow_present'] ?? 'No', ); return wp_json_encode( $params ); } /** * Render widget output. */ protected function render() { $settings = $this->get_settings_for_display(); $attributes = array( 'action' => $settings['control_type'] ?? '', 'item' => $settings['product'] ?? '', 'retailer' => $settings['retailer'] ?? '', 'lang' => $settings['lang'] ?? '', 'mtop' => $settings['mtop'] ?? '0', 'mbottom' => $settings['mbottom'] ?? '80px', 'custom_css' => $settings['custom_css'] ?? '', ); $params = json_decode( $this->build_params_json(), true ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Shared renderer escapes every attribute. echo Selectika_Renderer::render( $attributes, is_array( $params ) ? $params : array() ); } /** * Sanitize action type. * * @param string $action Action code. * @return string */ private function sanitize_action( $action ) { $allowed = array( 'sbi', 'ctl', 'stl', 'mtl', 'rdc', 'ffs', 'ffk', 'fit', 'sps', 'tag' ); return in_array( $action, $allowed, true ) ? $action : 'sbi'; } /** * Sanitize CSS length. * * @param string $value Raw value. * @return string */ private function sanitize_css_length( $value ) { $value = preg_replace( '/[^0-9a-zA-Z%\s\.\-]/', '', (string) $value ); return '' !== $value ? $value : '0'; } }