PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.0.2
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.0.2
2.1.3 2.1.2 2.1.1 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 trunk 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 All 57 releases
darkify / src / Admin / Rest / SettingsRest.php

SettingsRest.php in Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) 2.0.2, at src/Admin/Rest/SettingsRest.php

133 lines 5.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Settings REST controller for the React admin SPA.
5 *
6 * Exposes the normalized settings schema (read from the SchemaRegistry) plus the
7 * current values for an option key, and persists changes back into that same
8 * option the frontend already reads.
9 *
10 * Backward compatible by design. The field ids, defaults and the `darkify` option
11 * key are the ones the config classes in src/Admin/Views/*.php already declared,
12 * so existing settings load and save unchanged — no migration runs, and nothing
13 * about the stored data model changes. The save also still fires the same
14 * `darkify_darkify_save*` filter/actions the old framework did, so any add-on or
15 * snippet hooked into them keeps working.
16 *
17 * @package darkify
18 * @subpackage darkify/src/Admin/Rest
19 * @author ThemeAtelier<themeatelierbd@gmail.com>
20 */
21
22 namespace ThemeAtelier\Darkify\Admin\Rest;
23
24 use WP_REST_Server;
25 use WP_REST_Request;
26 use WP_REST_Response;
27
28 if (! defined('ABSPATH')) {
29 die;
30 }
31
32 class SettingsRest extends AbstractRestController
33 {
34 public function register_routes(): void
35 {
36 \register_rest_route(self::NS, '/settings/(?P<key>[A-Za-z0-9_\-]+)', [
37 [
38 'methods' => WP_REST_Server::READABLE,
39 'callback' => [$this, 'get_settings'],
40 'permission_callback' => [$this, 'can_manage'],
41 ],
42 [
43 'methods' => WP_REST_Server::CREATABLE,
44 'callback' => [$this, 'save_settings'],
45 'permission_callback' => [$this, 'can_manage'],
46 ],
47 ]);
48 }
49
50 /**
51 * GET /settings/{key} — the normalized schema tree and the current values.
52 */
53 public function get_settings(WP_REST_Request $request): WP_REST_Response
54 {
55 $key = (string) $request->get_param('key');
56 if (! $this->is_valid_settings_key($key)) {
57 return new WP_REST_Response(['message' => \__('Unknown settings key.', 'darkify')], 404);
58 }
59
60 $sections = $this->get_registered_sections($key);
61 // `apply_pro_flags` stamps `pro` / `pro_options` from the config's
62 // long-standing lock markers so the React admin renders those fields as
63 // locked previews (Chat Help's ProLock contract).
64 $tree = $this->apply_pro_flags($this->normalize_sections($sections));
65 $defaults = $this->collect_defaults($sections);
66
67 $saved = \get_option($key, []);
68 $saved = \is_array($saved) ? $saved : [];
69
70 return \rest_ensure_response([
71 'key' => $key,
72 'schema' => $tree,
73 'values' => $this->merge_defaults($defaults, $saved),
74 ]);
75 }
76
77 /**
78 * POST /settings/{key} — sanitize by field type and persist to the option.
79 *
80 * The submitted values are merged *over* the existing option rather than
81 * replacing it. That matters for backward compatibility: any key a previous
82 * version wrote but the current schema no longer declares (an old field, or
83 * one owned by an add-on) survives the save instead of being dropped.
84 */
85 public function save_settings(WP_REST_Request $request): WP_REST_Response
86 {
87 $key = (string) $request->get_param('key');
88 if (! $this->is_valid_settings_key($key)) {
89 return new WP_REST_Response(['message' => \__('Unknown settings key.', 'darkify')], 404);
90 }
91
92 $incoming = $request->get_param('values');
93 if (! \is_array($incoming)) {
94 return new WP_REST_Response([
95 'saved' => false,
96 'message' => \__('Invalid payload.', 'darkify'),
97 ], 400);
98 }
99
100 $sections = $this->get_registered_sections($key);
101 $sanitized = $this->sanitize_values($incoming, $this->collect_field_types($sections));
102 // Free plugin: locked fields/choices can never be persisted, no matter
103 // what the request claims (the locked UI never submits them anyway).
104 $sanitized = $this->strip_pro_keys($sanitized, $sections);
105
106 $existing = \get_option($key, []);
107 $existing = \is_array($existing) ? $existing : [];
108 $data = \array_merge($existing, $sanitized);
109
110 /**
111 * The same filter/actions the retired options framework fired around a
112 * save, with the same names and argument order, so anything hooked into
113 * them keeps working. The second argument used to be the framework
114 * instance; it is now this controller — callbacks in the wild use the
115 * `$data` array, which is unchanged.
116 */
117 $data = \apply_filters("darkify_{$key}_save", $data, $this);
118
119 \do_action("darkify_{$key}_save_before", $data, $this);
120
121 \update_option($key, $data);
122
123 \do_action("darkify_{$key}_saved", $data, $this);
124 \do_action("darkify_{$key}_save_after", $data, $this);
125
126 return \rest_ensure_response([
127 'saved' => true,
128 'key' => $key,
129 'values' => $data,
130 ]);
131 }
132 }
133