PluginProbe
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin / trunk
wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin vtrunk
6.5.1.7 6.5.1.6 6.5.1.5 6.5.1.4 6.5.1.3 6.5.1.2 6.5.1.1 6.5.0.9 6.5.0.8 6.5.0.7 6.5.0.6 trunk 3.4.2.40 3.4.2.41 3.4.2.42 3.4.2.43 3.4.2.44 3.4.2.45 3.4.2.46 3.4.2.47 3.4.2.48 3.4.2.49 3.4.2.50 6.3.2 6.3.3.1 All 47 releases
wpdatatables / Infrastructure / WP / MCP / Abilities / update-global-settings.php

update-global-settings.php in wpDataTables – WordPress Data Table, Dynamic Tables & Table Charts Plugin trunk, at Infrastructure/WP/MCP/Abilities/update-global-settings.php

359 lines 14.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ability: wpdatatables/update-global-settings
4 *
5 * Reads and/or updates wpDataTables global plugin settings: date/time format,
6 * number format, default skin, CSV delimiter, custom CSS/JS, and feature toggles.
7 *
8 * Uses WDTSettingsController::getCurrentPluginConfig() for reading and
9 * WDTSettingsController::saveSettings() for writing.
10 *
11 * @package wpDataTables_MCP_Server
12 * @since 0.2.0
13 */
14
15 defined( 'ABSPATH' ) or die('Access denied.');
16
17 add_action( 'wp_abilities_api_init', 'wdtmcp_register_update_global_settings_ability' );
18
19 function wdtmcp_register_update_global_settings_ability() {
20 wp_register_ability(
21 'wpdatatables/update-global-settings',
22 array(
23 'label' => __( 'Update Global Settings', 'wpdatatables' ),
24 'description' => __( 'Reads or updates wpDataTables global plugin settings. When called with no settings to change, returns the current configuration. Provide key-value pairs to update specific settings (date format, number format, skin, CSV delimiter, etc.). WHEN TO CALL: to read site-wide wpDataTables defaults, or to change global formats/skins/CSS/JS that affect all tables. OPTIONAL INPUT: settings (object) — omit or pass {} to read only; pass key-value pairs to update. RETURNS: current_settings and updated_keys (empty on read-only call). NOTE: get-system-info also returns a settings snapshot — use update-global-settings when you need to change them. Requires manage_options capability.', 'wpdatatables' ),
25 'category' => 'wpdatatables-data',
26
27 'input_schema' => array(
28 'type' => 'object',
29 'properties' => array(
30 'settings' => wdtmcp_get_updatable_global_settings_input_schema(),
31 ),
32 ),
33
34 'output_schema' => array(
35 'type' => 'object',
36 'properties' => array(
37 'current_settings' => array( 'type' => 'object', 'description' => 'Current global settings after any updates.' ),
38 'updated_keys' => array( 'type' => 'array', 'description' => 'Keys that were changed (empty if read-only call).', 'items' => array( 'type' => 'string' ) ),
39 ),
40 ),
41
42 'execute_callback' => 'wdtmcp_execute_update_global_settings',
43
44 'permission_callback' => function () {
45 return current_user_can( 'manage_options' );
46 },
47
48 'meta' => array(
49 'annotations' => array(
50 'instructions' => __( 'Pass an empty settings object {} to read current global configuration without changes. Pass key-value pairs to update site-wide wpDataTables defaults.', 'wpdatatables' ),
51 'readonly' => false,
52 'destructive' => false,
53 'idempotent' => true,
54 ),
55 ),
56 )
57 );
58 }
59
60 /**
61 * JSON Schema property definitions for updatable global settings (source of truth).
62 *
63 * @return array<string, array{type: string, description: string}>
64 */
65 function wdtmcp_get_updatable_global_setting_definitions() {
66 return array(
67 'wdtInterfaceLanguage' => array(
68 'type' => 'string',
69 'description' => 'Interface language file (e.g. de_DE.inc.php) or empty string for English default.',
70 ),
71 'wdtTablesPerPage' => array(
72 'type' => 'integer',
73 'description' => 'Number of tables shown per page in the admin browse screen (typically 10–50).',
74 ),
75 'wdtDateFormat' => array(
76 'type' => 'string',
77 'description' => 'PHP date format for date columns (e.g. d/m/Y, Y-m-d).',
78 ),
79 'wdtTimeFormat' => array(
80 'type' => 'string',
81 'description' => 'PHP time format for time/datetime columns (e.g. H:i, h:i A).',
82 ),
83 'wdtBaseSkin' => array(
84 'type' => 'string',
85 'description' => 'Base table skin (material, light, graphite, aqua, purple, dark, etc.).',
86 ),
87 'wdtNumberFormat' => array(
88 'type' => 'integer',
89 'description' => 'Number format preset: 1 = 15.000,00; 2 = 15,000.00.',
90 ),
91 'wdtRenderFilter' => array(
92 'type' => 'string',
93 'description' => 'Where to render the advanced filter: header or footer.',
94 ),
95 'wdtDecimalPlaces' => array(
96 'type' => 'integer',
97 'description' => 'Decimal places for float number columns.',
98 ),
99 'wdtCSVDelimiter' => array(
100 'type' => 'string',
101 'description' => 'CSV export delimiter character (e.g. , ; | or tab).',
102 ),
103 'wdtSortingOrderBrowseTables' => array(
104 'type' => 'string',
105 'description' => 'Admin browse tables sort direction: ASC or DESC.',
106 ),
107 'wdtTabletWidth' => array(
108 'type' => 'integer',
109 'description' => 'Viewport width in pixels treated as tablet for responsive tables.',
110 ),
111 'wdtMobileWidth' => array(
112 'type' => 'integer',
113 'description' => 'Viewport width in pixels treated as mobile for responsive tables.',
114 ),
115 'wdtGettingStartedPageStatus' => array(
116 'type' => 'integer',
117 'description' => 'Getting Started admin page visibility (0 = hidden, 1 = shown).',
118 ),
119 'wdtLiteVSPremiumPageStatus' => array(
120 'type' => 'integer',
121 'description' => 'Lite vs Premium admin page visibility (0 = hidden, 1 = shown).',
122 ),
123 'wdtIncludeGoogleFonts' => array(
124 'type' => 'integer',
125 'description' => 'Load Google Fonts on the front end (0 = off, 1 = on).',
126 ),
127 'wdtIncludeBootstrap' => array(
128 'type' => 'integer',
129 'description' => 'Load Bootstrap on the front end (0 = off, 1 = on).',
130 ),
131 'wdtIncludeBootstrapBackEnd' => array(
132 'type' => 'integer',
133 'description' => 'Load Bootstrap in wp-admin (0 = off, 1 = on).',
134 ),
135 'wdtPreventDeletingTables' => array(
136 'type' => 'integer',
137 'description' => 'Prevent non-admin users from deleting tables (0 = off, 1 = on).',
138 ),
139 'wdtParseShortcodes' => array(
140 'type' => 'integer',
141 'description' => 'Parse WordPress shortcodes inside table cell strings (0 = off, 1 = on).',
142 ),
143 'wdtNumbersAlign' => array(
144 'type' => 'integer',
145 'description' => 'Right-align integer and float columns (0 = off, 1 = on).',
146 ),
147 'wdtGlobalTableLoader' => array(
148 'type' => 'integer',
149 'description' => 'Global default table loader/spinner style ID.',
150 ),
151 'wdtGlobalChartLoader' => array(
152 'type' => 'integer',
153 'description' => 'Global default chart loader/spinner style ID.',
154 ),
155 'wdtBorderRemoval' => array(
156 'type' => 'integer',
157 'description' => 'Remove table cell borders globally (0 = off, 1 = on).',
158 ),
159 'wdtBorderRemovalHeader' => array(
160 'type' => 'integer',
161 'description' => 'Remove table header borders globally (0 = off, 1 = on).',
162 ),
163 'wdtUseSeparateCon' => array(
164 'type' => 'integer',
165 'description' => 'Enable separate database connections feature (0 = off, 1 = on).',
166 ),
167 'wdtCustomCss' => array(
168 'type' => 'string',
169 'description' => 'Custom CSS appended to wpDataTables front-end output.',
170 ),
171 'wdtCustomJs' => array(
172 'type' => 'string',
173 'description' => 'Custom JavaScript for wpDataTables (requires unfiltered_html to save non-empty values).',
174 ),
175 'wdtMinifiedJs' => array(
176 'type' => 'integer',
177 'description' => 'Serve minified plugin JS assets (0 = off, 1 = on).',
178 ),
179 'wdtSumFunctionsLabel' => array(
180 'type' => 'string',
181 'description' => 'Label for Sum aggregate functions (default Σ =).',
182 ),
183 'wdtAvgFunctionsLabel' => array(
184 'type' => 'string',
185 'description' => 'Label for Average aggregate functions.',
186 ),
187 'wdtMinFunctionsLabel' => array(
188 'type' => 'string',
189 'description' => 'Label for Min aggregate functions.',
190 ),
191 'wdtMaxFunctionsLabel' => array(
192 'type' => 'string',
193 'description' => 'Label for Max aggregate functions.',
194 ),
195 'wdtFontColorSettings' => array(
196 'type' => 'object',
197 'description' => 'Global font and color settings map (keys such as wdtTableFont, wdtFontSize, wdtFontColor).',
198 'additionalProperties' => true,
199 ),
200 'wdtAutoUpdateOption' => array(
201 'type' => 'integer',
202 'description' => 'Auto-update table/chart cache (0 = off, 1 = on).',
203 ),
204 'wdtGoogleApiMaps' => array(
205 'type' => 'string',
206 'description' => 'Google Maps API key for map-type columns.',
207 ),
208 );
209 }
210
211 /**
212 * JSON Schema for the settings patch object (built from {@see wdtmcp_get_updatable_global_setting_definitions()}).
213 *
214 * @return array<string, mixed>
215 */
216 function wdtmcp_get_updatable_global_settings_input_schema() {
217 return array(
218 'type' => 'object',
219 'description' => 'Key-value pairs of settings to update. Omit or pass empty to read current settings without changes.',
220 'properties' => wdtmcp_get_updatable_global_setting_definitions(),
221 'additionalProperties' => false,
222 );
223 }
224
225 /**
226 * Setting keys MCP clients may change. Excludes licences, Google service-account
227 * blobs, separate-connection payloads, and internal version pins.
228 *
229 * @return string[]
230 */
231 function wdtmcp_get_updatable_global_setting_keys() {
232 return array_keys( wdtmcp_get_updatable_global_setting_definitions() );
233 }
234
235 /**
236 * Return only MCP-readable global settings from a full plugin config payload.
237 *
238 * Uses {@see wdtmcp_get_updatable_global_setting_keys()} plus read-only MCP keys
239 * so licence codes, tokens, separate-connection credentials, and other internal
240 * keys from {@see WDTSettingsController::getCurrentPluginConfig()} are never returned.
241 * The Google Maps API key value is omitted (presence is indicated via read-only
242 * wdtGoogleApiMapsValidated).
243 *
244 * @param array $config Result of {@see WDTSettingsController::getCurrentPluginConfig()}.
245 * @return array
246 */
247 function wdtmcp_redact_plugin_config_for_mcp( array $config ) {
248 $safe = array();
249
250 foreach ( wdtmcp_get_updatable_global_setting_keys() as $key ) {
251 if ( ! array_key_exists( $key, $config ) ) {
252 continue;
253 }
254
255 if ( 'wdtGoogleApiMaps' === $key ) {
256 continue;
257 }
258
259 $safe[ $key ] = $config[ $key ];
260 }
261
262 if ( array_key_exists( 'wdtGoogleApiMapsValidated', $config ) ) {
263 $safe['wdtGoogleApiMapsValidated'] = $config['wdtGoogleApiMapsValidated'];
264 }
265
266 return $safe;
267 }
268
269 /**
270 * Keys whose persisted values differ between two plugin config snapshots.
271 *
272 * @param array $before Config from {@see WDTSettingsController::getCurrentPluginConfig()} before save.
273 * @param array $after Config after save.
274 * @return string[]
275 */
276 function wdtmcp_get_changed_global_setting_keys( array $before, array $after ) {
277 $changed = array();
278
279 foreach ( wdtmcp_get_updatable_global_setting_keys() as $key ) {
280 $prev = array_key_exists( $key, $before ) ? $before[ $key ] : null;
281 $next = array_key_exists( $key, $after ) ? $after[ $key ] : null;
282
283 if ( serialize( $prev ) !== serialize( $next ) ) {
284 $changed[] = $key;
285 }
286 }
287
288 return $changed;
289 }
290
291 /**
292 * Execute callback for wpdatatables/update-global-settings.
293 *
294 * @param array $input
295 * @return array|\WP_Error
296 */
297 function wdtmcp_execute_update_global_settings( $input ) {
298 if ( ! class_exists( 'WDTSettingsController' ) ) {
299 return new \WP_Error(
300 'wdtmcp_missing_class',
301 __( 'WDTSettingsController is required.', 'wpdatatables' )
302 );
303 }
304
305 $patch = array();
306 if ( isset( $input['settings'] ) && is_array( $input['settings'] ) ) {
307 $patch = $input['settings'];
308 }
309
310 $allowed = array_flip( wdtmcp_get_updatable_global_setting_keys() );
311 $current = \WDTSettingsController::getCurrentPluginConfig();
312 if ( ! is_array( $current ) ) {
313 return new \WP_Error(
314 'wdtmcp_config_invalid',
315 __( 'Could not read current plugin configuration.', 'wpdatatables' )
316 );
317 }
318
319 foreach ( array_keys( $patch ) as $key ) {
320 if ( ! isset( $allowed[ $key ] ) ) {
321 return new \WP_Error(
322 'wdtmcp_invalid_setting_key',
323 sprintf(
324 /* translators: %s: setting option key */
325 __( 'Unknown or disallowed setting key: %s', 'wpdatatables' ),
326 (string) $key
327 )
328 );
329 }
330 }
331
332 if ( empty( $patch ) ) {
333 return array(
334 'current_settings' => wdtmcp_redact_plugin_config_for_mcp( $current ),
335 'updated_keys' => array(),
336 );
337 }
338
339 $merged = $current;
340 foreach ( $patch as $key => $value ) {
341 $merged[ $key ] = $value;
342 }
343
344 \WDTSettingsController::saveSettings( $merged );
345
346 $after = \WDTSettingsController::getCurrentPluginConfig();
347 if ( ! is_array( $after ) ) {
348 return new \WP_Error(
349 'wdtmcp_config_invalid',
350 __( 'Could not read plugin configuration after save.', 'wpdatatables' )
351 );
352 }
353
354 return array(
355 'current_settings' => wdtmcp_redact_plugin_config_for_mcp( $after ),
356 'updated_keys' => wdtmcp_get_changed_global_setting_keys( $current, $after ),
357 );
358 }
359