PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.9.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.9.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 1.0.1 All 51 releases
← All changes | includes/seo/email-report-sections/class-position-summary-section.php +45 -20 2.5.0 → 2.9.0 View file →
@@ -1,10 +1,11 @@
1 1 <?php
2 2 /**
3 - * Position Summary Section
3 + * Position Summary Section — "Where your keywords rank".
4 4 *
5 - * Buckets tracked keywords into Top 3 / 4–10 / 11–50 / 51–100 brackets.
6 - * Source: GSC `position_distribution` already computed by Analytics_Manager.
5 + * Buckets the period's queries into Top 3 / 4–10 / 11–50 / 51–100 and draws
6 + * them as bars. Source: GSC `position_distribution` already computed by
7 + * Analytics_Manager.
7 8 *
8 9 * @package ThinkRank
9 10 * @subpackage SEO\Email_Report_Sections
10 11 * @since 1.9.0
@@ -24,9 +25,9 @@
24 25 return 'position_summary';
25 26 }
26 27
27 28 public function label(): string {
28 - return __('Position Summary', 'thinkrank');
29 + return __('Where your keywords rank', 'thinkrank');
29 30 }
30 31
31 32 public function default_enabled(): bool {
32 33 return true;
@@ -35,8 +36,12 @@
35 36 public function requires_capability(): ?string {
36 37 return null;
37 38 }
38 39
40 + public function renders_own_heading(): bool {
41 + return true;
42 + }
43 +
39 44 public function collect(array $context): array {
40 45 $shared = $context['shared'] ?? [];
41 46 if (empty($shared['available'])) {
42 47 return [];
@@ -52,29 +57,49 @@
52 57 '51_100' => (int) ($dist['51_100'] ?? 0),
53 58 ];
54 59 }
55 60
61 + public function has_data(array $payload): bool {
62 + return array_sum(array_map('intval', $payload)) > 0;
63 + }
64 +
56 65 public function render(array $payload): string {
57 - $rows = [
58 - __('Top 3', 'thinkrank') => $payload['top_3'],
59 - __('Position 4–10', 'thinkrank') => $payload['4_10'],
60 - __('Position 11–50', 'thinkrank') => $payload['11_50'],
61 - __('Position 51–100', 'thinkrank') => $payload['51_100'],
66 + $counts = [
67 + 'top_3' => (int) ($payload['top_3'] ?? 0),
68 + '4_10' => (int) ($payload['4_10'] ?? 0),
69 + '11_50' => (int) ($payload['11_50'] ?? 0),
70 + '51_100' => (int) ($payload['51_100'] ?? 0),
62 71 ];
72 + $total = array_sum($counts);
73 + if ($total === 0) {
74 + return '';
75 + }
76 + $page_one = $counts['top_3'] + $counts['4_10'];
63 77
64 - $html = '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="border-collapse:collapse;">';
65 - foreach ($rows as $label => $count) {
66 - $html .= '<tr>'
67 - . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;color:#374151;font:500 14px/1.4 -apple-system,Segoe UI,Roboto,sans-serif;">' . esc_html($label) . '</td>'
68 - . '<td style="padding:10px 12px;border-bottom:1px solid #e5e7eb;text-align:right;color:#111827;font:700 14px/1.4 -apple-system,Segoe UI,Roboto,sans-serif;">' . esc_html(number_format_i18n((int) $count)) . '</td>'
69 - . '</tr>';
70 - }
71 - $html .= '</table>';
78 + $html = Email_Report_Html::heading(
79 + $this->label(),
80 + sprintf(
81 + /* translators: %s: number of queries. */
82 + _n('%s query got at least one impression this period', '%s queries got at least one impression this period', $total, 'thinkrank'),
83 + number_format_i18n($total)
84 + )
85 + );
86 + $html .= '<table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="margin-top:14px;">'
87 + . Email_Report_Html::bar_row(__('Top 3', 'thinkrank'), $counts['top_3'], $total, Email_Report_Html::PRIMARY)
88 + . Email_Report_Html::bar_row(__('Positions 4–10', 'thinkrank'), $counts['4_10'], $total, '#6e79ff')
89 + . Email_Report_Html::bar_row(__('Positions 11–50', 'thinkrank'), $counts['11_50'], $total, '#b3b9ff')
90 + . Email_Report_Html::bar_row(__('Positions 51–100', 'thinkrank'), $counts['51_100'], $total, '#dcdfff')
91 + . '</table>';
92 + $html .= Email_Report_Html::note(sprintf(
93 + /* translators: %s: number of queries ranking in positions 1–10. */
94 + _n('%s query is on page one.', '%s queries are on page one.', $page_one, 'thinkrank'),
95 + number_format_i18n($page_one)
96 + ));
97 + $html .= Email_Report_Html::link(__('See all keywords', 'thinkrank'), Email_Report_Html::admin_link('analytics', 'keywords'));
98 +
72 99 return $html;
73 100 }
74 101
75 102 public function fallback_html(): string {
76 - return '<p style="color:#6b7280;font-style:italic;">'
77 - . esc_html__('Search Console data unavailable. Connect Search Console to see position distribution.', 'thinkrank')
78 - . '</p>';
103 + return '';
79 104 }
80 105 }