self::sanitize_default( $field ), 'label' => self::sanitize_label( $field ), 'help' => self::sanitize_help( $field ), 'description' => self::sanitize_description( $field ), 'required' => self::sanitize_required( $field ), 'transport' => self::sanitize_transport( $field ), 'type' => self::sanitize_control_type( $field ), 'option_type' => self::sanitize_type( $field ), 'option_name' => self::sanitize_option_name( $field ), 'section' => self::sanitize_section( $field ), 'settings' => self::sanitize_settings( $field ), 'priority' => self::sanitize_priority( $field ), 'choices' => self::sanitize_choices( $field ), 'output' => self::sanitize_output( $field ), 'sanitize_callback' => self::sanitize_callback( $field ), 'js_vars' => self::sanitize_js_vars( $field ), 'id' => self::sanitize_id( $field ), 'capability' => self::sanitize_capability( $field ), 'variables' => self::sanitize_variables( $field ), 'active_callback' => self::sanitize_active_callback( $field ) ); /** * Return a merged array so any extra custom properties are parse as well (but not sanitized) */ return array_merge( $field, $sanitized ); } /** * Sanitizes the control type. * * @param array the field definition * @return string If not set, then defaults to text. */ public static function sanitize_control_type( $field ) { // If no field type has been defined then fallback to text if ( ! isset( $field['type'] ) ) { return 'text'; } switch ( $field['type'] ) { case 'checkbox': /** * Tweaks for backwards-compatibility: * Prior to version 0.8 switch & toggle were part of the checkbox control. */ if ( isset( $field['mode'] ) && 'switch' == $field['mode'] ) { $field['type'] = 'switch'; } elseif ( isset( $field['mode'] ) && 'toggle' == $field['mode'] ) { $field['type'] = 'toggle'; } break; case 'radio': /** * Tweaks for backwards-compatibility: * Prior to version 0.8 radio-buttonset & radio-image were part of the checkbox control. */ if ( isset( $field['mode'] ) && 'buttonset' == $field['mode'] ) { $field['type'] = 'radio-buttonset'; } elseif ( isset( $field['mode'] ) && 'image' == $field['mode'] ) { $field['type'] = 'radio-image'; } break; case 'group-title': case 'group_title': /** * Tweaks for backwards-compatibility: * Prior to version 0.8 there was a group-title control. */ $field['type'] = 'custom'; break; case 'color_alpha': // Just making sure that common mistakes will still work. $field['type'] = 'color-alpha'; break; case 'color': // If a default value of rgba() is defined for a color control then use color-alpha instead. if ( isset( $field['default'] ) && false !== strpos( $field['default'], 'rgba' ) ) { $field['type'] = 'color-alpha'; } break; } /** * sanitize using esc_attr and return the value. */ return esc_attr( $field['type'] ); } /** * Sanitizes the setting type. * * @param array the field definition * @return string (theme_mod|option) */ public static function sanitize_type( $field ) { /** * If we've set an 'option_type' in the field properties * then sanitize the value using esc_attr and return it. */ if ( isset( $field['option_type'] ) ) { return esc_attr( $field['option_type'] ); } /** * If no 'option_type' has been defined * then try to get the option from the kirki/config filter. */ $config = apply_filters( 'kirki/config', array() ); if ( isset( $config['option_type'] ) ) { return esc_attr( $config['option_type'] ); } /** * If all else fails, fallback to theme_mod */ return 'theme_mod'; } /** * Sanitizes the setting name. * * @param array the field definition * @return string (theme_mod|option) */ public static function sanitize_option_name( $field ) { if ( isset( $field['option_name'] ) ) { return esc_attr( $field['option_name'] ); } /** * If no 'option_type' has been defined * then try to get the option from the kirki/config filter. */ $config = apply_filters( 'kirki/config', array() ); if ( isset( $config['option_name'] ) ) { return esc_attr( $config['option_type'] ); } /** * If all else fails, return empty. */ return ''; } /** * Sanitizes the setting variables. * * @param array the field definition * @return mixed */ public static function sanitize_variables( $field ) { /** * Return null if no value has been defined * or if not properly formatted as an array. */ if ( ! isset( $field['variables'] ) || ! is_array( $field['variables'] ) ) { return null; } return $field['variables']; } /** * Sanitizes the setting active callback. * * @param array the field definition * @return string callable function name. */ public static function sanitize_active_callback( $field ) { /** * If a custom 'active_callback' has been defined then return that. */ if ( isset( $field['active_callback'] ) ) { return $field['active_callback']; } /** * If the 'required' argument is set then we'll need to auto-calculate things. * Set 'active_callback' to 'kirki_active_callback'. ALl extra calculations will be handled there. */ if ( isset( $field['required'] ) ) { return 'kirki_active_callback'; } /** * If all else fails, then fallback to __return_true * This way the control is always shown. */ return '__return_true'; } /** * Sanitizes the setting permissions. * * @param array the field definition * @return string (theme_mod|option) */ public static function sanitize_capability( $field ) { /** * If we have not set a custom 'capability' then we'll need to figure it out. */ if ( ! isset( $field['capability'] ) ) { /** * If there's a global configuration then perhaps we're defining a capability there. * Use the 'kirki/config' filter to figure it out. */ $config = apply_filters( 'kirki/config', array() ); if ( isset( $config['capability'] ) ) { return esc_attr( $config['capability'] ); } /** * No capability has been found, fallback to edit_theme_options */ return 'edit_theme_options'; } /** * All good, a capability has been defined so return that escaped. */ return esc_attr( $field['capability'] ); } /** * Sanitizes the setting name * * @param array the field definition * @return string */ public static function sanitize_settings( $field ) { /** * If we're using options & option_name is set, then we need to modify the setting. */ if ( 'option' == self::sanitize_type( $field ) && '' != self::sanitize_option_name( $field ) ) { $field['settings'] = esc_attr( $field['option_name'] ).'['.esc_attr( $field['settings'] ).']'; } return $field['settings']; } /** * Sanitizes the control label. * * @param array the field definition * @return string */ public static function sanitize_label( $field ) { /** * If a label has been defined then we need to sanitize it and then return it. * Sanitization here will be done using the 'wp_strip_all_tags' function. */ if ( isset( $field['label'] ) ) { return wp_strip_all_tags( $field['label'] ); } /** * If no label has been defined then we're returning an empty value. * This is simply done to prevent any 'undefined index' PHP notices. */ return ''; } /** * Sanitizes the control section * * @param array the field definition * @return string */ public static function sanitize_section( $field ) { /** * If no section is defined then make sure we add the one section that is ALWAYS present: 'title_tagline' * Though it's wrong to use a section arbitrarily, at least this way we're making sure that the control will be rendered, * even if you forget to add a section argument. */ if ( ! isset( $field['section'] ) ) { return 'title_tagline'; } /** * Sanitize the section name and return it. */ return sanitize_key( $field['section'] ); } /** * Sanitizes the control id. * Sanitizing the ID should happen after the 'settings' sanitization. * This way we can also properly handle cases where the option_type is set to 'option' * and we're using an array instead of individual options. * * @param array the field definition * @return string */ public static function sanitize_id( $field ) { return sanitize_key( str_replace( '[', '-', str_replace( ']', '', $field['settings'] ) ) ); } /** * Sanitizes the setting default value * * @param array the field definition * @return mixed */ public static function sanitize_default( $field ) { /** * make sure a default value is defined. */ if ( ! isset( $field['default'] ) ) { return ''; } /** * If an array then sanitize the array items separately * TODO: the array_walk_recursive that we used was over-sanitizing things causing malfunctions. * We've commented this out and will revisit this in a future release. */ if ( is_array( $field['default'] ) ) { // array_walk_recursive( $field['default'], array( 'Kirki_Field', 'sanitize_defaults_array' ) ); return $field['default']; } /** * Return raw & unfiltered for custom controls */ if ( isset( $field['type'] ) && 'custom' == $field['type'] ) { return $field['default']; } /** * fallback to escaping the default value. */ return esc_textarea( $field['default'] ); } /** * Sanitizes the control description * * @param array the field definition * @return string */ public static function sanitize_description( $field ) { if ( ! isset( $field['description'] ) && ! isset( $field['subtitle'] ) ) { return ''; } /** * Compatibility tweak * * Previous verions of the Kirki Customizer had the 'description' field mapped to the new 'help' * and instead of 'description' we were using 'subtitle'. * This has been deprecated in favor of WordPress core's 'description' field that was recently introduced. * */ if ( isset( $field['subtitle'] ) ) { return wp_strip_all_tags( $field['subtitle'] ); } return wp_strip_all_tags( $field['description'] ); } /** * Sanitizes the control help * * @param array the field definition * @return string */ public static function sanitize_help( $field ) { /** * Compatibility tweak * * Previous verions of the Kirki Customizer had the 'description' field mapped to the new 'help' * and instead of 'description' we were using 'subtitle'. * This has been deprecated in favor of WordPress core's 'description' field that was recently introduced. * */ if ( isset( $field['subtitle'] ) ) { // Use old arguments form. if ( isset( $field['description'] ) ) { return wp_strip_all_tags( $field['description'] ); } return ''; } /** * Return empty string if not set. */ if ( ! isset( $field['help'] ) ) { return ''; } /** * Fallback to stripping all tags and returning. */ return wp_strip_all_tags( $field['help'] ); } /** * Sanitizes the control choices. * * @param array the field definition * @return array|string */ public static function sanitize_choices( $field ) { /** * If not set then return an empty array. * This will prevent PHP 'undefined index' notices. */ if ( ! isset( $field['choices'] ) ) { return array(); } /** * If an array then sanitize the array items separately * TODO: the array_walk_recursive that we used was over-sanitizing things causing malfunctions. * We've commented this out and will revisit this in a future release. */ if ( is_array( $field['choices'] ) ) { // array_walk_recursive( $field['choices'], array( 'Kirki_Field', 'sanitize_defaults_array' ) ); return $field['choices']; } /** * This is a string so fallback to escaping the value and return. */ return esc_attr( $field['choices'] ); } /** * Sanitizes the control output * * @param array the field definition * @return array */ public static function sanitize_output( $field ) { /** * Early exit and return a NULL value if output is not set */ if ( ! isset( $field['output'] ) ) { return null; } /** * sanitize using esc_attr if output is string. */ if ( ! is_array( $field['output'] ) ) { return esc_attr( $field['output'] ); } $output_sanitized = array(); /** * convert to multidimentional array if necessary */ if ( isset( $field['output']['element'] ) ) { $field['output'] = array( $field['output'] ); } /** * sanitize array items individually */ foreach ( $field['output'] as $output ) { if ( ! isset( $output['media_query'] ) ) { if ( isset( $output['prefix'] ) && ( false !== strpos( $output['prefix'], '@media' ) ) ) { $output['media_query'] = $output['prefix']; $output['prefix'] = ''; $output['suffix'] = ''; } else { $output['media_query'] = 'global'; } } $output_sanitized[] = array( 'element' => ( isset( $output['element'] ) ) ? sanitize_text_field( $output['element'] ) : '', 'property' => ( isset( $output['property'] ) ) ? sanitize_text_field( $output['property'] ) : '', 'units' => ( isset( $output['units'] ) ) ? sanitize_text_field( $output['units'] ) : '', 'media_query' => trim( sanitize_text_field( str_replace( '{', '', $output['media_query'] ) ) ), ); } return $output_sanitized; } /** * Sanitizes the control transport. * * @param array the field definition * @return string postMessage|refresh (defaults to refresh) */ public static function sanitize_transport( $field ) { if ( isset( $field['transport'] ) && 'postMessage' == $field['transport'] ) { return 'postMessage'; } /** * fallback to 'refresh' */ return 'refresh'; } /** * Sanitizes the setting sanitize_callback * * @param array the field definition * @return mixed the sanitization callback for this setting */ public static function sanitize_callback( $field ) { if ( isset( $field['sanitize_callback'] ) && ! empty( $field['sanitize_callback'] ) ) { return $field['sanitize_callback']; } // Fallback callback return self::fallback_callback( $field['type'] ); } /** * Sanitizes the control js_vars. * * @param array the field definition * @return array|null */ public static function sanitize_js_vars( $field ) { $js_vars_sanitized = null; if ( isset( $field['js_vars'] ) && is_array( $field['js_vars'] ) ) { $js_vars_sanitized = array(); if ( isset( $field['js_vars']['element'] ) ) { $field['js_vars'] = array( $field['js_vars'] ); } foreach ( $field['js_vars'] as $js_vars ) { $js_vars_sanitized[] = array( 'element' => ( isset( $js_vars['element'] ) ) ? sanitize_text_field( $js_vars['element'] ) : '', 'function' => ( isset( $js_vars['function'] ) ) ? esc_js( $js_vars['function'] ) : '', 'property' => ( isset( $js_vars['property'] ) ) ? esc_js( $js_vars['property'] ) : '', 'units' => ( isset( $js_vars['units'] ) ) ? esc_js( $js_vars['units'] ) : '', ); } } return $js_vars_sanitized; } /** * Sanitizes the control required argument. * * @param array the field definition * @return array|null */ public static function sanitize_required( $field ) { $required_sanitized = null; if ( isset( $field['required'] ) && is_array( $field['required'] ) ) { $required_sanitized = array(); if ( isset( $field['required']['setting'] ) ) { $field['required'] = array( $field['required'] ); } foreach ( $field['required'] as $required ) { $required_sanitized[] = array( 'setting' => ( isset( $required['setting'] ) ) ? sanitize_text_field( $required['setting'] ) : '', 'operator' => ( isset( $required['operator'] ) && in_array( $required['operator'], array( '==', '===', '!=', '!==', '>=', '<=', '>', '<' ) ) ) ? $required['operator'] : '==', 'value' => ( isset( $required['value'] ) ) ? sanitize_text_field( $required['value'] ) : true, ); } } return $required_sanitized; } /** * Sanitizes the control priority * * @param array the field definition * @return int */ public static function sanitize_priority( $field ) { if ( ! isset( $field['priority'] ) || '0' == absint( intval( $field['priority'] ) ) ) { return 10; } return absint( intval( $field['priority'] ) ); } /** * Sanitizes the control transport. * * @param string the control type * @return string|string[] the function name of a sanitization callback */ public static function fallback_callback( $field_type ) { switch ( $field_type ) { case 'checkbox': case 'toggle': case 'switch': $sanitize_callback = array( 'Kirki_Sanitize', 'checkbox' ); break; case 'color': case 'color-alpha': $sanitize_callback = array( 'Kirki_Sanitize', 'color' ); break; case 'image': case 'upload': $sanitize_callback = 'esc_url_raw'; break; case 'radio': case 'radio-image': case 'radio-buttonset': case 'select': case 'select2': case 'palette': $sanitize_callback = 'esc_attr'; break; case 'dropdown-pages': $sanitize_callback = array( 'Kirki_Sanitize', 'dropdown_pages' ); break; case 'slider': case 'number': $sanitize_callback = array( 'Kirki_Sanitize', 'number' ); break; case 'text': case 'textarea': case 'editor': $sanitize_callback = 'esc_textarea'; break; case 'multicheck': $sanitize_callback = array( 'Kirki_Sanitize', 'multicheck' ); break; case 'sortable': $sanitize_callback = array( 'Kirki_Sanitize', 'sortable' ); break; default: $sanitize_callback = array( 'Kirki_Sanitize', 'unfiltered' ); break; } return $sanitize_callback; } /** * Sanitizes the defaults array. * This is used as a callback function in the sanitize_default method. */ public static function sanitize_defaults_array( $value = '', $key = '' ) { $value = esc_textarea( $value ); $key = esc_attr( $key ); } }