Steamer Lane Studio技術備忘録ユーティリティ

Google ビジネスプロフィールのクチコミと評価を取り込む

utility Google ビジネスプロフィールのクチコミと評価を取り込む
最終更新日: 2025年3月27日

嫌いなAPI使う系。
だがGoogleのクチコミ偏重に応じるためにどこかの案件で追加することにした。
追加とともに(今のアルゴリズムだとあまり意味はなさそうだが)descriptinに「クチコミを案内」とか書いておく。

必要要件として
Google cloudでPlace APIを有効にしてAPIkeyを得る。
登録してあるビジネスプロフィールのPlaceIDを取得。このIDは管理者でないものも得ようと思えば得られるがそれはどうなのかなと思うな。
ページの拡張子がphp。これは今回phpスクリプトでコード書いたからだが、ベースはWordpressってのもある。またサーバーサイドの方が安定するしSEO上の評価が上がる可能性もあるのでphp版、実装コードからIDなどを抜いたものをサンプルとして。

<?php // Google Places APIのキー $apiKey = 'APIkey'; // 場所ID (事前にGoogle Maps Platformで取得) $placeId = 'GBP PlaceID'; // APIのエンドポイント $endpoint = 'https://maps.googleapis.com/maps/api/place/details/json?place_id=' . $placeId . '&fields=name,rating,reviews,user_ratings_total&language=ja&key=' . $apiKey; // APIを呼び出し、結果をJSON形式で取得 $response = file_get_contents($endpoint); $data = json_decode($response, true); // エラー処理 if (!$data || !isset($data['result'])) {     echo 'API呼び出しに失敗しました。または、指定された場所が見つかりません。';     exit; } // 評価件数を取得 $reviewCount = isset($data['result']['user_ratings_total']) ? (int)$data['result']['user_ratings_total'] : 0; // 口コミ・評価が0の場合 if ($reviewCount === 0) {               echo '<p>クチコミ・評価はありません。</p>'; } else {     // 評価を取得     $rating = isset($data['result']['rating']) ? round($data['result']['rating'], 1) : 0;     // 星を表示する関数     function displayStars($rating) {         for ($i = 0; $i < 5; $i++) {             $fractionalPart = $rating - floor($rating);             if ($i < floor($rating)) {                 echo '<span class="star filled"></span>';             } elseif ($fractionalPart >= 0.7 && $i == floor($rating)) {                 echo '<span class="star three-quarters"></span>';             } elseif ($fractionalPart >= 0.4 && $i == floor($rating)) {                 echo '<span class="star half"></span>';             } elseif ($fractionalPart >= 0.1 && $i == floor($rating)) {                 echo '<span class="star quarter"></span>';             } else {                 echo '<span class="star"></span>';             }         }     }     // 評価の表示     echo '<div class="rating"><p>';     echo '<span class="rating-value">' . htmlspecialchars($rating, ENT_QUOTES, 'UTF-8') . '</span>';     displayStars($rating);     echo '<span>' . htmlspecialchars($reviewCount, ENT_QUOTES, 'UTF-8') . '件の評価</span>';     echo '</p></div>';     // クチコミ数をカウント     $actualReviewCount = 0;     if (isset($data['result']['reviews'])) {         foreach ($data['result']['reviews'] as $review) {             if (!empty($review['text'])) {                 $actualReviewCount++;             }         }     }     // クチコミを表示     echo '<div class="reviewsWrap">';     if ($actualReviewCount > 0) {         echo '<p>' . htmlspecialchars($actualReviewCount, ENT_QUOTES, 'UTF-8') . '件のクチコミ</p>';         $reviews = array_slice($data['result']['reviews'], 0, 5);         foreach ($reviews as $review) {             if (!empty($review['text'])) {                 echo '<div class="review">';                 echo '<p><b>' . htmlspecialchars($review['author_name'], ENT_QUOTES, 'UTF-8') . '</b>';                 echo '' . htmlspecialchars($review['text'], ENT_QUOTES, 'UTF-8') . '</p>';                 echo '</div>';             }         }     } else {               echo '<p>クチコミはありません。</p>';     } // クチコミが5件を超えている場合に「もっと見る」リンクを表示、次の行の5を変えれば表示件数が変わり同時に何件以上からリンク先での閲覧になるかも変わる if ($actualReviewCount > 5) {     $linkUrl = 'GBPを表示するページのURL'; // クチコミをもっと見るリンクのURLを指定     echo '<a class="form-btn" style="width:auto;margin-top:30px;padding:0 20px" href="' . $linkUrl . '" target="_blank">クチコミをもっと見る</a>';     }     echo '</div>'; } ?>

APIkeyとPlaceIDは別個で取得して記述。
入れ子のhtmlは適当に直せばOK。
星マークは画像作ってCSSで当てればOK。ちなみにこのコードでは、レートに対する星の欠け具合を0.1~0.3、0.4~0.6、0.7~0.9と少し大雑把にしている。小さいものの見た目だけだが、拘るなら // 星を表示する関数部分を細かくすればOK。
PlaceIDを誰でも取れるのはちょっとどうかなとも思うな、取れないとそれで色々あるのだろうが、なら管理者以外は制限かかるとかしてほしいな。

APIだが、Newが発表され順次古いものが使えなくなるので、NewPlaceAPI用

<?php// Google Places APIのキー$apiKey = 'YOUR_API_KEY';// 場所ID (Google Maps Platformで取得済み)$placeId = 'TARGET_PLACE_ID';// 新しいAPIのエンドポイント$endpoint = "https://places.googleapis.com/v1/places/{$placeId}";// リクエストヘッダーとフィールド指定$fields = 'displayName,rating,userRatingCount,reviews'; // 必要なフィールドを指定$language = 'ja'; // 日本語を指定

// APIリクエストの設定$options = ['http' => ['method' => 'GET','header' => "X-Goog-Api-Key: {$apiKey}\r\n" ."X-Goog-FieldMask: {$fields}\r\n" ."Accept-Language: {$language}\r\n",],];$context = stream_context_create($options);

// APIを呼び出し、結果をJSON形式で取得$response = file_get_contents($endpoint, false, $context);$data = json_decode($response, true);

// エラー処理if (!$data || !isset($data['displayName'])) {echo 'API呼び出しに失敗しました。または、指定された場所が見つかりません。';exit;}

// 評価件数を取得$reviewCount = isset($data['userRatingCount']) ? (int)$data['userRatingCount'] : 0;

// 口コミ・評価が0の場合if ($reviewCount === 0) {echo '<p>クチコミ・評価はありません。</p>';} else {echo '<section class="guide"><h2>Googleでの評価・クチコミ</h2>';// 評価を取得$rating = isset($data['rating']) ? round($data['rating'], 1) : 0;

// 星を表示する関数(変更なし)function displayStars($rating) {for ($i = 0; $i < 5; $i++) {$fractionalPart = $rating - floor($rating);if ($i < floor($rating)) {echo '<span class="star filled"></span>';} elseif ($fractionalPart >= 0.7 && $i == floor($rating)) {echo '<span class="star three-quarters"></span>';} elseif ($fractionalPart >= 0.4 && $i == floor($rating)) {echo '<span class="star half"></span>';} elseif ($fractionalPart >= 0.1 && $i == floor($rating)) {echo '<span class="star quarter"></span>';} else {echo '<span class="star"></span>';}}}

// 評価の表示echo '<div class="rating"><p>';echo '<span class="rating-value">' . htmlspecialchars($rating, ENT_QUOTES, 'UTF-8') . '</span>';displayStars($rating);echo '<span>' . htmlspecialchars($reviewCount, ENT_QUOTES, 'UTF-8') . '件の評価</span>';echo '</p></div>';

// クチコミ数をカウント$actualReviewCount = 0;if (isset($data['reviews'])) {foreach ($data['reviews'] as $review) {if (!empty($review['text']['text'])) {$actualReviewCount++;}}}

// クチコミを表示echo '<div class="reviewsWrap">';if ($actualReviewCount > 0) {echo '<p>' . htmlspecialchars($actualReviewCount, ENT_QUOTES, 'UTF-8') . '件のクチコミ</p>';

$reviews = array_slice($data['reviews'], 0, 5);foreach ($reviews as $review) {if (!empty($review['text']['text'])) {echo '<div class="review">';echo '<p><b>' . htmlspecialchars($review['authorAttribution']['displayName'], ENT_QUOTES, 'UTF-8') . '</b>';echo htmlspecialchars($review['text']['text'], ENT_QUOTES, 'UTF-8') . '</p>';echo '</div>';}}} else {echo '<p>クチコミはありません。</p>';}

// 口コミをもっと見るリンク if ($actualReviewCount > 5) {$linkUrl = "https://www.google.com/maps/place/?q=place_id:{$placeId}";echo '<a class="form-btn" style="width:auto;margin-top:30px;padding:0 20px" href="' . htmlspecialchars($linkUrl, ENT_QUOTES, 'UTF-8') . '" target="_blank">クチコミをもっと見る</a>';}echo '</div>';echo '</section>';}?>

追記
上記コードでは、APIキー設定で「キーの制限」をリファラで行った際に403が返される。
どうもGoogle側のセキュリティが厳しいらしいので、リファラでのキー制限する際の差し替えコードを作った。
APIキーをIPアドレスでの制限にすれば大丈夫かもしれない(未検証)。

以下差し替え部分// APIリクエストの設定$options = ['http' => ['method' => 'GET','header' => "X-Goog-Api-Key: {$apiKey}\r\n" ."X-Goog-FieldMask: {$fields}\r\n" ."Accept-Language: {$language}\r\n",],];$context = stream_context_create($options);

// APIを呼び出し、結果をJSON形式で取得$response = file_get_contents($endpoint, false, $context);$data = json_decode($response, true);

以下に差し替え

$scheme = isset($_SERVER['REQUEST_SCHEME']) ? $_SERVER['REQUEST_SCHEME'] : 'https'; // プロトコル取得、デフォルトは https$host = $_SERVER['HTTP_HOST']; // ホスト名取得$referer = "$scheme://$host"; // リファラー生成

$ch = curl_init();curl_setopt($ch, CURLOPT_URL, $endpoint);curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);curl_setopt($ch, CURLOPT_HTTPHEADER, ["X-Goog-Api-Key: {$apiKey}","X-Goog-FieldMask: {$fields}","Accept-Language: {$language}","Referer: {$referer}" // 動的リファラー]);$response = curl_exec($ch);$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);if ($response === false || $httpCode !== 200) {error_log("cURL Error: " . curl_error($ch) . " | HTTP Code: $httpCode | Response: " . $response);echo 'API呼び出しに失敗しました。詳細はログを確認してください。';curl_close($ch);exit;}curl_close($ch);

$data = json_decode($response, true);