PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.3.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.3.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-section-registry.php

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

129 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Email Report Section Registry
4 *
5 * Holds the ordered list of section objects that make up the email body.
6 * Free code registers the six built-in sections at boot. The Pro plugin
7 * adds AI Highlights (or any other section) by hooking
8 * `thinkrank_email_report_register_sections` and calling register().
9 *
10 * @package ThinkRank
11 * @subpackage SEO
12 * @since 1.9.0
13 */
14
15 declare(strict_types=1);
16
17 namespace ThinkRank\SEO;
18
19 use ThinkRank\Core\Plan_Config;
20 use ThinkRank\SEO\Email_Report_Sections\Email_Report_Section_Interface;
21
22 if (!defined('ABSPATH')) {
23 exit;
24 }
25
26 /**
27 * Email_Report_Section_Registry
28 *
29 * @since 1.9.0
30 */
31 final class Email_Report_Section_Registry {
32
33 /**
34 * @var array<string,Email_Report_Section_Interface>
35 */
36 private array $sections = [];
37
38 /**
39 * Register a section. Last writer wins on key collision so Pro can
40 * intentionally override a free section if it ever needs to (rare).
41 */
42 public function register(Email_Report_Section_Interface $section): void {
43 $this->sections[$section->key()] = $section;
44 }
45
46 /**
47 * Drop a section by key. Free code shouldn't call this — it's here
48 * for tests and for the Pro plugin if ever needed.
49 */
50 public function unregister(string $key): void {
51 unset($this->sections[$key]);
52 }
53
54 /**
55 * @return array<string,Email_Report_Section_Interface>
56 */
57 public function all(): array {
58 return $this->sections;
59 }
60
61 /**
62 * Resolve the ordered, capability-filtered, user-enabled section list
63 * for a given config. Returned in the order they should render.
64 *
65 * Pro can re-order or insert sections via the
66 * `thinkrank_email_report_sections` filter — that's how AI Highlights
67 * jumps to the top of the list.
68 *
69 * @param array $config Per-site Email Report config.
70 * @return array<int,Email_Report_Section_Interface>
71 */
72 public function resolve_for(array $config): array {
73 $enabled = $config['sections_enabled'] ?? [];
74 $caps = Plan_Config::email_report();
75
76 $resolved = [];
77 foreach ($this->sections as $key => $section) {
78 if (!in_array($key, $enabled, true)) {
79 continue;
80 }
81 $required = $section->requires_capability();
82 if ($required !== null && empty($caps[$required])) {
83 // Capability not granted by current plan — silently skip.
84 continue;
85 }
86 $resolved[$key] = $section;
87 }
88
89 /**
90 * Filter the ordered section list for a single report.
91 *
92 * Pro plugin uses this to insert AI Highlights at the top, or
93 * re-arrange sections per agency preference.
94 *
95 * @since 1.9.0
96 *
97 * @param array<string,Email_Report_Section_Interface> $resolved Ordered sections, key => section.
98 * @param array $config Per-site config.
99 */
100 $resolved = apply_filters('thinkrank_email_report_sections', $resolved, $config);
101
102 // Re-validate after filter: drop anything that doesn't implement the contract.
103 return array_values(array_filter(
104 $resolved,
105 static fn ($s) => $s instanceof Email_Report_Section_Interface
106 ));
107 }
108
109 /**
110 * Convenience: list of section keys to expose in the admin UI.
111 * Mirrors the registry order, includes pro-gated sections so the UI
112 * can render them with a lock chip.
113 *
114 * @return array<int,array{key:string,label:string,requires_capability:?string}>
115 */
116 public function describe_for_ui(): array {
117 $out = [];
118 foreach ($this->sections as $key => $section) {
119 $out[] = [
120 'key' => $key,
121 'label' => $section->label(),
122 'requires_capability' => $section->requires_capability(),
123 'default_enabled' => $section->default_enabled(),
124 ];
125 }
126 return $out;
127 }
128 }
129