| | |
| | | <?php |
| | | /** |
| | | * GMB Reviews Block - Render Template |
| | | * |
| | | * Displays recent Google My Business reviews with a link to leave a review |
| | | */ |
| | | function jvbRenderGMBReviewsBlock(array $attributes): string |
| | | { |
| | | $count = $attributes['count'] ?? 5; |
| | | $showRating = $attributes['showRating'] ?? true; |
| | | $showDate = $attributes['showDate'] ?? true; |
| | | $showReviewLink = $attributes['showReviewLink'] ?? true; |
| | | $showViewAllLink = $attributes['showViewAllLink'] ?? true; |
| | | $showStats = $attributes['showStats'] ?? true; |
| | | $minStars = $attributes['minStars'] ?? 4; // Only show 4+ star reviews |
| | | $inheritUser = $attributes['inheritUser']??null; |
| | | if ($inheritUser) { |
| | | global $post; |
| | | $inheritUser = $post->post_author; |
| | | } |
| | | try { |
| | | $gmb = JVB()->connect('gmb', $inheritUser); |
| | | if (!$gmb->isSetUp()) { |
| | | error_log('GMB Not set up for: '.(int)$inheritUser); |
| | | return ''; |
| | | } |
| | | $gotReviews = $gmb->getReviews(); |
| | | // Get all data |
| | | $allReviews = $gotReviews['reviews']??[]; |
| | | $reviewUrl = $gmb->getReviewUrl(); |
| | | $viewAllUrl = $gmb->getReviewsViewUrl(); |
| | | |
| | | $average = $gotReviews['averageRating']??null; |
| | | $total = $gotReviews['totalReviewCount']??null; |
| | | |
| | | // Filter reviews by minimum stars |
| | | $reviews = []; |
| | | if (!empty($allReviews)) { |
| | | foreach ($allReviews as $review) { |
| | | $rating = $review['starRating'] ?? 0; |
| | | if ($rating >= $minStars) { |
| | | $reviews[] = $review; |
| | | if (count($reviews) >= $count) { |
| | | break; // Got enough reviews |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (empty($reviews) && empty($reviewUrl) && empty($stats)) { |
| | | error_log('No reviews to display...'); |
| | | return ''; |
| | | } |
| | | |
| | | ob_start(); |
| | | ?> |
| | | <div class="gmb-reviews"> |
| | | <div class="row btw"> |
| | | <?php |
| | | if ($showStats && !empty($average) && !empty($total)) { |
| | | ?> |
| | | <p> |
| | | <span class="stars" aria-label="<?= $average ?> out of 5 stars"> |
| | | <?php |
| | | $fullStars = floor($average); |
| | | $hasHalfStar = ($average - $fullStars) >= 0.5; |
| | | |
| | | for ($i = 1; $i <= 5; $i++) { |
| | | if ($i <= $fullStars) { |
| | | echo jvbIcon('star', ['style' => 'fill']); |
| | | } elseif ($i == $fullStars + 1 && $hasHalfStar) { |
| | | echo jvbIcon('star-half', ['style'=> 'fill']); |
| | | } else { |
| | | echo jvbIcon('star', ['style' => 'light']); |
| | | } |
| | | } |
| | | ?> |
| | | </span> |
| | | <i>Average</i> |
| | | </p> |
| | | <?php |
| | | if ($total > 0) { |
| | | ?> |
| | | <p><i>{ <?= number_format($total ) . ' ' . _n('Review', 'Reviews', $total, 'jvb')?> Total }</i></p> |
| | | <?php |
| | | } |
| | | ?> |
| | | <?php |
| | | } |
| | | ?> |
| | | |
| | | <?php |
| | | if ($showReviewLink && !empty($reviewUrl)) { |
| | | ?> |
| | | <a href="<?=esc_url($reviewUrl)?>" |
| | | class="button" |
| | | target="_blank" |
| | | rel="noopener noreferrer"> |
| | | <?= jvbIcon('star', ['style' => 'fill']) ?> |
| | | Leave Your Review |
| | | </a> |
| | | <?php |
| | | } |
| | | ?> |
| | | </div> |
| | | |
| | | <ul> |
| | | <?php |
| | | foreach ($reviews as $review) { |
| | | $reviewer = $review['reviewer']['displayName'] ?? 'Anonymous'; |
| | | $reviewer = strtok($reviewer, ' '); |
| | | $profilePhoto = $review['reviewer']['profilePhotoUrl'] ?? ''; |
| | | $rating = $review['starRating'] ?? 0; |
| | | $rating = match($rating) { |
| | | 'FIVE' => 5, |
| | | 'FOUR' => 4, |
| | | 'THREE' => 3, |
| | | 'TWO' => 2, |
| | | 'ONE' => 1, |
| | | default => $rating |
| | | }; |
| | | $comment = $review['comment'] ?? ''; |
| | | $date = $review['updateTime'] ?? ''; |
| | | ?> |
| | | <li> |
| | | <blockquote class="review"> |
| | | <?php |
| | | // Review text |
| | | if (!empty($comment)) { ?> |
| | | <div class="content review"> |
| | | <?= apply_filters('wpautop', $comment) ?> |
| | | </div> |
| | | <?php } ?> |
| | | <cite class="row start nowrap"> |
| | | <?php if (!empty($profilePhoto)) { ?> |
| | | <img src="<?=esc_url($profilePhoto)?>" |
| | | alt="<?=esc_attr($reviewer)?>" |
| | | 'loading="lazy"> |
| | | <?php } else { ?> |
| | | <div class="avatar"> |
| | | <?= jvbIcon('user-circle')?> |
| | | </div> |
| | | <?php } ?> |
| | | |
| | | <div class="row start wrap"> |
| | | <p><?= esc_html($reviewer)?></p> |
| | | <?php |
| | | // Date |
| | | if ($showDate && !empty($date)) { |
| | | $formatted_date = human_time_diff(strtotime($date), current_time('timestamp')) . ' ago'; |
| | | ?> |
| | | <time datetime="<?=esc_attr($date)?>"> |
| | | <?= esc_html($formatted_date) ?> |
| | | </time> |
| | | <?php } ?> |
| | | <?php if ($showRating && $rating > 0) { ?> |
| | | <div class="stars" aria-label="<?= $rating ?> out of 5 stars"> |
| | | <?php |
| | | for ($i = 1; $i <= 5; $i++) { |
| | | echo ($i <= $rating) ? jvbIcon('star', ['style' => 'fill']) : jvbIcon('star', ['style' => 'light']); |
| | | } ?> |
| | | </div> |
| | | <?php } ?> |
| | | </div> |
| | | </cite> |
| | | </blockquote> |
| | | </li> |
| | | <?php |
| | | } |
| | | ?> |
| | | </ul> |
| | | <?php |
| | | // Footer with "See All Reviews" button |
| | | if ($showViewAllLink && !empty($viewAllUrl)) { |
| | | ?> |
| | | <div class="footer"> |
| | | <a href=" <?= esc_url($viewAllUrl) ?>" |
| | | class="button" |
| | | target="_blank" |
| | | rel="noopener noreferrer"> |
| | | |
| | | <?php |
| | | if ($showStats ) { |
| | | echo 'See All ' . number_format($total) . ' Reviews'; |
| | | } else { |
| | | echo ' See All Reviews'; |
| | | } |
| | | ?> |
| | | <?= jvbIcon('arrow-square-out') ?> |
| | | </a> |
| | | </div> |
| | | <?php |
| | | } |
| | | ?> |
| | | </div> |
| | | <?php |
| | | return ob_get_clean(); |
| | | |
| | | } catch (\Exception $e) { |
| | | error_log('[GMB Reviews Block] Error: ' . $e->getMessage()); |
| | | return ''; |
| | | } |
| | | } |