File: /mnt/data/dreamssalon-wp/wp-content/plugins/dreamsalon-widgets/widgets/class-home3-hero-section.php
<?php
/**
* DS Home3 Hero Section Widget
*/
namespace dreamsalonelementor\Widgets;
use Elementor\Widget_Base;
use Elementor\Controls_Manager;
use Elementor\Group_Control_Typography;
if ( ! defined( 'ABSPATH' ) ) { exit; }
class DSHome3HeroSection extends Widget_Base {
public function get_name() { return 'dreamsalon-home3-hero-section'; }
public function get_title() { return __( 'Home3 Hero Section', 'dreamsalon_elementor' ); }
public function get_icon() { return 'eicon-banner'; }
public function get_categories() { return [ 'dreamsalonelemetortheme' ]; }
protected function _register_controls() {
// Content controls
$this->start_controls_section('section_content', [
'label' => __( 'Content', 'dreamsalon_elementor' ),
'tab' => Controls_Manager::TAB_CONTENT,
]);
// Rating / avatars
$this->add_control('rating_value', [
'label' => __( 'Rating Value', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => '4.8 / 5.0',
]);
$this->add_control('reviews_text', [
'label' => __( 'Reviews Text', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => 'From 2000+ Reviews',
]);
$this->add_control('reviews_mode', [
'label' => __( 'Reviews Mode', 'dreamsalon_elementor' ),
'type' => Controls_Manager::SELECT,
'options' => [
'static' => __( 'Static (use text above)', 'dreamsalon_elementor' ),
// 'dynamic' => __( 'Dynamic (from service reviews)', 'dreamsalon_elementor' ),
],
'default' => 'static',
]);
$this->add_control('avatars', [
'label' => __( 'Avatar Images (1)', 'dreamsalon_elementor' ),
'type' => Controls_Manager::GALLERY,
'default' => [],
'description' => __( 'First 1 images will be used.', 'dreamsalon_elementor' ),
]);
// Heading & description
$this->add_control('heading', [
'label' => __( 'Heading', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => 'Luxury Appointments, Instantly Scheduled',
]);
$this->add_control('heading_highlight_text', [
'label' => __( 'Highlight Text', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => 'Appointments',
]);
$this->add_control('description', [
'label' => __( 'Description', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXTAREA,
'default' => 'Discover personalized salon services that enhance your natural beauty, delivered by professionals who understand that every detail matters.',
]);
// Buttons
$this->add_control('primary_btn_text', [
'label' => __( 'Primary Button Text', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => 'View All Listings',
]);
$this->add_control('primary_btn_url', [
'label' => __( 'Primary Button URL', 'dreamsalon_elementor' ),
'type' => Controls_Manager::URL,
'default' => [ 'url' => '#' ],
]);
$this->add_control('secondary_btn_text', [
'label' => __( 'Phone', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => 'View All Listings',
]);
$this->add_control('secondary_btn_url', [
'label' => __( 'Phone To Call', 'dreamsalon_elementor' ),
'type' => Controls_Manager::URL,
'default' => [ 'url' => '#' ],
]);
// Images
$this->add_control('stat_img', [
'label' => __( 'Image', 'dreamsalon_elementor' ),
'type' => Controls_Manager::MEDIA,
'default' => [ 'url' => get_template_directory_uri() . '/assets/image/smile.png' ],
]);
$this->add_control('stat1_text', [
'label' => __( 'Stat 1 Text', 'dreamsalon_elementor' ),
'type' => Controls_Manager::TEXT,
'default' => 'Total Customers',
]);
// Images
$this->add_control('shape_1', [
'label' => __( 'Shape 1 Image', 'dreamsalon_elementor' ),
'type' => Controls_Manager::MEDIA,
'default' => [ 'url' => get_template_directory_uri() . '/assets/img/home-2/shape-04.svg' ],
]);
$this->add_control('shape_2', [
'label' => __( 'Shape 2 Image', 'dreamsalon_elementor' ),
'type' => Controls_Manager::MEDIA,
'default' => [ 'url' => get_template_directory_uri() . '/assets/img/home-2/shape-05.svg' ],
]);
$this->add_control('banner_img1', [
'label' => __( 'Banner Image 1', 'dreamsalon_elementor' ),
'type' => Controls_Manager::MEDIA,
'default' => [ 'url' => get_template_directory_uri() . '/assets/img/home-2/banner-01.jpg' ],
]);
$this->add_control('banner_img2', [
'label' => __( 'Banner Image 2', 'dreamsalon_elementor' ),
'type' => Controls_Manager::MEDIA,
'default' => [ 'url' => get_template_directory_uri() . '/assets/img/home-2/banner-02.jpg' ],
]);
$this->add_control('banner_img3', [
'label' => __( 'Banner Image 3', 'dreamsalon_elementor' ),
'type' => Controls_Manager::MEDIA,
'default' => [ 'url' => get_template_directory_uri() . '/assets/img/home-2/banner-03.jpg' ],
]);
$this->end_controls_section();
// Style controls
$this->start_controls_section(
'section_style',
[
'label' => __( 'Style', 'dreamsalon_elementor' ),
'tab' => Controls_Manager::TAB_STYLE,
]
);
// Title
$this->add_control('title_color', [
'label' => __( 'Title Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two h1' => 'color: {{VALUE}};',
],
]);
$this->add_control('title_highlight_color', [
'label' => __( 'Highlight Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two h1 .text-primary' => 'color: {{VALUE}};',
],
]);
$this->add_group_control(
Group_Control_Typography::get_type(),
[
'name' => 'title_typography',
'label' => __( 'Title Typography', 'dreamsalon_elementor' ),
'selector' => '{{WRAPPER}} .banner-section-two h1',
]
);
// Description
$this->add_control('desc_color', [
'label' => __( 'Description Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .banner-content > p' => 'color: {{VALUE}};',
],
]);
$this->add_group_control(
Group_Control_Typography::get_type(),
[
'name' => 'desc_typography',
'label' => __( 'Description Typography', 'dreamsalon_elementor' ),
'selector' => '{{WRAPPER}} .banner-section-two .banner-content > p',
]
);
// Rating / reviews
$this->add_control('rating_text_color', [
'label' => __( 'Rating Text Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .user-rating p' => 'color: {{VALUE}};',
],
]);
$this->add_control('rating_star_color', [
'label' => __( 'Rating Star Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .rating i' => 'color: {{VALUE}};',
],
]);
$this->add_group_control(
Group_Control_Typography::get_type(),
[
'name' => 'rating_typography',
'label' => __( 'Rating Typography', 'dreamsalon_elementor' ),
'selector' => '{{WRAPPER}} .banner-section-two .rating .fw-bold',
]
);
// Stats
$this->add_control('stats_number_color', [
'label' => __( 'Stats Number Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .item-padding h3' => 'color: {{VALUE}};',
],
]);
$this->add_group_control(
Group_Control_Typography::get_type(),
[
'name' => 'stats_number_typography',
'label' => __( 'Stats Number Typography', 'dreamsalon_elementor' ),
'selector' => '{{WRAPPER}} .banner-section-two .item-padding h3',
]
);
$this->add_control('stats_text_color', [
'label' => __( 'Stats Text Color', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .item-padding .item-text' => 'color: {{VALUE}};',
],
]);
$this->add_group_control(
Group_Control_Typography::get_type(),
[
'name' => 'stats_text_typography',
'label' => __( 'Stats Text Typography', 'dreamsalon_elementor' ),
'selector' => '{{WRAPPER}} .banner-section-two .item-padding .item-text',
]
);
// Buttons
$this->add_group_control(
Group_Control_Typography::get_type(),
[
'name' => 'button_typography',
'label' => __( 'Button Typography', 'dreamsalon_elementor' ),
'selector' => '{{WRAPPER}} .banner-section-two .banner-btns .btn',
]
);
$this->add_control('primary_button_bg', [
'label' => __( 'Primary Button BG', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .btn.btn-primary' => 'background-color: {{VALUE}};',
],
]);
$this->add_control('secondary_button_bg', [
'label' => __( 'Secondary Button BG', 'dreamsalon_elementor' ),
'type' => Controls_Manager::COLOR,
'selectors' => [
'{{WRAPPER}} .banner-section-two .btn.btn-white' => 'background-color: {{VALUE}};',
],
]);
$this->end_controls_section();
}
protected function render() {
$s = $this->get_settings_for_display();
$avatars = [];
if ( ! empty( $s['avatars'] ) && is_array( $s['avatars'] ) ) {
$items = array_slice( $s['avatars'], 0, 3 );
foreach ( $items as $item ) {
if ( ! empty( $item['url'] ) ) {
$avatars[] = $item['url'];
}
}
}
$rating_value = ! empty( $s['rating_value'] ) ? $s['rating_value'] : '';
$reviews_text = ! empty( $s['reviews_text'] ) ? $s['reviews_text'] : '';
$heading = ! empty( $s['heading'] ) ? $s['heading'] : '';
$highlight_txt = ! empty( $s['heading_highlight_text'] ) ? $s['heading_highlight_text'] : '';
$description = ! empty( $s['description'] ) ? $s['description'] : '';
$primary_btn_text = ! empty( $s['primary_btn_text'] ) ? $s['primary_btn_text'] : '';
$primary_btn_url = ! empty( $s['primary_btn_url']['url'] ) ? $s['primary_btn_url']['url'] : '#';
$secondary_btn_text = ! empty( $s['secondary_btn_text'] ) ? $s['secondary_btn_text'] : '';
$secondary_btn_url = ! empty( $s['secondary_btn_url']['url'] ) ? $s['secondary_btn_url']['url'] : '#';
$stat1_text = ! empty( $s['stat1_text'] ) ? $s['stat1_text'] : '';
// Dynamic mode: compute stats and rating from service reviews
if ( isset( $s['reviews_mode'] ) && $s['reviews_mode'] === 'dynamic' ) {
$total_reviews = 0;
$avg_rating = 0;
$rating_sum = 0;
$rating_count = 0;
$unique_customers = [];
if ( class_exists( '\\WP_Comment_Query' ) ) {
try {
// Count total approved comments with rating meta on service posts
$count_query = new \WP_Comment_Query();
$total_reviews = (int) $count_query->query([
'count' => true,
'status' => 'approve',
'post_type' => 'service',
'meta_query' => [
[
'key' => 'rating',
'compare' => 'EXISTS',
],
],
]);
// Fetch a subset of comments to compute average and avatars/customers
$comment_query = new \WP_Comment_Query();
$comments = $comment_query->query([
'status' => 'approve',
'post_type' => 'service',
'meta_query' => [
[
'key' => 'rating',
'compare' => 'EXISTS',
],
],
'number' => 500,
]);
if ( ! is_wp_error( $comments ) && ! empty( $comments ) ) {
$avatar_urls_dynamic = [];
foreach ( $comments as $c ) {
$rating_val = get_comment_meta( $c->comment_ID, 'rating', true );
if ( is_numeric( $rating_val ) ) {
$rating_sum += (float) $rating_val;
$rating_count ++;
}
// Track unique customers by user ID or email
$key = 0;
if ( ! empty( $c->user_id ) ) {
$key = 'user_' . (int) $c->user_id;
} elseif ( ! empty( $c->comment_author_email ) ) {
$key = 'email_' . strtolower( $c->comment_author_email );
}
if ( $key && ! isset( $unique_customers[ $key ] ) ) {
$unique_customers[ $key ] = true;
// Collect up to 3 avatars for display
if ( count( $avatar_urls_dynamic ) < 3 ) {
if ( ! empty( $c->user_id ) ) {
$av = get_avatar_url( $c->user_id, [ 'size' => 64 ] );
} else {
$av = get_avatar_url( $c->comment_author_email, [ 'size' => 64 ] );
}
if ( $av ) {
$avatar_urls_dynamic[] = $av;
}
}
}
}
if ( $rating_count > 0 ) {
$avg_rating = $rating_sum / $rating_count;
}
// Override gallery avatars with dynamic reviewer avatars if available
if ( ! empty( $avatar_urls_dynamic ) ) {
$avatars = $avatar_urls_dynamic;
}
}
} catch ( \Exception $e ) {
$total_reviews = 0;
}
}
// Average rating text like "4.8 / 5.0"
if ( $avg_rating > 0 ) {
$rating_value = sprintf( '%.1f / 5.0', $avg_rating );
}
// Reviews text from total
if ( $total_reviews > 0 ) {
$reviews_text = sprintf(
__( 'From %s+ Reviews', 'dreamsalon_elementor' ),
number_format_i18n( $total_reviews )
);
}
}
$shape_1 = ! empty( $s['shape_1']['url'] ) ? $s['shape_1']['url'] : '';
$stat_img = ! empty( $s['stat_img']['url'] ) ? $s['stat_img']['url'] : '';
$shape_2 = ! empty( $s['shape_2']['url'] ) ? $s['shape_2']['url'] : '';
$banner_img1 = ! empty( $s['banner_img1']['url'] ) ? $s['banner_img1']['url'] : '';
$banner_img2 = ! empty( $s['banner_img2']['url'] ) ? $s['banner_img2']['url'] : '';
$banner_img3 = ! empty( $s['banner_img3']['url'] ) ? $s['banner_img3']['url'] : '';
?>
<!-- Banner Section Two -->
<section class="banner-section-two z-0">
<?php if ( $shape_1 ) : ?>
<img src="<?php echo esc_url( $shape_1 ); ?>" alt="shape" class="start-0 top-0 position-absolute d-lg-flex d-none z-n1 home-5-shape shape-01">
<?php endif; ?>
<?php if ( $shape_2 ) : ?>
<img src="<?php echo esc_url( $shape_2 ); ?>" alt="bg" class="end-0 bottom-0 position-absolute d-lg-flex d-none z-n1 home-5-shape shape-02">
<?php endif; ?>
<div class="container">
<div class="row align-items-center">
<div class="col-lg-7">
<div class="banner-content wow fadeInUp" data-wow-duration="3s">
<?php if ( $heading ) : ?>
<h1 class="mb-4">
<?php
if ( $highlight_txt && strpos( $heading, $highlight_txt ) !== false ) {
echo wp_kses_post( str_replace( $highlight_txt, '<span class="text-primary text-decoration-underline">' . esc_html( $highlight_txt ) . '</span>', esc_html( $heading ) ) );
} else {
echo esc_html( $heading );
}
?>
</h1>
<?php endif; ?>
<?php if ( $description ) : ?>
<p><?php echo esc_html( $description ); ?></p>
<?php endif; ?>
<div class="d-flex align-items-center gap-3 flex-wrap banner-btns">
<?php if ( $primary_btn_text ) : ?>
<a href="<?php echo esc_url( $primary_btn_url ); ?>" class="btn btn-primary btn-lg d-flex align-items-center rounded-pill">
<?php echo esc_html( $primary_btn_text ); ?><i class="ti ti-chevron-right ms-1"></i>
</a>
<?php endif; ?>
<?php if ( $secondary_btn_text ) : ?>
<a href="tel:<?php echo esc_html( $secondary_btn_url ); ?>" class="btn btn-white btn-lg d-flex align-items-center rounded-pill">
<i class="ti ti-phone me-1"></i> <?php echo esc_html( $secondary_btn_text ); ?>
</a>
<?php endif; ?>
</div>
<div class="banner3 pt-3 mt-3">
<div class="user-rating rounded-pill bg-transparent mb-3 d-inline-flex align-items-center justify-content-center justify-content-sm-between flex-wrap gap-4">
<div class="d-flex align-items-center gap-2">
<?php if ( $stat_img ) : ?>
<div class="avatar-list-stacked flex-shrink-0">
<span class="avatar rounded-circle"> <img src="<?php echo esc_url( $stat_img ); ?>" alt="shape" class="img-fluid rounded-circle"></span>
</div>
<?php endif; ?>
<?php if ( $stat1_text ) : ?>
<p class="fs-14"><?php echo wp_kses_post( $stat1_text ); ?></p>
<?php endif; ?>
</div>
<div class="d-flex align-items-center gap-2">
<div class="avatar-list-stacked flex-shrink-0">
<?php foreach ( $avatars as $av ) : ?>
<span class="avatar rounded-circle"><img src="<?php echo esc_url( $av ); ?>" class="img-fluid rounded-circle" alt="avatar"></span>
<?php endforeach; ?>
</div>
<div>
<div class="d-flex align-items-center rating gap-1 fs-14 text-warning">
<?php if ( $rating_value ) : ?>
<p class="fs-14 heading-color fw-bold me-2 mb-0"><?php echo esc_html( $rating_value ); ?></p>
<?php endif; ?>
<i class="ti ti-star-filled filled"></i>
<i class="ti ti-star-filled filled"></i>
<i class="ti ti-star-filled filled"></i>
<i class="ti ti-star-filled filled"></i>
<i class="ti ti-star-filled filled"></i>
</div>
<?php if ( $reviews_text ) : ?>
<p class="fs-14"><?php echo esc_html( $reviews_text ); ?></p>
<?php endif; ?>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-lg-5">
<div class="banner-image">
<?php if ( $banner_img1 ) : ?>
<img src="<?php echo esc_url( $banner_img1 ); ?>" alt="banner-1" class="banner-img1">
<?php endif; ?>
<?php if ( $banner_img2 ) : ?>
<img src="<?php echo esc_url( $banner_img2 ); ?>" alt="banner-2" class="banner-img2">
<?php endif; ?>
<?php if ( $banner_img3 ) : ?>
<img src="<?php echo esc_url( $banner_img3 ); ?>" alt="banner-3" class="banner-img3">
<?php endif; ?>
</div>
</div>
</div>
</div>
</section>
<!-- Hero Section Three End -->
<?php
}
}