From 46d681c6b825d21b3f698d793c4e630c687d90ad Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 21 May 2026 21:41:53 +0000
Subject: [PATCH] =Major CustomBlocks.php overhaul, expanding block support and customization from the editor. theme.json should now be updated on new themes to set brand colours, etc. Also note: major change to .col vs .row alignment: simplifying it to .top .bottom vs the confusion of the differences for .col/.row .start and .a-start

---
 src/gmbreviews/render.php |  207 +++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 207 insertions(+), 0 deletions(-)

diff --git a/src/gmbreviews/render.php b/src/gmbreviews/render.php
new file mode 100644
index 0000000..487f394
--- /dev/null
+++ b/src/gmbreviews/render.php
@@ -0,0 +1,207 @@
+<?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;
+	}else {
+		$inheritUser = null;
+	}
+	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 center">
+			<?php
+			if ($showStats && !empty($average) && !empty($total)) {
+				?>
+				<p>
+					<span class="stars" title="<?= $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
+			}
+			?>
+
+
+		</div>
+			<?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
+			}
+			?>
+
+		<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 left 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 left wrap">
+								<?php if ($showRating && $rating > 0) { ?>
+									<div class="stars" title="<?= $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 } ?>
+								<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 } ?>
+
+							</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 '';
+	}
+}

--
Gitblit v1.10.0