PluginProbe ʕ •ᴥ•ʔ
Responsive Lightbox & Gallery / 2.7.2
Responsive Lightbox & Gallery v2.7.2
2.7.8 trunk 1.0.0 1.0.1 1.0.1.1 1.0.2 1.0.3 1.0.4 1.1.0 1.1.1 1.1.2 1.2.0 1.2.1 1.2.2 1.2.3 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.4.0 1.4.0.1 1.4.1 1.4.11 1.4.12 1.4.13 1.4.14 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.1 1.6.10 1.6.11 1.6.12 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 2.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1 2.2.0 2.2.1 2.2.2 2.2.3 2.2.3.1 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.3.5 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.4.7 2.4.8 2.4.9 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 2.6.0 2.6.1 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7
responsive-lightbox / includes / settings / class-settings-base.php
responsive-lightbox / includes / settings Last commit date
class-settings-addons.php 4 months ago class-settings-base.php 5 months ago class-settings-builder.php 5 months ago class-settings-capabilities.php 5 months ago class-settings-folders.php 5 months ago class-settings-galleries.php 5 months ago class-settings-general.php 5 months ago class-settings-licenses.php 5 months ago class-settings-lightboxes.php 4 months ago class-settings-remote-library.php 5 months ago
class-settings-base.php
447 lines
1 <?php
2 /**
3 * Responsive Lightbox Settings Base Class
4 *
5 * Abstract base class providing common structure for all Settings API page classes.
6 * Enforces consistent patterns while allowing flexibility through abstract methods.
7 *
8 * @package Responsive_Lightbox
9 */
10
11 // exit if accessed directly
12 if ( ! defined( 'ABSPATH' ) )
13 exit;
14
15 /**
16 * Responsive_Lightbox_Settings_Base class.
17 *
18 * Base class for settings page migration to new Settings API.
19 * Provides standardized structure and common functionality.
20 *
21 * @abstract
22 * @class Responsive_Lightbox_Settings_Base
23 */
24 abstract class Responsive_Lightbox_Settings_Base {
25
26 /**
27 * Tab key identifier.
28 *
29 * Must be defined in child class.
30 *
31 * @var string
32 */
33 const TAB_KEY = '';
34
35 /**
36 * Class constructor.
37 *
38 * Registers filters for Settings API integration.
39 *
40 * @return void
41 */
42 public function __construct() {
43 // provide settings data for this tab
44 $priority = $this->get_settings_data_priority();
45 add_filter( 'rl_settings_data', [ $this, 'settings_data' ], $priority );
46 }
47
48 /**
49 * Get the priority for settings_data filter.
50 *
51 * Override in child class if tab needs late loading (e.g., Remote Library uses 100).
52 * Default is 10 for standard tabs.
53 *
54 * @return int Filter priority.
55 */
56 protected function get_settings_data_priority() {
57 return 10;
58 }
59
60 /**
61 * Validate settings for this tab.
62 *
63 * Default implementation uses base class field sanitization.
64 * Child classes can override to provide tab-specific validation logic.
65 *
66 * @param array $input Input data from form submission.
67 * @return array Validated data.
68 */
69 public function validate( $input ) {
70 // Use base class sanitization by default
71 // Child classes override for custom validation logic
72 return $this->sanitize_fields( $input, static::TAB_KEY );
73 }
74
75 /**
76 * Provide settings data for this tab.
77 *
78 * Must be implemented by child class.
79 * Should return array with structure:
80 * [
81 * 'option_name' => 'responsive_lightbox_*',
82 * 'option_group' => 'responsive_lightbox_*',
83 * 'validate' => [ $this, 'validate' ],
84 * 'sections' => [ ... ],
85 * 'fields' => [ ... ] // or nested in sections
86 * ]
87 *
88 * @abstract
89 * @param array $data Settings data from other tabs.
90 * @return array Modified settings data.
91 */
92 abstract public function settings_data( $data );
93
94 /**
95 * Get the tab key.
96 *
97 * Convenience method to access TAB_KEY constant.
98 *
99 * @return string
100 */
101 public function get_tab_key() {
102 return static::TAB_KEY;
103 }
104
105 /**
106 * Check if this is the current tab.
107 *
108 * @return bool
109 */
110 protected function is_current_tab() {
111 $current_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'settings';
112 return $current_tab === static::TAB_KEY;
113 }
114
115 /**
116 * Get current section key from URL.
117 *
118 * @return string
119 */
120 protected function get_current_section() {
121 return isset( $_GET['section'] ) ? sanitize_key( $_GET['section'] ) : '';
122 }
123
124 /**
125 * Merge input with current saved options.
126 *
127 * Useful for preserving fields not included in the current form.
128 *
129 * @param array $input New input values.
130 * @return array Merged values.
131 */
132 protected function merge_with_saved( $input ) {
133 $rl = Responsive_Lightbox();
134 $tab_key = static::TAB_KEY;
135
136 if ( isset( $rl->options[$tab_key] ) && is_array( $rl->options[$tab_key] ) ) {
137 return array_merge( $rl->options[$tab_key], $input );
138 }
139
140 return $input;
141 }
142
143 /**
144 * Merge input with default options.
145 *
146 * Useful for reset operations or ensuring required fields exist.
147 *
148 * @param array $input Input values.
149 * @return array Merged values with defaults.
150 */
151 protected function merge_with_defaults( $input ) {
152 $rl = Responsive_Lightbox();
153 $tab_key = static::TAB_KEY;
154
155 if ( isset( $rl->defaults[$tab_key] ) && is_array( $rl->defaults[$tab_key] ) ) {
156 return array_merge( $rl->defaults[$tab_key], $input );
157 }
158
159 return $input;
160 }
161
162 /**
163 * Preserve specific system fields from current options.
164 *
165 * Useful for fields that should never be modified by user input
166 * (e.g., version numbers, internal flags).
167 *
168 * @param array $input New input values.
169 * @param array $field_keys Array of field keys to preserve.
170 * @return array Input with preserved system fields.
171 */
172 protected function preserve_system_fields( $input, $field_keys = [] ) {
173 $rl = Responsive_Lightbox();
174 $tab_key = static::TAB_KEY;
175
176 if ( isset( $rl->options[$tab_key] ) && is_array( $rl->options[$tab_key] ) ) {
177 foreach ( $field_keys as $field_key ) {
178 if ( isset( $rl->options[$tab_key][$field_key] ) ) {
179 $input[$field_key] = $rl->options[$tab_key][$field_key];
180 }
181 }
182 }
183
184 return $input;
185 }
186
187 /**
188 * Check if current request is a save operation.
189 *
190 * @param string $option_page Option page name to check.
191 * @return bool
192 */
193 protected function is_save_request( $option_page = '' ) {
194 if ( $option_page === '' ) {
195 $option_page = 'responsive_lightbox_' . static::TAB_KEY;
196 }
197
198 $legacy_save = 'save_rl_' . static::TAB_KEY;
199 $api_save = 'save_' . $option_page;
200
201 return isset( $_POST[$legacy_save] ) || isset( $_POST[$api_save] );
202 }
203
204 /**
205 * Check if current request is a reset operation.
206 *
207 * @param string $option_page Option page name to check.
208 * @return bool
209 */
210 protected function is_reset_request( $option_page = '' ) {
211 if ( $option_page === '' ) {
212 $option_page = 'responsive_lightbox_' . static::TAB_KEY;
213 }
214
215 $legacy_reset = 'reset_rl_' . static::TAB_KEY;
216 $api_reset = 'reset_' . $option_page;
217
218 return isset( $_POST[$legacy_reset] ) || isset( $_POST[$api_reset] );
219 }
220
221 /**
222 * Normalize fields from Settings API data structure.
223 *
224 * Flattens fields that may be nested under sections or at top-level.
225 * Returns array of [field_id => field_definition] for processing.
226 *
227 * @param array $settings_data Settings data array with sections/fields.
228 * @return array Flat array of fields.
229 */
230 protected function normalize_fields( $settings_data ) {
231 $fields = [];
232
233 // collect top-level fields
234 if ( ! empty( $settings_data['fields'] ) && is_array( $settings_data['fields'] ) ) {
235 $fields = $settings_data['fields'];
236 }
237
238 // collect fields nested in sections (PVC-style)
239 if ( ! empty( $settings_data['sections'] ) && is_array( $settings_data['sections'] ) ) {
240 foreach ( $settings_data['sections'] as $section_id => $section ) {
241 if ( ! empty( $section['fields'] ) && is_array( $section['fields'] ) ) {
242 $fields = array_merge( $fields, $section['fields'] );
243 }
244 }
245 }
246
247 return $fields;
248 }
249
250 /**
251 * Sanitize all fields for this tab using local sanitization logic.
252 *
253 * Handles multiple field groups, parent mapping, checkbox arrays, and
254 * boolean/checkbox defaults. Uses local sanitize_field() method.
255 *
256 * @param array $input Input data from form submission.
257 * @param string $settings_key Settings key (e.g., 'settings', 'builder').
258 * @param array $fields Field definitions (pass null to auto-detect from settings_data).
259 * @return array Sanitized input.
260 */
261 protected function sanitize_fields( $input, $settings_key = '', $fields = null ) {
262 $rl = Responsive_Lightbox();
263
264 // auto-detect settings key if not provided
265 if ( $settings_key === '' ) {
266 $settings_key = static::TAB_KEY;
267 }
268
269 // auto-detect fields if not provided
270 if ( $fields === null ) {
271 // try to get from Settings API data
272 $settings_data = apply_filters( 'rl_settings_data', [] );
273 if ( isset( $settings_data[$settings_key] ) ) {
274 $fields = $this->normalize_fields( $settings_data[$settings_key] );
275 } else {
276 // fallback to legacy settings using getter method
277 if ( $rl->settings->has_setting_tab( $settings_key ) ) {
278 $fields = $rl->settings->get_setting_fields( $settings_key );
279 } else {
280 return $input;
281 }
282 }
283 }
284
285 // sanitize each field
286 foreach ( $fields as $field_id => $field ) {
287 if ( $field['type'] === 'multiple' ) {
288 // handle grouped subfields
289 if ( ! empty( $field['fields'] ) ) {
290 foreach ( $field['fields'] as $subfield_id => $subfield ) {
291 $args = $subfield;
292 $args['setting_id'] = $settings_key;
293 $args['field_id'] = $field_id;
294 $args['subfield_id'] = $subfield_id;
295
296 $default_value = '';
297 if ( $subfield['type'] === 'boolean' )
298 $default_value = false;
299 elseif ( $subfield['type'] === 'checkbox' )
300 $default_value = [];
301 elseif ( $subfield['type'] === 'number' )
302 $default_value = 0;
303
304 // check if subfield has parent (nested options like configuration[glightbox][loop])
305 if ( ! empty( $field['fields'][$subfield_id]['parent'] ) ) {
306 $field_parent = $field['fields'][$subfield_id]['parent'];
307
308 if ( isset( $rl->defaults[$settings_key][$field_parent][$subfield_id] ) )
309 $default_value = $rl->defaults[$settings_key][$field_parent][$subfield_id];
310
311 $input[$field_parent][$subfield_id] = isset( $input[$field_parent][$subfield_id] )
312 ? $this->sanitize_field( $input[$field_parent][$subfield_id], $subfield['type'], $args )
313 : ( $subfield['type'] === 'boolean' ? false : $default_value );
314 } else {
315 if ( isset( $rl->defaults[$settings_key][$field_id][$subfield_id] ) )
316 $default_value = $rl->defaults[$settings_key][$field_id][$subfield_id];
317
318 $input[$subfield_id] = isset( $input[$subfield_id] )
319 ? $this->sanitize_field( $input[$subfield_id], $subfield['type'], $args )
320 : ( $subfield['type'] === 'boolean' ? false : $default_value );
321 }
322 }
323 }
324 } else {
325 // handle single fields
326 $args = $field;
327 $args['setting_id'] = $settings_key;
328 $args['field_id'] = $field_id;
329
330 $default_value = '';
331 if ( $field['type'] === 'boolean' )
332 $default_value = false;
333 elseif ( $field['type'] === 'checkbox' )
334 $default_value = [];
335 elseif ( $field['type'] === 'number' )
336 $default_value = 0;
337
338 // check if field has parent (nested options)
339 if ( ! empty( $field['parent'] ) ) {
340 $field_parent = $field['parent'];
341
342 if ( isset( $rl->defaults[$settings_key][$field_parent][$field_id] ) )
343 $default_value = $rl->defaults[$settings_key][$field_parent][$field_id];
344
345 $input[$field_parent][$field_id] = isset( $input[$field_parent][$field_id] )
346 ? ( $field['type'] === 'checkbox'
347 ? array_keys( $this->sanitize_field( $input[$field_parent][$field_id], $field['type'], $args ) )
348 : $this->sanitize_field( $input[$field_parent][$field_id], $field['type'], $args ) )
349 : ( in_array( $field['type'], [ 'boolean', 'checkbox' ], true ) ? false : $default_value );
350 } else {
351 if ( isset( $rl->defaults[$settings_key][$field_id] ) )
352 $default_value = $rl->defaults[$settings_key][$field_id];
353
354 $input[$field_id] = isset( $input[$field_id] )
355 ? ( $field['type'] === 'checkbox'
356 ? array_keys( $this->sanitize_field( $input[$field_id], $field['type'], $args ) )
357 : $this->sanitize_field( $input[$field_id], $field['type'], $args ) )
358 : ( in_array( $field['type'], [ 'boolean', 'checkbox' ], true ) ? false : $default_value );
359 }
360 }
361 }
362
363 return $input;
364 }
365
366 /**
367 * Sanitize field value.
368 *
369 * Copied from legacy class-settings.php sanitize_field() to make Base class
370 * self-contained. Applies type-specific sanitization rules.
371 *
372 * @param mixed $value Field value to sanitize.
373 * @param string $type Field type (boolean, checkbox, radio, textarea, etc.).
374 * @param array $args Field arguments (optional, for context-specific validation).
375 * @return mixed Sanitized value.
376 */
377 protected function sanitize_field( $value = null, $type = '', $args = [] ) {
378 if ( is_null( $value ) )
379 return null;
380
381 switch ( $type ) {
382 case 'button':
383 case 'boolean':
384 // handle string 'false' from new Settings API
385 if ( $value === 'false' )
386 $value = false;
387 else
388 $value = empty( $value ) ? false : true;
389 break;
390
391 case 'checkbox':
392 $value = is_array( $value ) && ! empty( $value ) ? array_map( 'sanitize_key', $value ) : [];
393 break;
394
395 case 'radio':
396 $value = is_array( $value ) ? false : sanitize_key( $value );
397 break;
398
399 case 'textarea':
400 case 'wysiwyg':
401 $value = wp_kses_post( $value );
402 break;
403
404 case 'color_picker':
405 $value = sanitize_hex_color( $value );
406
407 if ( empty( $value ) )
408 $value = '#666666';
409 break;
410
411 case 'number':
412 $value = (int) $value;
413
414 // is value lower than?
415 if ( isset( $args['min'] ) && $value < $args['min'] )
416 $value = $args['min'];
417
418 // is value greater than?
419 if ( isset( $args['max'] ) && $value > $args['max'] )
420 $value = $args['max'];
421 break;
422
423 case 'custom':
424 // do nothing
425 break;
426
427 case 'text':
428 if ( ! empty( $args ) ) {
429 // validate custom events
430 if ( $args['setting_id'] === 'settings' ) {
431 if ( $args['field_id'] === 'enable_custom_events' && $args['subfield_id'] === 'custom_events' )
432 $value = preg_replace( '/[^a-z0-9\s.-]/i', '', $value );
433 } elseif ( $args['setting_id'] === 'builder' ) {
434 if ( $args['field_id'] === 'permalink' || $args['field_id'] === 'permalink_categories' || $args['field_id'] === 'permalink_tags' )
435 $value = sanitize_title( $value );
436 }
437 }
438 // intentional fallthrough to default sanitization
439 case 'select':
440 default:
441 $value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
442 break;
443 }
444
445 return stripslashes_deep( $value );
446 }
447 }