From 0e4b986e81f8132a44e61fa8df18860301cc3468 Mon Sep 17 00:00:00 2001
From: Jake Vanderwerf <get@jakevanderwerf.ca>
Date: Thu, 01 Jan 2026 20:31:10 +0000
Subject: [PATCH] =JakeVan preliminary additions
---
inc/integrations/GoogleMyBusiness.php | 178 +++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 159 insertions(+), 19 deletions(-)
diff --git a/inc/integrations/GoogleMyBusiness.php b/inc/integrations/GoogleMyBusiness.php
index 37a6821..6ac8ed5 100644
--- a/inc/integrations/GoogleMyBusiness.php
+++ b/inc/integrations/GoogleMyBusiness.php
@@ -10,9 +10,12 @@
class GoogleMyBusiness extends Integrations
{
- private string $access_token;
+ private ?string $access_token = null;
protected string $readMask = 'name,title,storefrontAddress,metadata,openInfo,storeCode,categories,phoneNumbers,labels,specialHours';
private ?string $location = null;
+ private ?string $refresh_token = null;
+ private ?string $client_id = null;
+ private ?string $client_secret = null;
private ?string $account_id = null;
public function __construct(?int $userID = null)
@@ -35,6 +38,7 @@
];
$this->apiEndpoints = [
+ '/accounts/[^/]+/locations/[^/]+/reviews',
'/accounts/[^/]+/locations/[^/]+/foodMenus',
'/v4/accounts/[^/]+/locations/[^/]+/media',
'/v4/accounts/[^/]+/locations/[^/]+/localPosts',
@@ -81,18 +85,18 @@
'label' => 'OAuth Client Secret',
'required' => true,
],
- 'access_token' => [
- 'type' => 'text',
- 'subtype' => 'password',
- 'label' => 'Access Token',
- 'hint' => 'Generated automagically after OAuth authorization.'
- ],
- 'refresh_token' => [
- 'type' => 'text',
- 'subtype' => 'password',
- 'label' => 'Refresh Token',
- 'hint' => 'Generated automagically after OAuth authorization.'
- ]
+// 'access_token' => [
+// 'type' => 'text',
+// 'subtype' => 'password',
+// 'label' => 'Access Token',
+// 'hint' => 'Generated automagically after OAuth authorization.'
+// ],
+// 'refresh_token' => [
+// 'type' => 'text',
+// 'subtype' => 'password',
+// 'label' => 'Refresh Token',
+// 'hint' => 'Generated automagically after OAuth authorization.'
+// ]
];
$this->advanced = [
@@ -124,6 +128,8 @@
'check_oauth_status' => 'Check OAuth Status'
]
);
+
+// $this->cache->clear();
}
protected function initialize(): void
@@ -131,12 +137,12 @@
if (empty($this->credentials)) {
$this->loadCredentials();
}
- $this->access_token = $this->credentials['access_token'] ?? '';
- $this->refresh_token = $this->credentials['refresh_token'] ?? '';
- $this->client_id = $this->credentials['client_id'] ?? '';
- $this->client_secret = $this->credentials['client_secret'] ?? '';
- $this->location = $this->credentials['location'] ?? null;
- $this->account_id = $this->credentials['account'] ?? null;
+ $this->access_token = (array_key_exists('access_token', $this->credentials)) ? $this->credentials['access_token'] : null;
+ $this->refresh_token = (array_key_exists('refresh_token', $this->credentials)) ? $this->credentials['refresh_token'] : null;
+ $this->client_id = (array_key_exists('client_id', $this->credentials)) ? $this->credentials['client_id'] : null;
+ $this->client_secret = (array_key_exists('client_secret', $this->credentials)) ? $this->credentials['client_secret'] : null;
+ $this->location = (array_key_exists('location', $this->credentials)) ? $this->credentials['location'] : null;
+ $this->account_id = (array_key_exists('account', $this->credentials)) ? $this->credentials['account'] : null;
if ($this->account_id) {
$this->apiEndpoints[] = "/v1/{$this->account_id}/locations";
@@ -157,6 +163,16 @@
}
}
+ /**
+ * Check if response contains an error - Google-specific
+ */
+ protected function isErrorResponse(array $response): bool
+ {
+ // Google APIs return errors in this format:
+ // {"error": {"code": 401, "message": "...", "status": "UNAUTHENTICATED"}}
+ return isset($response['error']) && isset($response['error']['code']);
+ }
+
protected function getRequestHeaders(): array
{
return [
@@ -1431,6 +1447,128 @@
}
/**
+ * Get reviews for the current location
+ * @param int $page_size Number of reviews to fetch (max 50)
+ * @return array|null
+ */
+ public function getReviews(int $page_size = 5): ?array
+ {
+ $this->ensureInitialized();
+ if (!$this->location) {
+ throw new \Exception('No location selected');
+ }
+ if (!$this->account_id) {
+ throw new \Exception('No account configured');
+ }
+
+ $location = $this->getSelectedLocationResourceName();
+ $account = $this->account_id;
+
+
+ // Check cache first (weekly refresh = 604800 seconds)
+ $cache_key = ['reviews', $location, $page_size];
+ $cached = $this->cache->get($cache_key);
+ if ($cached !== false) {
+ return $cached;
+ }
+
+ try {
+ // Reviews endpoint from My Business Account Management API
+ $response = $this->getRequest(
+ "/{$account}/{$location}/reviews",
+ [
+ 'orderBy' => 'updateTime desc'
+ ],
+ 'v4'
+ );
+
+ error_log('Review response: '.print_r($response, true));
+ $reviews = $response ?? [];
+
+ // Cache for 1 week (604800 seconds)
+ $this->cache->set($cache_key, $reviews, WEEK_IN_SECONDS);
+
+ return $reviews;
+
+ } catch (\Exception $e) {
+ $this->logError($e->getMessage(), [
+ 'method' => 'getReviews'
+ ]);
+ return null;
+ }
+ }
+
+ /**
+ * Get the URL to view all Google reviews for the current location
+ * @return string|null The reviews viewing URL or null if not available
+ */
+ public function getReviewsViewUrl(): ?string
+ {
+ $this->ensureInitialized();
+ try {
+ $location = $this->getLocation();
+
+ if (empty($location)) {
+ return null;
+ }
+
+ // Prefer maps URL as it shows all reviews directly
+ if (!empty($location['metadata']['mapsUrl'])) {
+ return $location['metadata']['mapsUrl'];
+ }
+
+ // Fallback: construct from Place ID
+ if (!empty($location['metadata']['placeId'])) {
+ return 'https://search.google.com/local/reviews?placeid=' .
+ urlencode($location['metadata']['placeId']);
+ }
+
+ return null;
+
+ } catch (\Exception $e) {
+ $this->logError('Failed to get reviews view URL: ' . $e->getMessage(), [
+ 'method' => 'getReviewsViewUrl'
+ ]);
+ return null;
+ }
+ }
+
+ /**
+ * Get the URL to leave a review for the current location
+ * @return string|null The review URL or null if not available
+ */
+ public function getReviewUrl(): ?string
+ {
+ $this->ensureInitialized();
+ try {
+ $location = $this->getLocation();
+
+ if (empty($location)) {
+ return null;
+ }
+
+ // Try to use Place ID for write review
+ if (!empty($location['metadata']['placeId'])) {
+ return 'https://search.google.com/local/writereview?placeid=' .
+ urlencode($location['metadata']['placeId']);
+ }
+
+ // Fallback to maps URL
+ if (!empty($location['metadata']['mapsUrl'])) {
+ return $location['metadata']['mapsUrl'] . '/reviews';
+ }
+
+ return null;
+
+ } catch (\Exception $e) {
+ $this->logError('Failed to get review URL: ' . $e->getMessage(), [
+ 'method' => 'getReviewUrl'
+ ]);
+ return null;
+ }
+ }
+
+ /**
* Get locations for an account (with persistent storage)
* Allowed Fields: https://developers.google.com/my-business/content/location-data#list_of_all_supported_filter_fields
*/
@@ -2884,4 +3022,6 @@
]
];
}
+
+
}
--
Gitblit v1.10.0