mirror of
https://ghproxy.net/https://github.com/AlxMedia/curver.git
synced 2025-08-28 09:25:45 +08:00
Initial commit
This commit is contained in:
commit
ee50200fe7
353 changed files with 78977 additions and 0 deletions
483
functions/kirki/controls/php/class-kirki-control-repeater.php
Normal file
483
functions/kirki/controls/php/class-kirki-control-repeater.php
Normal file
|
@ -0,0 +1,483 @@
|
|||
<?php
|
||||
/**
|
||||
* Customizer Control: repeater.
|
||||
*
|
||||
* @package Kirki
|
||||
* @subpackage Controls
|
||||
* @copyright Copyright (c) 2017, Aristeides Stathopoulos
|
||||
* @license https://opensource.org/licenses/MIT
|
||||
* @since 2.0
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Repeater control
|
||||
*/
|
||||
class Kirki_Control_Repeater extends Kirki_Control_Base {
|
||||
|
||||
/**
|
||||
* The control type.
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $type = 'repeater';
|
||||
|
||||
/**
|
||||
* The fields that each container row will contain.
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
public $fields = array();
|
||||
|
||||
/**
|
||||
* Will store a filtered version of value for advenced fields (like images).
|
||||
*
|
||||
* @access protected
|
||||
* @var array
|
||||
*/
|
||||
protected $filtered_value = array();
|
||||
|
||||
/**
|
||||
* The row label
|
||||
*
|
||||
* @access public
|
||||
* @var array
|
||||
*/
|
||||
public $row_label = array();
|
||||
|
||||
/**
|
||||
* The button label
|
||||
*
|
||||
* @access public
|
||||
* @var string
|
||||
*/
|
||||
public $button_label = '';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* Supplied `$args` override class property defaults.
|
||||
* If `$args['settings']` is not defined, use the $id as the setting ID.
|
||||
*
|
||||
* @param WP_Customize_Manager $manager Customizer bootstrap instance.
|
||||
* @param string $id Control ID.
|
||||
* @param array $args {@see WP_Customize_Control::__construct}.
|
||||
*/
|
||||
public function __construct( $manager, $id, $args = array() ) {
|
||||
parent::__construct( $manager, $id, $args );
|
||||
|
||||
// Set up defaults for row labels.
|
||||
$this->row_label = array(
|
||||
'type' => 'text',
|
||||
'value' => esc_attr__( 'row', 'kirki' ),
|
||||
'field' => false,
|
||||
);
|
||||
|
||||
// Validate row-labels.
|
||||
$this->row_label( $args );
|
||||
|
||||
if ( empty( $this->button_label ) ) {
|
||||
/* translators: %s represents the label of the row. */
|
||||
$this->button_label = sprintf( esc_html__( 'Add new %s', 'kirki' ), $this->row_label['value'] );
|
||||
}
|
||||
|
||||
if ( empty( $args['fields'] ) || ! is_array( $args['fields'] ) ) {
|
||||
$args['fields'] = array();
|
||||
}
|
||||
|
||||
// An array to store keys of fields that need to be filtered.
|
||||
$media_fields_to_filter = array();
|
||||
|
||||
foreach ( $args['fields'] as $key => $value ) {
|
||||
if ( ! isset( $value['default'] ) ) {
|
||||
$args['fields'][ $key ]['default'] = '';
|
||||
}
|
||||
if ( ! isset( $value['label'] ) ) {
|
||||
$args['fields'][ $key ]['label'] = '';
|
||||
}
|
||||
$args['fields'][ $key ]['id'] = $key;
|
||||
|
||||
// We check if the filed is an uploaded media ( image , file, video, etc.. ).
|
||||
if ( isset( $value['type'] ) ) {
|
||||
switch ( $value['type'] ) {
|
||||
case 'image':
|
||||
case 'cropped_image':
|
||||
case 'upload':
|
||||
|
||||
// We add it to the list of fields that need some extra filtering/processing.
|
||||
$media_fields_to_filter[ $key ] = true;
|
||||
break;
|
||||
|
||||
case 'dropdown-pages':
|
||||
|
||||
// If the field is a dropdown-pages field then add it to args.
|
||||
$dropdown = wp_dropdown_pages(
|
||||
array(
|
||||
'name' => '',
|
||||
'echo' => 0,
|
||||
'show_option_none' => esc_html__( 'Select a Page', 'kirki' ),
|
||||
'option_none_value' => '0',
|
||||
'selected' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// Hackily add in the data link parameter.
|
||||
$dropdown = str_replace( '<select', '<select data-field="' . esc_attr( $args['fields'][ $key ]['id'] ) . '"' . $this->get_link(), $dropdown ); // phpcs:ignore Generic.Formatting.MultipleStatementAlignment.NotSameWarning
|
||||
$args['fields'][ $key ]['dropdown'] = $dropdown;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->fields = $args['fields'];
|
||||
|
||||
// Now we are going to filter the fields.
|
||||
// First we create a copy of the value that would be used otherwise.
|
||||
$this->filtered_value = $this->value();
|
||||
|
||||
if ( is_array( $this->filtered_value ) && ! empty( $this->filtered_value ) ) {
|
||||
|
||||
// We iterate over the list of fields.
|
||||
foreach ( $this->filtered_value as &$filtered_value_field ) {
|
||||
|
||||
if ( is_array( $filtered_value_field ) && ! empty( $filtered_value_field ) ) {
|
||||
|
||||
// We iterate over the list of properties for this field.
|
||||
foreach ( $filtered_value_field as $key => &$value ) {
|
||||
|
||||
// We check if this field was marked as requiring extra filtering (in this case image, cropped_images, upload).
|
||||
if ( array_key_exists( $key, $media_fields_to_filter ) ) {
|
||||
|
||||
// What follows was made this way to preserve backward compatibility.
|
||||
// The repeater control use to store the URL for images instead of the attachment ID.
|
||||
// We check if the value look like an ID (otherwise it's probably a URL so don't filter it).
|
||||
if ( is_numeric( $value ) ) {
|
||||
|
||||
// "sanitize" the value.
|
||||
$attachment_id = (int) $value;
|
||||
|
||||
// Try to get the attachment_url.
|
||||
$url = wp_get_attachment_url( $attachment_id );
|
||||
|
||||
$filename = basename( get_attached_file( $attachment_id ) );
|
||||
|
||||
// If we got a URL.
|
||||
if ( $url ) {
|
||||
|
||||
// 'id' is needed for form hidden value, URL is needed to display the image.
|
||||
$value = array(
|
||||
'id' => $attachment_id,
|
||||
'url' => $url,
|
||||
'filename' => $filename,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the parameters passed to the JavaScript via JSON.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function to_json() {
|
||||
parent::to_json();
|
||||
|
||||
$fields = $this->fields;
|
||||
|
||||
$this->json['fields'] = $fields;
|
||||
$this->json['row_label'] = $this->row_label;
|
||||
|
||||
// If filtered_value has been set and is not empty we use it instead of the actual value.
|
||||
if ( is_array( $this->filtered_value ) && ! empty( $this->filtered_value ) ) {
|
||||
$this->json['value'] = $this->filtered_value;
|
||||
}
|
||||
$this->json['value'] = apply_filters( "kirki_controls_repeater_value_{$this->id}", $this->json['value'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Render the control's content.
|
||||
* Allows the content to be overriden without having to rewrite the wrapper in $this->render().
|
||||
*
|
||||
* @access protected
|
||||
*/
|
||||
protected function render_content() {
|
||||
?>
|
||||
<label>
|
||||
<?php if ( ! empty( $this->label ) ) : ?>
|
||||
<span class="customize-control-title"><?php echo esc_html( $this->label ); ?></span>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! empty( $this->description ) ) : ?>
|
||||
<span class="description customize-control-description"><?php echo wp_kses_post( $this->description ); ?></span>
|
||||
<?php endif; ?>
|
||||
<input type="hidden" {{{ data.inputAttrs }}} value="" <?php echo wp_kses_post( $this->get_link() ); ?> />
|
||||
</label>
|
||||
|
||||
<ul class="repeater-fields"></ul>
|
||||
|
||||
<?php if ( isset( $this->choices['limit'] ) ) : ?>
|
||||
<?php /* translators: %s represents the number of rows we're limiting the repeater to allow. */ ?>
|
||||
<p class="limit"><?php printf( esc_html__( 'Limit: %s rows', 'kirki' ), esc_html( $this->choices['limit'] ) ); ?></p>
|
||||
<?php endif; ?>
|
||||
<button class="button-secondary repeater-add"><?php echo esc_html( $this->button_label ); ?></button>
|
||||
|
||||
<?php
|
||||
|
||||
$this->repeater_js_template();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* An Underscore (JS) template for this control's content (but not its container).
|
||||
* Class variables for this control class are available in the `data` JS object.
|
||||
*
|
||||
* @access public
|
||||
*/
|
||||
public function repeater_js_template() {
|
||||
?>
|
||||
<script type="text/html" class="customize-control-repeater-content">
|
||||
<# var field; var index = data.index; #>
|
||||
|
||||
<li class="repeater-row minimized" data-row="{{{ index }}}">
|
||||
|
||||
<div class="repeater-row-header">
|
||||
<span class="repeater-row-label"></span>
|
||||
<i class="dashicons dashicons-arrow-down repeater-minimize"></i>
|
||||
</div>
|
||||
<div class="repeater-row-content">
|
||||
<# _.each( data, function( field, i ) { #>
|
||||
|
||||
<div class="repeater-field repeater-field-{{{ field.type }}} repeater-field-{{ field.id }}">
|
||||
|
||||
<# if ( 'text' === field.type || 'url' === field.type || 'link' === field.type || 'email' === field.type || 'tel' === field.type || 'date' === field.type || 'number' === field.type ) { #>
|
||||
<# var fieldExtras = ''; #>
|
||||
<# if ( 'link' === field.type ) { #>
|
||||
<# field.type = 'url' #>
|
||||
<# } #>
|
||||
|
||||
<# if ( 'number' === field.type ) { #>
|
||||
<# if ( ! _.isUndefined( field.choices ) && ! _.isUndefined( field.choices.min ) ) { #>
|
||||
<# fieldExtras += ' min="' + field.choices.min + '"'; #>
|
||||
<# } #>
|
||||
<# if ( ! _.isUndefined( field.choices ) && ! _.isUndefined( field.choices.max ) ) { #>
|
||||
<# fieldExtras += ' max="' + field.choices.max + '"'; #>
|
||||
<# } #>
|
||||
<# if ( ! _.isUndefined( field.choices ) && ! _.isUndefined( field.choices.step ) ) { #>
|
||||
<# fieldExtras += ' step="' + field.choices.step + '"'; #>
|
||||
<# } #>
|
||||
<# } #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
<input type="{{field.type}}" name="" value="{{{ field.default }}}" data-field="{{{ field.id }}}"{{ fieldExtras }}>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'number' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
<input type="{{ field.type }}" name="" value="{{{ field.default }}}" data-field="{{{ field.id }}}"{{ numberFieldExtras }}>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'hidden' === field.type ) { #>
|
||||
|
||||
<input type="hidden" data-field="{{{ field.id }}}" <# if ( field.default ) { #> value="{{{ field.default }}}" <# } #> />
|
||||
|
||||
<# } else if ( 'checkbox' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" value="{{{ field.default }}}" data-field="{{{ field.id }}}" <# if ( field.default ) { #> checked="checked" <# } #> /> {{{ field.label }}}
|
||||
<# if ( field.description ) { #>{{{ field.description }}}<# } #>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'select' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
<select data-field="{{{ field.id }}}"<# if ( ! _.isUndefined( field.multiple ) && false !== field.multiple ) { #> multiple="multiple" data-multiple="{{ field.multiple }}"<# } #>>
|
||||
<# _.each( field.choices, function( choice, i ) { #>
|
||||
<option value="{{{ i }}}" <# if ( -1 !== jQuery.inArray( i, field.default ) || field.default == i ) { #> selected="selected" <# } #>>{{ choice }}</option>
|
||||
<# }); #>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'dropdown-pages' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ data.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
<div class="customize-control-content repeater-dropdown-pages">{{{ field.dropdown }}}</div>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'radio' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
|
||||
<# _.each( field.choices, function( choice, i ) { #>
|
||||
<label><input type="radio" name="{{{ field.id }}}{{ index }}" data-field="{{{ field.id }}}" value="{{{ i }}}" <# if ( field.default == i ) { #> checked="checked" <# } #>> {{ choice }} <br/></label>
|
||||
<# }); #>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'radio-image' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
|
||||
<# _.each( field.choices, function( choice, i ) { #>
|
||||
<input type="radio" id="{{{ field.id }}}_{{ index }}_{{{ i }}}" name="{{{ field.id }}}{{ index }}" data-field="{{{ field.id }}}" value="{{{ i }}}" <# if ( field.default == i ) { #> checked="checked" <# } #>>
|
||||
<label for="{{{ field.id }}}_{{ index }}_{{{ i }}}"><img src="{{ choice }}"></label>
|
||||
</input>
|
||||
<# }); #>
|
||||
</label>
|
||||
|
||||
<# } else if ( 'color' === field.type ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
</label>
|
||||
<# var defaultValue = '';
|
||||
if ( field.default ) {
|
||||
if ( -1 === field.default.indexOf( 'rgba' ) ) {
|
||||
defaultValue = ( '#' !== field.default.substring( 0, 1 ) ) ? '#' + field.default : field.default;
|
||||
defaultValue = ' data-default-color=' + defaultValue; // Quotes added automatically.
|
||||
} else {
|
||||
defaultValue = ' data-default-color="' + defaultValue + '" data-alpha="true"';
|
||||
}
|
||||
} #>
|
||||
<input class="color-picker-hex" type="text" maxlength="7" value="{{{ field.default }}}" data-field="{{{ field.id }}}" {{ defaultValue }} />
|
||||
|
||||
<# } else if ( 'textarea' === field.type ) { #>
|
||||
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
<textarea rows="5" data-field="{{{ field.id }}}">{{ field.default }}</textarea>
|
||||
|
||||
<# } else if ( field.type === 'image' || field.type === 'cropped_image' ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
</label>
|
||||
|
||||
<figure class="kirki-image-attachment" data-placeholder="<?php esc_attr_e( 'No Image Selected', 'kirki' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<# var defaultImageURL = ( field.default.url ) ? field.default.url : field.default; #>
|
||||
<img src="{{{ defaultImageURL }}}">
|
||||
<# } else { #>
|
||||
<?php esc_html_e( 'No Image Selected', 'kirki' ); ?>
|
||||
<# } #>
|
||||
</figure>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="button remove-button<# if ( ! field.default ) { #> hidden<# } #>"><?php esc_html_e( 'Remove', 'kirki' ); ?></button>
|
||||
<button type="button" class="button upload-button" data-label=" <?php esc_attr_e( 'Add Image', 'kirki' ); ?>" data-alt-label="<?php echo esc_attr_e( 'Change Image', 'kirki' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<?php esc_html_e( 'Change Image', 'kirki' ); ?>
|
||||
<# } else { #>
|
||||
<?php esc_html_e( 'Add Image', 'kirki' ); ?>
|
||||
<# } #>
|
||||
</button>
|
||||
<# if ( field.default.id ) { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default.id }}}" data-field="{{{ field.id }}}" >
|
||||
<# } else { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default }}}" data-field="{{{ field.id }}}" >
|
||||
<# } #>
|
||||
</div>
|
||||
|
||||
<# } else if ( field.type === 'upload' ) { #>
|
||||
|
||||
<label>
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
</label>
|
||||
|
||||
<figure class="kirki-file-attachment" data-placeholder="<?php esc_attr_e( 'No File Selected', 'kirki' ); ?>" >
|
||||
<# if ( field.default ) { #>
|
||||
<# var defaultFilename = ( field.default.filename ) ? field.default.filename : field.default; #>
|
||||
<span class="file"><span class="dashicons dashicons-media-default"></span> {{ defaultFilename }}</span>
|
||||
<# } else { #>
|
||||
<?php esc_html_e( 'No File Selected', 'kirki' ); ?>
|
||||
<# } #>
|
||||
</figure>
|
||||
|
||||
<div class="actions">
|
||||
<button type="button" class="button remove-button<# if ( ! field.default ) { #> hidden<# } #>"></button>
|
||||
<button type="button" class="button upload-button" data-label="<?php esc_attr_e( 'Add File', 'kirki' ); ?>" data-alt-label="<?php esc_attr_e( 'Change File', 'kirki' ); ?>">
|
||||
<# if ( field.default ) { #>
|
||||
<?php esc_html_e( 'Change File', 'kirki' ); ?>
|
||||
<# } else { #>
|
||||
<?php esc_html_e( 'Add File', 'kirki' ); ?>
|
||||
<# } #>
|
||||
</button>
|
||||
<# if ( field.default.id ) { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default.id }}}" data-field="{{{ field.id }}}" >
|
||||
<# } else { #>
|
||||
<input type="hidden" class="hidden-field" value="{{{ field.default }}}" data-field="{{{ field.id }}}" >
|
||||
<# } #>
|
||||
</div>
|
||||
|
||||
<# } else if ( 'custom' === field.type ) { #>
|
||||
|
||||
<# if ( field.label ) { #><span class="customize-control-title">{{{ field.label }}}</span><# } #>
|
||||
<# if ( field.description ) { #><span class="description customize-control-description">{{{ field.description }}}</span><# } #>
|
||||
<div data-field="{{{ field.id }}}">{{{ field.default }}}</div>
|
||||
|
||||
<# } #>
|
||||
|
||||
</div>
|
||||
<# }); #>
|
||||
<button type="button" class="button-link repeater-row-remove"><?php esc_html_e( 'Remove', 'kirki' ); ?></button>
|
||||
</div>
|
||||
</li>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate row-labels.
|
||||
*
|
||||
* @access protected
|
||||
* @since 3.0.0
|
||||
* @param array $args {@see WP_Customize_Control::__construct}.
|
||||
*/
|
||||
protected function row_label( $args ) {
|
||||
|
||||
// Validating args for row labels.
|
||||
if ( isset( $args['row_label'] ) && is_array( $args['row_label'] ) && ! empty( $args['row_label'] ) ) {
|
||||
|
||||
// Validating row label type.
|
||||
if ( isset( $args['row_label']['type'] ) && ( 'text' === $args['row_label']['type'] || 'field' === $args['row_label']['type'] ) ) {
|
||||
$this->row_label['type'] = $args['row_label']['type'];
|
||||
}
|
||||
|
||||
// Validating row label type.
|
||||
if ( isset( $args['row_label']['value'] ) && ! empty( $args['row_label']['value'] ) ) {
|
||||
$this->row_label['value'] = esc_html( $args['row_label']['value'] );
|
||||
}
|
||||
|
||||
// Validating row label field.
|
||||
if ( isset( $args['row_label']['field'] ) && ! empty( $args['row_label']['field'] ) && isset( $args['fields'][ sanitize_key( $args['row_label']['field'] ) ] ) ) {
|
||||
$this->row_label['field'] = esc_html( $args['row_label']['field'] );
|
||||
} else {
|
||||
// If from field is not set correctly, making sure standard is set as the type.
|
||||
$this->row_label['type'] = 'text';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue