<?php
/**
* Module to work with standard WordPress customizer
*
* Version: 1.0.3
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
if ( ! class_exists( 'CX_Customizer' ) ) {
/**
* Contains methods for customizing the theme customization screen.
*
* @since 1.0.0
*/
class CX_Customizer {
/**
* Unique prefix.
* This is a theme or plugin slug.
*
* @since 1.0.0
* @access protected
* @var string
*/
protected $prefix;
/**
* Capability.
*
* @since 1.0.0
* @access protected
* @var string
*/
protected $capability;
/**
* Setting type.
*
* @since 1.0.0
* @access protected
* @var string
*/
protected $type;
/**
* Options.
*
* @since 1.0.0
* @access protected
* @var array
*/
protected $options;
/**
* Path to module folder.
*
* @since 1.0.0
* @access protected
* @var object
*/
protected $path;
/**
* WP_Customize_Manager instance.
*
* @since 1.0.0
* @access protected
* @var object.
*/
protected $customize;
/**
* Module directory URI.
*
* @since 1.0.0
* @access protected
* @var array.
*/
protected $fonts;
/**
* Fonts manager instance
*
* @var object
*/
protected $fonts_manager = null;
/**
* Fonts options list
*
* @var array
*/
protected $fonts_options = array();
/**
* Module initialization.
*
* @since 1.0.0
* @param array $args Arguments.
*/
/*
* $args = array(
* 'just_fonts' => false, // set to TRUE if you want use customizer only as fonts manager.
* 'prefix' => 'unique_prefix', // theme or plugin slug (*).
* 'capability' => 'edit_theme_options', // (default: `edit_theme_options`).
* 'type' => 'theme_mod', // `theme_mod` - for themes; `option` - for plugins (default: `theme_mod`)
* 'options' => array(
* 'unique_panel_ID' => array(
* 'title' => esc_html__( 'Panel Title', 'text-domain' ),
* 'description' => esc_html__( 'Panel Description', 'text-domain' ),
* 'priority' => 140,
* 'capability' => '', (optional)
* 'theme_supports' => '', (optional)
* 'active_callback' => '', // (optional: is_front_page, is_single)
* 'type' => 'panel', // panel, section or control (*).
* ),
* 'unique_section_ID' => array(
* 'title' => esc_html__( 'Section Title', 'text-domain' ),
* 'description' => esc_html__( 'Section Description', 'text-domain' ),
* 'priority' => 10, (10, 20, 30, ...)
* 'panel' => 'unique_panel_ID', (*)
* 'type' => 'section', (*)
* ),
* 'unique_control_ID' => array(
* 'title' => esc_html__( 'Control Title', 'text-domain' ),
* 'description' => esc_html__( 'Control Description', 'text-domain' ),
* 'section' => 'unique_section_ID', (*)
* 'default' => '',
* 'field' => 'text', // text, textarea, checkbox, radio, select,
* // iconpicker, fonts, hex_color, image, file.
* 'choices' => array(), // for `select` and `radio` field.
* 'type' => 'control', (*)
* 'active_callback' => '', (optional: is_front_page, is_single)
* 'transport' => 'refresh', // refresh or postMessage (default: refresh)
* 'sanitize_callback' => '', (optional) Maybe need to use a custom function or sanitization.
* 'sanitize_js_callback' => '', (optional)
* ),
* )
* );
*/
/**
* Cherry customizer class construct.
*/
public function __construct( array $args = array() ) {
/**
* Cherry Customizer only works in WordPress 4.0 or later.
*/
if ( version_compare( $GLOBALS['wp_version'], '4.0', '<' ) ) {
return;
}
$this->path = isset( $args['path'] ) ? $args['path'] : false;
$this->fonts_manager = isset( $args['fonts_manager'] ) ? $args['fonts_manager'] : false;
$this->fonts = array();
$this->prefix = $this->prepare_prefix( $args['prefix'] );
$this->options = $args['options'];
$this->capability = ! empty( $args['capability'] ) ? $args['capability'] : 'edit_theme_options';
$this->type = ! empty( $args['type'] ) && $this->sanitize_type( $args['type'] ) ? $args['type'] : 'theme_mod';
// Prepare options after theme activation.
add_action( 'after_switch_theme', array( $this, 'add_options' ), 11 );
if ( ! empty( $this->fonts_manager ) ) {
$this->init_fonts_manager();
}
/**
* Fonts are loaded, abort if $args['just_fonts'] set to TRUE
*/
if ( isset( $args['just_fonts'] ) && true === $args['just_fonts'] ) {
return;
}
$this->type = ! empty( $args['type'] ) && $this->sanitize_type( $args['type'] ) ? $args['type'] : 'theme_mod';
if ( empty( $args['options'] ) || ( ( 'option' === $this->type ) && empty( $args['prefix'] ) ) ) {
return;
}
add_action( 'customize_register', array( $this, 'register' ) );
}
/**
* Initialize fonts manager if its instance was passed in arguments.
*
* @return void
*/
public function init_fonts_manager() {
$this->fonts_manager->set_args( array(
'prefix' => $this->prefix,
'single' => false,
'type' => $this->type,
'get_fonts' => array( $this, 'get_fonts' ),
'options' => $this->get_fonts_options()
) );
}
/**
* Return fonts options list
*
* @return array
*/
public function get_fonts_options() {
array_walk( $this->options, array( $this, '_get_fonts_options' ) );
return $this->fonts_options;
}
/**
* Callback for fonts options grabber walker.
*
* @param array $item Option data.
* @param string $key Option key.
* @return [type] [description]
*/
public function _get_fonts_options( $item, $key ) {
if ( ! isset( $item['field'] ) || 'fonts' !== $item['field'] ) {
return;
}
$pairs = array(
'style' => '_font_style',
'weight' => '_font_weight',
'charset' => '_character_set',
);
$opt_key = str_replace( '_font_family', '', $key );
$data = array(
'family' => $key
);
foreach ( $pairs as $prop => $mod ) {
$data[ $prop ] = $opt_key . $mod;
}
$this->fonts_options[ $opt_key ] = $data;
}
/**
* Registeration for a new panel, sections, settings and controls.
*
* @since 1.0.0
* @param object $wp_customize WP_Customize_Manager instance.
*/
public function register( $wp_customize ) {
// Failsafe is safe.
if ( ! isset( $wp_customize ) ) {
return;
}
$this->set_customize( $wp_customize );
foreach ( (array) $this->options as $id => $option ) {
if ( empty( $option['type'] ) ) {
continue;
}
if ( 'panel' === $option['type'] ) {
$this->add_panel( $id, $option );
}
if ( 'section' === $option['type'] ) {
$this->add_section( $id, $option );
}
if ( 'control' === $option['type'] ) {
$this->add_control( $id, $option );
}
}
}
/**
* Add a customize panel.
*
* @since 1.0.0
* @param number $id Settings ID.
* @param array $args Panel arguments.
*/
public function add_panel( $id, $args ) {
$prefix = $this->prefix . '_';
$priority = isset( $args['priority'] ) ? $args['priority'] : 160;
$theme_supports = isset( $args['theme_supports'] ) ? $args['theme_supports'] : '';
$title = isset( $args['title'] ) ? esc_attr( $args['title'] ) : '';
$description = isset( $args['description'] ) ? esc_attr( $args['description'] ) : '';
$active_callback = isset( $args['active_callback'] ) ? $this->active_callback( $args['active_callback'] ) : '';
$this->customize->add_panel( $prefix . esc_attr( $id ), array(
'priority' => $priority,
'capability' => $this->capability,
'theme_supports' => $theme_supports,
'title' => $title,
'description' => $description,
'active_callback' => $active_callback,
) );
}
/**
* Add a customize section.
*
* @since 1.0.0
* @param array $id Settings ID.
* @param array $args Section arguments.
*/
/**
* The priorities of the core sections are below:
*
* Title ID Priority (Order)
* Site Title & Tagline title_tagline 20
* Colors colors 40
* Header Image header_image 60
* Background Image background_image 80
* Navigation nav 100
* Widgets (Panel) widgets 110
* Static Front Page static_front_page 120
*/
public function add_section( $id, $args ) {
$prefix = $this->prefix . '_';
$title = isset( $args['title'] ) ? esc_attr( $args['title'] ) : '';
$description = isset( $args['description'] ) ? esc_attr( $args['description'] ) : '';
$panel = isset( $args['panel'] ) ? $prefix . esc_attr( $args['panel'] ) : '';
$priority = isset( $args['priority'] ) ? $args['priority'] : 160;
$theme_supports = isset( $args['theme_supports'] ) ? $args['theme_supports'] : '';
$active_callback = isset( $args['active_callback'] ) ? $this->active_callback( $args['active_callback'] ) : '';
$this->customize->add_section( $prefix . esc_attr( $id ), array(
'title' => $title,
'description' => $description,
'panel' => $panel,
'priority' => $priority,
'capability' => $this->capability,
'theme_supports' => $theme_supports,
'active_callback' => $active_callback,
) );
}
/**
* Add a customize control.
*
* @since 1.0.0
* @since 1.0.2 Added a `cropped_image` support.
* @param number $id Settings ID.
* @param array $args Control arguments.
*/
public function add_control( $id, $args ) {
static $control_priority = 0;
$prefix = $this->prefix . '_';
$section = $this->get_control_section( $args );
$id = ( 'option' === $this->type ) ? sprintf( '%1$s_options[%2$s]', $this->prefix, esc_attr( $id ) ) : esc_attr( $id );
$priority = isset( $args['priority'] ) ? $args['priority'] : ++$control_priority;
$default = isset( $args['default'] ) ? $args['default'] : '';
$title = isset( $args['title'] ) ? esc_attr( $args['title'] ) : '';
$description = isset( $args['description'] ) ? esc_attr( $args['description'] ) : '';
$transport = isset( $args['transport'] ) ? esc_attr( $args['transport'] ) : 'refresh';
$field_type = isset( $args['field'] ) ? esc_attr( $args['field'] ) : 'text';
$sanitize_callback = isset( $args['sanitize_callback'] ) ? esc_attr( $args['sanitize_callback'] ) : array( $this, 'sanitize_' . $field_type );
$sanitize_callback = is_callable( $sanitize_callback ) ? $sanitize_callback : 'sanitize_text_field';
$sanitize_js_callback = isset( $args['sanitize_js_callback'] ) ? esc_attr( $args['sanitize_js_callback'] ) : '';
$active_callback = isset( $args['active_callback'] ) ? $this->active_callback( $args['active_callback'] ) : '';
// Add a customize setting.
$this->customize->add_setting( $id, array(
'type' => $this->type,
'capability' => $this->capability,
'default' => $default,
'transport' => $transport,
'sanitize_callback' => $sanitize_callback,
'sanitize_js_callback' => $sanitize_js_callback,
) );
// Prepare arguments for a customize control.
$control_args = array(
'priority' => $priority,
'section' => $section,
'label' => $title,
'description' => $description,
'active_callback' => $active_callback,
'choices' => '', // select, radio
);
$control_class = '';
switch ( $field_type ) {
case 'text':
case 'textarea':
case 'email':
case 'url':
case 'password':
case 'checkbox':
case 'dropdown-pages':
$control_args = wp_parse_args( array(
'type' => $field_type,
), $control_args );
break;
case 'range':
case 'number':
$input_attrs = ( isset( $args['input_attrs'] ) ) ? $args['input_attrs'] : array();
$control_args = wp_parse_args( array(
'type' => $field_type,
'input_attrs' => $input_attrs,
), $control_args );
break;
case 'select':
$choices = ( isset( $args['choices'] ) ) ? $args['choices'] : array();
$control_args = wp_parse_args( array(
'type' => 'select',
'choices' => $choices,
), $control_args );
break;
case 'fonts':
$choices = ( isset( $args['choices'] ) ) ? $args['choices'] : $this->get_fonts();
$control_args = wp_parse_args( array(
'type' => 'select',
'choices' => $choices,
), $control_args );
break;
case 'radio':
$choices = ( isset( $args['choices'] ) ) ? $args['choices'] : array();
$control_args = wp_parse_args( array(
'type' => 'radio',
'choices' => $choices,
), $control_args );
break;
case 'hex_color':
$control_class = 'WP_Customize_Color_Control';
break;
case 'image':
$control_class = 'WP_Customize_Image_Control';
break;
case 'file':
$control_class = 'WP_Customize_Upload_Control';
break;
case 'cropped_image':
$control_class = 'WP_Customize_Cropped_Image_Control';
$cropped_args = ( isset( $args['cropped_args'] ) ) ? $args['cropped_args'] : array();
$control_args = wp_parse_args( array(
'width' => ( isset( $cropped_args['width'] ) ) ? esc_attr( $cropped_args['width'] ) : 150,
'height' => ( isset( $cropped_args['height'] ) ) ? esc_attr( $cropped_args['height'] ) : 150,
'flex-width' => ( isset( $cropped_args['flex-width'] ) ) ? $cropped_args['flex-width'] : false,
'flex-height' => ( isset( $cropped_args['flex-height'] ) ) ? $cropped_args['flex-height'] : false,
'button_labels' => ( isset( $cropped_args['labels'] ) ) ? $cropped_args['labels'] : array(),
), $control_args );
break;
default:
/**
* Filter arguments for a `$field_type` customize control.
*
* @since 1.0.0
* @param array $control_args Control's arguments.
* @param string $id Control's ID.
* @param object $this Cherry_Customizer instance.
*/
$control_args = apply_filters(
'cx_customizer/control_args/{$field_type}',
$control_args,
$id,
$this
);
break;
}
/**
* Filter arguments for a customize control.
*
* @since 1.0.0
* @param array $control_args Control's arguments.
* @param string $id Control's ID.
* @param object $this Cherry_Customizer instance.
*/
$control_args = apply_filters( 'cx_customizer/control_args', $control_args, $id, $this );
/**
* Filter PHP-class name for a customize control (maybe custom).
*
* @since 1.0.0
* @param array $control_args Control's PHP-class name.
* @param string $id Control's ID.
* @param object $this Cherry_Customizer instance.
*/
$control_class = apply_filters( 'cx_customizer/control_class', $control_class, $id, $this );
if ( class_exists( $control_class ) ) {
$this->customize->add_control( new $control_class( $this->customize, $id, $control_args ) );
} else {
$this->customize->add_control( $id, $control_args );
}
}
/**
* Get section name from arguments - prefixed, if is custom section, unprefixed - if is core section.
*
* @since 1.0.0
* @param array $args Control arguments.
* @return string
*/
public function get_control_section( $args ) {
if ( ! isset( $args['section'] ) ) {
return '';
}
$default_sections = apply_filters( 'cx_customizer/core_sections', array(
'title_tagline',
'colors',
'header_image',
'background_image',
'nav',
'widgets',
'static_front_page',
) );
if ( in_array( esc_attr( $args['section'] ), $default_sections ) ) {
return esc_attr( $args['section'] );
}
return $this->prefix . '_' . esc_attr( $args['section'] );
}
/**
* Retrieve a prefix.
*
* @since 1.0.0
* @return string
*/
public function prepare_prefix( $prefix ) {
$prefix = preg_replace( '/\W/', '-', strtolower( $prefix ) );
$prefix = sanitize_key( $prefix );
return $prefix;
}
/**
* Save WP_Customize_Manager instance to prorerty.
*
* @since 1.0.0
* @param object $customize WP_Customize_Manager instance.
*/
public function set_customize( $customize ) {
$this->customize = $customize;
}
/**
* Retrieve a option value by ID.
*
* @since 1.0.0
* @param mixed $id Settings ID.
* @return bool|mixed
*/
public function get_value( $id, $default = null ) {
if ( null === $default ) {
$default = $this->get_default( $id );
}
if ( 'theme_mod' === $this->type ) {
return get_theme_mod( $id, $default );
}
if ( 'option' === $this->type ) {
$options = get_option( $this->prefix . '_options', array() );
return isset( $options[ $id ] ) ? $options[ $id ] : $default;
}
return $default;
}
/**
* Retrieve a default option value.
*
* @since 1.0.0
* @param [string] $id Settings ID.
* @return mixed
*/
public function get_default( $id ) {
return isset( $this->options[ $id ]['default'] ) ? $this->options[ $id ]['default'] : null;
}
/**
* Whitelist for setting type.
*
* @since 1.0.0
* @param [string] $type Settings type.
* @return bool
*/
public function sanitize_type( $type ) {
return in_array( $type, array( 'theme_mod', 'option' ) );
}
/**
* Text sanitization callback.
*
* - Sanitization: html
* - Control: text, textarea
*
* Sanitization callback for 'html' type text inputs. This callback sanitizes `$html`
* for HTML allowable in posts.
*
* NOTE: wp_filter_post_kses() can be passed directly as `$wp_customize->add_setting()`
* 'sanitize_callback'. It is wrapped in a callback here merely for example purposes.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see wp_filter_post_kses() https://developer.wordpress.org/reference/functions/wp_filter_post_kses/
* @since 1.0.0
* @param [string] $html HTML to sanitize.
* @return string Sanitized HTML.
*/
public function sanitize_text( $html ) {
return wp_filter_post_kses( $html );
}
/**
* Email sanitization callback.
*
* - Sanitization: email
* - Control: text
*
* Sanitization callback for 'email' type text controls. This callback sanitizes `$email`
* as a valid email address.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see sanitize_email() https://developer.wordpress.org/reference/functions/sanitize_key/
* @link sanitize_email() https://codex.wordpress.org/Function_Reference/sanitize_email
* @since 1.0.0
* @param [string] $email Email address to sanitize.
* @param WP_Customize_Setting $setting Setting instance.
* @return string The sanitized email if not null; otherwise, the setting default.
*/
public function sanitize_email( $email, $setting ) {
// Sanitize $input as a hex value without the hash prefix.
$email = sanitize_email( $email );
// If $email is a valid email, return it; otherwise, return the default.
return ( '' === $email ) ? $setting->default : $email;
}
/**
* Textarea sanitization callback.
*
* @since 1.0.0
* @param [string] $html HTML to sanitize.
* @return string Sanitized HTML.
*/
public function sanitize_textarea( $html ) {
return $this->sanitize_text( $html );
}
/**
* Select sanitization callback.
*
* - Sanitization: select
* - Control: select, radio
*
* Sanitization callback for 'select' and 'radio' type controls. This callback sanitizes `$input`
* as a slug, and then validates `$input` against the choices defined for the control.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see sanitize_key() https://developer.wordpress.org/reference/functions/sanitize_key/
* @see $wp_customize->get_control() https://developer.wordpress.org/reference/classes/wp_customize_manager/get_control/
* @since 1.0.0
* @param [string] $input Slug to sanitize.
* @param WP_Customize_Setting $setting Setting instance.
* @return string Sanitized slug if it is a valid choice; otherwise, the setting default.
*/
public function sanitize_select( $input, $setting ) {
// Ensure input is a slug.
$input = sanitize_key( $input );
// Get list of choices from the control associated with the setting.
$choices = $setting->manager->get_control( $setting->id )->choices;
// If the input is a valid key, return it; otherwise, return the default.
return ( array_key_exists( $input, $choices ) ? $input : $setting->default );
}
/**
* Function sanitize_radio
*/
public function sanitize_radio( $input, $setting ) {
return $this->sanitize_select( $input, $setting );
}
/**
* Checkbox sanitization callback.
*
* Sanitization callback for 'checkbox' type controls. This callback sanitizes `$checked`
* as a boolean value, either TRUE or FALSE.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @since 1.0.0
* @param bool $checked Whether the checkbox is checked.
* @return bool Whether the checkbox is checked.
*/
public function sanitize_checkbox( $checked ) {
return ( ( isset( $checked ) && true == $checked ) ? true : false );
}
/**
* HEX Color sanitization callback example.
*
* - Sanitization: hex_color
* - Control: text, WP_Customize_Color_Control
*
* Note: sanitize_hex_color_no_hash() can also be used here, depending on whether
* or not the hash prefix should be stored/retrieved with the hex color value.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see sanitize_hex_color() https://developer.wordpress.org/reference/functions/sanitize_hex_color/
* @link sanitize_hex_color_no_hash() https://developer.wordpress.org/reference/functions/sanitize_hex_color_no_hash/
* @since 1.0.0
* @param [string] $hex_color HEX color to sanitize.
* @param WP_Customize_Setting $setting Setting instance.
* @return string The sanitized hex color if not null; otherwise, the setting default.
*/
public function sanitize_hex_color( $hex_color, $setting ) {
// Sanitize $input as a hex value without the hash prefix.
$hex_color = sanitize_hex_color( $hex_color );
// If $input is a valid hex value, return it; otherwise, return the default.
return ( '' === $hex_color ) ? $setting->default : $hex_color;
}
/**
* Image sanitization callback.
*
* Checks the image's file extension and mime type against a whitelist. If they're allowed,
* send back the filename, otherwise, return the setting default.
*
* - Sanitization: image file extension
* - Control: text, WP_Customize_Image_Control
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see wp_check_filetype() https://developer.wordpress.org/reference/functions/wp_check_filetype/
* @since 1.0.0
* @param [string] $image Image filename.
* @param WP_Customize_Setting $setting Setting instance.
* @return string The image filename if the extension is allowed; otherwise, the setting default.
*/
public function sanitize_image( $image, $setting ) {
// Allow to correctly remove selected image
if ( empty( $image ) ) {
return $image;
}
$mimes = $this->get_image_types();
// Return an array with file extension and mime_type.
$file = wp_check_filetype( $image, $mimes );
// If $image has a valid mime_type, return it; otherwise, return the default.
return ( $file['ext'] ? $image : $setting->default );
}
/**
* URL sanitization callback.
*
* - Sanitization: url
* - Control: text, url
*
* Sanitization callback for 'url' type text inputs. This callback sanitizes `$url` as a valid URL.
*
* NOTE: esc_url_raw() can be passed directly as `$wp_customize->add_setting()` 'sanitize_callback'.
* It is wrapped in a callback here merely for example purposes.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see esc_url_raw() https://developer.wordpress.org/reference/functions/esc_url_raw/
* @since 1.0.0
* @param [string] $url URL to sanitize.
* @return string Sanitized URL.
*/
public function sanitize_url( $url ) {
return esc_url_raw( $url );
}
/**
* File URL sanitization callback.
*
* @since 1.0.0
* @param [string] $url File URL to sanitize.
* @return string Sanitized URL.
*/
public function sanitize_file( $url ) {
return $this->sanitize_url( $url );
}
/**
* Range sanitization callback.
*
* - Sanitization: number_range
* - Control: number, tel
*
* Sanitization callback for 'number' or 'tel' type text inputs. This callback sanitizes
* `$number` as an absolute integer within a defined min-max range.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @see absint() https://developer.wordpress.org/reference/functions/absint/
* @since 1.0.0
* @param int $number Number to check within the numeric range defined by the setting.
* @param WP_Customize_Setting $setting Setting instance.
* @return int|string The number, if it is zero or greater and falls within the defined range;
* otherwise, the setting default.
*/
public function sanitize_range( $number, $setting ) {
// Get the input attributes associated with the setting.
$atts = $setting->manager->get_control( $setting->id )->input_attrs;
// Get step.
$step = ( isset( $atts['step'] ) ? $atts['step'] : 1 );
$number = ( ! isset( $atts['min'] ) && 0 > $number ) ? $setting->default : $number ;
if ( is_float( $step ) ) {
// Ensure input is a float value.
$number = floatval( $number );
$checker = is_float( $number / $step );
} else {
// Ensure input is an absolute integer.
$number = ( isset( $atts['min'] ) && 0 > $atts['min'] && 0 > $number ) ? intval( $number ) : absint( $number );
$checker = is_int( $number / $step );
}
// Get minimum number in the range.
$min = ( isset( $atts['min'] ) ? $atts['min'] : $number );
// Get maximum number in the range.
$max = ( isset( $atts['max'] ) ? $atts['max'] : $number );
// If the number is within the valid range, return it; otherwise, return the default
return ( $min <= $number && $number <= $max && $checker ? $number : $setting->default );
}
/**
* Number sanitization callback.
*
* @since 1.0.0
* @param int $number Number to check within the numeric range defined by the setting.
* @param WP_Customize_Setting $setting Setting instance.
* @return int|string The number, if it is zero or greater and falls within the defined range;
* otherwise, the setting default.
*/
public function sanitize_number( $number, $setting ) {
return $this->sanitize_range( $number, $setting );
}
/**
* Cropped image sanitization callback.
*
* @since 1.0.2
* @param int $number Number to check within the numeric range defined by the setting.
* @param WP_Customize_Setting $setting Setting instance.
* @return int|string The number, if it is zero or greater and falls within the defined range;
* otherwise, the setting default.
*/
public function sanitize_cropped_image( $number, $setting ) {
return $this->sanitize_range( $number, $setting );
}
/**
* Retrieve array of image file types.
*
* @author WPTRT <https://github.com/WPTRT>
* @author Cherry Team <cherryframework@gmail.com>
* @since 1.0.0
* @return array
*/
public function get_image_types() {
/**
* Filter array of valid image file types.
*
* The array includes image mime types that are included in wp_get_mime_types()
*
* @since 1.0.0
* @param array $mimes Image mime types.
* @param object $this Cherry_Customiser instance.
*/
return apply_filters( 'cx_customizer/image_types', array(
'jpg|jpeg|jpe' => 'image/jpeg',
'gif' => 'image/gif',
'png' => 'image/png',
'bmp' => 'image/bmp',
'tif|tiff' => 'image/tiff',
'ico' => 'image/x-icon',
), $this );
}
/**
* Prepare fonts.
*
* @since 1.0.0
*/
public function prepare_fonts() {
$fonts_data = $this->get_fonts_data();
foreach ( $fonts_data as $type => $file ) {
$fonts = $this->read_font_file( $file );
if ( is_array( $fonts ) ) {
$this->fonts = array_merge( $this->fonts, $this->satizite_font_family( $fonts ) );
}
}
/**
* Filter array of prepared fonts.
* You can add new fonts from here
*
* @var array $this->fonts
* @param CX_Customizer $this
*/
$this->fonts = apply_filters( 'cx_customizer/fonts_list', $this->fonts, $this );
}
/**
* Retrieve array with fonts file path.
*
* @since 1.0.0
* @return array
*/
public function get_fonts_data() {
/**
* Filter array of fonts data.
*
* @since 1.0.0
* @param array $data Set of fonts data.
* @param object $this Cherry_Customiser instance.
*/
return apply_filters( 'cx_customizer/fonts_data', array(
'standard' => $this->path . 'assets/fonts/standard.json',
'google' => $this->path . 'assets/fonts/google.json',
), $this );
}
/**
* Retrieve array with font-family (for select element).
*
* @since 1.0.0
* @param string $type Font type.
* @return array
*/
public function get_fonts( $type = '' ) {
if ( ! empty( $this->fonts[ $type ] ) ) {
return $this->fonts[ $type ];
}
if ( ! empty( $this->fonts ) ) {
return $this->fonts;
}
$this->prepare_fonts( $type );
return ! empty( $type ) && isset( $this->fonts[ $type ] ) ? $this->fonts[ $type ] : $this->fonts;
}
/**
* Retrieve a data from font's file.
*
* @since 1.0.0
* @param string $file File path.
* @return array Fonts data.
*/
public function read_font_file( $file ) {
if ( ! $this->file_exists( $file ) ) {
return false;
}
// Read the file.
$json = $this->get_file( $file );
if ( ! $json ) {
return new WP_Error( 'reading_error', 'Error when reading file' );
}
$content = json_decode( $json, true );
return $content['items'];
}
/**
* Safely checks exists file or not.
*
* @since 1.1.4
* @global object $wp_filesystem
* @param string $file File path.
* @return bool
*/
public function file_exists( $file ) {
return file_exists( $file );
}
/**
* Safely get file content.
*
* @since 1.1.4
* @global object $wp_filesystem
* @param string $file File path.
* @return bool
*/
public function get_file( $file ) {
if ( ! file_exists( $file ) ) {
return false;
}
ob_start();
include $file;
return ob_get_clean();
}
/**
* Retrieve a set with `font-family` ( 'foo' => 'foo' ).
*
* @since 1.0.0
* @param array $data All fonts data.
* @return array
*/
public function satizite_font_family( $data ) {
$keys = array_map( array( $this, '_build_keys' ), $data );
$values = array_map( array( $this, '_build_values' ), $data );
array_filter( $keys );
array_filter( $values );
return array_combine( $keys, $values );
}
/**
* Function _build_keys.
*
* @since 1.0.0
*/
public function _build_keys( $item ) {
if ( empty( $item['family'] ) ) {
return false;
}
return sprintf( '%1$s, %2$s', $item['family'], $item['category'] );
}
/**
* Function _build_values.
*
* @since 1.0.0
*/
public function _build_values( $item ) {
if ( empty( $item['family'] ) ) {
return false;
}
return $item['family'];
}
/**
* Function add_options
*
* @since 1.0.0
*/
public function add_options() {
if ( empty( $this->options ) ) {
return;
}
$mods = get_theme_mods();
foreach ( $this->options as $id => $option ) {
if ( 'control' != $option['type'] ) {
continue;
}
if ( isset( $mods[ $id ] ) ) {
continue;
}
$mods[ $id ] = $this->get_default( $id );
}
$theme = get_option( 'stylesheet' );
update_option( "theme_mods_$theme", $mods );
}
/**
* Handler for custom `active_callback` feature.
*
* @since 1.0.0
* @param string $callback Callback-function.
* @return mixed
*/
public function active_callback( $callback ) {
$callback = esc_attr( $callback );
if ( is_callable( array( $this, $callback ) ) ) {
return array( $this, $callback );
}
return $callback;
}
/**
* Is the customizer preview a single post?
*
* @since 1.0.0
* @return bool
*/
public function callback_single() {
return is_single();
}
}
}