PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.8.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.8.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 1.0.2 1.1.0 All 49 releases
← All changes | includes/seo/class-email-report-config.php +35 -1 2.7.02.8.0 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,39 @@
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 + * @param string $reason Machine-readable reason.
200 + */
201 + public function record_skip(string $reason): void {
202 + $stored = $this->stored();
203 + $stored['last_skip'] = [
204 + 'reason' => sanitize_key($reason),
205 + 'at' => current_time('mysql'),
206 + ];
207 + update_option(self::OPTION_KEY, $stored, false);
208 + }
209 +
210 + /**
211 + * A report went out — whatever paused it earlier no longer applies.
212 + */
213 + public function clear_skip(): void {
214 + $stored = $this->stored();
215 + if (!array_key_exists('last_skip', $stored)) {
216 + return;
217 + }
218 + unset($stored['last_skip']);
219 + update_option(self::OPTION_KEY, $stored, false);
186 220 }
187 221
188 222 /**
189 223 * Update only the schedule timestamps. Called from the scheduler after