PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
elasticpress / includes / classes / REST / Features.php

Features.php in ElasticPress 5.3.5, at includes/classes/REST/Features.php

272 lines 6.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Features REST API Controller
4 *
5 * @since 5.0.0
6 * @package elasticpress
7 */
8
9 namespace ElasticPress\REST;
10
11 use ElasticPress\Features as FeaturesStore;
12 use ElasticPress\Utils;
13
14 /**
15 * Features API controller class.
16 *
17 * @since 5.0.0
18 * @package elasticpress
19 */
20 class Features {
21
22 /**
23 * Register routes.
24 *
25 * @return void
26 */
27 public function register_routes() {
28 register_rest_route(
29 'elasticpress/v1',
30 'features',
31 [
32 [
33 'callback' => [ $this, 'get_features' ],
34 'methods' => 'GET',
35 'permission_callback' => [ $this, 'check_permission' ],
36 ],
37 [
38 'args' => $this->get_args(),
39 'callback' => [ $this, 'update_settings' ],
40 'methods' => 'PUT',
41 'permission_callback' => [ $this, 'check_permission' ],
42 ],
43 ]
44 );
45 }
46
47 /**
48 * Get args schema.
49 *
50 * @return array
51 */
52 public function get_args() {
53 $args = [];
54
55 $features = \ElasticPress\Features::factory()->registered_features;
56
57 foreach ( $features as $feature ) {
58 $properties = [];
59
60 $schema = $feature->get_settings_schema();
61
62 foreach ( $schema as $schema ) {
63 if ( ! isset( $schema['label'] ) ) {
64 continue;
65 }
66
67 $type = $schema['type'] ?? '';
68 $property = [
69 'description' => $schema['label'],
70 'type' => 'string',
71 ];
72
73 switch ( $type ) {
74 case 'select':
75 case 'radio':
76 $property['enum'] = array_map( fn( $o ) => $o['value'], $schema['options'] );
77 break;
78 case 'toggle':
79 $property['type'] = 'boolean';
80 break;
81 case 'number':
82 $property['type'] = 'number';
83 break;
84 case 'url':
85 $property['type'] = 'string';
86 $property['format'] = 'uri';
87 break;
88 case 'field_group':
89 $property['type'] = 'object';
90 $property['properties'] = [];
91 }
92
93 $properties[ $schema['key'] ] = $property;
94 }
95
96 $args[ $feature->slug ] = [
97 'description' => $feature->get_title(),
98 'properties' => $properties,
99 'type' => 'object',
100 ];
101
102 if ( method_exists( $feature, 'sanitize_settings_callback' ) ) {
103 $args[ $feature->slug ]['sanitize_callback'] = [ $feature, 'sanitize_settings_callback' ];
104 }
105 }
106
107 return $args;
108 }
109
110 /**
111 * Check that the request has permission to save features.
112 *
113 * @return boolean
114 */
115 public function check_permission() {
116 $capability = Utils\get_capability();
117
118 return current_user_can( $capability );
119 }
120
121 /**
122 * Update features settings.
123 *
124 * @param \WP_REST_Request $request Full details about the request.
125 * @return array
126 */
127 public function update_settings( \WP_REST_Request $request ) {
128 if ( Utils\is_indexing() ) {
129 wp_send_json_error( 'is_syncing', 400 );
130 exit;
131 }
132
133 $current_settings = FeaturesStore::factory()->get_feature_settings();
134 $new_settings = $current_settings;
135
136 $features = \ElasticPress\Features::factory()->registered_features;
137
138 $settings_that_requires_features = [];
139
140 foreach ( $features as $slug => $feature ) {
141 $param = $request->get_param( $slug );
142
143 if ( ! $param ) {
144 continue;
145 }
146
147 if ( empty( $current_settings[ $slug ] ) ) {
148 $current_settings[ $slug ] = [];
149 $new_settings[ $slug ] = [];
150 }
151
152 $schema = $feature->get_settings_schema();
153
154 foreach ( $schema as $schema ) {
155 $key = $schema['key'];
156 $type = $schema['type'] ?? '';
157
158 if ( isset( $param[ $key ] ) ) {
159 // Handle field group values
160 if ( 'field_group' === $type ) {
161 // Save the nested structure for the settings UI
162 $new_settings[ $slug ][ $key ] = $param[ $key ];
163
164 // Flatten the field group values into the main settings array
165 foreach ( $schema['fields'] as $field ) {
166 $field_key = $field['key'];
167 if ( isset( $param[ $key ][ $field_key ] ) ) {
168 $new_settings[ $slug ][ $field_key ] = $param[ $key ][ $field_key ];
169
170 // Only apply to current settings if no sync required
171 if ( empty( $schema['requires_sync'] ) ) {
172 $current_settings[ $slug ][ $field_key ] = $param[ $key ][ $field_key ];
173 }
174 }
175 }
176 } else {
177 $new_settings[ $slug ][ $key ] = $param[ $key ];
178 }
179
180 // Only apply to the current settings if does not require a sync or if it is activating it
181 if ( ! empty( $schema['requires_sync'] ) && ! empty( $param[ $key ] ) ) {
182 continue;
183 }
184
185 /*
186 * If a setting requires another feature, we have to check for it after running through everything,
187 * as it is possible that the feature will be active after this foreach.
188 */
189 if ( empty( $schema['requires_feature'] ) ) {
190 $current_settings[ $slug ][ $key ] = $param[ $key ];
191 } else {
192 if ( ! isset( $settings_that_requires_features[ $slug ] ) ) {
193 $settings_that_requires_features[ $slug ] = [];
194 }
195 $settings_that_requires_features[ $slug ][ $key ] = [
196 'required_feature' => $schema['requires_feature'],
197 'value' => $param[ $key ],
198 ];
199 }
200 }
201 }
202 }
203
204 foreach ( $settings_that_requires_features as $feature => $fields ) {
205 foreach ( $fields as $field_key => $field_data ) {
206 $required_features = (array) $field_data['required_feature'];
207
208 $all_required_active = true;
209 foreach ( $required_features as $required_feature_slug ) {
210 if ( empty( $current_settings[ $required_feature_slug ]['active'] ) ) {
211 $all_required_active = false;
212 break;
213 }
214 }
215
216 if ( $all_required_active ) {
217 $current_settings[ $feature ][ $field_key ] = $field_data['value'];
218 }
219 }
220 }
221
222 foreach ( $current_settings as $slug => $feature ) {
223 FeaturesStore::factory()->update_feature( $slug, $feature );
224 }
225
226 foreach ( $new_settings as $slug => $feature ) {
227 FeaturesStore::factory()->update_feature( $slug, $feature, true, 'draft' );
228 }
229
230 return [
231 'success' => true,
232 ];
233 }
234
235 /**
236 * Return the current features payload along with persisted settings.
237 *
238 * @since 5.3.0
239 * @return array
240 */
241 public function get_features() {
242 $store = FeaturesStore::factory();
243
244 $settings = $store->get_feature_settings();
245 $settings_draft = $store->get_feature_settings_draft();
246
247 return [
248 'features' => $this->get_features_payload(),
249 'settings' => is_array( $settings ) ? $settings : [],
250 'settingsDraft' => is_array( $settings_draft ) ? $settings_draft : null,
251 'success' => true,
252 ];
253 }
254
255 /**
256 * Build the serialized features payload.
257 *
258 * @since 5.3.0
259 * @return array
260 */
261 protected function get_features_payload() {
262 $features_objects = FeaturesStore::factory()->registered_features;
263
264 foreach ( $features_objects as $feature ) {
265 $feature->reset_settings_schema();
266 }
267
268 $features_data = array_map( fn( $feature ) => $feature->get_json(), $features_objects );
269 return array_values( $features_data );
270 }
271 }
272