PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.10.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.10.0
2.11.0 2.10.0 2.9.0 2.8.0 2.7.0 2.6.0 2.5.0 2.4.0 2.3.0 2.2.0 2.1.1 2.1.0 2.0.2 2.0.1 2.0.0 1.32.0 1.31.0 1.30.0 1.29.0 1.28.0 1.27.0 1.26.0 1.25.0 trunk 1.0.0 All 52 releases
← All changes | includes/seo/email-report-sections/class-top-losing-posts-section.php +24 -7 2.0.2 → 2.10.0 View file →
@@ -1,11 +1,12 @@
1 1 <?php
2 2 /**
3 - * Top Losing Posts Section
3 + * Top Losing Posts Section — "Pages losing ground".
4 4 *
5 5 * Pages with the largest click loss vs the previous period, computed from
6 6 * the shared current-vs-previous comparison the Data Provider builds from
7 - * Search Console (page dimension).
7 + * Search Console (page dimension). A page that dropped out of the current
8 + * window entirely still appears — the comparison keys off both windows.
8 9 *
9 10 * @package ThinkRank
10 11 * @subpackage SEO\Email_Report_Sections
11 12 * @since 1.9.0
@@ -27,9 +28,9 @@
27 28 return 'top_losing_posts';
28 29 }
29 30
30 31 public function label(): string {
31 - return __('Top Losing Posts', 'thinkrank');
32 + return __('Pages losing ground', 'thinkrank');
32 33 }
33 34
34 35 public function default_enabled(): bool {
35 36 return true;
@@ -38,8 +39,12 @@
38 39 public function requires_capability(): ?string {
39 40 return null;
40 41 }
41 42
43 + public function renders_own_heading(): bool {
44 + return true;
45 + }
46 +
42 47 public function collect(array $context): array {
43 48 $shared = $context['shared'] ?? [];
44 49 $comparison = $shared['comparison'] ?? [];
45 50 if (empty($comparison['available']) || empty($comparison['pages'])) {
@@ -59,8 +64,9 @@
59 64 'change' => $delta,
60 65 ];
61 66 }
62 67
68 + // Biggest click loss first (most negative).
63 69 usort($rows, static fn($a, $b) => $a['change'] <=> $b['change']);
64 70
65 71 return [
66 72 'rows' => array_slice($rows, 0, self::MAX_ROWS),
@@ -66,14 +72,25 @@
66 72 'rows' => array_slice($rows, 0, self::MAX_ROWS),
67 73 ];
68 74 }
69 75
76 + public function has_data(array $payload): bool {
77 + return !empty($payload['rows']);
78 + }
79 +
70 80 public function render(array $payload): string {
71 - return Top_Posts_Renderer::render($payload['rows'] ?? [], 'loss');
81 + $rows = Top_Posts_Renderer::page_rows($payload['rows'] ?? []);
82 + if ($rows === []) {
83 + return '';
84 + }
85 + return Email_Report_Html::heading(
86 + $this->label(),
87 + __('Worth a look: these pages lost the most clicks vs the previous period', 'thinkrank')
88 + )
89 + . Email_Report_Html::list_rows($rows, 'down')
90 + . Email_Report_Html::link(__('See all pages', 'thinkrank'), Email_Report_Html::admin_link('analytics', 'dashboard'));
72 91 }
73 92
74 93 public function fallback_html(): string {
75 - return '<p style="color:#6b7280;font-style:italic;">'
76 - . esc_html__('Search Console data unavailable. Connect Search Console to see your losing posts.', 'thinkrank')
77 - . '</p>';
94 + return '';
78 95 }
79 96 }