PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.14.1
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.14.1
2.14.1 2.14.0 2.13.0 2.12.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 All 56 releases
← All changes | includes/seo/class-email-report-config.php +43 -1 2.6.0 → 2.14.1 View file →
@@ -60,9 +60,9 @@
60 60
61 61 /**
62 62 * The resolved config every consumer reads.
63 63 *
64 - * @return array{enabled: bool, frequency_days: int, recipients: string[], sections_enabled: string[], next_scheduled_at: ?string, last_sent_at: ?string}
64 + * @return array{enabled: bool, frequency_days: int, recipients: string[], sections_enabled: string[], next_scheduled_at: ?string, last_sent_at: ?string, last_skip: ?array}
65 65 */
66 66 public function get(): array {
67 67 $this->load_defaults_file();
68 68
@@ -70,8 +70,11 @@
70 70 $state = [
71 71 'enabled' => !empty($stored['enabled']),
72 72 'next_scheduled_at' => $stored['next_scheduled_at'] ?? null,
73 73 'last_sent_at' => $stored['last_sent_at'] ?? null,
74 + // Why the last scheduled run sent nothing, or null. Read by the
75 + // panel so a paused report is never mistaken for a healthy one.
76 + 'last_skip' => is_array($stored['last_skip'] ?? null) ? $stored['last_skip'] : null,
74 77 ];
75 78
76 79 $report = [
77 80 'frequency_days' => self::FREQUENCY_DAYS,
@@ -182,8 +185,47 @@
182 185 return $this->update_schedule(
183 186 $config['last_sent_at'],
184 187 wp_date('Y-m-d H:i:s', max($next ?: time(), time()))
185 188 );
189 + }
190 +
191 + /**
192 + * Note why a scheduled run sent nothing (#742).
193 + *
194 + * `search_console_not_connected` leaves the schedule alone so the next
195 + * hourly tick tries again; `no_data` is recorded by the generator after
196 + * it has already pushed the schedule out a period. Either way the panel
197 + * shows the reason and when it was last seen.
198 + *
199 + * `fetch_failed` (#912) is recorded by the generator when Search Console
200 + * answered with an error; it carries the API's message so the panel can
201 + * say what went wrong, and the schedule was moved to a retry.
202 + *
203 + * @param string $reason Machine-readable reason.
204 + * @param string $message Optional plain-text detail, e.g. the API error.
205 + */
206 + public function record_skip(string $reason, string $message = ''): void {
207 + $stored = $this->stored();
208 + $stored['last_skip'] = [
209 + 'reason' => sanitize_key($reason),
210 + 'at' => current_time('mysql'),
211 + ];
212 + if ($message !== '') {
213 + $stored['last_skip']['message'] = sanitize_text_field($message);
214 + }
215 + update_option(self::OPTION_KEY, $stored, false);
216 + }
217 +
218 + /**
219 + * A report went out — whatever paused it earlier no longer applies.
220 + */
221 + public function clear_skip(): void {
222 + $stored = $this->stored();
223 + if (!array_key_exists('last_skip', $stored)) {
224 + return;
225 + }
226 + unset($stored['last_skip']);
227 + update_option(self::OPTION_KEY, $stored, false);
186 228 }
187 229
188 230 /**
189 231 * Update only the schedule timestamps. Called from the scheduler after