feat(reviews): ordenar por recentes/completas, só com foto, cartão com foto grande
A Places API (New) não tem parâmetro de ordenação e devolve no máximo 5 reviews, por isso ordem e filtro aplicam-se a essas 5: relevância (ordem da Google), mais recentes (publishTime) ou mais completas (texto mais longo), e opcionalmente só quem tem foto de perfil. Mudar estas opções já não apaga a cache — só uma nova chave ou Place ID obriga a um novo pedido pago. Cartão: foto de 84px (ou inicial), nome, data e estrelas grandes em cima; texto mais pequeno por baixo. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
f95c9ebc52
commit
1614bf327b
4 files changed
+101
-37
No files matched your search
@@ -8,11 +8,15 @@
|
||||
// google_reviews_min_rating — only reviews with at least this many stars (default 4)
|
||||
// google_reviews_max — how many to show (default 3)
|
||||
// google_reviews_cache_hours — how long a fetch is reused (default 24)
|
||||
// google_reviews_sort — relevance (Google's order) | newest | longest
|
||||
// google_reviews_photo_only — only reviewers with a profile photo (0/1)
|
||||
//
|
||||
// Two limits of the API shape the section:
|
||||
// - Place Details returns at most 5 reviews, chosen by Google ("most
|
||||
// relevant"). There is no "only positive" query: we filter those 5 by
|
||||
// rating, so on a bad week fewer than `max` may qualify.
|
||||
// relevant"), and the New API has no sort parameter (checked 2026-09:
|
||||
// places.get only takes languageCode/regionCode/sessionToken). Rating,
|
||||
// photo, newest and longest are therefore applied to those 5 here, so on a
|
||||
// bad week fewer than `max` may qualify.
|
||||
// - Reviews are a billed Enterprise + Atmosphere field. Without the cache every
|
||||
// page view would be one billed call; with it, one call per cache window.
|
||||
//
|
||||
@@ -30,9 +34,16 @@ function reviews_config(): array {
|
||||
'min_rating' => max(1, min(5, (int) setting('google_reviews_min_rating', 4))),
|
||||
'max' => max(1, min(5, (int) setting('google_reviews_max', 3))),
|
||||
'cache_hours' => max(1, (int) setting('google_reviews_cache_hours', 24)),
|
||||
'sort' => in_array(setting('google_reviews_sort', 'relevance'), ['relevance', 'newest', 'longest'], true)
|
||||
? (string) setting('google_reviews_sort', 'relevance') : 'relevance',
|
||||
'photo_only' => (bool) (int) setting('google_reviews_photo_only', 0),
|
||||
];
|
||||
}
|
||||
|
||||
function reviews_sort_options(): array {
|
||||
return ['relevance' => 'Relevância (ordem da Google)', 'newest' => 'Mais recentes', 'longest' => 'Mais completas (texto mais longo)'];
|
||||
}
|
||||
|
||||
function reviews_configured(): bool {
|
||||
$c = reviews_config();
|
||||
return $c['api_key'] !== '' && $c['place_id'] !== '';
|
||||
@@ -163,9 +174,15 @@ function site_reviews(): ?array {
|
||||
try { $data = reviews_get(); } catch (Throwable $e) { error_log('[reviews] ' . $e->getMessage()); return null; }
|
||||
if (!$data || empty($data['reviews'])) return null;
|
||||
$c = reviews_config();
|
||||
$picked = array_values(array_filter($data['reviews'], fn($r) => $r['rating'] >= $c['min_rating'] && trim($r['text']) !== ''));
|
||||
// Highest rating first; Google's relevance order breaks ties (usort is stable).
|
||||
usort($picked, fn($a, $b) => $b['rating'] <=> $a['rating']);
|
||||
$picked = array_values(array_filter($data['reviews'], fn($r) =>
|
||||
$r['rating'] >= $c['min_rating'] && trim($r['text']) !== ''
|
||||
&& (!$c['photo_only'] || $r['author_photo'] !== '')));
|
||||
// 'relevance' keeps Google's order. usort is stable, so ties keep it too.
|
||||
if ($c['sort'] === 'newest') {
|
||||
usort($picked, fn($a, $b) => strcmp($b['published'], $a['published'])); // ISO-8601 sorts as text
|
||||
} elseif ($c['sort'] === 'longest') {
|
||||
usort($picked, fn($a, $b) => mb_strlen($b['text']) <=> mb_strlen($a['text']));
|
||||
}
|
||||
$picked = array_slice($picked, 0, $c['max']);
|
||||
if (!$picked) return null;
|
||||
return [
|
||||
|
||||
Reference in new issue
Block a user