diff --git a/inc/js/woo-products.js b/inc/js/woo-products.js new file mode 100644 index 000000000..c12bfc795 --- /dev/null +++ b/inc/js/woo-products.js @@ -0,0 +1,42 @@ +/** + * HFE Woo Products Widget JavaScript + */ +(function($) { + 'use strict'; + + var HFEWooProducts = { + init: function() { + this.bindEvents(); + }, + + bindEvents: function() { + // Add any interactive functionality here + $(document).on('click', '.hfe-product-add-to-cart .button', this.handleAddToCart); + }, + + handleAddToCart: function(e) { + var $button = $(this); + + // Add loading state + $button.addClass('loading'); + + // Remove loading state after WooCommerce handles the request + setTimeout(function() { + $button.removeClass('loading'); + }, 2000); + } + }; + + // Initialize when document is ready + $(document).ready(function() { + HFEWooProducts.init(); + }); + + // Initialize for Elementor editor + $(window).on('elementor/frontend/init', function() { + elementorFrontend.hooks.addAction('frontend/element_ready/hfe-woo-product-grid.default', function($scope) { + HFEWooProducts.init(); + }); + }); + +})(jQuery); diff --git a/inc/widgets-css/frontend.css b/inc/widgets-css/frontend.css index d52f43664..c55e972ef 100644 --- a/inc/widgets-css/frontend.css +++ b/inc/widgets-css/frontend.css @@ -2171,4 +2171,4 @@ body .elementor .hfe-button-wrapper a { } .hfe-post-title { font-size: 20px; -} \ No newline at end of file +} diff --git a/inc/widgets-css/woo-products.css b/inc/widgets-css/woo-products.css new file mode 100644 index 000000000..fed7ab3fe --- /dev/null +++ b/inc/widgets-css/woo-products.css @@ -0,0 +1,290 @@ +/* HFE Woo Products Widget Styles */ +.hfe-woo-products-wrapper { + width: 100%; +} + +.hfe-woo-products-grid { + display: grid; + grid-template-columns: repeat(4, 1fr); + gap: 35px 20px; +} + +.hfe-product-item { + background: #ffffff; + border-radius: 8px; + overflow: hidden; + border: 1px solid #f0f0f0; +} + + +.hfe-product-image { + position: relative; + overflow: hidden; +} + +.hfe-product-image img { + width: 100%; + height: auto; + display: block; +} + + +.hfe-product-content { + padding: 20px; + display: flex; + flex-direction: column; + height: 100%; +} + +.hfe-product-category { + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.8px; + margin-bottom: 8px; + opacity: 0.75; + font-weight: 500; + color: #666; +} + +.hfe-product-title { + margin: 0 0 12px 0; + font-size: 16px; + line-height: 1.5; + font-weight: 600; + flex-grow: 1; +} + +.hfe-product-title a { + color: #333; + text-decoration: none; +} + +.hfe-product-title h2 { + margin: 0; + font-size: inherit; + line-height: inherit; + font-weight: inherit; + color: inherit; +} + +.hfe-product-title .hfe-loop-product__link { + display: block; +} + + +.hfe-product-rating { + margin-bottom: 12px; +} + +.hfe-product-rating .review-rating { + display: flex; + align-items: center; + min-height: 16px; +} + +.hfe-product-rating .star-rating { + font-size: 14px; + color: #ffa500; + display: inline-block; +} + +.hfe-product-price { + margin-bottom: 16px; + font-weight: 700; + font-size: 18px; +} + +.hfe-product-price .price { + color: #333; +} + +.hfe-product-price .price del { + opacity: 0.6; + margin-right: 8px; + font-weight: 400; +} + +.hfe-product-description { + margin-bottom: 16px; + font-size: 14px; + line-height: 1.6; + color: #666; + flex-grow: 1; +} + +.hfe-product-add-to-cart { + margin-top: auto; +} + +.hfe-woo-products-wrapper .hfe-product-add-to-cart .button { + width: auto; + min-width: 100px; + padding: 12px 20px; + border: none; + border-radius: 4px; + background: #007cba; + color: #ffffff; + font-size: 14px; + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + cursor: pointer; + text-decoration: none; + display: inline-block; + text-align: center; +} + +.hfe-woo-products-wrapper .hfe-product-add-to-cart .button:hover, +.hfe-woo-products-wrapper .hfe-product-add-to-cart .button:focus, +.hfe-woo-products-wrapper .hfe-product-add-to-cart .button:active, +.hfe-woo-products-wrapper .hfe-product-add-to-cart a.button:link { + text-decoration: none; +} + + +.hfe-woo-products-notice, +.hfe-woo-products-empty { + text-align: center; + padding: 40px 20px; + background: #f8f9fa; + border-radius: 4px; + color: #666; +} + +/* Card Hover Effects */ +.hfe-product-item { + height: 100%; + display: flex; + flex-direction: column; +} + +.hfe-product-content { + flex: 1; + display: flex; + flex-direction: column; +} + +/* Content Alignment Classes */ +.hfe-content-align-left .hfe-product-item { + text-align: left; +} + +.hfe-content-align-left .hfe-product-item .star-rating { + margin-left: 0; + margin-right: auto; +} + +.hfe-content-align-center .hfe-product-item { + text-align: center; +} + +.hfe-content-align-center .hfe-product-item .star-rating { + margin-left: auto; + margin-right: auto; +} + +.hfe-content-align-right .hfe-product-item { + text-align: right; +} + +.hfe-content-align-right .hfe-product-item .star-rating { + margin-left: auto; + margin-right: 0; +} + +/* Tablet Responsive Alignment */ +@media (max-width: 1024px) { + .hfe-content-tablet-align-left .hfe-product-item { + text-align: left; + } + + .hfe-content-tablet-align-left .hfe-product-item .star-rating { + margin-left: 0; + margin-right: auto; + } + + .hfe-content-tablet-align-center .hfe-product-item { + text-align: center; + } + + .hfe-content-tablet-align-center .hfe-product-item .star-rating { + margin-left: auto; + margin-right: auto; + } + + .hfe-content-tablet-align-right .hfe-product-item { + text-align: right; + } + + .hfe-content-tablet-align-right .hfe-product-item .star-rating { + margin-left: auto; + margin-right: 0; + } +} + +/* Mobile Responsive Alignment */ +@media (max-width: 767px) { + .hfe-content-mobile-align-left .hfe-product-item { + text-align: left; + } + + .hfe-content-mobile-align-left .hfe-product-item .star-rating { + margin-left: 0; + margin-right: auto; + } + + .hfe-content-mobile-align-center .hfe-product-item { + text-align: center; + } + + .hfe-content-mobile-align-center .hfe-product-item .star-rating { + margin-left: auto; + margin-right: auto; + } + + .hfe-content-mobile-align-right .hfe-product-item { + text-align: right; + } + + .hfe-content-mobile-align-right .hfe-product-item .star-rating { + margin-left: auto; + margin-right: 0; + } +} + +/* Responsive Design */ +@media (max-width: 1200px) { + .hfe-woo-products-grid { + grid-template-columns: repeat(3, 1fr); + } +} + +@media (max-width: 768px) { + .hfe-woo-products-grid { + grid-template-columns: repeat(2, 1fr); + gap: 20px 15px; + } + + .hfe-product-content { + padding: 16px; + } + + .hfe-product-title { + font-size: 15px; + } + + .hfe-product-price { + font-size: 16px; + } +} + +@media (max-width: 480px) { + .hfe-woo-products-grid { + grid-template-columns: 1fr; + gap: 25px; + } + + .hfe-product-content { + padding: 18px; + } +} diff --git a/inc/widgets-manager/base/hfe-helper.php b/inc/widgets-manager/base/hfe-helper.php index f05e61da9..1eb47463d 100644 --- a/inc/widgets-manager/base/hfe-helper.php +++ b/inc/widgets-manager/base/hfe-helper.php @@ -528,6 +528,7 @@ public static function get_used_widget() { 'hfe-site-tagline', 'hfe-site-title', 'hfe-infocard', + 'hfe-woo-product-grid', 'hfe-basic-posts', ]; diff --git a/inc/widgets-manager/base/widgets-config.php b/inc/widgets-manager/base/widgets-config.php index 463b13d9b..b6499a0a2 100644 --- a/inc/widgets-manager/base/widgets-config.php +++ b/inc/widgets-manager/base/widgets-config.php @@ -249,6 +249,19 @@ public static function get_widget_list() { 'demo_url' => 'https://ultimateelementor.com/widgets/search/', 'category' => 'content', ], + 'Woo_Product_Grid' => [ + 'slug' => 'hfe-woo-product-grid', + 'title' => __( 'Woo Products Grid', 'header-footer-elementor' ), + 'description' => __( 'Display WooCommerce products in a responsive grid layout with customizable styling options.', 'header-footer-elementor' ), + 'keywords' => [ 'hfe', 'woo', 'products', 'grid' ], + 'icon' => 'hfe-icon-woo-product', + 'title_url' => '#', + 'default' => true, + 'doc_url' => HFE_DOMAIN . 'docs-category/widgets/woo-products/?utm_source=uael-pro-dashboard&utm_medium=uael-menu-page&utm_campaign=uael-pro-plugin', + 'category' => 'content', + 'is_pro' => false, + 'demo_url' => HFE_DOMAIN . 'widgets/woo-products/', + ], ]; return apply_filters( 'hfe_widgets_data', self::$widget_list ); diff --git a/inc/widgets-manager/class-widgets-loader.php b/inc/widgets-manager/class-widgets-loader.php index c7d63440a..8753019ce 100644 --- a/inc/widgets-manager/class-widgets-loader.php +++ b/inc/widgets-manager/class-widgets-loader.php @@ -193,7 +193,6 @@ public function register_widget_category( $this_cat ) { 'icon' => 'eicon-font', ] ); - return $this_cat; } @@ -210,6 +209,11 @@ public static function get_widget_script() { 'dep' => [ 'jquery' ], 'in_footer' => true, ], + 'hfe-woo-product-grid' => [ + 'path' => 'inc/js/woo-products.js', + 'dep' => [ 'jquery' ], + 'in_footer' => true, + ], ]; return $js_files; @@ -245,6 +249,11 @@ public function include_js_files() { // Emqueue the widgets style. wp_enqueue_style( 'hfe-widgets-style', HFE_URL . 'inc/widgets-css/frontend.css', [], HFE_VER ); + + // Enqueue Woo Products widget styles + if ( class_exists( 'WooCommerce' ) ) { + wp_enqueue_style( 'hfe-woo-product-grid', HFE_URL . 'inc/widgets-css/woo-products.css', [], HFE_VER ); + } } /** diff --git a/inc/widgets-manager/modules-manager.php b/inc/widgets-manager/modules-manager.php index 7a4a5f994..8fb7f16e9 100644 --- a/inc/widgets-manager/modules-manager.php +++ b/inc/widgets-manager/modules-manager.php @@ -57,6 +57,7 @@ public function register_modules() { 'breadcrumbs-widget', 'post-info', 'infocard', + 'woo-product-grid', 'basic-posts', ]; diff --git a/inc/widgets-manager/widgets/woo-product-grid/module.php b/inc/widgets-manager/widgets/woo-product-grid/module.php new file mode 100644 index 000000000..5f2166331 --- /dev/null +++ b/inc/widgets-manager/widgets/woo-product-grid/module.php @@ -0,0 +1,68 @@ + ! defined( 'UAEL_VER' ), + 'image' => esc_url( HFE_URL . 'assets/images/upgrade-pro.png' ), + 'image_alt' => esc_attr__( 'Upgrade', 'header-footer-elementor' ), + 'title' => esc_html__( 'Upgrade your Woo Products widget', 'header-footer-elementor' ), + 'description' => esc_html__( 'Get the advanced Woo Products widget and unlock powerful layouts, filters, and customization options with UAE Pro.', 'header-footer-elementor' ), + 'upgrade_url' => esc_url( 'https://ultimateelementor.com/pricing/?utm_source=UAE-Basic-Post&utm_medium=editor&utm_campaign=static-promotion' ), + 'upgrade_text' => esc_html__( 'Upgrade Now', 'header-footer-elementor' ), + ]; + } + + /** + * Register widget controls. + * + * @since x.x.x + * @access protected + */ + protected function register_controls() { + if ( ! $this->is_woocommerce_active() ) { + $this->register_woocommerce_notice_controls(); + return; + } + + $this->register_general_controls(); + $this->register_content_controls(); + $this->register_query_controls(); + $this->register_layout_style_controls(); + $this->register_content_style_controls(); + $this->register_pro_promotion_controls(); + } + + /** + * Register WooCommerce notice controls. + * + * @since x.x.x + * @access protected + */ + protected function register_woocommerce_notice_controls() { + $this->start_controls_section( + 'section_woocommerce_notice', + [ + 'label' => __( 'WooCommerce Required', 'header-footer-elementor' ), + ] + ); + + $this->add_control( + 'woocommerce_notice', + [ + 'type' => Controls_Manager::RAW_HTML, + 'raw' => sprintf( + /* translators: %1$s: opening link tag, %2$s: closing link tag */ + __( 'This widget requires WooCommerce to be installed and activated. %1$sInstall WooCommerce%2$s', 'header-footer-elementor' ), + '', + '' + ), + 'content_classes' => 'elementor-panel-alert elementor-panel-alert-warning', + ] + ); + + $this->end_controls_section(); + } + + /** + * Register general controls. + * + * @since x.x.x + * @access protected + */ + protected function register_general_controls() { + $this->start_controls_section( + 'section_general', + [ + 'label' => __( 'General', 'header-footer-elementor' ), + ] + ); + + $this->add_responsive_control( + 'columns', + [ + 'label' => __( 'Columns', 'header-footer-elementor' ), + 'type' => Controls_Manager::SELECT, + 'default' => '4', + 'tablet_default' => '3', + 'mobile_default' => '1', + 'options' => [ + '1' => '1', + '2' => '2', + '3' => '3', + '4' => '4', + '5' => '5', + '6' => '6', + ], + 'frontend_available' => true, + 'selectors' => [ + '{{WRAPPER}} .hfe-woo-products-grid' => 'grid-template-columns: repeat({{VALUE}}, 1fr);', + ], + ] + ); + + $this->add_control( + 'products_per_page', + [ + 'label' => __( 'Products Per Page', 'header-footer-elementor' ), + 'type' => Controls_Manager::NUMBER, + 'default' => 8, + 'min' => 1, + 'max' => 100, + ] + ); + + + $this->end_controls_section(); + } + + /** + * Register content controls. + * + * @since x.x.x + * @access protected + */ + protected function register_content_controls() { + $this->start_controls_section( + 'section_content_toggles', + [ + 'label' => __( 'Content', 'header-footer-elementor' ), + ] + ); + + $this->add_control( + 'show_image', + [ + 'label' => __( 'Show Image', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => 'yes', + ] + ); + + $this->add_control( + 'show_category', + [ + 'label' => __( 'Show Category', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => 'yes', + ] + ); + + $this->add_control( + 'show_title', + [ + 'label' => __( 'Show Title', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => 'yes', + ] + ); + + $this->add_control( + 'show_rating', + [ + 'label' => __( 'Show Rating', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => 'yes', + ] + ); + + $this->add_control( + 'show_price', + [ + 'label' => __( 'Show Price', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => 'yes', + ] + ); + + $this->add_control( + 'show_description', + [ + 'label' => __( 'Show Short Description', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => '', + ] + ); + + $this->add_control( + 'show_add_to_cart', + [ + 'label' => __( 'Show Add to Cart', 'header-footer-elementor' ), + 'type' => Controls_Manager::SWITCHER, + 'label_on' => __( 'Yes', 'header-footer-elementor' ), + 'label_off' => __( 'No', 'header-footer-elementor' ), + 'return_value' => 'yes', + 'default' => 'yes', + ] + ); + + $this->end_controls_section(); + } + + /** + * Register query controls. + * + * @since x.x.x + * @access protected + */ + protected function register_query_controls() { + $this->start_controls_section( + 'section_query', + [ + 'label' => __( 'Query', 'header-footer-elementor' ), + ] + ); + + $this->add_control( + 'orderby', + [ + 'label' => __( 'Order By', 'header-footer-elementor' ), + 'type' => Controls_Manager::SELECT, + 'default' => 'date', + 'options' => [ + 'date' => __( 'Date', 'header-footer-elementor' ), + 'title' => __( 'Title', 'header-footer-elementor' ), + 'price' => __( 'Price', 'header-footer-elementor' ), + 'popularity' => __( 'Popularity', 'header-footer-elementor' ), + 'rating' => __( 'Rating', 'header-footer-elementor' ), + 'rand' => __( 'Random', 'header-footer-elementor' ), + ], + ] + ); + + $this->add_control( + 'order', + [ + 'label' => __( 'Order', 'header-footer-elementor' ), + 'type' => Controls_Manager::SELECT, + 'default' => 'desc', + 'options' => [ + 'desc' => __( 'Descending', 'header-footer-elementor' ), + 'asc' => __( 'Ascending', 'header-footer-elementor' ), + ], + 'condition' => [ + 'orderby!' => 'rand', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register layout style controls. + * + * @since x.x.x + * @access protected + */ + protected function register_layout_style_controls() { + $this->start_controls_section( + 'section_layout_style', + [ + 'label' => __( 'Layout', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + ] + ); + + $this->add_responsive_control( + 'column_gap', + [ + 'label' => __( 'Column Gap', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em', 'rem' ], + 'range' => [ + 'px' => [ + 'min' => 0, + 'max' => 100, + ], + ], + 'default' => [ + 'size' => 20, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-woo-products-grid' => 'column-gap: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->add_responsive_control( + 'row_gap', + [ + 'label' => __( 'Row Gap', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em', 'rem' ], + 'range' => [ + 'px' => [ + 'min' => 0, + 'max' => 100, + ], + ], + 'default' => [ + 'size' => 35, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-woo-products-grid' => 'row-gap: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->add_group_control( + Group_Control_Box_Shadow::get_type(), + [ + 'name' => 'product_box_shadow', + 'label' => __( 'Box Shadow', 'header-footer-elementor' ), + 'selector' => '{{WRAPPER}} .hfe-product-item', + ] + ); + + $this->add_group_control( + Group_Control_Border::get_type(), + [ + 'name' => 'product_border', + 'label' => __( 'Border', 'header-footer-elementor' ), + 'selector' => '{{WRAPPER}} .hfe-product-item', + ] + ); + + $this->add_responsive_control( + 'product_border_radius', + [ + 'label' => __( 'Border Radius', 'header-footer-elementor' ), + 'type' => Controls_Manager::DIMENSIONS, + 'size_units' => [ 'px', '%', 'em' ], + 'default' => [ + 'top' => 0, + 'right' => 0, + 'bottom' => 0, + 'left' => 0, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-item' => 'border-radius: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register content style controls. + * + * @since x.x.x + * @access protected + */ + protected function register_content_style_controls() { + // Content Area Styling + $this->start_controls_section( + 'section_content_area_style', + [ + 'label' => __( 'Card', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + ] + ); + + $this->add_responsive_control( + 'content_alignment', + [ + 'label' => __( 'Alignment', 'header-footer-elementor' ), + 'type' => Controls_Manager::CHOOSE, + 'options' => [ + 'left' => [ + 'title' => __( 'Left', 'header-footer-elementor' ), + 'icon' => 'eicon-text-align-left', + ], + 'center' => [ + 'title' => __( 'Center', 'header-footer-elementor' ), + 'icon' => 'eicon-text-align-center', + ], + 'right' => [ + 'title' => __( 'Right', 'header-footer-elementor' ), + 'icon' => 'eicon-text-align-right', + ], + ], + 'default' => 'left', + 'prefix_class' => 'hfe-content%s-align-', + 'frontend_available' => true, + ] + ); + + $this->add_group_control( + Group_Control_Background::get_type(), + [ + 'name' => 'content_background', + 'label' => __( 'Background', 'header-footer-elementor' ), + 'types' => [ 'classic', 'gradient' ], + 'selector' => '{{WRAPPER}} .hfe-product-item', + 'fields_options' => [ + 'background' => [ + 'default' => 'classic', + ], + 'color' => [ + 'default' => '#f6f6f6', + ], + ], + ] + ); + + $this->add_responsive_control( + 'product_content_padding', + [ + 'label' => __( 'Content Padding', 'header-footer-elementor' ), + 'type' => Controls_Manager::DIMENSIONS, + 'size_units' => [ 'px', 'em', '%' ], + 'default' => [ + 'top' => 20, + 'right' => 20, + 'bottom' => 20, + 'left' => 20, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-content' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + + $this->register_image_size_style_controls(); + + + // Category Styling + $this->start_controls_section( + 'section_category_style', + [ + 'label' => __( 'Category', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ + 'show_category' => 'yes', + ], + ] + ); + + $this->add_control( + 'category_color', + [ + 'label' => __( 'Text Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'global' => [ + 'default' => Global_Colors::COLOR_SECONDARY, + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-category' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_group_control( + Group_Control_Typography::get_type(), + [ + 'name' => 'category_typography', + 'global' => [ + 'default' => Global_Typography::TYPOGRAPHY_TEXT, + ], + 'selector' => '{{WRAPPER}} .hfe-product-category', + ] + ); + + $this->add_responsive_control( + 'category_spacing', + [ + 'label' => __( 'Spacing', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em' ], + 'default' => [ + 'size' => 10, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-category' => 'margin-bottom: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + + // Title, Rating, Price, Add to Cart styles (condensed) + $this->register_title_style_controls(); + $this->register_rating_style_controls(); + $this->register_price_style_controls(); + $this->register_short_description_style_controls(); + $this->register_add_to_cart_style_controls(); + } + + /** + * Register title style controls. + * + * @since x.x.x + * @access private + */ + private function register_title_style_controls() { + $this->start_controls_section( + 'section_title_style', + [ + 'label' => __( 'Title', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ 'show_title' => 'yes' ], + ] + ); + + $this->add_control( + 'title_color', + [ + 'label' => __( 'Text Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'global' => [ + 'default' => Global_Colors::COLOR_PRIMARY, + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-title, {{WRAPPER}} .hfe-product-title a' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_control( + 'title_hover_color', + [ + 'label' => __( 'Hover Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'selectors' => [ + '{{WRAPPER}} .hfe-product-title a:hover' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_group_control( + Group_Control_Typography::get_type(), + [ + 'name' => 'title_typography', + 'global' => [ + 'default' => Global_Typography::TYPOGRAPHY_PRIMARY, + ], + 'selector' => '{{WRAPPER}} .hfe-product-title', + ] + ); + + $this->add_responsive_control( + 'title_spacing', + [ + 'label' => __( 'Spacing', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em' ], + 'default' => [ + 'size' => 10, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-title' => 'margin-bottom: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register rating style controls. + * + * @since x.x.x + * @access private + */ + private function register_rating_style_controls() { + $this->start_controls_section( + 'section_rating_style', + [ + 'label' => __( 'Rating', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ 'show_rating' => 'yes' ], + ] + ); + + $this->add_control( + 'rating_color', + [ + 'label' => __( 'Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'global' => [ + 'default' => Global_Colors::COLOR_ACCENT, + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-woo-products-grid .hfe-product-rating .star-rating' => 'color: {{VALUE}};', + '{{WRAPPER}} .hfe-woo-products-grid .hfe-product-rating .star-rating::before' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_responsive_control( + 'rating_spacing', + [ + 'label' => __( 'Spacing', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em' ], + 'default' => [ + 'size' => 10, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-rating' => 'margin-bottom: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register price style controls. + * + * @since x.x.x + * @access private + */ + private function register_price_style_controls() { + $this->start_controls_section( + 'section_price_style', + [ + 'label' => __( 'Price', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ 'show_price' => 'yes' ], + ] + ); + + $this->add_group_control( + Group_Control_Typography::get_type(), + [ + 'name' => 'price_typography', + 'label' => __( 'Typography', 'header-footer-elementor' ), + 'selector' => '{{WRAPPER}} .hfe-product-price span', + ] + ); + + $this->add_control( + 'price_color', + [ + 'label' => __( 'Text Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'global' => [ + 'default' => Global_Colors::COLOR_PRIMARY, + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-price span' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_responsive_control( + 'price_spacing', + [ + 'label' => __( 'Spacing', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em' ], + 'default' => [ + 'size' => 10, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-price' => 'margin-bottom: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register short description style controls. + * + * @since x.x.x + * @access private + */ + private function register_short_description_style_controls() { + $this->start_controls_section( + 'section_short_description_style', + [ + 'label' => __( 'Short Description', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ 'show_description' => 'yes' ], + ] + ); + + $this->add_group_control( + Group_Control_Typography::get_type(), + [ + 'name' => 'short_description_typography', + 'label' => __( 'Typography', 'header-footer-elementor' ), + 'selector' => '{{WRAPPER}} .hfe-product-description', + ] + ); + + $this->add_control( + 'short_description_color', + [ + 'label' => __( 'Text Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'global' => [ + 'default' => Global_Colors::COLOR_TEXT, + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-description' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_responsive_control( + 'short_description_spacing', + [ + 'label' => __( 'Spacing', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'size_units' => [ 'px', 'em' ], + 'default' => [ + 'size' => 10, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-description' => 'margin-bottom: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register add to cart style controls. + * + * @since x.x.x + * @access private + */ + private function register_add_to_cart_style_controls() { + $this->start_controls_section( + 'section_add_to_cart_style', + [ + 'label' => __( 'Add to Cart', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ 'show_add_to_cart' => 'yes' ], + ] + ); + + $this->add_responsive_control( + 'add_to_cart_padding', + [ + 'label' => __( 'Padding', 'header-footer-elementor' ), + 'type' => Controls_Manager::DIMENSIONS, + 'size_units' => [ 'px', 'em', '%' ], + 'default' => [ + 'top' => 12, + 'right' => 20, + 'bottom' => 12, + 'left' => 20, + 'unit' => 'px', + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-add-to-cart .button' => 'padding: {{TOP}}{{UNIT}} {{RIGHT}}{{UNIT}} {{BOTTOM}}{{UNIT}} {{LEFT}}{{UNIT}};', + ], + ] + ); + + $this->start_controls_tabs( 'add_to_cart_tabs' ); + + $this->start_controls_tab( + 'add_to_cart_normal_tab', + [ + 'label' => __( 'Normal', 'header-footer-elementor' ), + ] + ); + + $this->add_control( + 'add_to_cart_color', + [ + 'label' => __( 'Text Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'default' => '', + 'selectors' => [ + '{{WRAPPER}} .hfe-product-add-to-cart .button' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_group_control( + Group_Control_Background::get_type(), + [ + 'name' => 'add_to_cart_background_color', + 'label' => __( 'Background Color', 'header-footer-elementor' ), + 'types' => [ 'classic', 'gradient' ], + 'selector' => '{{WRAPPER}} .hfe-product-add-to-cart .button', + 'fields_options' => [ + 'color' => [ + 'global' => [ + 'default' => Global_Colors::COLOR_ACCENT, + ], + ], + ], + ] + ); + + $this->end_controls_tab(); + + $this->start_controls_tab( + 'add_to_cart_hover_tab', + [ + 'label' => __( 'Hover', 'header-footer-elementor' ), + ] + ); + + $this->add_control( + 'add_to_cart_hover_color', + [ + 'label' => __( 'Text Color', 'header-footer-elementor' ), + 'type' => Controls_Manager::COLOR, + 'selectors' => [ + '{{WRAPPER}} .hfe-product-add-to-cart .button:hover' => 'color: {{VALUE}};', + ], + ] + ); + + $this->add_group_control( + Group_Control_Background::get_type(), + [ + 'name' => 'add_to_cart_hover_background_color', + 'label' => __( 'Background Color', 'header-footer-elementor' ), + 'types' => [ 'classic', 'gradient' ], + 'selector' => '{{WRAPPER}} .hfe-product-add-to-cart .button:hover', + ] + ); + + $this->end_controls_tab(); + + $this->end_controls_tabs(); + + $this->add_group_control( + Group_Control_Typography::get_type(), + [ + 'name' => 'add_to_cart_typography', + 'selector' => '{{WRAPPER}} .hfe-product-add-to-cart .button', + 'global' => [ + 'default' => Global_Typography::TYPOGRAPHY_ACCENT, + ], + ] + ); + + $this->add_responsive_control( + 'add_to_cart_margin_bottom', + [ + 'label' => __( 'Margin Bottom', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'range' => [ + 'px' => [ + 'max' => 100, + ], + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-add-to-cart .button' => 'margin-bottom: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->add_responsive_control( + 'add_to_cart_margin_right', + [ + 'label' => __( 'Margin Right', 'header-footer-elementor' ), + 'type' => Controls_Manager::SLIDER, + 'range' => [ + 'px' => [ + 'max' => 100, + ], + ], + 'selectors' => [ + '{{WRAPPER}} .hfe-product-add-to-cart .button' => 'margin-right: {{SIZE}}{{UNIT}};', + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register image hover style controls. + * + * @since x.x.x + * @access private + */ + private function register_image_size_style_controls() { + $this->start_controls_section( + 'section_image_size_style', + [ + 'label' => __( 'Image', 'header-footer-elementor' ), + 'tab' => Controls_Manager::TAB_STYLE, + 'condition' => [ 'show_image' => 'yes' ], + ] + ); + + $this->add_control( + 'image_size', + [ + 'label' => __( 'Image Size', 'header-footer-elementor' ), + 'type' => Controls_Manager::SELECT, + 'default' => 'woocommerce_thumbnail', + 'options' => [ + 'thumbnail' => __( 'Thumbnail', 'header-footer-elementor' ), + 'medium' => __( 'Medium', 'header-footer-elementor' ), + 'large' => __( 'Large', 'header-footer-elementor' ), + 'full' => __( 'Full Size', 'header-footer-elementor' ), + 'woocommerce_thumbnail' => __( 'WooCommerce Thumbnail', 'header-footer-elementor' ), + 'woocommerce_single' => __( 'WooCommerce Single', 'header-footer-elementor' ), + ], + ] + ); + + $this->end_controls_section(); + } + + /** + * Register promotion controls. + * + * @since x.x.x + * @access protected + */ + protected function register_pro_promotion_controls() { + // Add promotion controls if needed for pro features + } + + /** + * Build query arguments. + * + * @since x.x.x + * @access private + * @return array + */ + private function build_query_args() { + $settings = $this->get_settings_for_display(); + + $args = [ + 'post_type' => 'product', + 'post_status' => 'publish', + 'posts_per_page' => $settings['products_per_page'], + 'meta_query' => WC()->query->get_meta_query(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query + 'tax_query' => WC()->query->get_tax_query(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query + ]; + + // Set ordering + switch ( $settings['orderby'] ) { + case 'price': + $args['meta_key'] = '_price'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + $args['orderby'] = 'meta_value_num'; + break; + case 'popularity': + $args['meta_key'] = 'total_sales'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + $args['orderby'] = 'meta_value_num'; + break; + case 'rating': + $args['meta_key'] = '_wc_average_rating'; // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key + $args['orderby'] = 'meta_value_num'; + break; + default: + $args['orderby'] = $settings['orderby']; + break; + } + + $args['order'] = $settings['order']; + + return $args; + } + + /** + * Get products query. + * + * @since x.x.x + * @access private + * @return \WP_Query + */ + private function get_products_query() { + if ( null === $this->query ) { + $this->query = new \WP_Query( $this->build_query_args() ); + } + + return $this->query; + } + + /** + * Render widget output on both frontend and editor. + * + * @since x.x.x + * @access protected + */ + protected function render() { + if ( ! $this->is_woocommerce_active() ) { + $this->render_woocommerce_notice(); + return; + } + + $settings = $this->get_settings_for_display(); + $query = $this->get_products_query(); + + if ( ! $query->have_posts() ) { + $this->render_no_products_message(); + return; + } + + $this->add_render_attribute( 'wrapper', 'class', 'hfe-woo-products-wrapper' ); + $this->add_render_attribute( 'grid', 'class', 'hfe-woo-products-grid' ); + + ?> +