src/settings/class-wp-site-identity-standard-setting-registry.php
<?php
/**
* WP_Site_Identity_Setting_Registry class
*
* @package WPSiteIdentity
* @since 1.0.0
*/
/**
* Class responsible for registering settings.
*
* @since 1.0.0
*/
class WP_Site_Identity_Standard_Setting_Registry implements WP_Site_Identity_Setting_Registry {
/**
* Prefix to use for all setting names within WordPress.
*
* @since 1.0.0
* @var string
*/
protected $prefix = '';
/**
* Group to use for all settings within WordPress.
*
* @since 1.0.0
* @var string
*/
protected $group = '';
/**
* All registered settings as `$name => $instance` pairs.
*
* @since 1.0.0
* @var array
*/
protected $settings = array();
/**
* Factory to create setting objects.
*
* @since 1.0.0
* @var WP_Site_Identity_Setting_Factory
*/
protected $factory;
/**
* Feedback handler to use for registered settings.
*
* @since 1.0.0
* @var WP_Site_Identity_Setting_Feedback_Handler
*/
protected $feedback_handler;
/**
* Validator to use for registered settings.
*
* @since 1.0.0
* @var WP_Site_Identity_Setting_Validator
*/
protected $validator;
/**
* Sanitizer to use for registered settings.
*
* @since 1.0.0
* @var WP_Site_Identity_Setting_Sanitizer
*/
protected $sanitizer;
/**
* Constructor.
*
* Sets the prefix and group to use for registered settings, plus dependencies.
*
* @since 1.0.0
*
* @param string $prefix Prefix to use for all setting names within WordPress.
* @param string $group Group to use for all settings within WordPress.
* @param WP_Site_Identity_Setting_Feedback_Handler $feedback_handler Optional. Feedback handler to use.
* @param WP_Site_Identity_Setting_Validator $validator Optional. Validator to use.
* @param WP_Site_Identity_Setting_Sanitizer $sanitizer Optional. Sanitizer to use.
*/
public function __construct( $prefix, $group, WP_Site_Identity_Setting_Feedback_Handler $feedback_handler = null, WP_Site_Identity_Setting_Validator $validator = null, WP_Site_Identity_Setting_Sanitizer $sanitizer = null ) {
$this->prefix = $prefix;
$this->group = $group;
$this->factory = new WP_Site_Identity_Setting_Factory( $this );
if ( $feedback_handler ) {
$this->feedback_handler = $feedback_handler;
} else {
$this->feedback_handler = new WP_Site_Identity_Setting_Feedback_Handler();
}
if ( $validator ) {
$this->validator = $validator;
} else {
$this->validator = new WP_Site_Identity_Setting_Validator();
}
if ( $sanitizer ) {
$this->sanitizer = $sanitizer;
} else {
$this->sanitizer = new WP_Site_Identity_Setting_Sanitizer();
}
$this->feedback_handler->set_prefix( $this->prefix );
}
/**
* Gets the current value for a setting.
*
* @since 1.0.0
*
* @param string $name Name of the setting.
* @return mixed Current setting value.
*
* @throws WP_Site_Identity_Setting_Not_Found_Exception Thrown when a setting cannot be found.
*/
public function get_value( $name ) {
if ( ! isset( $this->settings[ $name ] ) ) {
/* translators: %s: setting name */
throw new WP_Site_Identity_Setting_Not_Found_Exception( sprintf( __( 'The setting with the name %s could not be found.', 'wp-site-identity' ), $name ) );
}
return $this->get_value_from_wp( $this->settings[ $name ] );
}
/**
* Gets all registered settings.
*
* @since 1.0.0
*
* @return array Array of `$name => $instance` pairs.
*/
public function get_all_settings() {
return $this->settings;
}
/**
* Gets a registered setting instance.
*
* @since 1.0.0
*
* @param string $name Name of the setting.
* @return WP_Site_Identity_Setting Registered setting.
*
* @throws WP_Site_Identity_Setting_Not_Found_Exception Thrown when a setting cannot be found.
*/
public function get_setting( $name ) {
if ( ! isset( $this->settings[ $name ] ) ) {
/* translators: %s: setting name */
throw new WP_Site_Identity_Setting_Not_Found_Exception( sprintf( __( 'The setting with the name %s could not be found.', 'wp-site-identity' ), $name ) );
}
return $this->settings[ $name ];
}
/**
* Checks whether a setting is registered.
*
* @since 1.0.0
*
* @param string $name Name of the setting.
* @return bool True if the setting is registered, false otherwise.
*/
public function has_setting( $name ) {
return isset( $this->settings[ $name ] );
}
/**
* Registers a new setting.
*
* @since 1.0.0
*
* @param WP_Site_Identity_Setting $setting Setting to register.
*/
public function register_setting( WP_Site_Identity_Setting $setting ) {
$name = $setting->get_name();
$this->settings[ $name ] = $setting;
$this->register_in_wp( $setting );
}
/**
* Unregisters an existing setting.
*
* @since 1.0.0
*
* @param WP_Site_Identity_Setting $setting Setting to unregister.
*/
public function unregister_setting( WP_Site_Identity_Setting $setting ) {
$name = $setting->get_name();
if ( ! isset( $this->settings[ $name ] ) ) {
return;
}
$this->unregister_in_wp( $this->settings[ $name ] );
unset( $this->settings[ $name ] );
}
/**
* Gets the factory to create setting objects.
*
* @since 1.0.0
*
* @return WP_Site_Identity_Setting_Factory Factory to create setting objects.
*/
public function factory() {
return $this->factory;
}
/**
* Gets the feedback handler for the setting registry.
*
* @since 1.0.0
*
* @return WP_Site_Identity_Setting_Feedback_Handler Feedback handler to use for registered settings.
*/
public function feedback_handler() {
return $this->feedback_handler;
}
/**
* Gets the validator for the setting registry.
*
* @since 1.0.0
*
* @return WP_Site_Identity_Setting_Validator Validator to use for registered settings.
*/
public function validator() {
return $this->validator;
}
/**
* Gets the sanitizer for the setting registry.
*
* @since 1.0.0
*
* @return WP_Site_Identity_Setting_Sanitizer Sanitizer to use for registered settings.
*/
public function sanitizer() {
return $this->sanitizer;
}
/**
* Prefixes a setting name.
*
* If no name is given, the prefix is simply returned.
*
* @since 1.0.0
*
* @param string $name Setting name to prefix.
* @return string Prefixed setting name.
*/
public function prefix( $name = '' ) {
return $this->prefix . $name;
}
/**
* Gets the group to use for registered settings.
*
* Aggregate settings use an individual group and are unaffected by this.
*
* @since 1.0.0
*
* @return string Group identifier.
*/
public function group() {
return $this->group;
}
/**
* Sanitizes a value for a setting in WordPress.
*
* Due to WordPress using the respective hook for validation and sanitization,
* this method validates the value as well before sanitizing it. In case of a
* validation error it adds the error in WordPress to make sure it shows in the UI.
*
* @since 1.0.0
* @internal
*
* @param mixed $value Value to sanitize.
* @param string $name Name of the setting.
* @return mixed Sanitized value, or old value if an error occurred.
*/
public function sanitize_value_in_wp( $value, $name ) {
$name = substr( $name, strlen( $this->prefix ) );
$setting = $this->get_setting( $name );
try {
$validated_value = $this->validator->validate( $value, $setting );
} catch ( WP_Site_Identity_Setting_Validation_Error_Exception $e ) {
$this->feedback_handler->add_error( $setting, $e->getMessage() );
return $this->get_value_from_wp( $setting );
}
return $this->sanitizer->sanitize( $validated_value, $setting );
}
/**
* Gets the current value for a setting from WordPress.
*
* @since 1.0.0
*
* @param WP_Site_Identity_Setting $setting Setting to get the value for.
* @return mixed Current setting value.
*/
protected function get_value_from_wp( WP_Site_Identity_Setting $setting ) {
$name = $this->prefix( $setting->get_name() );
return get_option( $name );
}
/**
* Registers a new setting in WordPress.
*
* @since 1.0.0
*
* @param WP_Site_Identity_Setting $setting Setting to register.
*/
protected function register_in_wp( WP_Site_Identity_Setting $setting ) {
$name = $this->prefix( $setting->get_name() );
if ( is_a( $setting, 'WP_Site_Identity_Setting_Registry' ) ) {
$group = $setting->prefix( $setting->group() );
} else {
$group = $this->prefix( $this->group );
}
$args = array(
'type' => $setting->get_type(),
'group' => $group,
'description' => $setting->get_description(),
'sanitize_callback' => null,
'show_in_rest' => false,
);
if ( $setting->show_in_rest() ) {
$args['show_in_rest'] = array(
'schema' => $this->build_rest_schema_for_wp( $setting ),
);
}
register_setting( $group, $name, $args );
add_filter( "sanitize_option_{$name}", array( $this, 'sanitize_value_in_wp' ), 10, 2 );
}
/**
* Unregisters an existing setting in WordPress.
*
* @since 1.0.0
*
* @param WP_Site_Identity_Setting $setting Setting to unregister.
*/
protected function unregister_in_wp( WP_Site_Identity_Setting $setting ) {
$name = $this->prefix( $setting->get_name() );
if ( is_a( $setting, 'WP_Site_Identity_Setting_Registry' ) ) {
$group = $setting->prefix( $setting->group() );
} else {
$group = $this->prefix( $this->group );
}
remove_filter( "sanitize_option_{$name}", array( $this, 'sanitize_value_in_wp' ), 10 );
unregister_setting( $group, $name );
}
/**
* Builds the REST schema array to pass to WordPress.
*
* @since 1.0.0
*
* @param WP_Site_Identity_Setting $setting Setting to build the REST schema for.
* @return array REST schema.
*/
protected function build_rest_schema_for_wp( WP_Site_Identity_Setting $setting ) {
$default_schema = array(
'type' => $setting->get_type(),
'description' => $setting->get_description(),
'default' => $setting->get_default(),
);
switch ( $default_schema['type'] ) {
case 'string':
$choices = $setting->get_choices();
$format = $setting->get_format();
if ( ! empty( $choices ) ) {
$default_schema['enum'] = array_keys( $choices );
}
if ( ! empty( $format ) ) {
$default_schema['format'] = $format;
}
break;
case 'integer':
case 'number':
$min = $setting->get_min();
$max = $setting->get_max();
if ( is_float( $min ) || is_int( $min ) ) {
$default_schema['minimum'] = $min;
}
if ( is_float( $max ) || is_int( $max ) ) {
$default_schema['maximum'] = $max;
}
break;
}
return array_merge( $default_schema, $setting->get_rest_schema() );
}
}