Em 2013, adicionar um mapa era colar um <iframe> de maps.google.com. Em 2026 a Google Maps Platform exige chave API, faturação ativa, restrições de segurança e decisões explícitas de RGPD. Um iframe “rápido” ainda funciona para um pin isolado - mas em sites de produção portugueses e europeus o custo aparece em PageSpeed, cookies e faturas surpresa.
Este guia cobre o fluxo de programador: chave segura, enqueue correto no WordPress, padrão fachada, consentimento, Map IDs e alternativas. Sem plugins monólito a não ser que o âmbito o justifique.
Parte 1: chave API sem ir à falência
- Crie um projeto na Google Cloud Console.
- Ative Maps JavaScript API (e só as APIs que vai usar, por exemplo Geocoding se precisar).
- Crie uma chave API ligada a uma conta de faturação.
- Defina alertas de orçamento - a chave é um cartão de crédito com URL pública se a restringir mal.
Restringir a chave
- Referrers HTTP:
https://oseudominio.pt/*e o staging se existir (https://staging.oseudominio.pt/*). - Restrições de API: apenas Maps JavaScript API (e Geocoding se necessário). Nunca “Todas as APIs”.
- Chaves de servidor (Geocoding no PHP) usam restrição por IP, não por referrer - não misture os dois tipos.
Documentação oficial de práticas: API security best practices.
Guarde a chave em wp-config.php ou variável de ambiente, não no repositório Git:
define( 'WPPOLAND_GMAPS_KEY', getenv( 'GMAPS_KEY' ) ?: '' );Parte 2: o mapa como assassino de performance
A Maps JavaScript API descarrega na ordem de ~2 MB de JavaScript e compete pela thread principal. Carregar no first paint da homepage pode custar dezenas de pontos no Lighthouse e piorar LCP/INP.
Padrão fachada (facade)
- Mostre uma imagem estática (AVIF/WebP) ou um mapa Static Maps.
- Só injete
maps.googleapis.comapós clique, ou após o mapa entrar no viewport e existir consentimento. - Inicialize o mapa no
callback(initMap).
Conceito em JS puro:
function loadGoogleMaps( apiKey ) {
if ( window.google && window.google.maps ) {
window.initMap();
return;
}
const script = document.createElement( 'script' );
script.src = 'https://maps.googleapis.com/maps/api/js?key=' + encodeURIComponent( apiKey ) + '&callback=initMap';
script.async = true;
script.defer = true;
document.head.appendChild( script );
}
document.getElementById( 'map-placeholder' )?.addEventListener( 'click', function () {
loadGoogleMaps( window.wppolandMaps.key );
} );No WordPress, prefira wp_enqueue_script / wp_add_inline_script e localize a chave só nas páginas que precisam do mapa - nunca em todo o site.
function wppoland_enqueue_maps_facade() {
if ( ! is_page( 'contacto' ) ) {
return;
}
wp_register_script( 'wppoland-maps-facade', get_stylesheet_directory_uri() . '/js/maps-facade.js', array(), '2026.09', true );
wp_localize_script(
'wppoland-maps-facade',
'wppolandMaps',
array(
'key' => defined( 'WPPOLAND_GMAPS_KEY' ) ? WPPOLAND_GMAPS_KEY : '',
'mapId' => 'YOUR_MAP_ID',
'lat' => 38.7223,
'lng' => -9.1393,
'consent' => false,
)
);
wp_enqueue_script( 'wppoland-maps-facade' );
}
add_action( 'wp_enqueue_scripts', 'wppoland_enqueue_maps_facade' );Ajuste o slug da página e as coordenadas. Lisboa é só exemplo; use a morada real do cliente.
Parte 3: RGPD e consentimento
O script do Google Maps contacta infraestruturas Google e pode definir cookies de rastreio. No EEE, não carregue o mapa até o utilizador aceitar a categoria relevante (marketing / cookies de terceiros, conforme o seu CMP).
Implementação típica:
- Contentor vazio ou imagem + botão: “Aceitar cookies e ver o mapa”.
- Escute o evento do Cookiebot, Complianz, ou da sua CMP custom.
- Só então chame
loadGoogleMaps().
Pseudocódigo:
window.addEventListener( 'CookiebotOnAccept', function () {
if ( Cookiebot.consent.marketing ) {
window.wppolandMaps.consent = true;
// Ainda pode exigir clique na fachada para performance.
}
} );Se faltar consentimento, mantenha a fachada. Não “pré-aqueça” o script em background - isso já é processamento de dados.
Para sites só com um pin e sem necessidade de interação: considere Static Maps API (PNG) ou Leaflet + OSM, que mudam o perfil de privacidade.
Parte 4: shortcode mínimo para editores
function wppoland_map_shortcode( $atts ) {
$atts = shortcode_atts(
array(
'lat' => '38.7223',
'lng' => '-9.1393',
'zoom' => '14',
),
$atts,
'wppoland_map'
);
ob_start();
?>
<div class="wppoland-map"
data-lat="<?php echo esc_attr( $atts['lat'] ); ?>"
data-lng="<?php echo esc_attr( $atts['lng'] ); ?>"
data-zoom="<?php echo esc_attr( $atts['zoom'] ); ?>">
<button type="button" id="map-placeholder" class="wppoland-map__facade">
<?php esc_html_e( 'Ver mapa interativo', 'wppoland' ); ?>
</button>
<div id="map" class="wppoland-map__canvas" hidden></div>
</div>
<?php
return ob_get_clean();
}
add_shortcode( 'wppoland_map', 'wppoland_map_shortcode' );O JS lê data-*, respeita consentimento e só então cria google.maps.Map. Escape sempre atributos. Não imprima a chave no HTML do shortcode - use wp_localize_script.
Parte 5: estilos com Map IDs
Deixe de hardcodar JSON gigante de estilos no tema. Na Cloud Console:
- Crie um estilo (modo escuro, sem POI de concorrentes, etc.).
- Associe a um Map ID.
- Passe
mapIdna inicialização JS.
window.initMap = function () {
const el = document.getElementById( 'map' );
el.hidden = false;
const map = new google.maps.Map( el, {
center: { lat: Number( window.wppolandMaps.lat ), lng: Number( window.wppolandMaps.lng ) },
zoom: 14,
mapId: window.wppolandMaps.mapId,
} );
new google.maps.marker.AdvancedMarkerElement( {
map: map,
position: { lat: Number( window.wppolandMaps.lat ), lng: Number( window.wppolandMaps.lng ) },
} );
};Atualiza o visual na nuvem sem novo deploy do tema. Confirme na documentação atual se o seu projeto já migrou para Advanced Markers - a API clássica google.maps.Marker está em depreciação gradual.
Parte 6: alternativas quando o Google não é obrigatório
| Abordagem | Custo | Privacidade | Interatividade |
|---|---|---|---|
| Iframe Maps | “Grátis” + cookies | Fraca | Básica |
| Maps JS API + fachada | Faturação Google | Requer CMP | Completa |
| Static Maps API | Por pedido | Melhor (imagem) | Nenhuma |
| Leaflet + OpenStreetMap | Infra própria / CDN | Melhor | Completa |
Para uma página de contacto com um pin: Static Maps ou Leaflet costumam bastar. Reserve a Maps JavaScript API para rotas, várias marcas, Street View ou UX que justifique o peso.
Checklist de produção
- Chave restrita por domínio e por API.
- Alertas de orçamento na Cloud Console.
- Script só na página necessária (
is_page/ bloco condicional). - Fachada + lazy-load; zero Maps no critical path.
- Bloqueio até consentimento no EEE.
- Map ID para branding; sem JSON de estilo no Git se possível.
- Teste Lighthouse antes/depois na página de contacto.
- Staging com chave de teste separada.
wp_enqueue vs script solto no footer
Nunca cole <script src="https://maps.googleapis.com/..."> diretamente no footer.php. Perde dependências, versão e a capacidade de condicionar o carregamento. Use wp_register_script + wp_enqueue_script + wp_localize_script (ou wp_add_inline_script para o callback). Em block themes, o mesmo JS pode ser anexado via enqueue_block_assets só quando o bloco do mapa está presente na página - meça com has_block no conteúdo.
Erros comuns de faturação
- Chave sem restrição de referrer usada num CodePen ou site espelho: a fatura sobe em horas.
- Geocoding no browser com a mesma chave do Maps JS sem cota separada.
- Preview do Elementor/Gutenberg a disparar dezenas de cargas de mapa por edição.
- Staging partilhado com a chave de produção e sem referrer de staging na allow-list (mapa parte) - ou staging aberto na allow-list para
*(mapa funciona, segurança não).
Separe projetos Cloud ou pelo menos chaves: prod, staging. Rode alertas em 50% e 90% do orçamento mensal.
Testar Core Web Vitals na página de contacto
- Lighthouse mobile na URL de contacto sem clicar no mapa: o JS do Google não deve aparecer na cascata.
- Depois do clique (e consentimento): aceite o custo; confirme que LCP do hero não depende do mapa.
- Compare com Static Maps: muitas vezes o LCP melhora e o RGPD simplifica.
Se o mapa estiver above-the-fold, a fachada deve ser uma imagem real com dimensões reservadas (width/height ou aspect-ratio) para não introduzir CLS quando o canvas interativo substitui o botão.
Marker accessibility
O mapa interativo não é navegável por teclado da mesma forma que um link “Abrir no Google Maps”. Ofereça sempre um fallback textual: morada completa + link https://www.google.com/maps/dir/?api=1&destination=LAT,LNG (ou o equivalente OSM). Leitores de ecrã e utilizadores com mapa bloqueado pelo CMP ainda chegam ao local.
Quando um plugin compensa
Um plugin de mapas justifica-se se a equipa editorial precisa de dezenas de localizações, rotas ou store locators sem developer em cada alteração. Para uma única morada de escritório, shortcode + fachada + CMP é menos superfície de ataque e menos PHP de terceiros a atualizar.
Resumo
Integrar Google Maps em 2026 é equilíbrio entre UX, faturação e conformidade. Restrinja a chave, atrase o JS com uma fachada, respeite o RGPD e use Map IDs para estilo. Se só precisa de um pin, questione se a JavaScript API é necessária.
Mais sobre velocidade: como acelerar um site WordPress. Para implementação em produção (CMP + fachada + enqueue): contacto.







