Files
backPRO/templates/dashboard/seo-stats.php
Jacek Pyziak b2aead1fbe feat: Integrate DataForSEO for indexed pages tracking
- Updated CRON documentation to include DataForSEO metrics synchronization.
- Enhanced SettingsController to manage DataForSEO API credentials and settings.
- Modified SiteController to handle DataForSEO domain input.
- Updated Site model to accommodate DataForSEO data handling.
- Added methods in SiteSeoMetric model for DataForSEO data retrieval and validation.
- Implemented SiteSeoSyncService to synchronize SEO metrics from both SEMSTORM and DataForSEO.
- Enhanced dashboard templates to display indexed pages data.
- Updated settings and site creation/edit templates to include DataForSEO fields.
- Created migration for adding DataForSEO related columns in the database.
- Developed DataForSeoService to fetch indexed pages count from DataForSEO API.
2026-02-21 11:41:17 +01:00

159 lines
8.5 KiB
PHP

<h2 class="mb-4">Statystyki SEO (ostatnie dane)</h2>
<?php
$currentSort = (string) ($currentSort ?? 'traffic');
$currentDir = (string) ($currentDir ?? 'desc');
$sortLink = static function (string $column) use ($currentSort, $currentDir): string {
$nextDir = ($currentSort === $column && $currentDir === 'asc') ? 'desc' : 'asc';
return '/seo/stats?sort=' . urlencode($column) . '&dir=' . urlencode($nextDir);
};
$sortMark = static function (string $column) use ($currentSort, $currentDir): string {
if ($currentSort !== $column) {
return '';
}
return $currentDir === 'asc' ? ' ↑' : ' ↓';
};
$formatDelta = static function ($current, $previous): string {
if ($previous === null || $previous === '') {
return '<span class="text-muted">n/a</span>';
}
$curr = (float) $current;
$prev = (float) $previous;
if ($prev == 0.0) {
if ($curr == 0.0) {
return '<span class="text-muted">0%</span>';
}
return '<span class="text-muted">n/a</span>';
}
$delta = (($curr - $prev) / $prev) * 100.0;
$class = $delta > 0 ? 'text-success' : ($delta < 0 ? 'text-danger' : 'text-muted');
$sign = $delta > 0 ? '+' : '';
return '<span class="' . $class . '">' . $sign . number_format($delta, 1, '.', '') . '%</span>';
};
?>
<div class="card">
<div class="card-body p-0 table-responsive">
<table class="table table-sm table-hover mb-0 align-middle small">
<thead>
<tr>
<th>Strona</th>
<th>Status</th>
<th>Miesiac</th>
<th class="text-nowrap"><a class="link-dark text-decoration-none" href="<?= htmlspecialchars($sortLink('top3')) ?>">TOP3<?= htmlspecialchars($sortMark('top3')) ?></a></th>
<th class="text-nowrap"><a class="link-dark text-decoration-none" href="<?= htmlspecialchars($sortLink('top10')) ?>">TOP10<?= htmlspecialchars($sortMark('top10')) ?></a></th>
<th class="text-nowrap"><a class="link-dark text-decoration-none" href="<?= htmlspecialchars($sortLink('top20')) ?>">TOP20<?= htmlspecialchars($sortMark('top20')) ?></a></th>
<th class="text-nowrap"><a class="link-dark text-decoration-none" href="<?= htmlspecialchars($sortLink('top50')) ?>">TOP50<?= htmlspecialchars($sortMark('top50')) ?></a></th>
<th class="text-nowrap"><a class="link-dark text-decoration-none" href="<?= htmlspecialchars($sortLink('traffic')) ?>">Ruch<?= htmlspecialchars($sortMark('traffic')) ?></a></th>
<th class="text-nowrap"><a class="link-dark text-decoration-none" href="<?= htmlspecialchars($sortLink('indexed_pages')) ?>">Zaindeksowane<?= htmlspecialchars($sortMark('indexed_pages')) ?></a></th>
<th>Aktualizacja</th>
<th></th>
</tr>
</thead>
<tbody>
<?php if (empty($rows)): ?>
<tr>
<td colspan="11" class="text-center text-muted py-4">Brak danych SEO.</td>
</tr>
<?php else: ?>
<?php foreach ($rows as $row): ?>
<?php
$siteUrl = (string) ($row['site_url'] ?? '');
$host = parse_url($siteUrl, PHP_URL_HOST);
$domain = is_string($host) && $host !== '' ? $host : $siteUrl;
?>
<tr>
<td class="text-nowrap" style="max-width: 260px;">
<a href="/sites/<?= (int) $row['site_id'] ?>/seo" class="text-decoration-none fw-semibold">
<?= htmlspecialchars($domain) ?>
</a>
</td>
<td class="text-nowrap">
<?php if ((int) ($row['is_active'] ?? 0) === 1): ?>
<span class="badge bg-success">ON</span>
<?php else: ?>
<span class="badge bg-secondary">OFF</span>
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= htmlspecialchars(date('m.Y', strtotime((string) $row['metric_month']))) ?>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= (int) $row['top3'] ?>
<small><?= $formatDelta($row['top3'], $row['prev_top3'] ?? null) ?></small>
<?php else: ?>
-
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= (int) $row['top10'] ?>
<small><?= $formatDelta($row['top10'], $row['prev_top10'] ?? null) ?></small>
<?php else: ?>
-
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= (int) $row['top20'] ?>
<small><?= $formatDelta($row['top20'], $row['prev_top20'] ?? null) ?></small>
<?php else: ?>
-
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= (int) $row['top50'] ?>
<small><?= $formatDelta($row['top50'], $row['prev_top50'] ?? null) ?></small>
<?php else: ?>
-
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= (int) $row['traffic'] ?>
<small><?= $formatDelta($row['traffic'], $row['prev_traffic'] ?? null) ?></small>
<?php else: ?>
-
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['metric_month'])): ?>
<?= (int) ($row['indexed_pages'] ?? 0) ?>
<small><?= $formatDelta($row['indexed_pages'] ?? 0, $row['prev_indexed_pages'] ?? null) ?></small>
<?php else: ?>
-
<?php endif; ?>
</td>
<td class="text-nowrap">
<?php if (!empty($row['updated_at'])): ?>
<?= htmlspecialchars(date('d.m.Y H:i', strtotime((string) $row['updated_at']))) ?>
<?php else: ?>
<span class="text-muted">-</span>
<?php endif; ?>
</td>
<td class="text-nowrap">
<a href="/sites/<?= (int) $row['site_id'] ?>/seo" class="btn btn-sm btn-outline-primary" title="SEO Panel">
<i class="bi bi-graph-up"></i>
</a>
</td>
</tr>
<?php endforeach; ?>
<?php endif; ?>
</tbody>
</table>
</div>
</div>