PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 1.25.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v1.25.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 1.10.0 All 48 releases
thinkrank / includes / seo / class-email-report-scheduler.php

class-email-report-scheduler.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 1.25.0, at includes/seo/class-email-report-scheduler.php

101 lines 2.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Email Report Scheduler
4 *
5 * Owns the cron lifecycle for Email Reporting:
6 * - registers the recurring `thinkrank_email_report_tick` event
7 * - on each tick, asks the config whether the site is due
8 * - delegates to Email_Report_Generator::generate_for_due()
9 *
10 * The cron event is cleared on plugin deactivation by ThinkRank\Core\Deactivator
11 * (see its clear_scheduled_hooks()).
12 *
13 * Cron cadence: hourly. Per-site frequency (7/15/30 days) is enforced
14 * by checking next_scheduled_at against now — not by scheduling N
15 * different cron events. One event for all sites, simple to reason about.
16 *
17 * @package ThinkRank
18 * @subpackage SEO
19 * @since 1.9.0
20 */
21
22 declare(strict_types=1);
23
24 namespace ThinkRank\SEO;
25
26 if (!defined('ABSPATH')) {
27 exit;
28 }
29
30 /**
31 * Email_Report_Scheduler
32 *
33 * @since 1.9.0
34 */
35 final class Email_Report_Scheduler {
36
37 public const CRON_HOOK = 'thinkrank_email_report_tick';
38
39 private Email_Report_Config $config;
40 private Email_Report_Generator $generator;
41
42 public function __construct(Email_Report_Config $config, Email_Report_Generator $generator) {
43 $this->config = $config;
44 $this->generator = $generator;
45 }
46
47 /**
48 * Register cron + handler. Called once at plugin boot.
49 */
50 public function register(): void {
51 add_action(self::CRON_HOOK, [$this, 'on_tick']);
52
53 if (!wp_next_scheduled(self::CRON_HOOK)) {
54 wp_schedule_event(time() + 60, 'hourly', self::CRON_HOOK);
55 }
56 }
57
58 /**
59 * Cron tick handler. Runs every hour.
60 *
61 * Decision tree:
62 * 1. Feature disabled → skip
63 * 2. No next_scheduled_at on file → set one and skip this tick
64 * (gives the user a fresh cycle starting from "now" rather than
65 * firing immediately on first enable)
66 * 3. next_scheduled_at is in the future → skip
67 * 4. Otherwise → generate.
68 */
69 public function on_tick(): void {
70 $config = $this->config->get();
71 if (empty($config['enabled'])) {
72 return;
73 }
74
75 if (empty($config['next_scheduled_at'])) {
76 $next = wp_date('Y-m-d H:i:s', strtotime('+' . max(1, (int) $config['frequency_days']) . ' days'));
77 $this->config->update_schedule(null, $next);
78 return;
79 }
80
81 $next_ts = strtotime((string) $config['next_scheduled_at']);
82 if ($next_ts && $next_ts > time()) {
83 return;
84 }
85
86 $this->generator->generate_for_due();
87 }
88
89 /**
90 * Convenience used by REST + admin UI to surface the next-send timestamp
91 * to the user. Defends against an empty or stale next_scheduled_at.
92 */
93 public function next_run_iso(): ?string {
94 $config = $this->config->get();
95 if (empty($config['enabled']) || empty($config['next_scheduled_at'])) {
96 return null;
97 }
98 return (string) $config['next_scheduled_at'];
99 }
100 }
101