PluginProbe
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO / 2.14.0
ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO v2.14.0
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 1.26.0 All 55 releases
thinkrank / includes / abilities / settings / class-update-schema-settings.php

class-update-schema-settings.php in ThinkRank AI SEO – AI SEO Plugin for WordPress: Schema, XML Sitemaps, Meta Tags, Search Console & Local SEO 2.14.0, at includes/abilities/settings/class-update-schema-settings.php

267 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Update schema settings ability.
4 *
5 * @package ThinkRank\Abilities\Settings
6 */
7
8 declare(strict_types=1);
9
10 namespace ThinkRank\Abilities\Settings;
11
12 use ThinkRank\Abilities\Ability_Base;
13 use ThinkRank\SEO\Schema_Management_System;
14
15 if ( ! defined( 'ABSPATH' ) ) {
16 exit; // Exit if accessed directly.
17 }
18
19 /**
20 * Updates ThinkRank structured-data (schema) settings.
21 *
22 * Schema settings are persisted through the Schema_Management_System SEO
23 * manager. When auto_deploy is enabled, saving these settings automatically
24 * regenerates and redeploys the site-wide schema markup.
25 */
26 class Update_Schema_Settings extends Ability_Base {
27 /**
28 * Boolean-typed schema keys.
29 */
30 private const BOOL_KEYS = [
31 'enabled',
32 'auto_generate_schema',
33 'rich_snippets_optimization',
34 'auto_deploy',
35 'organization_schema',
36 'knowledge_graph',
37 'website_enable_search',
38 'enable_breadcrumbs_schema',
39 'enable_local_business',
40 'enable_accordion_faq_schema',
41 ];
42
43 /**
44 * Integer-typed schema keys.
45 */
46 private const INT_KEYS = [
47 'cache_duration',
48 ];
49
50 /**
51 * Array-typed schema keys.
52 */
53 private const ARRAY_KEYS = [
54 'enabled_schema_types',
55 'business_opening_hours',
56 'person_same_as',
57 ];
58
59 /**
60 * String-typed schema keys.
61 */
62 private const STRING_KEYS = [
63 'validation_level',
64 'organization_name',
65 'organization_type',
66 'organization_logo',
67 'organization_url',
68 'organization_description',
69 'organization_social_facebook',
70 'organization_social_twitter',
71 'organization_social_linkedin',
72 'organization_social_instagram',
73 'organization_social_youtube',
74 'organization_social_pinterest',
75 'organization_social_whatsapp',
76 'organization_social_telegram',
77 'organization_contact_type',
78 'organization_contact_phone',
79 'organization_contact_email',
80 'organization_contact_hours',
81 'website_name',
82 'website_url',
83 'website_description',
84 'website_author',
85 'website_search_url',
86 'business_price_range',
87 'business_geo_latitude',
88 'business_geo_longitude',
89 'person_name',
90 'person_job_title',
91 'person_description',
92 'person_image',
93 'person_url',
94 'person_email',
95 'person_telephone',
96 'person_address',
97 'person_birth_date',
98 'person_nationality',
99 'person_works_for',
100 ];
101
102 /**
103 * Constructor.
104 */
105 public function __construct() {
106 $this->id = 'thinkrank/update-schema-settings';
107 $this->label = __( 'Update ThinkRank Schema Settings', 'thinkrank' );
108 $this->description = __( 'Update ThinkRank structured-data (schema) settings. When auto_deploy is enabled, saving automatically regenerates and redeploys the site-wide schema markup. Read the current values with get-schema-settings first; only the keys you pass are changed.', 'thinkrank' );
109 }
110
111 /**
112 * {@inheritDoc}
113 *
114 * @return array<string, bool|float|string>
115 */
116 public function get_annotations() {
117 return [
118 'readonly' => false,
119 // Settings writes are recoverable: the matching get-* ability reads
120 // the previous value, so nothing is lost that cannot be put back.
121 // `destructive` is reserved for calls that lose data or reach
122 // outside the site, and marking routine configuration with it made
123 // MCP clients demand a human approval for every save — which users
124 // reported as a permission bug, because the client's refusal reads
125 // as "No approval received" (#675).
126 'destructive' => false,
127 'idempotent' => true,
128 'priority' => 2.0,
129 'openWorldHint' => false,
130 ];
131 }
132
133 /**
134 * Build the JSON schema properties for schema settings.
135 *
136 * @return array<string, mixed>
137 */
138 private static function schema_properties() {
139 $props = [];
140
141 foreach ( self::BOOL_KEYS as $key ) {
142 $props[ $key ] = [ 'type' => 'boolean' ];
143 }
144 foreach ( self::INT_KEYS as $key ) {
145 $props[ $key ] = [ 'type' => 'integer' ];
146 }
147 foreach ( self::ARRAY_KEYS as $key ) {
148 $props[ $key ] = [ 'type' => 'array' ];
149 }
150 foreach ( self::STRING_KEYS as $key ) {
151 $props[ $key ] = [ 'type' => 'string' ];
152 }
153
154 return $props;
155 }
156
157 /**
158 * {@inheritDoc}
159 *
160 * @return array<string, mixed>
161 */
162 public function get_input_schema() {
163 return [
164 'type' => 'object',
165 'additionalProperties' => false,
166 'properties' => [
167 'settings' => [
168 'type' => 'object',
169 'description' => __( 'Schema settings to update.', 'thinkrank' ),
170 'properties' => self::schema_properties(),
171 ],
172 ],
173 'required' => [ 'settings' ],
174 ];
175 }
176
177 /**
178 * {@inheritDoc}
179 *
180 * @return array<string, mixed>
181 */
182 public function get_output_schema() {
183 return [
184 'type' => 'object',
185 'properties' => [
186 'success' => [ 'type' => 'boolean' ],
187 'message' => [ 'type' => 'string' ],
188 ],
189 ];
190 }
191
192 /**
193 * Execute ability.
194 *
195 * @param array<string, mixed> $input Ability input payload.
196 * @return array<string, mixed>|\WP_Error
197 */
198 public function execute( $input ) {
199 $settings = isset( $input['settings'] ) && is_array( $input['settings'] ) ? $input['settings'] : [];
200
201 if ( empty( $settings ) ) {
202 return new \WP_Error(
203 'thinkrank_missing_schema_settings_payload',
204 __( 'A schema settings payload is required.', 'thinkrank' ),
205 [ 'status' => 400 ]
206 );
207 }
208
209 $mgr = new Schema_Management_System();
210 $merged = $mgr->get_settings( 'site', null );
211 $found = false;
212
213 foreach ( self::BOOL_KEYS as $key ) {
214 if ( array_key_exists( $key, $settings ) ) {
215 $merged[ $key ] = (bool) $settings[ $key ];
216 $found = true;
217 }
218 }
219 foreach ( self::INT_KEYS as $key ) {
220 if ( array_key_exists( $key, $settings ) ) {
221 $merged[ $key ] = (int) $settings[ $key ];
222 $found = true;
223 }
224 }
225 foreach ( self::ARRAY_KEYS as $key ) {
226 if ( array_key_exists( $key, $settings ) && is_array( $settings[ $key ] ) ) {
227 $merged[ $key ] = array_values( $settings[ $key ] );
228 $found = true;
229 }
230 }
231 foreach ( self::STRING_KEYS as $key ) {
232 if ( array_key_exists( $key, $settings ) ) {
233 $value = sanitize_text_field( (string) $settings[ $key ] );
234
235 // validation_level is an enum. An out-of-range value would make
236 // the downstream all-or-nothing validator reject the entire
237 // save, silently dropping the other valid fields — so skip an
238 // invalid value here and let the rest of the payload save.
239 if ( 'validation_level' === $key
240 && ! in_array( $value, [ 'strict', 'moderate', 'lenient' ], true ) ) {
241 continue;
242 }
243
244 $merged[ $key ] = $value;
245 $found = true;
246 }
247 }
248
249 if ( ! $found ) {
250 return new \WP_Error(
251 'thinkrank_no_valid_schema_setting_keys',
252 __( 'No valid schema setting keys were provided.', 'thinkrank' ),
253 [ 'status' => 400 ]
254 );
255 }
256
257 $result = $mgr->save_settings( 'site', null, $merged );
258
259 return [
260 'success' => (bool) $result,
261 'message' => (bool) $result
262 ? __( 'Schema settings updated.', 'thinkrank' )
263 : __( 'Failed to update schema settings.', 'thinkrank' ),
264 ];
265 }
266 }
267