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.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
thinkrank / templates / email-report / email.html.php

email.html.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.10.0, at templates/email-report/email.html.php

197 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Email Report Layout
4 *
5 * Receives a $payload array assembled by Email_Report_Renderer.
6 *
7 * A light canvas with one centred 600px column: the logo row, an optional
8 * test-send banner, an optional intro, the section cards (each already a
9 * <tr> from Email_Report_Renderer::card()), the dashboard call to action
10 * and a quiet footer (#742).
11 *
12 * Email-client safety notes:
13 * - Inline styles only — Gmail / Outlook / Apple Mail strip / partially
14 * support <style> blocks. Anything that must render reliably is inline.
15 * - Tables for outer layout — most reliable across clients (especially
16 * older Outlook versions).
17 * - The header logo, logo link, header background, intro, footer, extra CSS
18 * and dashboard link are slots filled through the
19 * `thinkrank_email_report_payload` filter. A header background turns the
20 * logo row into a coloured band. Extra CSS goes into a <style> tag; CSS
21 * support varies across email clients.
22 *
23 * @var array $payload
24 *
25 * @package ThinkRank
26 */
27
28 declare(strict_types=1);
29
30 use ThinkRank\SEO\Email_Report_Renderer;
31 use ThinkRank\SEO\Email_Report_Sections\Email_Report_Html;
32
33 // This file is included from Email_Report_Renderer, so its variables live in
34 // that method's scope, not the global one — the prefix sniff assumes file
35 // scope means global scope. The unescaped echoes are the logo anchor, the
36 // section HTML and the cards, all assembled from esc_url()/esc_html() output
37 // above and in the section renderers; escaping them again would print
38 // entities in the email body.
39 // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound, WordPress.Security.EscapeOutput.OutputNotEscaped
40
41 if (!defined('ABSPATH')) {
42 exit;
43 }
44
45 $payload = isset($payload) && is_array($payload) ? $payload : [];
46 $site_title = (string) ($payload['site_title'] ?? '');
47 $site_url = (string) ($payload['site_url'] ?? '');
48 $header_logo = (string) ($payload['header_logo'] ?? '');
49 $header_bg = (string) ($payload['header_bg'] ?? '');
50 $logo_link = (string) ($payload['logo_link'] ?? '');
51 $intro_text = (string) ($payload['intro_text'] ?? '');
52 $sections_html = (string) ($payload['sections_html'] ?? '');
53 $footer_text = (string) ($payload['footer_text'] ?? '');
54 $additional_css = (string) ($payload['additional_css'] ?? '');
55 $cta_url = (string) ($payload['cta_url'] ?? '');
56 $settings_url = (string) ($payload['settings_url'] ?? '');
57 $frequency_label = (string) ($payload['frequency_label'] ?? '');
58 $context = (array) ($payload['context'] ?? []);
59 $period_label = (string) ($context['period_label'] ?? '');
60 $is_test = !empty($context['is_test']);
61 $not_connected = !empty($context['not_connected']);
62
63 $font = Email_Report_Html::FONT;
64 $ink = Email_Report_Html::INK;
65 $muted = Email_Report_Html::MUTED;
66 $canvas = Email_Report_Html::CANVAS;
67 $brand = Email_Report_Html::PRIMARY;
68
69 // Logo row. With a Pro header background it becomes a coloured band and the
70 // right-hand label goes white; otherwise it sits straight on the canvas.
71 $band = $header_bg !== '';
72 $header_style = $band
73 ? 'padding:18px 24px;background:' . esc_attr($header_bg) . ';border-radius:14px;'
74 : 'padding:0 4px;';
75 $label_color = $band ? '#ffffff' : $muted;
76
77 $logo_img = $header_logo !== ''
78 ? '<img src="' . esc_url($header_logo) . '" alt="' . esc_attr($site_title !== '' ? $site_title : 'ThinkRank') . '" height="32" style="display:block;border:0;max-height:32px;width:auto;" />'
79 : '<span style="' . $font . 'font-size:20px;font-weight:800;letter-spacing:-0.02em;color:' . ($band ? '#ffffff' : $ink) . ';">'
80 . esc_html($site_title !== '' ? $site_title : 'ThinkRank')
81 . '</span>';
82
83 if ($logo_link !== '') {
84 $logo_img = '<a href="' . esc_url($logo_link) . '" style="text-decoration:none;">' . $logo_img . '</a>';
85 }
86
87 $preheader = $not_connected
88 ? sprintf(
89 /* translators: %s: site title. */
90 __('Connect Google Search Console to start receiving SEO reports for %s.', 'thinkrank'),
91 $site_title
92 )
93 : sprintf(
94 /* translators: 1: site title, 2: period label. */
95 __('%1$s: your search performance for %2$s.', 'thinkrank'),
96 $site_title,
97 $period_label
98 );
99 ?>
100 <!doctype html>
101 <html lang="<?php echo esc_attr(str_replace('_', '-', get_locale())); ?>">
102 <head>
103 <meta charset="UTF-8" />
104 <meta name="viewport" content="width=device-width,initial-scale=1" />
105 <meta name="color-scheme" content="light" />
106 <title><?php echo esc_html($site_title); ?></title>
107 <?php if ($additional_css !== '') : ?>
108 <style type="text/css">
109 <?php echo esc_html($additional_css); ?>
110 </style>
111 <?php endif; ?>
112 </head>
113 <body style="margin:0;padding:0;background:<?php echo esc_attr($canvas); ?>;-webkit-font-smoothing:antialiased;">
114 <div style="display:none;max-height:0;overflow:hidden;opacity:0;mso-hide:all;"><?php echo esc_html($preheader); ?></div>
115 <table role="presentation" width="100%" cellpadding="0" cellspacing="0" style="background:<?php echo esc_attr($canvas); ?>;">
116 <tr>
117 <td align="center" style="padding:32px 16px;">
118 <table role="presentation" width="600" cellpadding="0" cellspacing="0" style="max-width:600px;width:100%;">
119
120 <tr>
121 <td style="padding:0 0 20px 0;">
122 <table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr><td style="<?php echo $header_style; ?>">
123 <table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr>
124 <td valign="middle"><?php echo $logo_img; ?></td>
125 <?php if ($frequency_label !== '') : ?>
126 <td align="right" valign="middle" style="<?php echo $font; ?>font-size:12px;color:<?php echo esc_attr($label_color); ?>;white-space:nowrap;"><?php echo esc_html($frequency_label); ?></td>
127 <?php endif; ?>
128 </tr></table>
129 </td></tr></table>
130 </td>
131 </tr>
132
133 <?php if ($is_test) : ?>
134 <tr>
135 <td style="padding:0 0 16px 0;">
136 <div style="<?php echo $font; ?>font-size:13px;color:#7a4b00;background:#fff4d6;border:1px solid #f5d98a;border-radius:10px;padding:10px 14px;">
137 <?php
138 // The connect state is not what a scheduled run sends: while
139 // Search Console is disconnected nothing goes out at all, so
140 // promising "the same layout" here contradicts the card below.
141 echo esc_html(
142 $not_connected
143 ? __('This is a test email sent from the ThinkRank dashboard. Scheduled reports stay paused until Search Console is connected.', 'thinkrank')
144 : __('This is a test email sent from the ThinkRank dashboard. Scheduled reports use the same layout.', 'thinkrank')
145 );
146 ?>
147 </div>
148 </td>
149 </tr>
150 <?php endif; ?>
151
152 <?php if ($intro_text !== '') : ?>
153 <?php echo Email_Report_Renderer::card('<div style="' . $font . 'font-size:15px;line-height:1.6;color:' . $ink . ';">' . wp_kses_post(wpautop($intro_text)) . '</div>', 'tr-email-intro'); ?>
154 <?php endif; ?>
155
156 <?php echo $sections_html; ?>
157
158 <?php if ($cta_url !== '' && !$not_connected) : ?>
159 <?php
160 echo Email_Report_Renderer::card(
161 '<table role="presentation" width="100%" cellpadding="0" cellspacing="0"><tr><td align="center" style="padding:6px 0 2px 0;">'
162 . '<a href="' . esc_url($cta_url) . '" style="display:inline-block;background:' . $brand . ';color:#ffffff;' . $font . 'font-size:15px;font-weight:700;text-decoration:none;padding:14px 28px;border-radius:10px;">'
163 . esc_html__('Open the full report in ThinkRank', 'thinkrank') . '</a>'
164 . '<div style="' . $font . 'font-size:12px;color:' . $muted . ';margin-top:12px;">'
165 . esc_html__('Page-by-page metrics, keyword history and AI suggestions live in your dashboard.', 'thinkrank')
166 . '</div></td></tr></table>',
167 'tr-email-cta',
168 '22px 28px'
169 );
170 ?>
171 <?php endif; ?>
172
173 <tr>
174 <td style="padding:8px 4px 0 4px;<?php echo $font; ?>font-size:12px;color:<?php echo esc_attr($muted); ?>;line-height:1.7;text-align:center;">
175 <?php echo wp_kses_post($footer_text); ?>
176 <?php if ($settings_url !== '' || $site_url !== '') : ?>
177 <br>
178 <?php if ($settings_url !== '') : ?>
179 <a href="<?php echo esc_url($settings_url); ?>" style="color:<?php echo esc_attr($muted); ?>;"><?php echo esc_html__('Report settings', 'thinkrank'); ?></a>
180 <?php endif; ?>
181 <?php if ($settings_url !== '' && $site_url !== '') : ?>
182 &nbsp;·&nbsp;
183 <?php endif; ?>
184 <?php if ($site_url !== '') : ?>
185 <a href="<?php echo esc_url($site_url); ?>" style="color:<?php echo esc_attr($muted); ?>;"><?php echo esc_html(wp_parse_url($site_url, PHP_URL_HOST) ?: $site_url); ?></a>
186 <?php endif; ?>
187 <?php endif; ?>
188 </td>
189 </tr>
190
191 </table>
192 </td>
193 </tr>
194 </table>
195 </body>
196 </html>
197