Initial Commit
This commit is contained in:
503
inc/ui/class-field.php
Normal file
503
inc/ui/class-field.php
Normal file
@ -0,0 +1,503 @@
|
||||
<?php
|
||||
/**
|
||||
* Describes a field and contains helper functions for sanitization and validation.
|
||||
*
|
||||
* @package WP_Ultimo
|
||||
* @subpackage UI
|
||||
* @since 2.0.0
|
||||
*/
|
||||
|
||||
namespace WP_Ultimo\UI;
|
||||
|
||||
// Exit if accessed directly
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Describes a field and contains helper functions for sanitization and validation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Field implements \JsonSerializable {
|
||||
|
||||
/**
|
||||
* Holds the attributes of this field.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @var array
|
||||
*/
|
||||
protected $atts = array();
|
||||
|
||||
/**
|
||||
* Holds the value of the settings represented by this field.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @var mixed
|
||||
*/
|
||||
protected $value = null;
|
||||
|
||||
/**
|
||||
* Set and the attributes passed via the constructor.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $id Field id. This is going to be used to retrieve the value from the database later.
|
||||
* @param array $atts Field attributes.
|
||||
*/
|
||||
public function __construct($id, $atts) {
|
||||
|
||||
$this->set_attributes($id, $atts);
|
||||
|
||||
} // end __construct;
|
||||
|
||||
/**
|
||||
* Set and the attributes passed via the constructor.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $id Field id. This is going to be used to retrieve the value from the database later.
|
||||
* @param array $atts Field attributes.
|
||||
* @return void
|
||||
*/
|
||||
public function set_attributes($id, $atts) {
|
||||
|
||||
$this->atts = wp_parse_args($atts, array(
|
||||
'id' => $id,
|
||||
'type' => 'text',
|
||||
'icon' => 'dashicons-wu-cog',
|
||||
'action' => false,
|
||||
'form' => false,
|
||||
'title' => false,
|
||||
'img' => false,
|
||||
'desc' => false,
|
||||
'content' => false,
|
||||
'display_value' => false,
|
||||
'default_value' => false,
|
||||
'tooltip' => false,
|
||||
'args' => false,
|
||||
'sortable' => false,
|
||||
'placeholder' => false,
|
||||
'options' => false,
|
||||
'options_template' => false,
|
||||
'require' => false,
|
||||
'button' => false,
|
||||
'width' => false,
|
||||
'rules' => false,
|
||||
'min' => false,
|
||||
'max' => false,
|
||||
'allow_html' => false,
|
||||
'append' => false,
|
||||
'order' => false,
|
||||
'dummy' => false,
|
||||
'disabled' => false,
|
||||
'capability' => false,
|
||||
'edit' => false,
|
||||
'copy' => false,
|
||||
'validation' => false,
|
||||
'meter' => false,
|
||||
'href' => false,
|
||||
'raw' => false,
|
||||
'money' => false,
|
||||
'stacked' => false, // If the field is inside a restricted container
|
||||
'columns' => 1,
|
||||
'classes' => '',
|
||||
'wrapper_classes' => '',
|
||||
'html_attr' => array(),
|
||||
'wrapper_html_attr' => array(),
|
||||
'sub_fields' => array(),
|
||||
'prefix' => '',
|
||||
'suffix' => '',
|
||||
'prefix_html_attr' => array(),
|
||||
'suffix_html_attr' => array(),
|
||||
));
|
||||
|
||||
} // end set_attributes;
|
||||
|
||||
/**
|
||||
* Set a particular attribute.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $att The attribute name.
|
||||
* @param mixed $value The new attribute value.
|
||||
* @return void
|
||||
*/
|
||||
public function set_attribute($att, $value) {
|
||||
|
||||
$this->atts[$att] = $value;
|
||||
|
||||
} // end set_attribute;
|
||||
|
||||
/**
|
||||
* Returns the list of field attributes.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return array
|
||||
*/
|
||||
public function get_attributes() {
|
||||
|
||||
return $this->atts;
|
||||
|
||||
} // end get_attributes;
|
||||
|
||||
/**
|
||||
* Makes sure old fields remain compatible.
|
||||
*
|
||||
* We are making some field type name changes in 2.0.
|
||||
* This method lists an array with aliases in the following format:
|
||||
*
|
||||
* - old_type_name => new_type_name.
|
||||
*
|
||||
* We throw a deprecation notice to make sure developers update their code appropriately.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_compat_template_name() {
|
||||
|
||||
$aliases = array(
|
||||
'heading' => 'header',
|
||||
'heading_collapsible' => 'header',
|
||||
'select2' => 'select',
|
||||
'checkbox' => 'toggle',
|
||||
);
|
||||
|
||||
$deprecated = array(
|
||||
'heading',
|
||||
'heading_collapsible',
|
||||
'select2',
|
||||
);
|
||||
|
||||
if (array_key_exists($this->type, $aliases)) {
|
||||
|
||||
$new_type_name = $aliases[$this->type];
|
||||
|
||||
if (array_key_exists($this->type, $deprecated)) {
|
||||
|
||||
// translators: The %1$s placeholder is the old type name, the second, the new type name.
|
||||
_doing_it_wrong('wu_add_field', sprintf(__('The field type "%1$s" is no longer supported, use "%2$s" instead.'), $this->type, $new_type_name), '2.0.0');
|
||||
|
||||
} // end if;
|
||||
|
||||
/*
|
||||
* Back Compat for Select2 Fields
|
||||
*/
|
||||
if ($this->type === 'select2') {
|
||||
|
||||
$this->atts['html_attr']['data-selectize'] = 1;
|
||||
$this->atts['html_attr']['multiple'] = 1;
|
||||
|
||||
} // end if;
|
||||
|
||||
return $new_type_name;
|
||||
|
||||
} // end if;
|
||||
|
||||
return false;
|
||||
|
||||
} // end get_compat_template_name;
|
||||
|
||||
/**
|
||||
* Returns the template name for a field.
|
||||
*
|
||||
* We use this to go to the views folder and fetch the HTML template.
|
||||
* The return here is not an absolute path, as the folder depends on the view the form is using.
|
||||
*
|
||||
* @see \WP_Ultimo\UI\Forms
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_template_name() {
|
||||
|
||||
$compat_name = $this->get_compat_template_name();
|
||||
|
||||
$view_name = $compat_name ? $compat_name : $this->type;
|
||||
|
||||
return str_replace('_', '-', (string) $view_name);
|
||||
|
||||
} // end get_template_name;
|
||||
|
||||
/**
|
||||
* Returns attributes as class properties.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $att Attribute to retrieve.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($att) {
|
||||
|
||||
$allowed_callable = array(
|
||||
'title',
|
||||
'desc',
|
||||
'content',
|
||||
'display_value',
|
||||
'default_value',
|
||||
'tooltip',
|
||||
'options',
|
||||
'require',
|
||||
'validation',
|
||||
'value',
|
||||
'html_attr',
|
||||
'img',
|
||||
);
|
||||
|
||||
$attr = isset($this->atts[$att]) ? $this->atts[$att] : false;
|
||||
|
||||
$allow_callable_prefix = is_string($attr) && strncmp($attr, 'wu_get_', strlen('wu_get_')) === 0 && is_callable($attr);
|
||||
$allow_callable_method = is_array($attr) && is_callable($attr);
|
||||
|
||||
if (in_array($att, $allowed_callable, true) && ($allow_callable_prefix || $allow_callable_method || is_a($attr, \Closure::class))) {
|
||||
|
||||
$attr = call_user_func($attr, $this);
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($att === 'wrapper_classes' && isset($this->atts['wrapper_html_attr']['v-show'])) {
|
||||
|
||||
$this->atts['wrapper_classes'] = $this->atts['wrapper_classes'] . ' wu-requires-other';
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($att === 'type' && $this->atts[$att] === 'submit') {
|
||||
|
||||
$this->atts['wrapper_classes'] = $this->atts['wrapper_classes'] . ' wu-submit-field';
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($att === 'type' && $this->atts[$att] === 'tab-select') {
|
||||
|
||||
$this->atts['wrapper_classes'] = $this->atts['wrapper_classes'] . ' wu-tab-field';
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($att === 'wrapper_classes' && is_a($this->form, '\\WP_Ultimo\\UI\\Form')) {
|
||||
|
||||
return $this->form->field_wrapper_classes . ' ' . $this->atts['wrapper_classes'];
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($att === 'classes' && is_a($this->form, '\\WP_Ultimo\\UI\\Form')) {
|
||||
|
||||
return $this->form->field_classes . ' ' . $this->atts['classes'];
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($att === 'title' && $attr === false && isset($this->atts['name'])) {
|
||||
|
||||
$attr = $this->atts['name'];
|
||||
|
||||
} // end if;
|
||||
|
||||
return $attr;
|
||||
|
||||
} // end __get;
|
||||
|
||||
/**
|
||||
* Returns the list of sanitization callbacks for each field type
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return array
|
||||
*/
|
||||
protected function sanitization_rules() {
|
||||
|
||||
$rules = array(
|
||||
'text' => 'sanitize_text_field',
|
||||
'header' => '__return_null',
|
||||
'number' => array($this, 'validate_number_field'),
|
||||
'wp_editor' => array($this, 'validate_textarea_field'),
|
||||
'textarea' => array($this, 'validate_textarea_field'),
|
||||
'checkbox' => 'wu_string_to_bool',
|
||||
'multi_checkbox' => false,
|
||||
'select2' => false,
|
||||
'multiselect' => false,
|
||||
);
|
||||
|
||||
return apply_filters('wu_settings_fields_sanitization_rules', $rules);
|
||||
|
||||
} // end sanitization_rules;
|
||||
|
||||
/**
|
||||
* Returns the value of the setting represented by this field.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_value() {
|
||||
|
||||
return $this->value;
|
||||
|
||||
} // end get_value;
|
||||
|
||||
/**
|
||||
* Sets the value of the settings represented by this field.
|
||||
*
|
||||
* This alone won't save the setting to the database. This method also invokes the
|
||||
* sanitization callback, so we can be sure the data is ready for database insertion.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param mixed $value Value of the settings being represented by this field.
|
||||
* @return WP_Ultimo\UI\Field
|
||||
*/
|
||||
public function set_value($value) {
|
||||
|
||||
$this->value = $value;
|
||||
|
||||
if (!$this->raw) {
|
||||
|
||||
$this->sanitize();
|
||||
|
||||
} // end if;
|
||||
|
||||
return $this;
|
||||
|
||||
} // end set_value;
|
||||
|
||||
/**
|
||||
* Runs the value of the field through the sanitization callback.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return void
|
||||
*/
|
||||
public function sanitize() {
|
||||
|
||||
$rules = $this->sanitization_rules();
|
||||
|
||||
$sanitize_method = isset($rules[$this->type]) ? $rules[$this->type] : $rules['text'];
|
||||
|
||||
if ($sanitize_method) {
|
||||
|
||||
$this->value = call_user_func($sanitize_method, $this->value);
|
||||
|
||||
} // end if;
|
||||
|
||||
} // end sanitize;
|
||||
/**
|
||||
* Sanitization callback for fields of type number.
|
||||
*
|
||||
* Checks if the new value set is between the min and max boundaries.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param int|float $value Value of the settings being represented by this field.
|
||||
* @return int|float
|
||||
*/
|
||||
protected function validate_number_field($value) {
|
||||
|
||||
/**
|
||||
* Check if the value respects the min/max values.
|
||||
*/
|
||||
if ($this->min && $value < $this->min) {
|
||||
|
||||
return $this->min;
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($this->max && $value > $this->max) {
|
||||
|
||||
return $this->max;
|
||||
|
||||
} // end if;
|
||||
|
||||
return $value;
|
||||
|
||||
} // end validate_number_field;
|
||||
|
||||
/**
|
||||
* Cleans the value submitted via a textarea or wp_editor field for database insertion.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
* @param string $value Value of the settings being represented by this field.
|
||||
* @return string
|
||||
*/
|
||||
protected function validate_textarea_field($value) {
|
||||
|
||||
if ($this->allow_html) {
|
||||
|
||||
return stripslashes(wp_filter_post_kses(addslashes($value)));
|
||||
|
||||
} // end if;
|
||||
|
||||
return wp_strip_all_tags(stripslashes($value));
|
||||
|
||||
} // end validate_textarea_field;
|
||||
|
||||
/**
|
||||
* Return HTML attributes for the field.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_html_attributes() {
|
||||
|
||||
if (is_callable($this->atts['html_attr'])) {
|
||||
|
||||
$this->atts['html_attr'] = call_user_func($this->atts['html_attr']);
|
||||
|
||||
} // end if;
|
||||
|
||||
$attributes = $this->atts['html_attr'];
|
||||
|
||||
unset($this->atts['html_attr']['class']);
|
||||
|
||||
if ($this->type === 'number') {
|
||||
|
||||
if ($this->min !== false) {
|
||||
|
||||
$attributes['min'] = $this->min;
|
||||
|
||||
} // end if;
|
||||
|
||||
if ($this->max !== false) {
|
||||
|
||||
$attributes['max'] = $this->max;
|
||||
|
||||
} // end if;
|
||||
|
||||
} // end if;
|
||||
|
||||
/*
|
||||
* Adds money formatting and masking
|
||||
*/
|
||||
if ($this->money !== false) {
|
||||
|
||||
$attributes['v-bind'] = 'money_settings';
|
||||
|
||||
} // end if;
|
||||
|
||||
return wu_array_to_html_attrs($attributes);
|
||||
|
||||
} // end get_html_attributes;
|
||||
|
||||
/**
|
||||
* Return HTML attributes for the field.
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return string
|
||||
*/
|
||||
public function get_wrapper_html_attributes() {
|
||||
|
||||
$attributes = $this->atts['wrapper_html_attr'];
|
||||
|
||||
unset($this->atts['wrapper_html_attr']['class']);
|
||||
|
||||
return wu_array_to_html_attrs($attributes);
|
||||
|
||||
} // end get_wrapper_html_attributes;
|
||||
|
||||
/**
|
||||
* Implements our on json_decode version of this object. Useful for use in vue.js
|
||||
*
|
||||
* @since 2.0.0
|
||||
* @return array
|
||||
*/
|
||||
#[\ReturnTypeWillChange]
|
||||
public function jsonSerialize() {
|
||||
|
||||
return $this->atts;
|
||||
|
||||
} // end jsonSerialize;
|
||||
|
||||
} // end class Field;
|
Reference in New Issue
Block a user