PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.7.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.7.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
← All changes | includes/api/class-email-report-endpoint.php +22 -78 2.0.22.7.0 View file →
@@ -2,16 +2,13 @@
2 2 /**
3 3 * Email Report REST Endpoint
4 4 *
5 5 * Three routes:
6 - * GET /thinkrank/v1/email-report/config — returns config + capability map + section catalog
7 - * POST /thinkrank/v1/email-report/config — saves config (sanitized + capability-clamped)
6 + * GET /thinkrank/v1/email-report/config — returns the resolved config + section catalog
7 + * POST /thinkrank/v1/email-report/config — switches the report on or off
8 8 * POST /thinkrank/v1/email-report/test-send — triggers an immediate one-off send
9 9 *
10 - * Permissions: admin (`manage_options`) + valid REST nonce. Pro-only
11 - * fields submitted on a free plan are silently dropped by
12 - * Email_Report_Config::sanitize() — we don't 403 on those, since the
13 - * client may not know its current capabilities yet (e.g. mid-downgrade).
10 + * Permissions: admin (`manage_options`) + valid REST nonce.
14 11 *
15 12 * @package ThinkRank
16 13 * @subpackage API
17 14 * @since 1.9.0
@@ -21,9 +18,8 @@
21 18
22 19 namespace ThinkRank\API;
23 20
24 21 use ThinkRank\API\Traits\CSRF_Protection;
25 -use ThinkRank\Core\Plan_Config;
26 22 use ThinkRank\SEO\Email_Report_Manager;
27 23 use WP_REST_Controller;
28 24 use WP_REST_Request;
29 25 use WP_REST_Response;
@@ -61,9 +57,14 @@
61 57 [
62 58 'methods' => 'POST',
63 59 'callback' => [$this, 'save_config'],
64 60 'permission_callback' => [$this, 'check_admin_csrf_permissions'],
65 - 'args' => $this->save_args(),
61 + 'args' => [
62 + 'enabled' => [
63 + 'type' => 'boolean',
64 + 'sanitize_callback' => 'rest_sanitize_boolean',
65 + ],
66 + ],
66 67 ],
67 68 ]
68 69 );
69 70
@@ -82,11 +83,10 @@
82 83
83 84 /**
84 85 * GET /email-report/config
85 86 *
86 - * Returns the current per-site config along with the plan's capability
87 - * map and the section catalog so the React panel can render the right
88 - * fields without a second round-trip.
87 + * Returns the resolved config (on/off, frequency, recipients, sections)
88 + * along with the section catalog and the next scheduled run.
89 89 */
90 90 public function get_config(WP_REST_Request $request): WP_REST_Response {
91 91 $manager = $this->resolve_manager();
92 92 if ($manager === null) {
@@ -95,13 +95,11 @@
95 95 ], 500);
96 96 }
97 97
98 98 return new WP_REST_Response([
99 - 'config' => $manager->config()->get(),
100 - 'capabilities' => Plan_Config::email_report(),
101 - 'sections' => $manager->registry()->describe_for_ui(),
102 - 'next_run' => $manager->scheduler()->next_run_iso(),
103 - 'tokens' => $this->supported_tokens(),
99 + 'config' => $manager->config()->get(),
100 + 'sections' => $manager->registry()->describe_for_ui(),
101 + 'next_run' => $manager->scheduler()->next_run_iso(),
104 102 ]);
105 103 }
106 104
107 105 /**
@@ -115,20 +113,19 @@
115 113 'message' => __('Email Report Manager unavailable.', 'thinkrank'),
116 114 ], 500);
117 115 }
118 116
119 - $input = $request->get_json_params();
120 - if (!is_array($input)) {
121 - $input = $request->get_params();
117 + $input = [];
118 + if ($request->has_param('enabled')) {
119 + $input['enabled'] = (bool) $request->get_param('enabled');
122 120 }
123 121
124 - $saved = $manager->config()->save(is_array($input) ? $input : []);
122 + $saved = $manager->config()->save($input);
125 123
126 124 return new WP_REST_Response([
127 - 'success' => true,
128 - 'config' => $saved,
129 - 'capabilities' => Plan_Config::email_report(),
130 - 'next_run' => $manager->scheduler()->next_run_iso(),
125 + 'success' => true,
126 + 'config' => $saved,
127 + 'next_run' => $manager->scheduler()->next_run_iso(),
131 128 ]);
132 129 }
133 130
134 131 /**
@@ -189,10 +186,9 @@
189 186 }
190 187
191 188 /**
192 189 * Reach into the plugin DI container for the Email_Report_Manager
193 - * instance built at boot. Falls back to creating one on demand if
194 - * the function doesn't exist yet (defensive — shouldn't happen).
190 + * instance built at boot.
195 191 */
196 192 private function resolve_manager(): ?Email_Report_Manager {
197 193 if ($this->manager !== null) {
198 194 return $this->manager;
@@ -204,58 +200,6 @@
204 200 return $this->manager;
205 201 }
206 202 }
207 203 return null;
208 - }
209 -
210 - /**
211 - * REST args: permissive on type so we accept the full config object
212 - * the panel sends back (including nulls for paid fields the user
213 - * isn't allowed to set). Heavy sanitization happens in
214 - * Email_Report_Config::sanitize() so the cron path benefits too.
215 - *
216 - * Don't add `sanitize_callback` here for nullable fields — the
217 - * sanitized value is what reaches the handler, and
218 - * `esc_url_raw(null)` coerces to '', defeating the point of
219 - * preserving "unset". (WP_REST_Server::respond_to_request runs
220 - * has_valid_params() first and sanitize_params() second, so the
221 - * ['string','null'] type above is what admits the null; sanitizing
222 - * afterwards would throw it away.)
223 - */
224 - private function save_args(): array {
225 - $nullable_string = ['type' => ['string', 'null']];
226 - return [
227 - 'enabled' => [
228 - 'type' => 'boolean',
229 - 'sanitize_callback' => 'rest_sanitize_boolean',
230 - ],
231 - 'frequency_days' => [
232 - 'type' => 'integer',
233 - 'sanitize_callback' => 'absint',
234 - ],
235 - 'recipients' => [
236 - 'type' => ['array', 'string', 'null'],
237 - ],
238 - 'subject_template' => $nullable_string,
239 - 'logo_url' => $nullable_string,
240 - 'logo_link' => $nullable_string,
241 - 'header_background' => $nullable_string,
242 - 'link_to_full_report' => [
243 - 'type' => 'boolean',
244 - 'sanitize_callback' => 'rest_sanitize_boolean',
245 - ],
246 - 'intro_text' => $nullable_string,
247 - 'sections_enabled' => [
248 - 'type' => ['array', 'null'],
249 - ],
250 - 'footer_text' => $nullable_string,
251 - 'additional_css' => $nullable_string,
252 - ];
253 - }
254 -
255 - private function supported_tokens(): array {
256 - if (!function_exists('thinkrank_get_email_report_tokens')) {
257 - require_once THINKRANK_PLUGIN_DIR . 'includes/config/email-report-settings-config.php';
258 - }
259 - return thinkrank_get_email_report_tokens();
260 204 }
261 205 }