Tutorial: Google Analytics 4 Custom Dashboard + Serverside Tracking în WordPress
Partea 1: Setup Google Analytics 4 API
Pas 1: Creează Service Account în Google Cloud
-
Mergi la Google Cloud Console: console.cloud.google.com/
-
Click Create Project → nume: “Analytics Blog” → Create
-
Selectează project-ul nou creat din dropdown (sus)
-
Mergi la APIs & Services → Library
-
Caută “Google Analytics Data API” → Click → Enable
Pas 2: Creează Service Account
-
APIs & Services → Credentials
-
Click Create Credentials → Service Account
-
Nume: “analytics-reader” → Create
-
Skip permisiuni (click Continue → Done)
Pas 3: Generează JSON Key
-
Click pe service account creat (email care se termină în
@...iam.gserviceaccount.com) -
Tab Keys → Add Key → Create new key
-
Format: JSON → Create
-
Se descarcă automat
credentials.json– salvează-l!
Pas 4: Adaugă Service Account la Google Analytics
-
Mergi la Google Analytics: analytics.google.com/
-
Click Admin (gear icon, jos stânga)
-
Property Settings → Property Access Management
-
Click + → Add users
-
Email: copiază email-ul service account (din step 2.3:
analytics-reader@...iam.gserviceaccount.com) -
Role: Viewer → Add
Pas 5: Găsește Property ID
-
În Google Analytics: Admin → Property Settings
-
Copiază Property ID (ex:
448899004) – îl vei folosi mai târziu
Partea 2: Setup WordPress – Google Analytics Dashboard
Pas 6: Creează folder pentru credentials
# Via FTP sau File Manager
wp-content/ga-credentials/
Încarcă credentials.json în acest folder.
IMPORTANT: Adaugă fișier index.php gol în folder pentru securitate:
<?php
// Empty index for security
?>
Pas 7: Creează Template pentru dashboard
Locație: /wp-content/themes/YOUR-THEME/page-trafic.php
<?php
/**
* Template Name: GA Traffic Dashboard
*/
get_header();
$cache_key = 'ga_analytics_data_all';
$cache_time = 30 * MINUTE_IN_SECONDS;
$cached_data = get_transient($cache_key);
if ($cached_data) {
$ga_data = $cached_data['ga_data'];
$ga2_data = $cached_data['ga2_data'];
$pages_data = $cached_data['pages_data'];
$devices_data = $cached_data['devices_data'];
} else {
$credentials_path = WP_CONTENT_DIR . '/ga-credentials/credentials.json';
$credentials = json_decode(file_get_contents($credentials_path), true);
$property_id = 'YOUR_PROPERTY_ID'; // Paste Property ID din Pas 5
$client_email = $credentials['client_email'];
$private_key = $credentials['private_key'];
$now = time();
$header = ['alg' => 'RS256', 'typ' => 'JWT'];
$claim = [
'iss' => $client_email,
'scope' => 'https://www.googleapis.com/auth/analytics.readonly',
'aud' => 'https://oauth2.googleapis.com/token',
'exp' => $now + 3600,
'iat' => $now
];
$header64 = strtr(rtrim(base64_encode(json_encode($header)), '='), '+/', '-_');
$claim64 = strtr(rtrim(base64_encode(json_encode($claim)), '='), '+/', '-_');
$sign_input = $header64 . '.' . $claim64;
Citește și
Testele și evaluările pentru ADHD: Ghid complet pentru oricine vrea să afle sigur
pe Divergent.ro →
openssl_sign($sign_input, $signature, $private_key, 'RSA-SHA256');
$signature64 = strtr(rtrim(base64_encode($signature), '='), '+/', '-_');
$jwt = $sign_input . '.' . $signature64;
$ch = curl_init('https://oauth2.googleapis.com/token');
curl_setopt_array($ch, [CURLOPT_RETURNTRANSFER => true, CURLOPT_POST => true, CURLOPT_POSTFIELDS => http_build_query(['grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer', 'assertion' => $jwt]), CURLOPT_TIMEOUT => 10]);
$token_response = curl_exec($ch);
curl_close($ch);
$token_data = json_decode($token_response, true);
$access_token = $token_data['access_token'] ?? null;
if (!$access_token) {
echo '<p>Error: No token</p>';
get_footer();
return;
}
// 30 DAYS METRICS
$ch = curl_init("https://analyticsdata.googleapis.com/v1beta/properties/{$property_id}:runReport");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $access_token, 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'dateRanges' => [['startDate' => '30daysAgo', 'endDate' => 'today']],
'metrics' => [
['name' => 'screenPageViews'],
['name' => 'activeUsers'],
['name' => 'sessions'],
['name' => 'averageSessionDuration'],
['name' => 'engagementRate'],
['name' => 'eventCount'],
['name' => 'conversions'],
['name' => 'totalUsers']
]
]),
CURLOPT_TIMEOUT => 10
]);
$ga_response = curl_exec($ch);
curl_close($ch);
$ga_data = json_decode($ga_response, true);
// TODAY vs YESTERDAY
$ch = curl_init("https://analyticsdata.googleapis.com/v1beta/properties/{$property_id}:runReport");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $access_token, 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'dateRanges' => [
['startDate' => 'today', 'endDate' => 'today'],
['startDate' => 'yesterday', 'endDate' => 'yesterday']
],
'metrics' => [
['name' => 'screenPageViews'],
['name' => 'activeUsers'],
['name' => 'sessions']
]
]),
CURLOPT_TIMEOUT => 10
]);
$ga2_response = curl_exec($ch);
curl_close($ch);
$ga2_data = json_decode($ga2_response, true);
// TOP PAGES
$ch = curl_init("https://analyticsdata.googleapis.com/v1beta/properties/{$property_id}:runReport");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $access_token, 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'dateRanges' => [['startDate' => '7daysAgo', 'endDate' => 'today']],
'metrics' => [['name' => 'screenPageViews']],
'dimensions' => [['name' => 'pagePath']],
'orderBys' => [['metric' => ['metricName' => 'screenPageViews'], 'desc' => true]],
'limit' => 10
]),
CURLOPT_TIMEOUT => 10
]);
$pages_response = curl_exec($ch);
curl_close($ch);
$pages_data = json_decode($pages_response, true);
// DEVICES
$ch = curl_init("https://analyticsdata.googleapis.com/v1beta/properties/{$property_id}:runReport");
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $access_token, 'Content-Type: application/json'],
CURLOPT_POSTFIELDS => json_encode([
'dateRanges' => [['startDate' => '7daysAgo', 'endDate' => 'today']],
'metrics' => [['name' => 'screenPageViews']],
'dimensions' => [['name' => 'deviceCategory']],
'orderBys' => [['metric' => ['metricName' => 'screenPageViews'], 'desc' => true]]
]),
CURLOPT_TIMEOUT => 10
]);
$devices_response = curl_exec($ch);
curl_close($ch);
$devices_data = json_decode($devices_response, true);
// SAVE CACHE
set_transient($cache_key, [
'ga_data' => $ga_data,
'ga2_data' => $ga2_data,
'pages_data' => $pages_data,
'devices_data' => $devices_data
], $cache_time);
}
?>
<div style="padding: 40px 20px; background: #f8f9fa; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;">
<h1 style="text-align: center; margin-bottom: 40px; color: #2d2d2d;">📊 Analytics</h1>
<?php if (isset($ga_data['rows'][0])): $row = $ga_data['rows'][0]; ?>
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
<h2 style="margin-top: 0; border-bottom: 2px solid #4285f4; padding-bottom: 10px;">Ultimele 30 de zile</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 15px;">
<div style="text-align: center; padding: 15px; background: #f9f9f9; border-radius: 4px;">
<small style="color: #999; display: block; text-transform: uppercase; font-size: 11px; font-weight: 600;">Views</small>
<strong style="font-size: 26px; color: #4285f4; display: block;"><?php echo number_format((int)($row['metricValues'][0]['value'] ?? 0)); ?></strong>
</div>
<div style="text-align: center; padding: 15px; background: #f9f9f9; border-radius: 4px;">
<small style="color: #999; display: block; text-transform: uppercase; font-size: 11px; font-weight: 600;">Active Users</small>
<strong style="font-size: 26px; color: #34a853; display: block;"><?php echo number_format((int)($row['metricValues'][1]['value'] ?? 0)); ?></strong>
</div>
<div style="text-align: center; padding: 15px; background: #f9f9f9; border-radius: 4px;">
<small style="color: #999; display: block; text-transform: uppercase; font-size: 11px; font-weight: 600;">Sessions</small>
<strong style="font-size: 26px; color: #fbbc04; display: block;"><?php echo number_format((int)($row['metricValues'][2]['value'] ?? 0)); ?></strong>
</div>
<div style="text-align: center; padding: 15px; background: #f9f9f9; border-radius: 4px;">
<small style="color: #999; display: block; text-transform: uppercase; font-size: 11px; font-weight: 600;">Events</small>
<strong style="font-size: 26px; color: #fbbc04; display: block;"><?php echo number_format((int)($row['metricValues'][5]['value'] ?? 0)); ?></strong>
</div>
</div>
</div>
<?php endif; ?>
<?php if (isset($ga2_data['rows'][0]) && isset($ga2_data['rows'][1])): $today = $ga2_data['rows'][0]; $yesterday = $ga2_data['rows'][1]; ?>
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
<h2 style="margin-top: 0; border-bottom: 2px solid #34a853; padding-bottom: 10px;">Today vs Yesterday</h2>
<div style="display: grid; grid-template-columns: 1fr 1fr; gap: 20px;">
<div>
<h3 style="color: #2d2d2d; margin-top: 0;">📅 Today</h3>
<div style="display: grid; gap: 8px;">
<div style="display: flex; justify-content: space-between; padding: 8px; background: #f9f9f9; border-radius: 4px;"><span>Views:</span><strong><?php echo number_format((int)($today['metricValues'][0]['value'] ?? 0)); ?></strong></div>
<div style="display: flex; justify-content: space-between; padding: 8px; background: #f9f9f9; border-radius: 4px;"><span>Users:</span><strong><?php echo number_format((int)($today['metricValues'][1]['value'] ?? 0)); ?></strong></div>
</div>
</div>
<div>
<h3 style="color: #2d2d2d; margin-top: 0;">📅 Yesterday</h3>
<div style="display: grid; gap: 8px;">
<div style="display: flex; justify-content: space-between; padding: 8px; background: #f9f9f9; border-radius: 4px;"><span>Views:</span><strong><?php echo number_format((int)($yesterday['metricValues'][0]['value'] ?? 0)); ?></strong></div>
<div style="display: flex; justify-content: space-between; padding: 8px; background: #f9f9f9; border-radius: 4px;"><span>Users:</span><strong><?php echo number_format((int)($yesterday['metricValues'][1]['value'] ?? 0)); ?></strong></div>
</div>
</div>
</div>
</div>
<?php endif; ?>
<?php if (isset($pages_data['rows']) && count($pages_data['rows']) > 0): ?>
<div style="background: white; padding: 20px; border-radius: 8px; margin-bottom: 20px;">
<h2 style="margin-top: 0; border-bottom: 2px solid #fbbc04; padding-bottom: 10px;">🔥 Top Pages (7 days)</h2>
<table style="width: 100%; border-collapse: collapse;">
<?php foreach (array_slice($pages_data['rows'], 0, 10) as $page): ?>
<tr style="border-bottom: 1px solid #f0f0f0;">
<td style="padding: 10px; font-size: 14px;"><?php echo htmlspecialchars($page['dimensionValues'][0]['value']); ?></td>
<td style="padding: 10px; text-align: right; font-weight: 600; color: #4285f4;"><?php echo number_format((int)($page['metricValues'][0]['value'] ?? 0)); ?></td>
</tr>
<?php endforeach; ?>
</table>
</div>
<?php endif; ?>
<?php if (isset($devices_data['rows']) && count($devices_data['rows']) > 0): ?>
<div style="background: white; padding: 20px; border-radius: 8px;">
<h2 style="margin-top: 0; border-bottom: 2px solid #ea4335; padding-bottom: 10px;">📱 Devices (7 days)</h2>
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 15px;">
<?php foreach ($devices_data['rows'] as $device): ?>
<div style="text-align: center; padding: 15px; background: #f9f9f9; border-radius: 4px;">
<small style="color: #999; display: block; text-transform: uppercase; font-size: 11px; font-weight: 600;"><?php echo htmlspecialchars($device['dimensionValues'][0]['value']); ?></small>
<strong style="font-size: 24px; color: #4285f4; display: block;"><?php echo number_format((int)($device['metricValues'][0]['value'] ?? 0)); ?></strong>
</div>
<?php endforeach; ?>
</div>
</div>
<?php endif; ?>
</div>
<?php get_footer();
Pas 8: Creează pagină în WordPress
-
WordPress Admin → Pages → Add New
-
Titlu: “Trafic”
-
Template: selectează GA Traffic Dashboard
-
Publish
-
Vizualizează pagina:
yoursite.com/trafic
Checklist Final
-
✅ Google Cloud Project creat
-
✅ Analytics Data API activată
-
✅ Service Account creat cu JSON key
-
✅ Service Account adăugat în GA cu rol Viewer
-
✅
credentials.jsonîncărcat în/wp-content/ga-credentials/ -
✅
page-trafic.phpcreat cu Property ID setat -
✅ Pagină WordPress creată cu template
-
Gata! Accesează
/traficși vezi dashboard-ul tău custom!
Adaugă comentariu