File: /home/lucendi/www/wp-content/plugins/responsive-lightbox/includes/settings/class-settings-base.php
<?php
/**
* Responsive Lightbox Settings Base Class
*
* Abstract base class providing common structure for all Settings API page classes.
* Enforces consistent patterns while allowing flexibility through abstract methods.
*
* @package Responsive_Lightbox
*/
// exit if accessed directly
if ( ! defined( 'ABSPATH' ) )
exit;
/**
* Responsive_Lightbox_Settings_Base class.
*
* Base class for settings page migration to new Settings API.
* Provides standardized structure and common functionality.
*
* @abstract
* @class Responsive_Lightbox_Settings_Base
*/
abstract class Responsive_Lightbox_Settings_Base {
/**
* Tab key identifier.
*
* Must be defined in child class.
*
* @var string
*/
const TAB_KEY = '';
/**
* Class constructor.
*
* Registers filters for Settings API integration.
*
* @return void
*/
public function __construct() {
// provide settings data for this tab
$priority = $this->get_settings_data_priority();
add_filter( 'rl_settings_data', [ $this, 'settings_data' ], $priority );
}
/**
* Get the priority for settings_data filter.
*
* Override in child class if tab needs late loading (e.g., Remote Library uses 100).
* Default is 10 for standard tabs.
*
* @return int Filter priority.
*/
protected function get_settings_data_priority() {
return 10;
}
/**
* Validate settings for this tab.
*
* Default implementation uses base class field sanitization.
* Child classes can override to provide tab-specific validation logic.
*
* @param array $input Input data from form submission.
* @return array Validated data.
*/
public function validate( $input ) {
// Use base class sanitization by default
// Child classes override for custom validation logic
return $this->sanitize_fields( $input, static::TAB_KEY );
}
/**
* Provide settings data for this tab.
*
* Must be implemented by child class.
* Should return array with structure:
* [
* 'option_name' => 'responsive_lightbox_*',
* 'option_group' => 'responsive_lightbox_*',
* 'validate' => [ $this, 'validate' ],
* 'sections' => [ ... ],
* 'fields' => [ ... ] // or nested in sections
* ]
*
* @abstract
* @param array $data Settings data from other tabs.
* @return array Modified settings data.
*/
abstract public function settings_data( $data );
/**
* Get the tab key.
*
* Convenience method to access TAB_KEY constant.
*
* @return string
*/
public function get_tab_key() {
return static::TAB_KEY;
}
/**
* Check if this is the current tab.
*
* @return bool
*/
protected function is_current_tab() {
$current_tab = isset( $_GET['tab'] ) ? sanitize_key( $_GET['tab'] ) : 'settings';
return $current_tab === static::TAB_KEY;
}
/**
* Get current section key from URL.
*
* @return string
*/
protected function get_current_section() {
return isset( $_GET['section'] ) ? sanitize_key( $_GET['section'] ) : '';
}
/**
* Merge input with current saved options.
*
* Useful for preserving fields not included in the current form.
*
* @param array $input New input values.
* @return array Merged values.
*/
protected function merge_with_saved( $input ) {
$rl = Responsive_Lightbox();
$tab_key = static::TAB_KEY;
if ( isset( $rl->options[$tab_key] ) && is_array( $rl->options[$tab_key] ) ) {
return array_merge( $rl->options[$tab_key], $input );
}
return $input;
}
/**
* Merge input with default options.
*
* Useful for reset operations or ensuring required fields exist.
*
* @param array $input Input values.
* @return array Merged values with defaults.
*/
protected function merge_with_defaults( $input ) {
$rl = Responsive_Lightbox();
$tab_key = static::TAB_KEY;
if ( isset( $rl->defaults[$tab_key] ) && is_array( $rl->defaults[$tab_key] ) ) {
return array_merge( $rl->defaults[$tab_key], $input );
}
return $input;
}
/**
* Preserve specific system fields from current options.
*
* Useful for fields that should never be modified by user input
* (e.g., version numbers, internal flags).
*
* @param array $input New input values.
* @param array $field_keys Array of field keys to preserve.
* @return array Input with preserved system fields.
*/
protected function preserve_system_fields( $input, $field_keys = [] ) {
$rl = Responsive_Lightbox();
$tab_key = static::TAB_KEY;
if ( isset( $rl->options[$tab_key] ) && is_array( $rl->options[$tab_key] ) ) {
foreach ( $field_keys as $field_key ) {
if ( isset( $rl->options[$tab_key][$field_key] ) ) {
$input[$field_key] = $rl->options[$tab_key][$field_key];
}
}
}
return $input;
}
/**
* Check if current request is a save operation.
*
* @param string $option_page Option page name to check.
* @return bool
*/
protected function is_save_request( $option_page = '' ) {
if ( $option_page === '' ) {
$option_page = 'responsive_lightbox_' . static::TAB_KEY;
}
$legacy_save = 'save_rl_' . static::TAB_KEY;
$api_save = 'save_' . $option_page;
return isset( $_POST[$legacy_save] ) || isset( $_POST[$api_save] );
}
/**
* Check if current request is a reset operation.
*
* @param string $option_page Option page name to check.
* @return bool
*/
protected function is_reset_request( $option_page = '' ) {
if ( $option_page === '' ) {
$option_page = 'responsive_lightbox_' . static::TAB_KEY;
}
$legacy_reset = 'reset_rl_' . static::TAB_KEY;
$api_reset = 'reset_' . $option_page;
return isset( $_POST[$legacy_reset] ) || isset( $_POST[$api_reset] );
}
/**
* Normalize fields from Settings API data structure.
*
* Flattens fields that may be nested under sections or at top-level.
* Returns array of [field_id => field_definition] for processing.
*
* @param array $settings_data Settings data array with sections/fields.
* @return array Flat array of fields.
*/
protected function normalize_fields( $settings_data ) {
$fields = [];
// collect top-level fields
if ( ! empty( $settings_data['fields'] ) && is_array( $settings_data['fields'] ) ) {
$fields = $settings_data['fields'];
}
// collect fields nested in sections (PVC-style)
if ( ! empty( $settings_data['sections'] ) && is_array( $settings_data['sections'] ) ) {
foreach ( $settings_data['sections'] as $section_id => $section ) {
if ( ! empty( $section['fields'] ) && is_array( $section['fields'] ) ) {
$fields = array_merge( $fields, $section['fields'] );
}
}
}
return $fields;
}
/**
* Sanitize all fields for this tab using local sanitization logic.
*
* Handles multiple field groups, parent mapping, checkbox arrays, and
* boolean/checkbox defaults. Uses local sanitize_field() method.
*
* @param array $input Input data from form submission.
* @param string $settings_key Settings key (e.g., 'settings', 'builder').
* @param array $fields Field definitions (pass null to auto-detect from settings_data).
* @return array Sanitized input.
*/
protected function sanitize_fields( $input, $settings_key = '', $fields = null ) {
$rl = Responsive_Lightbox();
// auto-detect settings key if not provided
if ( $settings_key === '' ) {
$settings_key = static::TAB_KEY;
}
// auto-detect fields if not provided
if ( $fields === null ) {
// try to get from Settings API data
$settings_data = apply_filters( 'rl_settings_data', [] );
if ( isset( $settings_data[$settings_key] ) ) {
$fields = $this->normalize_fields( $settings_data[$settings_key] );
} else {
// fallback to legacy settings using getter method
if ( $rl->settings->has_setting_tab( $settings_key ) ) {
$fields = $rl->settings->get_setting_fields( $settings_key );
} else {
return $input;
}
}
}
// sanitize each field
foreach ( $fields as $field_id => $field ) {
if ( $field['type'] === 'multiple' ) {
// handle grouped subfields
if ( ! empty( $field['fields'] ) ) {
foreach ( $field['fields'] as $subfield_id => $subfield ) {
$args = $subfield;
$args['setting_id'] = $settings_key;
$args['field_id'] = $field_id;
$args['subfield_id'] = $subfield_id;
$default_value = '';
if ( $subfield['type'] === 'boolean' )
$default_value = false;
elseif ( $subfield['type'] === 'checkbox' )
$default_value = [];
elseif ( $subfield['type'] === 'number' )
$default_value = 0;
// check if subfield has parent (nested options like configuration[glightbox][loop])
if ( ! empty( $field['fields'][$subfield_id]['parent'] ) ) {
$field_parent = $field['fields'][$subfield_id]['parent'];
if ( isset( $rl->defaults[$settings_key][$field_parent][$subfield_id] ) )
$default_value = $rl->defaults[$settings_key][$field_parent][$subfield_id];
$input[$field_parent][$subfield_id] = isset( $input[$field_parent][$subfield_id] )
? $this->sanitize_field( $input[$field_parent][$subfield_id], $subfield['type'], $args )
: ( $subfield['type'] === 'boolean' ? false : $default_value );
} else {
if ( isset( $rl->defaults[$settings_key][$field_id][$subfield_id] ) )
$default_value = $rl->defaults[$settings_key][$field_id][$subfield_id];
$input[$subfield_id] = isset( $input[$subfield_id] )
? $this->sanitize_field( $input[$subfield_id], $subfield['type'], $args )
: ( $subfield['type'] === 'boolean' ? false : $default_value );
}
}
}
} else {
// handle single fields
$args = $field;
$args['setting_id'] = $settings_key;
$args['field_id'] = $field_id;
$default_value = '';
if ( $field['type'] === 'boolean' )
$default_value = false;
elseif ( $field['type'] === 'checkbox' )
$default_value = [];
elseif ( $field['type'] === 'number' )
$default_value = 0;
// check if field has parent (nested options)
if ( ! empty( $field['parent'] ) ) {
$field_parent = $field['parent'];
if ( isset( $rl->defaults[$settings_key][$field_parent][$field_id] ) )
$default_value = $rl->defaults[$settings_key][$field_parent][$field_id];
$input[$field_parent][$field_id] = isset( $input[$field_parent][$field_id] )
? ( $field['type'] === 'checkbox'
? array_keys( $this->sanitize_field( $input[$field_parent][$field_id], $field['type'], $args ) )
: $this->sanitize_field( $input[$field_parent][$field_id], $field['type'], $args ) )
: ( in_array( $field['type'], [ 'boolean', 'checkbox' ], true ) ? false : $default_value );
} else {
if ( isset( $rl->defaults[$settings_key][$field_id] ) )
$default_value = $rl->defaults[$settings_key][$field_id];
$input[$field_id] = isset( $input[$field_id] )
? ( $field['type'] === 'checkbox'
? array_keys( $this->sanitize_field( $input[$field_id], $field['type'], $args ) )
: $this->sanitize_field( $input[$field_id], $field['type'], $args ) )
: ( in_array( $field['type'], [ 'boolean', 'checkbox' ], true ) ? false : $default_value );
}
}
}
return $input;
}
/**
* Sanitize field value.
*
* Copied from legacy class-settings.php sanitize_field() to make Base class
* self-contained. Applies type-specific sanitization rules.
*
* @param mixed $value Field value to sanitize.
* @param string $type Field type (boolean, checkbox, radio, textarea, etc.).
* @param array $args Field arguments (optional, for context-specific validation).
* @return mixed Sanitized value.
*/
protected function sanitize_field( $value = null, $type = '', $args = [] ) {
if ( is_null( $value ) )
return null;
switch ( $type ) {
case 'button':
case 'boolean':
// handle string 'false' from new Settings API
if ( $value === 'false' )
$value = false;
else
$value = empty( $value ) ? false : true;
break;
case 'checkbox':
$value = is_array( $value ) && ! empty( $value ) ? array_map( 'sanitize_key', $value ) : [];
break;
case 'radio':
$value = is_array( $value ) ? false : sanitize_key( $value );
break;
case 'textarea':
case 'wysiwyg':
$value = wp_kses_post( $value );
break;
case 'color_picker':
$value = sanitize_hex_color( $value );
if ( empty( $value ) )
$value = '#666666';
break;
case 'number':
$value = (int) $value;
// is value lower than?
if ( isset( $args['min'] ) && $value < $args['min'] )
$value = $args['min'];
// is value greater than?
if ( isset( $args['max'] ) && $value > $args['max'] )
$value = $args['max'];
break;
case 'custom':
// do nothing
break;
case 'text':
if ( ! empty( $args ) ) {
// validate custom events
if ( $args['setting_id'] === 'settings' ) {
if ( $args['field_id'] === 'enable_custom_events' && $args['subfield_id'] === 'custom_events' )
$value = preg_replace( '/[^a-z0-9\s.-]/i', '', $value );
} elseif ( $args['setting_id'] === 'builder' ) {
if ( $args['field_id'] === 'permalink' || $args['field_id'] === 'permalink_categories' || $args['field_id'] === 'permalink_tags' )
$value = sanitize_title( $value );
}
}
// intentional fallthrough to default sanitization
case 'select':
default:
$value = is_array( $value ) ? array_map( 'sanitize_text_field', $value ) : sanitize_text_field( $value );
break;
}
return stripslashes_deep( $value );
}
}