first commit
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field__accordion' ) ) :
|
||||
|
||||
class acf_field__accordion extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @date 30/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'accordion';
|
||||
$this->label = __( 'Accordion', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Allows you to group and organize custom fields into collapsable panels that are shown while editing content. Useful for keeping large datasets tidy.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-accordion.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/accordion/', 'docs', 'field-type-selection' );
|
||||
$this->supports = array(
|
||||
'required' => false,
|
||||
'bindings' => false,
|
||||
);
|
||||
$this->defaults = array(
|
||||
'open' => 0,
|
||||
'multi_expand' => 0,
|
||||
'endpoint' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render_field
|
||||
*
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @date 30/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field
|
||||
* @return n/a
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array(
|
||||
'class' => 'acf-fields',
|
||||
'data-open' => $field['open'],
|
||||
'data-multi_expand' => $field['multi_expand'],
|
||||
'data-endpoint' => $field['endpoint'],
|
||||
);
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $atts ); ?>></div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Open', 'acf' ),
|
||||
'instructions' => __( 'Display this accordion as open on page load.', 'acf' ),
|
||||
'name' => 'open',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Multi-Expand', 'acf' ),
|
||||
'instructions' => __( 'Allow this accordion to open without closing others.', 'acf' ),
|
||||
'name' => 'multi_expand',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Endpoint', 'acf' ),
|
||||
'instructions' => __( 'Define an endpoint for the previous accordion to stop. This accordion will not be visible.', 'acf' ),
|
||||
'name' => 'endpoint',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field__accordion' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,308 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_button_group' ) ) :
|
||||
|
||||
class acf_field_button_group extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* initialize()
|
||||
*
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'button_group';
|
||||
$this->label = __( 'Button Group', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A group of buttons with values that you specify, users can choose one option from the values provided.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-button-group.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/button-group/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'value',
|
||||
'layout' => 'horizontal',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the field's input HTML
|
||||
*
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field settings array
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$html = '';
|
||||
$selected = null;
|
||||
$buttons = array();
|
||||
$value = esc_attr( $field['value'] );
|
||||
|
||||
// bail ealrly if no choices
|
||||
if ( empty( $field['choices'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// buttons
|
||||
foreach ( $field['choices'] as $_value => $_label ) {
|
||||
|
||||
// checked
|
||||
$checked = ( $value === esc_attr( $_value ) );
|
||||
if ( $checked ) {
|
||||
$selected = true;
|
||||
}
|
||||
|
||||
// append
|
||||
$buttons[] = array(
|
||||
'name' => $field['name'],
|
||||
'value' => $_value,
|
||||
'label' => $_label,
|
||||
'checked' => $checked,
|
||||
);
|
||||
}
|
||||
|
||||
// maybe select initial value
|
||||
if ( ! $field['allow_null'] && $selected === null ) {
|
||||
$buttons[0]['checked'] = true;
|
||||
}
|
||||
|
||||
// div
|
||||
$div = array( 'class' => 'acf-button-group' );
|
||||
|
||||
if ( $field['layout'] == 'vertical' ) {
|
||||
$div['class'] .= ' -vertical'; }
|
||||
if ( $field['class'] ) {
|
||||
$div['class'] .= ' ' . $field['class']; }
|
||||
if ( $field['allow_null'] ) {
|
||||
$div['data-allow_null'] = 1; }
|
||||
|
||||
// hdden input
|
||||
$html .= acf_get_hidden_input( array( 'name' => $field['name'] ) );
|
||||
|
||||
// open
|
||||
$html .= '<div ' . acf_esc_attrs( $div ) . '>';
|
||||
|
||||
// loop
|
||||
foreach ( $buttons as $button ) {
|
||||
|
||||
// checked
|
||||
if ( $button['checked'] ) {
|
||||
$button['checked'] = 'checked';
|
||||
} else {
|
||||
unset( $button['checked'] );
|
||||
}
|
||||
|
||||
// append
|
||||
$html .= acf_get_radio_input( $button );
|
||||
}
|
||||
|
||||
// close
|
||||
$html .= '</div>';
|
||||
|
||||
// return
|
||||
echo $html; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- safe HTML, escaped by input building functions.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render_field_settings()
|
||||
*
|
||||
* Creates the field's settings HTML
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field settings array
|
||||
* @return n/a
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
// Encode choices (convert from array).
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'type' => 'textarea',
|
||||
'name' => 'choices',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Layout', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'horizontal' => __( 'Horizontal', 'acf' ),
|
||||
'vertical' => __( 'Vertical', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $field
|
||||
*/
|
||||
function update_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->update_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param mixed $value The value found in the database
|
||||
* @param mixed $post_id The post ID from which the value was loaded from
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $value
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->load_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $field
|
||||
*/
|
||||
function translate_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->translate_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param mixed $value The value found in the database
|
||||
* @param mixed $post_id The post ID from which the value was loaded from
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->format_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
$schema['enum'] = acf_get_field_type( 'select' )->format_rest_choices( $field['choices'] );
|
||||
$schema['enum'][] = null;
|
||||
|
||||
// Allow null via UI will value to empty string.
|
||||
if ( ! empty( $field['allow_null'] ) ) {
|
||||
$schema['enum'][] = '';
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_button_group' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,592 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_checkbox' ) ) :
|
||||
|
||||
class acf_field_checkbox extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'checkbox';
|
||||
$this->label = __( 'Checkbox', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A group of checkbox inputs that allow the user to select one, or multiple values that you specify.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-checkbox.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/checkbox/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'layout' => 'vertical',
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'allow_custom' => 0,
|
||||
'save_custom' => 0,
|
||||
'toggle' => 0,
|
||||
'return_format' => 'value',
|
||||
'custom_choice_button_text' => __( 'Add new choice', 'acf' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field (array) the $field being rendered
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field (array) the $field being edited
|
||||
* @return n/a
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// reset vars
|
||||
$this->_values = array();
|
||||
$this->_all_checked = true;
|
||||
|
||||
// ensure array
|
||||
$field['value'] = acf_get_array( $field['value'] );
|
||||
$field['choices'] = acf_get_array( $field['choices'] );
|
||||
|
||||
// hiden input
|
||||
acf_hidden_input( array( 'name' => $field['name'] ) );
|
||||
|
||||
// vars
|
||||
$li = '';
|
||||
$ul = array(
|
||||
'class' => 'acf-checkbox-list',
|
||||
);
|
||||
|
||||
// append to class
|
||||
$ul['class'] .= ' ' . ( $field['layout'] == 'horizontal' ? 'acf-hl' : 'acf-bl' );
|
||||
$ul['class'] .= ' ' . $field['class'];
|
||||
|
||||
// checkbox saves an array
|
||||
$field['name'] .= '[]';
|
||||
|
||||
// choices
|
||||
if ( ! empty( $field['choices'] ) ) {
|
||||
|
||||
// choices
|
||||
$li .= $this->render_field_choices( $field );
|
||||
|
||||
// toggle
|
||||
if ( $field['toggle'] ) {
|
||||
$li = $this->render_field_toggle( $field ) . $li;
|
||||
}
|
||||
}
|
||||
|
||||
// custom
|
||||
if ( $field['allow_custom'] ) {
|
||||
$li .= $this->render_field_custom( $field );
|
||||
}
|
||||
|
||||
// return
|
||||
echo '<ul ' . acf_esc_attrs( $ul ) . '>' . "\n" . $li . '</ul>' . "\n"; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by specific render methods above.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 15/7/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function render_field_choices( $field ) {
|
||||
|
||||
// walk
|
||||
return $this->walk( $field['choices'], $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates values for the checkbox field
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param boolean $valid If the field is valid.
|
||||
* @param mixed $value The value to validate.
|
||||
* @param array $field The main field array.
|
||||
* @param string $input The input element's name attribute.
|
||||
* @return boolean
|
||||
*/
|
||||
public function validate_value( $valid, $value, $field, $input ) {
|
||||
if ( ! is_array( $value ) || empty( $field['allow_custom'] ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
foreach ( $value as $value ) {
|
||||
if ( empty( $value ) && $value !== '0' ) {
|
||||
return __( 'Checkbox custom values cannot be empty. Uncheck any empty values.', 'acf' );
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 15/7/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function render_field_toggle( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array(
|
||||
'type' => 'checkbox',
|
||||
'class' => 'acf-checkbox-toggle',
|
||||
'label' => __( 'Toggle All', 'acf' ),
|
||||
);
|
||||
|
||||
// custom label
|
||||
if ( is_string( $field['toggle'] ) ) {
|
||||
$atts['label'] = $field['toggle'];
|
||||
}
|
||||
|
||||
// checked
|
||||
if ( $this->_all_checked ) {
|
||||
$atts['checked'] = 'checked';
|
||||
}
|
||||
|
||||
// return
|
||||
return '<li>' . acf_get_checkbox_input( $atts ) . '</li>' . "\n";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 15/7/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function render_field_custom( $field ) {
|
||||
|
||||
// vars
|
||||
$html = '';
|
||||
|
||||
// loop
|
||||
foreach ( $field['value'] as $value ) {
|
||||
|
||||
// ignore if already eixsts
|
||||
if ( isset( $field['choices'][ $value ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// vars
|
||||
$esc_value = esc_attr( $value );
|
||||
$text_input = array(
|
||||
'name' => $field['name'],
|
||||
'value' => $value,
|
||||
);
|
||||
|
||||
// bail early if choice already exists
|
||||
if ( in_array( $esc_value, $this->_values ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append
|
||||
$html .= '<li><input class="acf-checkbox-custom" type="checkbox" checked="checked" />' . acf_get_text_input( $text_input ) . '</li>' . "\n";
|
||||
}
|
||||
|
||||
// append button
|
||||
$html .= '<li><a href="#" class="button acf-add-checkbox">' . esc_attr( $field['custom_choice_button_text'] ) . '</a></li>' . "\n";
|
||||
|
||||
// return
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
function walk( $choices = array(), $args = array(), $depth = 0 ) {
|
||||
|
||||
// bail early if no choices
|
||||
if ( empty( $choices ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// defaults
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'id' => '',
|
||||
'type' => 'checkbox',
|
||||
'name' => '',
|
||||
'value' => array(),
|
||||
'disabled' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$html = '';
|
||||
|
||||
// sanitize values for 'selected' matching
|
||||
if ( $depth == 0 ) {
|
||||
$args['value'] = array_map( 'esc_attr', $args['value'] );
|
||||
$args['disabled'] = array_map( 'esc_attr', $args['disabled'] );
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $choices as $value => $label ) {
|
||||
|
||||
// open
|
||||
$html .= '<li>';
|
||||
|
||||
// optgroup
|
||||
if ( is_array( $label ) ) {
|
||||
$html .= '<ul>' . "\n";
|
||||
$html .= $this->walk( $label, $args, $depth + 1 );
|
||||
$html .= '</ul>';
|
||||
|
||||
// option
|
||||
} else {
|
||||
|
||||
// vars
|
||||
$esc_value = esc_attr( $value );
|
||||
$atts = array(
|
||||
'id' => $args['id'] . '-' . str_replace( ' ', '-', $value ),
|
||||
'type' => $args['type'],
|
||||
'name' => $args['name'],
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
);
|
||||
|
||||
// selected
|
||||
if ( in_array( $esc_value, $args['value'] ) ) {
|
||||
$atts['checked'] = 'checked';
|
||||
} else {
|
||||
$this->_all_checked = false;
|
||||
}
|
||||
|
||||
// disabled
|
||||
if ( in_array( $esc_value, $args['disabled'] ) ) {
|
||||
$atts['disabled'] = 'disabled';
|
||||
}
|
||||
|
||||
// store value added
|
||||
$this->_values[] = $esc_value;
|
||||
|
||||
// append
|
||||
$html .= acf_get_checkbox_input( $atts );
|
||||
}
|
||||
|
||||
// close
|
||||
$html .= '</li>' . "\n";
|
||||
}
|
||||
|
||||
// return
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
// Encode choices (convert from array).
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_encode_choices( $field['default_value'], false );
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'type' => 'textarea',
|
||||
'name' => 'choices',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Enter each default value on a new line', 'acf' ),
|
||||
'type' => 'textarea',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Custom Values', 'acf' ),
|
||||
'name' => 'allow_custom',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Allow 'custom' values to be added", 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Custom Values', 'acf' ),
|
||||
'name' => 'save_custom',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Save 'custom' values to the field's choices", 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'allow_custom',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Layout', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'vertical' => __( 'Vertical', 'acf' ),
|
||||
'horizontal' => __( 'Horizontal', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Add Toggle All', 'acf' ),
|
||||
'instructions' => __( 'Prepend an extra checkbox to toggle all choices', 'acf' ),
|
||||
'name' => 'toggle',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the field group ID (post_type = acf)
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
function update_field( $field ) {
|
||||
|
||||
// Decode choices (convert to array).
|
||||
$field['choices'] = acf_decode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_decode_choices( $field['default_value'], true );
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if is empty
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// select -> update_value()
|
||||
$value = acf_get_field_type( 'select' )->update_value( $value, $post_id, $field );
|
||||
|
||||
// save_other_choice
|
||||
if ( $field['save_custom'] ) {
|
||||
|
||||
// get raw $field (may have been changed via repeater field)
|
||||
// if field is local, it won't have an ID
|
||||
$selector = $field['ID'] ? $field['ID'] : $field['key'];
|
||||
$field = acf_get_field( $selector );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if no ID (JSON only)
|
||||
if ( ! $field['ID'] ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $value as $v ) {
|
||||
|
||||
// ignore if already eixsts
|
||||
if ( isset( $field['choices'][ $v ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// unslash (fixes serialize single quote issue)
|
||||
$v = wp_unslash( $v );
|
||||
|
||||
// sanitize (remove tags)
|
||||
$v = sanitize_text_field( $v );
|
||||
|
||||
// append
|
||||
$field['choices'][ $v ] = $v;
|
||||
}
|
||||
|
||||
// save
|
||||
acf_update_field( $field );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
function translate_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'select' )->translate_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if is empty.
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Always convert to array of items.
|
||||
$value = acf_array( $value );
|
||||
|
||||
// Return.
|
||||
return acf_get_field_type( 'select' )->format_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'string', 'array', 'null' ),
|
||||
'required' => isset( $field['required'] ) && $field['required'],
|
||||
'items' => array(
|
||||
'type' => array( 'string', 'integer' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
// If we allow custom values, nothing else to do here.
|
||||
if ( ! empty( $field['allow_custom'] ) ) {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
$schema['items']['enum'] = acf_get_field_type( 'select' )->format_rest_choices( $field['choices'] );
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_checkbox' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,279 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_color_picker' ) ) :
|
||||
|
||||
class acf_field_color_picker extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'color_picker';
|
||||
$this->label = __( 'Color Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for selecting a color, or specifying a Hex value.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-color-picker.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/color-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'enable_opacity' => false,
|
||||
'return_format' => 'string', // 'string'|'array'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// Register scripts for non-admin.
|
||||
// Applies logic from wp_default_scripts() function defined in "wp-includes/script-loader.php".
|
||||
if ( ! is_admin() ) {
|
||||
$suffix = defined( 'ACF_DEVELOPMENT_MODE' ) && ACF_DEVELOPMENT_MODE ? '' : '.min';
|
||||
$scripts = wp_scripts();
|
||||
$scripts->add( 'iris', '/wp-admin/js/iris.min.js', array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), '1.0.7', 1 );
|
||||
$scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
|
||||
|
||||
// Handle localisation across multiple WP versions.
|
||||
// WP 5.0+
|
||||
if ( method_exists( $scripts, 'set_translations' ) ) {
|
||||
$scripts->set_translations( 'wp-color-picker' );
|
||||
// WP 4.9
|
||||
} else {
|
||||
$scripts->localize(
|
||||
'wp-color-picker',
|
||||
'wpColorPickerL10n',
|
||||
array(
|
||||
'clear' => __( 'Clear', 'acf' ),
|
||||
'clearAriaLabel' => __( 'Clear color', 'acf' ),
|
||||
'defaultString' => __( 'Default', 'acf' ),
|
||||
'defaultAriaLabel' => __( 'Select default color', 'acf' ),
|
||||
'pick' => __( 'Select Color', 'acf' ),
|
||||
'defaultLabel' => __( 'Color value', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue alpha color picker assets.
|
||||
wp_enqueue_script(
|
||||
'acf-color-picker-alpha',
|
||||
acf_get_url( 'assets/inc/color-picker-alpha/wp-color-picker-alpha.js' ),
|
||||
array( 'jquery', 'wp-color-picker' ),
|
||||
'3.0.0'
|
||||
);
|
||||
|
||||
// Enqueue.
|
||||
wp_enqueue_style( 'wp-color-picker' );
|
||||
wp_enqueue_script( 'wp-color-picker' );
|
||||
|
||||
acf_localize_data(
|
||||
array(
|
||||
'colorPickerL10n' => array(
|
||||
'hex_string' => __( 'Hex String', 'acf' ),
|
||||
'rgba_string' => __( 'RGBA String', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
$text_input = acf_get_sub_array( $field, array( 'id', 'class', 'name', 'value' ) );
|
||||
$hidden_input = acf_get_sub_array( $field, array( 'name', 'value' ) );
|
||||
$text_input['data-alpha-skip-debounce'] = true;
|
||||
|
||||
// Color picker alpha library requires a specific data attribute to exist.
|
||||
if ( $field['enable_opacity'] ) {
|
||||
$text_input['data-alpha-enabled'] = true;
|
||||
}
|
||||
|
||||
// html
|
||||
?>
|
||||
<div class="acf-color-picker">
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
|
||||
// display_format
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
'placeholder' => '#FFFFFF',
|
||||
)
|
||||
);
|
||||
|
||||
// Toggle opacity control.
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Enable Transparency', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'enable_opacity',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// Return format control.
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'string' => __( 'Hex String', 'acf' ),
|
||||
'array' => __( 'RGBA Array', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the value for use in templates. At this stage, the value has been loaded from the
|
||||
* database and is being returned by an API function such as get_field(), the_field(), etc.
|
||||
*
|
||||
* @since 5.10
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param integer $post_id The post ID
|
||||
* @param array $field The field array
|
||||
* @return string|array
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
if ( isset( $field['return_format'] ) && $field['return_format'] === 'array' ) {
|
||||
$value = $this->string_to_array( $value );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert either a Hexadecimal or RGBA string to an RGBA array.
|
||||
*
|
||||
* @since 5.10
|
||||
* @date 15/12/20
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
private function string_to_array( $value ) {
|
||||
$value = is_string( $value ) ? trim( $value ) : '';
|
||||
|
||||
// Match and collect r,g,b values from 6 digit hex code. If there are 4
|
||||
// match-results, we have the values we need to build an r,g,b,a array.
|
||||
preg_match( '/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i', $value, $matches );
|
||||
if ( count( $matches ) === 4 ) {
|
||||
return array(
|
||||
'red' => hexdec( $matches[1] ),
|
||||
'green' => hexdec( $matches[2] ),
|
||||
'blue' => hexdec( $matches[3] ),
|
||||
'alpha' => (float) 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Match and collect r,g,b values from 3 digit hex code. If there are 4
|
||||
// match-results, we have the values we need to build an r,g,b,a array.
|
||||
// We have to duplicate the matched hex digit for 3 digit hex codes.
|
||||
preg_match( '/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i', $value, $matches );
|
||||
if ( count( $matches ) === 4 ) {
|
||||
return array(
|
||||
'red' => hexdec( $matches[1] . $matches[1] ),
|
||||
'green' => hexdec( $matches[2] . $matches[2] ),
|
||||
'blue' => hexdec( $matches[3] . $matches[3] ),
|
||||
'alpha' => (float) 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Attempt to match an rgba(…) or rgb(…) string (case-insensitive), capturing the decimals
|
||||
// as a string. If there are two match results, we have the RGBA decimal values as a
|
||||
// comma-separated string. Break it apart and, depending on the number of values, return
|
||||
// our formatted r,g,b,a array.
|
||||
preg_match( '/^rgba?\(([0-9,.]+)\)/i', $value, $matches );
|
||||
if ( count( $matches ) === 2 ) {
|
||||
$decimals = explode( ',', $matches[1] );
|
||||
|
||||
// Handle rgba() format.
|
||||
if ( count( $decimals ) === 4 ) {
|
||||
return array(
|
||||
'red' => (int) $decimals[0],
|
||||
'green' => (int) $decimals[1],
|
||||
'blue' => (int) $decimals[2],
|
||||
'alpha' => (float) $decimals[3],
|
||||
);
|
||||
}
|
||||
|
||||
// Handle rgb() format.
|
||||
if ( count( $decimals ) === 3 ) {
|
||||
return array(
|
||||
'red' => (int) $decimals[0],
|
||||
'green' => (int) $decimals[1],
|
||||
'blue' => (int) $decimals[2],
|
||||
'alpha' => (float) 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'red' => 0,
|
||||
'green' => 0,
|
||||
'blue' => 0,
|
||||
'alpha' => (float) 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_color_picker' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,314 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_date_picker' ) ) :
|
||||
|
||||
class acf_field_date_picker extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'date_picker';
|
||||
$this->label = __( 'Date Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for picking a date. The date return format can be customized using the field settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-date-picker.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/date-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'display_format' => 'd/m/Y',
|
||||
'return_format' => 'd/m/Y',
|
||||
'first_day' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_datepicker' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// localize
|
||||
global $wp_locale;
|
||||
acf_localize_data(
|
||||
array(
|
||||
'datePickerL10n' => array(
|
||||
'closeText' => _x( 'Done', 'Date Picker JS closeText', 'acf' ),
|
||||
'currentText' => _x( 'Today', 'Date Picker JS currentText', 'acf' ),
|
||||
'nextText' => _x( 'Next', 'Date Picker JS nextText', 'acf' ),
|
||||
'prevText' => _x( 'Prev', 'Date Picker JS prevText', 'acf' ),
|
||||
'weekHeader' => _x( 'Wk', 'Date Picker JS weekHeader', 'acf' ),
|
||||
'monthNames' => array_values( $wp_locale->month ),
|
||||
'monthNamesShort' => array_values( $wp_locale->month_abbrev ),
|
||||
'dayNames' => array_values( $wp_locale->weekday ),
|
||||
'dayNamesMin' => array_values( $wp_locale->weekday_initial ),
|
||||
'dayNamesShort' => array_values( $wp_locale->weekday_abbrev ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// script
|
||||
wp_enqueue_script( 'jquery-ui-datepicker' );
|
||||
|
||||
// style
|
||||
wp_enqueue_style( 'acf-datepicker', acf_get_url( 'assets/inc/datepicker/jquery-ui.min.css' ), array(), '1.11.4' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$hidden_value = '';
|
||||
$display_value = '';
|
||||
|
||||
// format value
|
||||
if ( $field['value'] ) {
|
||||
$hidden_value = acf_format_date( $field['value'], 'Ymd' );
|
||||
$display_value = acf_format_date( $field['value'], $field['display_format'] );
|
||||
}
|
||||
|
||||
// elements
|
||||
$div = array(
|
||||
'class' => 'acf-date-picker acf-input-wrap',
|
||||
'data-date_format' => acf_convert_date_to_js( $field['display_format'] ),
|
||||
'data-first_day' => $field['first_day'],
|
||||
);
|
||||
$hidden_input = array(
|
||||
'id' => $field['id'],
|
||||
'name' => $field['name'],
|
||||
'value' => $hidden_value,
|
||||
);
|
||||
$text_input = array(
|
||||
'class' => $field['class'] . ' input',
|
||||
'value' => $display_value,
|
||||
);
|
||||
|
||||
// special attributes
|
||||
foreach ( array( 'readonly', 'disabled' ) as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$hidden_input[ $k ] = $k;
|
||||
$text_input[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// save_format - compatibility with ACF < 5.0.0
|
||||
if ( ! empty( $field['save_format'] ) ) {
|
||||
|
||||
// add custom JS save format
|
||||
$div['data-save_format'] = $field['save_format'];
|
||||
|
||||
// revert hidden input value to raw DB value
|
||||
$hidden_input['value'] = $field['value'];
|
||||
|
||||
// remove formatted value (will do this via JS)
|
||||
$text_input['value'] = '';
|
||||
}
|
||||
|
||||
// html
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
global $wp_locale;
|
||||
|
||||
$d_m_Y = date_i18n( 'd/m/Y' );
|
||||
$m_d_Y = date_i18n( 'm/d/Y' );
|
||||
$F_j_Y = date_i18n( 'F j, Y' );
|
||||
$Ymd = date_i18n( 'Ymd' );
|
||||
|
||||
echo '<div class="acf-field-settings-split">';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Display Format', 'acf' ),
|
||||
'hint' => __( 'The format displayed when editing a post', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'display_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y' => '<span>' . $d_m_Y . '</span><code>d/m/Y</code>',
|
||||
'm/d/Y' => '<span>' . $m_d_Y . '</span><code>m/d/Y</code>',
|
||||
'F j, Y' => '<span>' . $F_j_Y . '</span><code>F j, Y</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// save_format - compatibility with ACF < 5.0.0
|
||||
if ( ! empty( $field['save_format'] ) ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Format', 'acf' ),
|
||||
'hint' => __( 'The format used when saving a value', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'save_format',
|
||||
// 'readonly' => 1 // this setting was not readonly in v4
|
||||
)
|
||||
);
|
||||
} else {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'hint' => __( 'The format returned via template functions', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y' => '<span>' . $d_m_Y . '</span><code>d/m/Y</code>',
|
||||
'm/d/Y' => '<span>' . $m_d_Y . '</span><code>m/d/Y</code>',
|
||||
'F j, Y' => '<span>' . $F_j_Y . '</span><code>F j, Y</code>',
|
||||
'Ymd' => '<span>' . $Ymd . '</span><code>Ymd</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Week Starts On', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'first_day',
|
||||
'choices' => array_values( $wp_locale->weekday ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// save_format - compatibility with ACF < 5.0.0
|
||||
if ( ! empty( $field['save_format'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// return
|
||||
return acf_format_date( $value, $field['return_format'] );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is applied to the $field after it is loaded from the database
|
||||
* and ensures the return and display values are set.
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.11.0
|
||||
* @date 28/09/21
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return array
|
||||
*/
|
||||
public function load_field( $field ) {
|
||||
if ( empty( $field['display_format'] ) ) {
|
||||
$field['display_format'] = $this->defaults['display_format'];
|
||||
}
|
||||
|
||||
if ( empty( $field['return_format'] ) ) {
|
||||
$field['return_format'] = $this->defaults['return_format'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field The field array
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'description' => 'A `Ymd` formatted date string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
if ( ! $value ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_date_picker' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_date_and_time_picker' ) ) :
|
||||
|
||||
class acf_field_date_and_time_picker extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'date_time_picker';
|
||||
$this->label = __( 'Date Time Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for picking a date and time. The date return format can be customized using the field settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-date-time.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/date-time-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'display_format' => 'd/m/Y g:i a',
|
||||
'return_format' => 'd/m/Y g:i a',
|
||||
'first_day' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_datetimepicker' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// vars
|
||||
$version = '1.6.1';
|
||||
|
||||
// script
|
||||
wp_enqueue_script( 'acf-timepicker', acf_get_url( 'assets/inc/timepicker/jquery-ui-timepicker-addon.min.js' ), array( 'jquery-ui-datepicker' ), $version );
|
||||
|
||||
// style
|
||||
wp_enqueue_style( 'acf-timepicker', acf_get_url( 'assets/inc/timepicker/jquery-ui-timepicker-addon.min.css' ), '', $version );
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'dateTimePickerL10n' => array(
|
||||
'timeOnlyTitle' => _x( 'Choose Time', 'Date Time Picker JS timeOnlyTitle', 'acf' ),
|
||||
'timeText' => _x( 'Time', 'Date Time Picker JS timeText', 'acf' ),
|
||||
'hourText' => _x( 'Hour', 'Date Time Picker JS hourText', 'acf' ),
|
||||
'minuteText' => _x( 'Minute', 'Date Time Picker JS minuteText', 'acf' ),
|
||||
'secondText' => _x( 'Second', 'Date Time Picker JS secondText', 'acf' ),
|
||||
'millisecText' => _x( 'Millisecond', 'Date Time Picker JS millisecText', 'acf' ),
|
||||
'microsecText' => _x( 'Microsecond', 'Date Time Picker JS microsecText', 'acf' ),
|
||||
'timezoneText' => _x( 'Time Zone', 'Date Time Picker JS timezoneText', 'acf' ),
|
||||
'currentText' => _x( 'Now', 'Date Time Picker JS currentText', 'acf' ),
|
||||
'closeText' => _x( 'Done', 'Date Time Picker JS closeText', 'acf' ),
|
||||
'selectText' => _x( 'Select', 'Date Time Picker JS selectText', 'acf' ),
|
||||
'amNames' => array(
|
||||
_x( 'AM', 'Date Time Picker JS amText', 'acf' ),
|
||||
_x( 'A', 'Date Time Picker JS amTextShort', 'acf' ),
|
||||
),
|
||||
'pmNames' => array(
|
||||
_x( 'PM', 'Date Time Picker JS pmText', 'acf' ),
|
||||
_x( 'P', 'Date Time Picker JS pmTextShort', 'acf' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// Set value.
|
||||
$hidden_value = '';
|
||||
$display_value = '';
|
||||
|
||||
if ( $field['value'] ) {
|
||||
$hidden_value = acf_format_date( $field['value'], 'Y-m-d H:i:s' );
|
||||
$display_value = acf_format_date( $field['value'], $field['display_format'] );
|
||||
}
|
||||
|
||||
// Convert "display_format" setting to individual date and time formats.
|
||||
$formats = acf_split_date_time( $field['display_format'] );
|
||||
|
||||
// Elements.
|
||||
$div = array(
|
||||
'class' => 'acf-date-time-picker acf-input-wrap',
|
||||
'data-date_format' => acf_convert_date_to_js( $formats['date'] ),
|
||||
'data-time_format' => acf_convert_time_to_js( $formats['time'] ),
|
||||
'data-first_day' => $field['first_day'],
|
||||
);
|
||||
$hidden_input = array(
|
||||
'id' => $field['id'],
|
||||
'class' => 'input-alt',
|
||||
'name' => $field['name'],
|
||||
'value' => $hidden_value,
|
||||
);
|
||||
$text_input = array(
|
||||
'class' => $field['class'] . ' input',
|
||||
'value' => $display_value,
|
||||
);
|
||||
foreach ( array( 'readonly', 'disabled' ) as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$hidden_input[ $k ] = $k;
|
||||
$text_input[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// Output.
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
global $wp_locale;
|
||||
|
||||
$d_m_Y = date_i18n( 'd/m/Y g:i a' );
|
||||
$m_d_Y = date_i18n( 'm/d/Y g:i a' );
|
||||
$F_j_Y = date_i18n( 'F j, Y g:i a' );
|
||||
$Ymd = date_i18n( 'Y-m-d H:i:s' );
|
||||
|
||||
echo '<div class="acf-field-settings-split">';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Display Format', 'acf' ),
|
||||
'hint' => __( 'The format displayed when editing a post', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'display_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y g:i a' => '<span>' . $d_m_Y . '</span><code>d/m/Y g:i a</code>',
|
||||
'm/d/Y g:i a' => '<span>' . $m_d_Y . '</span><code>m/d/Y g:i a</code>',
|
||||
'F j, Y g:i a' => '<span>' . $F_j_Y . '</span><code>F j, Y g:i a</code>',
|
||||
'Y-m-d H:i:s' => '<span>' . $Ymd . '</span><code>Y-m-d H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'hint' => __( 'The format returned via template functions', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y g:i a' => '<span>' . $d_m_Y . '</span><code>d/m/Y g:i a</code>',
|
||||
'm/d/Y g:i a' => '<span>' . $m_d_Y . '</span><code>m/d/Y g:i a</code>',
|
||||
'F j, Y g:i a' => '<span>' . $F_j_Y . '</span><code>F j, Y g:i a</code>',
|
||||
'Y-m-d H:i:s' => '<span>' . $Ymd . '</span><code>Y-m-d H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Week Starts On', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'first_day',
|
||||
'choices' => array_values( $wp_locale->weekday ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database
|
||||
* @param mixed $post_id The post_id from which the value was loaded
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return mixed $value The modified value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
return acf_format_date( $value, $field['return_format'] );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is applied to the $field after it is loaded from the database
|
||||
* and ensures the return and display values are set.
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.11.0
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return array
|
||||
*/
|
||||
public function load_field( $field ) {
|
||||
if ( empty( $field['display_format'] ) ) {
|
||||
$field['display_format'] = $this->defaults['display_format'];
|
||||
}
|
||||
|
||||
if ( empty( $field['return_format'] ) ) {
|
||||
$field['return_format'] = $this->defaults['return_format'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'description' => 'A `Y-m-d H:i:s` formatted date string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_date_and_time_picker' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_email' ) ) :
|
||||
|
||||
class acf_field_email extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'email';
|
||||
$this->label = __( 'Email', 'acf' );
|
||||
$this->description = __( 'A text input specifically designed for storing email addresses.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-email.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/email/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required', 'multiple' );
|
||||
$html = '';
|
||||
|
||||
// prepend
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-prepended';
|
||||
$html .= '<div class="acf-input-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
}
|
||||
|
||||
// append
|
||||
if ( $field['append'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-appended';
|
||||
$html .= '<div class="acf-input-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
}
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// render
|
||||
$html .= '<div class="acf-input-wrap">' . acf_get_text_input( $atts ) . '</div>';
|
||||
|
||||
// return
|
||||
echo $html; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- safe HTML escaped by acf_get_text_input
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the email value. If this method returns TRUE, the input value is valid. If
|
||||
* FALSE or a string is returned, the input value is invalid and the user is shown a
|
||||
* notice. If a string is returned, the string is show as the message text.
|
||||
*
|
||||
* @param boolean $valid Whether the value is valid.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The request variable name for the inbound field.
|
||||
* @return boolean|string
|
||||
*/
|
||||
public function validate_value( $valid, $value, $field, $input ) {
|
||||
$flags = defined( 'FILTER_FLAG_EMAIL_UNICODE' ) ? FILTER_FLAG_EMAIL_UNICODE : 0;
|
||||
|
||||
if ( $value && filter_var( wp_unslash( $value ), FILTER_VALIDATE_EMAIL, $flags ) === false ) {
|
||||
return sprintf( __( "'%s' is not a valid email address", 'acf' ), esc_html( $value ) );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
$schema['format'] = 'email';
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_email' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,522 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_file' ) ) :
|
||||
|
||||
class acf_field_file extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'file';
|
||||
$this->label = __( 'File', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'Uses the native WordPress media picker to upload, or choose files.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-file.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/file/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
'library' => 'all',
|
||||
'min_size' => 0,
|
||||
'max_size' => 0,
|
||||
'mime_types' => '',
|
||||
);
|
||||
|
||||
// filters
|
||||
add_filter( 'get_media_item_args', array( $this, 'get_media_item_args' ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// localize
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Select File' => __( 'Select File', 'acf' ),
|
||||
'Edit File' => __( 'Edit File', 'acf' ),
|
||||
'Update File' => __( 'Update File', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$uploader = acf_get_setting( 'uploader' );
|
||||
|
||||
// allow custom uploader
|
||||
$uploader = acf_maybe_get( $field, 'uploader', $uploader );
|
||||
|
||||
// enqueue
|
||||
if ( $uploader == 'wp' ) {
|
||||
acf_enqueue_uploader();
|
||||
}
|
||||
|
||||
// vars
|
||||
$o = array(
|
||||
'icon' => '',
|
||||
'title' => '',
|
||||
'url' => '',
|
||||
'filename' => '',
|
||||
'filesize' => '',
|
||||
);
|
||||
|
||||
$div = array(
|
||||
'class' => 'acf-file-uploader',
|
||||
'data-library' => $field['library'],
|
||||
'data-mime_types' => $field['mime_types'],
|
||||
'data-uploader' => $uploader,
|
||||
);
|
||||
|
||||
// has value?
|
||||
if ( $field['value'] ) {
|
||||
$attachment = acf_get_attachment( $field['value'] );
|
||||
if ( $attachment ) {
|
||||
|
||||
// has value
|
||||
$div['class'] .= ' has-value';
|
||||
|
||||
// update
|
||||
$o['icon'] = $attachment['icon'];
|
||||
$o['title'] = $attachment['title'];
|
||||
$o['url'] = $attachment['url'];
|
||||
$o['filename'] = $attachment['filename'];
|
||||
if ( $attachment['filesize'] ) {
|
||||
$o['filesize'] = size_format( $attachment['filesize'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
'data-name' => 'id',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<div class="show-if-value file-wrap">
|
||||
<div class="file-icon">
|
||||
<img data-name="icon" src="<?php echo esc_url( $o['icon'] ); ?>" alt=""/>
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<p>
|
||||
<strong data-name="title"><?php echo esc_html( $o['title'] ); ?></strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'File name', 'acf' ); ?>:</strong>
|
||||
<a data-name="filename" href="<?php echo esc_url( $o['url'] ); ?>" target="_blank"><?php echo esc_html( $o['filename'] ); ?></a>
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php esc_html_e( 'File size', 'acf' ); ?>:</strong>
|
||||
<span data-name="filesize"><?php echo esc_html( $o['filesize'] ); ?></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="acf-actions -hover">
|
||||
<?php if ( $uploader != 'basic' ) : ?>
|
||||
<a class="acf-icon -pencil dark" data-name="edit" href="#" title="<?php esc_attr_e( 'Edit', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php esc_attr_e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide-if-value">
|
||||
<?php if ( $uploader == 'basic' ) : ?>
|
||||
|
||||
<?php if ( $field['value'] && ! is_numeric( $field['value'] ) ) : ?>
|
||||
<div class="acf-error-message"><p><?php echo acf_esc_html( $field['value'] ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<label class="acf-basic-uploader">
|
||||
<?php
|
||||
acf_file_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'id' => $field['id'],
|
||||
'key' => $field['key'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
</label>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<p><?php esc_html_e( 'No file selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php esc_html_e( 'Add File', 'acf' ); ?></a></p>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'array' => __( 'File Array', 'acf' ),
|
||||
'url' => __( 'File URL', 'acf' ),
|
||||
'id' => __( 'File ID', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Library', 'acf' ),
|
||||
'instructions' => __( 'Limit the media library choice', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'library',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'all' => __( 'All', 'acf' ),
|
||||
'uploadedTo' => __( 'Uploaded to post', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
// Clear numeric settings.
|
||||
$clear = array(
|
||||
'min_size',
|
||||
'max_size',
|
||||
);
|
||||
|
||||
foreach ( $clear as $k ) {
|
||||
if ( empty( $field[ $k ] ) ) {
|
||||
$field[ $k ] = '';
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum', 'acf' ),
|
||||
'instructions' => __( 'Restrict which files can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'min_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum', 'acf' ),
|
||||
'instructions' => __( 'Restrict which files can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'max_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allowed File Types', 'acf' ),
|
||||
'hint' => __( 'Comma separated list. Leave blank for all types', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'mime_types',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if not numeric (error message)
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert to int
|
||||
$value = intval( $value );
|
||||
|
||||
// format
|
||||
if ( $field['return_format'] == 'url' ) {
|
||||
return wp_get_attachment_url( $value );
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
return acf_get_attachment( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 27/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param $vars (array)
|
||||
* @return $vars
|
||||
*/
|
||||
function get_media_item_args( $vars ) {
|
||||
|
||||
$vars['send'] = true;
|
||||
return( $vars );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Parse value for id.
|
||||
$attachment_id = acf_idval( $value );
|
||||
|
||||
// Connect attacment to post.
|
||||
acf_connect_attachment_to_post( $attachment_id, $post_id );
|
||||
|
||||
// Return id.
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* This function will validate a basic file input
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// bail early if empty
|
||||
if ( empty( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// bail early if is numeric
|
||||
if ( is_numeric( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// bail early if not basic string
|
||||
if ( ! is_string( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// decode value
|
||||
$file = null;
|
||||
parse_str( $value, $file );
|
||||
|
||||
// bail early if no attachment
|
||||
if ( empty( $file ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// get errors
|
||||
$errors = acf_validate_attachment( $file, $field, 'basic_upload' );
|
||||
|
||||
// append error
|
||||
if ( ! empty( $errors ) ) {
|
||||
$valid = implode( "\n", $errors );
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates file fields updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( is_null( $value ) && empty( $field['required'] ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bit of a hack, but we use `wp_prepare_attachment_for_js()` here
|
||||
* since it returns all the data we need to validate the file, and we use this anyways
|
||||
* to validate fields updated via UI.
|
||||
*/
|
||||
$attachment = wp_prepare_attachment_for_js( $value );
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array(
|
||||
'param' => $param,
|
||||
'value' => (int) $value,
|
||||
);
|
||||
|
||||
if ( ! $attachment ) {
|
||||
$error = sprintf( __( '%s requires a valid attachment ID.', 'acf' ), $param );
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
$errors = acf_validate_attachment( $attachment, $field, 'prepare' );
|
||||
|
||||
if ( ! empty( $errors ) ) {
|
||||
$error = $param . ' - ' . implode( ' ', $errors );
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'null' ),
|
||||
'required' => isset( $field['required'] ) && $field['required'],
|
||||
);
|
||||
|
||||
if ( ! empty( $field['min_width'] ) ) {
|
||||
$schema['minWidth'] = (int) $field['min_width'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['min_height'] ) ) {
|
||||
$schema['minHeight'] = (int) $field['min_height'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['min_size'] ) ) {
|
||||
$schema['minSize'] = $field['min_size'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max_width'] ) ) {
|
||||
$schema['maxWidth'] = (int) $field['max_width'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max_height'] ) ) {
|
||||
$schema['maxHeight'] = (int) $field['max_height'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max_size'] ) ) {
|
||||
$schema['maxSize'] = $field['max_size'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['mime_types'] ) ) {
|
||||
$schema['mimeTypes'] = $field['mime_types'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_file' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,374 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_google_map' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field_google_map extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'google_map';
|
||||
$this->label = __( 'Google Map', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for selecting a location using Google Maps. Requires a Google Maps API key and additional configuration to display correctly.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-google-map.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/google-map/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'height' => '',
|
||||
'center_lat' => '',
|
||||
'center_lng' => '',
|
||||
'zoom' => '',
|
||||
);
|
||||
$this->default_values = array(
|
||||
'height' => '400',
|
||||
'center_lat' => '-37.81411',
|
||||
'center_lng' => '144.96328',
|
||||
'zoom' => '14',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// localize
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Sorry, this browser does not support geolocation' => __( 'Sorry, this browser does not support geolocation', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_google_maps' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// vars
|
||||
$api = array(
|
||||
'key' => acf_get_setting( 'google_api_key' ),
|
||||
'client' => acf_get_setting( 'google_api_client' ),
|
||||
'libraries' => 'places',
|
||||
'ver' => 3,
|
||||
'callback' => 'Function.prototype',
|
||||
'language' => acf_get_locale(),
|
||||
);
|
||||
|
||||
// filter
|
||||
$api = apply_filters( 'acf/fields/google_map/api', $api );
|
||||
|
||||
// remove empty
|
||||
if ( empty( $api['key'] ) ) {
|
||||
unset( $api['key'] );
|
||||
}
|
||||
if ( empty( $api['client'] ) ) {
|
||||
unset( $api['client'] );
|
||||
}
|
||||
|
||||
// construct url
|
||||
$url = add_query_arg( $api, 'https://maps.googleapis.com/maps/api/js' );
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'google_map_api' => $url,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// Apply defaults.
|
||||
foreach ( $this->default_values as $k => $v ) {
|
||||
if ( ! $field[ $k ] ) {
|
||||
$field[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Attrs.
|
||||
$attrs = array(
|
||||
'id' => $field['id'],
|
||||
'class' => "acf-google-map {$field['class']}",
|
||||
'data-lat' => $field['center_lat'],
|
||||
'data-lng' => $field['center_lng'],
|
||||
'data-zoom' => $field['zoom'],
|
||||
);
|
||||
|
||||
$search = '';
|
||||
if ( $field['value'] ) {
|
||||
$attrs['class'] .= ' -value';
|
||||
$search = $field['value']['address'];
|
||||
} else {
|
||||
$field['value'] = '';
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $attrs ); ?>>
|
||||
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<div class="title">
|
||||
|
||||
<div class="acf-actions -hover">
|
||||
<a href="#" data-name="search" class="acf-icon -search grey" title="<?php esc_attr_e( 'Search', 'acf' ); ?>"></a>
|
||||
<a href="#" data-name="clear" class="acf-icon -cancel grey" title="<?php esc_attr_e( 'Clear location', 'acf' ); ?>"></a>
|
||||
<a href="#" data-name="locate" class="acf-icon -location grey" title="<?php esc_attr_e( 'Find current location', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
|
||||
<input class="search" type="text" placeholder="<?php esc_attr_e( 'Search for address...', 'acf' ); ?>" value="<?php echo esc_attr( $search ); ?>" />
|
||||
<i class="acf-loading"></i>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="canvas" style="<?php echo esc_attr( 'height: ' . $field['height'] . 'px' ); ?>"></div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
|
||||
// center_lat
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Center', 'acf' ),
|
||||
'hint' => __( 'Center the initial map', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'center_lat',
|
||||
'prepend' => 'lat',
|
||||
'placeholder' => $this->default_values['center_lat'],
|
||||
)
|
||||
);
|
||||
|
||||
// center_lng
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Center', 'acf' ),
|
||||
'hint' => __( 'Center the initial map', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'center_lng',
|
||||
'prepend' => 'lng',
|
||||
'placeholder' => $this->default_values['center_lng'],
|
||||
'_append' => 'center_lat',
|
||||
)
|
||||
);
|
||||
|
||||
// zoom
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Zoom', 'acf' ),
|
||||
'instructions' => __( 'Set the initial zoom level', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'zoom',
|
||||
'placeholder' => $this->default_values['zoom'],
|
||||
)
|
||||
);
|
||||
|
||||
// allow_null
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Height', 'acf' ),
|
||||
'instructions' => __( 'Customize the map height', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'height',
|
||||
'append' => 'px',
|
||||
'placeholder' => $this->default_values['height'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* load_value
|
||||
*
|
||||
* Filters the value loaded from the database.
|
||||
*
|
||||
* @date 16/10/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param mixed $value The value loaded from the database.
|
||||
* @param mixed $post_id The post ID where the value is saved.
|
||||
* @param array $field The field settings array.
|
||||
* @return (array|false)
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// Ensure value is an array.
|
||||
if ( $value ) {
|
||||
return wp_parse_args(
|
||||
$value,
|
||||
array(
|
||||
'address' => '',
|
||||
'lat' => 0,
|
||||
'lng' => 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Return default.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// decode JSON string.
|
||||
if ( is_string( $value ) ) {
|
||||
$value = json_decode( wp_unslash( $value ), true );
|
||||
}
|
||||
|
||||
// Ensure value is an array.
|
||||
if ( $value ) {
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
// Return default.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'properties' => array(
|
||||
'address' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'lat' => array(
|
||||
'type' => array( 'string', 'float' ),
|
||||
),
|
||||
'lng' => array(
|
||||
'type' => array( 'string', 'float' ),
|
||||
),
|
||||
'zoom' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
),
|
||||
'place_id' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'name' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'street_number' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
),
|
||||
'street_name' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'street_name_short' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'city' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'state' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'state_short' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'post_code' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
),
|
||||
'country' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'country_short' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
if ( ! $value ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_google_map' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,649 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field__group' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field__group extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'group';
|
||||
$this->label = __( 'Group', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Provides a way to structure fields into groups to better organize the data and the edit screen.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-group.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/group/', 'docs', 'field-type-selection' );
|
||||
$this->supports = array(
|
||||
'bindings' => false,
|
||||
);
|
||||
$this->defaults = array(
|
||||
'sub_fields' => array(),
|
||||
'layout' => 'block',
|
||||
);
|
||||
$this->have_rows = 'single';
|
||||
|
||||
// field filters
|
||||
$this->add_field_filter( 'acf/prepare_field_for_export', array( $this, 'prepare_field_for_export' ) );
|
||||
$this->add_field_filter( 'acf/prepare_field_for_import', array( $this, 'prepare_field_for_import' ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// vars
|
||||
$sub_fields = acf_get_fields( $field );
|
||||
|
||||
// append
|
||||
if ( $sub_fields ) {
|
||||
$field['sub_fields'] = $sub_fields;
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is applied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value found in the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
* @return $value
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// load sub fields
|
||||
$value = array();
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// load
|
||||
$value[ $sub_field['key'] ] = acf_get_value( $post_id, $sub_field );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database.
|
||||
* @param mixed $post_id The $post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @param boolean $escape_html Should the field return a HTML safe formatted value.
|
||||
* @return mixed the modified value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field, $escape_html = false ) {
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// extract value
|
||||
$sub_value = acf_extract_var( $value, $sub_field['key'] );
|
||||
|
||||
// format value
|
||||
$sub_value = acf_format_value( $sub_value, $post_id, $sub_field, $escape_html );
|
||||
|
||||
// append to $row
|
||||
$value[ $sub_field['_name'] ] = $sub_value;
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( ! acf_is_array( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// vars
|
||||
$v = false;
|
||||
|
||||
// key (backend)
|
||||
if ( isset( $value[ $sub_field['key'] ] ) ) {
|
||||
$v = $value[ $sub_field['key'] ];
|
||||
|
||||
// name (frontend)
|
||||
} elseif ( isset( $value[ $sub_field['_name'] ] ) ) {
|
||||
$v = $value[ $sub_field['_name'] ];
|
||||
|
||||
// empty
|
||||
} else {
|
||||
|
||||
// input is not set (hidden by conditioanl logic)
|
||||
continue;
|
||||
}
|
||||
|
||||
// update value
|
||||
acf_update_value( $v, $post_id, $sub_field );
|
||||
}
|
||||
|
||||
// return
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will modify sub fields ready for update / load
|
||||
*
|
||||
* @type function
|
||||
* @date 4/11/16
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
function prepare_field_for_db( $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as &$sub_field ) {
|
||||
|
||||
// prefix name
|
||||
$sub_field['name'] = $field['name'] . '_' . $sub_field['_name'];
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load values
|
||||
foreach ( $field['sub_fields'] as &$sub_field ) {
|
||||
|
||||
// add value
|
||||
if ( isset( $field['value'][ $sub_field['key'] ] ) ) {
|
||||
|
||||
// this is a normal value
|
||||
$sub_field['value'] = $field['value'][ $sub_field['key'] ];
|
||||
} elseif ( isset( $sub_field['default_value'] ) ) {
|
||||
|
||||
// no value, but this sub field has a default value
|
||||
$sub_field['value'] = $sub_field['default_value'];
|
||||
}
|
||||
|
||||
// update prefix to allow for nested values
|
||||
$sub_field['prefix'] = $field['name'];
|
||||
|
||||
// restore required
|
||||
if ( $field['required'] ) {
|
||||
$sub_field['required'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
if ( $field['layout'] == 'table' ) {
|
||||
$this->render_field_table( $field );
|
||||
} else {
|
||||
$this->render_field_block( $field );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 12/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function render_field_block( $field ) {
|
||||
|
||||
// vars
|
||||
$label_placement = ( $field['layout'] == 'block' ) ? 'top' : 'left';
|
||||
|
||||
// html
|
||||
echo '<div class="acf-fields -' . esc_attr( $label_placement ) . ' -border">';
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_render_field_wrap( $sub_field );
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 12/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function render_field_table( $field ) {
|
||||
|
||||
?>
|
||||
<table class="acf-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
foreach ( $field['sub_fields'] as $sub_field ) :
|
||||
|
||||
// prepare field (allow sub fields to be removed)
|
||||
$sub_field = acf_prepare_field( $sub_field );
|
||||
|
||||
// bail early if no field
|
||||
if ( ! $sub_field ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$atts['class'] = 'acf-th';
|
||||
$atts['data-name'] = $sub_field['_name'];
|
||||
$atts['data-type'] = $sub_field['type'];
|
||||
$atts['data-key'] = $sub_field['key'];
|
||||
|
||||
// Add custom width
|
||||
if ( $sub_field['wrapper']['width'] ) {
|
||||
$atts['data-width'] = $sub_field['wrapper']['width'];
|
||||
$atts['style'] = 'width: ' . $sub_field['wrapper']['width'] . '%;';
|
||||
}
|
||||
|
||||
?>
|
||||
<th <?php echo acf_esc_attrs( $atts ); ?>>
|
||||
<?php acf_render_field_label( $sub_field ); ?>
|
||||
<?php acf_render_field_instructions( $sub_field ); ?>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="acf-row">
|
||||
<?php
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_render_field_wrap( $sub_field, 'td' );
|
||||
}
|
||||
|
||||
?>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
|
||||
// vars
|
||||
$args = array(
|
||||
'fields' => $field['sub_fields'],
|
||||
'parent' => $field['ID'],
|
||||
'is_subfield' => true,
|
||||
);
|
||||
|
||||
?>
|
||||
<div class="acf-field acf-field-setting-sub_fields" data-setting="group" data-name="sub_fields">
|
||||
<div class="acf-label">
|
||||
<label><?php esc_html_e( 'Sub Fields', 'acf' ); ?></label>
|
||||
</div>
|
||||
<div class="acf-input acf-input-sub">
|
||||
<?php
|
||||
|
||||
acf_get_view( 'acf-field-group/fields', $args );
|
||||
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
// layout
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Layout', 'acf' ),
|
||||
'instructions' => __( 'Specify the style used to render the selected fields', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'block' => __( 'Block', 'acf' ),
|
||||
'table' => __( 'Table', 'acf' ),
|
||||
'row' => __( 'Row', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// bail early if no $value
|
||||
if ( empty( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// get sub field
|
||||
$k = $sub_field['key'];
|
||||
|
||||
// bail early if value not set (conditional logic?)
|
||||
if ( ! isset( $value[ $k ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// required
|
||||
if ( $field['required'] ) {
|
||||
$sub_field['required'] = 1;
|
||||
}
|
||||
|
||||
// validate
|
||||
acf_validate_value( $value[ $k ], $sub_field, "{$input}[{$k}]" );
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field before it is duplicated and saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
function duplicate_field( $field ) {
|
||||
|
||||
// get sub fields
|
||||
$sub_fields = acf_extract_var( $field, 'sub_fields' );
|
||||
|
||||
// save field to get ID
|
||||
$field = acf_update_field( $field );
|
||||
|
||||
// duplicate sub fields
|
||||
acf_duplicate_fields( $sub_fields, $field['ID'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_field_for_export
|
||||
*
|
||||
* Prepares the field for export.
|
||||
*
|
||||
* @date 11/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field settings.
|
||||
* @return array
|
||||
*/
|
||||
function prepare_field_for_export( $field ) {
|
||||
|
||||
// Check for sub fields.
|
||||
if ( ! empty( $field['sub_fields'] ) ) {
|
||||
$field['sub_fields'] = acf_prepare_fields_for_export( $field['sub_fields'] );
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_field_for_import
|
||||
*
|
||||
* Returns a flat array of fields containing all sub fields ready for import.
|
||||
*
|
||||
* @date 11/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field settings.
|
||||
* @return array
|
||||
*/
|
||||
function prepare_field_for_import( $field ) {
|
||||
|
||||
// Check for sub fields.
|
||||
if ( ! empty( $field['sub_fields'] ) ) {
|
||||
$sub_fields = acf_extract_var( $field, 'sub_fields' );
|
||||
|
||||
// Modify sub fields.
|
||||
foreach ( $sub_fields as $i => $sub_field ) {
|
||||
$sub_fields[ $i ]['parent'] = $field['key'];
|
||||
$sub_fields[ $i ]['menu_order'] = $i;
|
||||
}
|
||||
|
||||
// Return array of [field, sub_1, sub_2, ...].
|
||||
return array_merge( array( $field ), $sub_fields );
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Called when deleting this field's value.
|
||||
*
|
||||
* @date 1/07/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param mixed $post_id The post ID being saved
|
||||
* @param string $meta_key The field name as seen by the DB
|
||||
* @param array $field The field settings
|
||||
* @return void
|
||||
*/
|
||||
function delete_value( $post_id, $meta_key, $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_delete_value( $post_id, $sub_field );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete_field
|
||||
*
|
||||
* Called when deleting a field of this type.
|
||||
*
|
||||
* @date 8/11/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param arra $field The field settings.
|
||||
* @return void
|
||||
*/
|
||||
function delete_field( $field ) {
|
||||
|
||||
// loop over sub fields and delete them
|
||||
if ( $field['sub_fields'] ) {
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_delete_field( $sub_field['ID'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'properties' => array(),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
if ( $sub_field_schema = acf_get_field_rest_schema( $sub_field ) ) {
|
||||
$schema['properties'][ $sub_field['name'] ] = $sub_field_schema;
|
||||
}
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param integer|string $post_id
|
||||
* @param array $field
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
if ( empty( $value ) || ! is_array( $value ) || empty( $field['sub_fields'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Loop through each row and within that, each sub field to process sub fields individually.
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// Extract the sub field 'field_key'=>'value' pair from the $value and format it.
|
||||
$sub_value = acf_extract_var( $value, $sub_field['key'] );
|
||||
$sub_value = acf_format_value_for_rest( $sub_value, $post_id, $sub_field );
|
||||
|
||||
// Add the sub field value back to the $value but mapped to the field name instead
|
||||
// of the key reference.
|
||||
$value[ $sub_field['name'] ] = $sub_value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field__group' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,823 @@
|
||||
<?php
|
||||
/**
|
||||
* This is a PHP file containing the code for the acf_field_icon_picker class.
|
||||
*
|
||||
* @package Advanced_Custom_Fields_Pro
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'acf_field_icon_picker' ) ) :
|
||||
|
||||
/**
|
||||
* Class acf_field_icon_picker.
|
||||
*/
|
||||
class acf_field_icon_picker extends acf_field {
|
||||
/**
|
||||
* Initialize icon picker field
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'icon_picker';
|
||||
$this->label = __( 'Icon Picker', 'acf' );
|
||||
$this->public = true;
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for selecting an icon. Select from Dashicons, the media library, or a standalone URL input.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-icon-picker.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/icon-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'library' => 'all',
|
||||
'tabs' => array_keys( $this->get_tabs() ),
|
||||
'return_format' => 'string',
|
||||
'default_value' => array(
|
||||
'type' => null,
|
||||
'value' => null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the available tabs for the icon picker field.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_tabs() {
|
||||
$tabs = array(
|
||||
'dashicons' => esc_html__( 'Dashicons', 'acf' ),
|
||||
);
|
||||
|
||||
if ( current_user_can( 'upload_files' ) ) {
|
||||
$tabs['media_library'] = esc_html__( 'Media Library', 'acf' );
|
||||
}
|
||||
|
||||
$tabs['url'] = esc_html__( 'URL', 'acf' );
|
||||
|
||||
/**
|
||||
* Allows filtering the tabs used by the icon picker.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $tabs An associative array of tabs in key => label format.
|
||||
* @return array
|
||||
*/
|
||||
return apply_filters( 'acf/fields/icon_picker/tabs', $tabs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an icon list tab (i.e. dashicons, custom icons).
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param string $tab_name The name of the tab being rendered.
|
||||
* @return void
|
||||
*/
|
||||
public function render_icon_list_tab( $tab_name ) {
|
||||
?>
|
||||
<div class="acf-icon-list-search-wrap">
|
||||
<?php
|
||||
acf_text_input(
|
||||
array(
|
||||
'class' => 'acf-icon-list-search-input',
|
||||
'placeholder' => esc_html__( 'Search icons...', 'acf' ),
|
||||
'type' => 'search',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<div class="acf-icon-list" role="radiogroup" data-parent-tab="<?php echo esc_attr( $tab_name ); ?>"></div>
|
||||
<div class="acf-icon-list-empty">
|
||||
<img src="<?php echo esc_url( acf_get_url( 'assets/images/face-sad.svg' ) ); ?>" />
|
||||
<p class="acf-no-results-text">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: The invalid search term */
|
||||
esc_html__( "No search results for '%s'", 'acf' ),
|
||||
'<span class="acf-invalid-icon-list-search-term"></span>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders icon picker field
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param object $field The ACF Field
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
$uploader = acf_get_setting( 'uploader' );
|
||||
|
||||
// Enqueue uploader scripts
|
||||
if ( $uploader === 'wp' ) {
|
||||
acf_enqueue_uploader();
|
||||
}
|
||||
|
||||
$div = array(
|
||||
'id' => $field['id'],
|
||||
'class' => $field['class'] . ' acf-icon-picker',
|
||||
);
|
||||
|
||||
echo '<div ' . acf_esc_attrs( $div ) . '>';
|
||||
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'] . '[type]',
|
||||
'value' => $field['value']['type'],
|
||||
'data-hidden-type' => 'type',
|
||||
)
|
||||
);
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'] . '[value]',
|
||||
'value' => $field['value']['value'],
|
||||
'data-hidden-type' => 'value',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! is_array( $field['tabs'] ) ) {
|
||||
$field['tabs'] = array();
|
||||
}
|
||||
|
||||
$tabs = $this->get_tabs();
|
||||
$shown = array_filter(
|
||||
$tabs,
|
||||
function ( $tab ) use ( $field ) {
|
||||
return in_array( $tab, $field['tabs'], true );
|
||||
},
|
||||
ARRAY_FILTER_USE_KEY
|
||||
);
|
||||
|
||||
foreach ( $shown as $name => $label ) {
|
||||
if ( count( $shown ) > 1 ) {
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'tab',
|
||||
'label' => $label,
|
||||
'key' => 'acf_icon_picker_tabs',
|
||||
'selected' => $name === $field['value']['type'],
|
||||
'unique_tab_key' => $name,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$wrapper_class = str_replace( '_', '-', $name );
|
||||
echo '<div class="acf-icon-picker-tabs acf-icon-picker-' . esc_attr( $wrapper_class ) . '-tabs" data-tab="' . esc_attr( $name ) . '">';
|
||||
|
||||
switch ( $name ) {
|
||||
case 'dashicons':
|
||||
$this->render_icon_list_tab( $name );
|
||||
break;
|
||||
case 'media_library':
|
||||
?>
|
||||
<div class="acf-icon-picker-tab" data-category="<?php echo esc_attr( $name ); ?>">
|
||||
<div class="acf-icon-picker-media-library">
|
||||
<?php
|
||||
$button_style = 'display: none;';
|
||||
|
||||
if ( in_array( $field['value']['type'], array( 'media_library', 'dashicons' ), true ) && ! empty( $field['value']['value'] ) ) {
|
||||
$button_style = '';
|
||||
}
|
||||
?>
|
||||
<button
|
||||
aria-label="<?php esc_attr_e( 'Click to change the icon in the Media Library', 'acf' ); ?>"
|
||||
class="acf-icon-picker-media-library-preview"
|
||||
style="<?php echo esc_attr( $button_style ); ?>"
|
||||
>
|
||||
<div class="acf-icon-picker-media-library-preview-img" style="<?php echo esc_attr( 'media_library' !== $field['value']['type'] ? 'display: none;' : '' ); ?>">
|
||||
<?php
|
||||
$img_url = wp_get_attachment_image_url( $field['value']['value'], 'thumbnail' );
|
||||
// If the type is media_library, then we need to show the media library preview.
|
||||
?>
|
||||
<img src="<?php echo esc_url( $img_url ); ?>" alt="<?php esc_attr_e( 'The currently selected image preview', 'acf' ); ?>" />
|
||||
</div>
|
||||
<div class="acf-icon-picker-media-library-preview-dashicon" style="<?php echo esc_attr( 'dashicons' !== $field['value']['type'] ? 'display: none;' : '' ); ?>">
|
||||
<div class="dashicons <?php echo esc_attr( $field['value']['value'] ); ?>">
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
<button class="acf-icon-picker-media-library-button">
|
||||
<div class="acf-icon-picker-media-library-button-icon dashicons dashicons-admin-media"></div>
|
||||
<span><?php esc_html_e( 'Browse Media Library', 'acf' ); ?></span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
break;
|
||||
case 'url':
|
||||
echo '<div class="acf-icon-picker-url">';
|
||||
acf_text_input(
|
||||
array(
|
||||
'class' => 'acf-icon_url',
|
||||
'value' => $field['value']['type'] === 'url' ? $field['value']['value'] : '',
|
||||
)
|
||||
);
|
||||
|
||||
// Helper Text
|
||||
?>
|
||||
<p class="description"><?php esc_html_e( 'The URL to the icon you\'d like to use, or svg as Data URI', 'acf' ); ?></p>
|
||||
<?php
|
||||
echo '</div>';
|
||||
break;
|
||||
default:
|
||||
do_action( 'acf/fields/icon_picker/tab/' . $name, $field );
|
||||
|
||||
$custom_icons = apply_filters( 'acf/fields/icon_picker/' . $name . '/icons', array(), $field );
|
||||
|
||||
if ( is_array( $custom_icons ) && ! empty( $custom_icons ) ) {
|
||||
$this->render_icon_list_tab( $name, $custom_icons );
|
||||
|
||||
acf_localize_data(
|
||||
array(
|
||||
'iconPickerIcons_' . $name => $custom_icons,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders field settings for the icon picker field.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $field The icon picker field object.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Tabs', 'acf' ),
|
||||
'instructions' => __( 'Select where content editors can choose the icon from.', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'tabs',
|
||||
'choices' => $this->get_tabs(),
|
||||
)
|
||||
);
|
||||
|
||||
$return_format_doc = sprintf(
|
||||
'<a href="%s" target="_blank">%s</a>',
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/icon-picker/', 'docs', 'icon-picker-return-format' ),
|
||||
__( 'Learn More', 'acf' )
|
||||
);
|
||||
|
||||
$return_format_instructions = sprintf(
|
||||
/* translators: %s - link to documentation */
|
||||
__( 'Specify the return format for the icon. %s', 'acf' ),
|
||||
$return_format_doc
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => $return_format_instructions,
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'string' => __( 'String', 'acf' ),
|
||||
'array' => __( 'Array', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Localizes text for Icon Picker
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function input_admin_enqueue_scripts() {
|
||||
acf_localize_data(
|
||||
array(
|
||||
'iconPickerA11yStrings' => array(
|
||||
'noResultsForSearchTerm' => esc_html__( 'No results found for that search term', 'acf' ),
|
||||
'newResultsFoundForSearchTerm' => esc_html__( 'The available icons matching your search query have been updated in the icon picker below.', 'acf' ),
|
||||
),
|
||||
'iconPickeri10n' => $this->get_dashicons(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the field value before it is saved into the database.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param integer $valid The current validation status.
|
||||
* @param mixed $value The value of the field.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @param string $input The corresponding input name for $_POST value.
|
||||
* @return boolean true If the value is valid, false if not.
|
||||
*/
|
||||
public function validate_value( $valid, $value, $field, $input ) {
|
||||
// If the value is empty, return true. You're allowed to save nothing.
|
||||
if ( empty( $value ) && empty( $field['required'] ) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If the value is not an array, return $valid status.
|
||||
if ( ! is_array( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// If the value is an array, but the type is not set, fail validation.
|
||||
if ( ! isset( $value['type'] ) ) {
|
||||
return __( 'Icon picker requires an icon type.', 'acf' );
|
||||
}
|
||||
|
||||
// If the value is an array, but the value is not set, fail validation.
|
||||
if ( ! isset( $value['value'] ) ) {
|
||||
return __( 'Icon picker requires a value.', 'acf' );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* format_value()
|
||||
*
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database.
|
||||
* @param integer $post_id The $post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return mixed $value The modified value.
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
// Handle empty values.
|
||||
if ( empty( $value ) ) {
|
||||
// Return the default value if there is one.
|
||||
if ( isset( $field['default_value'] ) ) {
|
||||
return $field['default_value'];
|
||||
} else {
|
||||
// Otherwise return false.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// If media_library, behave the same as an image field.
|
||||
if ( $value['type'] === 'media_library' ) {
|
||||
// convert to int
|
||||
$value['value'] = intval( $value['value'] );
|
||||
|
||||
// format
|
||||
if ( $field['return_format'] === 'string' ) {
|
||||
return wp_get_attachment_url( $value['value'] );
|
||||
} elseif ( $field['return_format'] === 'array' ) {
|
||||
$value['value'] = acf_get_attachment( $value['value'] );
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
// If the desired return format is a string
|
||||
if ( $field['return_format'] === 'string' ) {
|
||||
return $value['value'];
|
||||
}
|
||||
|
||||
// If nothing specific matched the return format, just return the value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_dashicons()
|
||||
*
|
||||
* This function will return an array of dashicons.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return array $dashicons an array of dashicons.
|
||||
*/
|
||||
public function get_dashicons() {
|
||||
$dashicons = array(
|
||||
'dashicons-admin-appearance' => esc_html__( 'Appearance Icon', 'acf' ),
|
||||
'dashicons-admin-collapse' => esc_html__( 'Collapse Icon', 'acf' ),
|
||||
'dashicons-admin-comments' => esc_html__( 'Comments Icon', 'acf' ),
|
||||
'dashicons-admin-customizer' => esc_html__( 'Customizer Icon', 'acf' ),
|
||||
'dashicons-admin-generic' => esc_html__( 'Generic Icon', 'acf' ),
|
||||
'dashicons-admin-home' => esc_html__( 'Home Icon', 'acf' ),
|
||||
'dashicons-admin-links' => esc_html__( 'Links Icon', 'acf' ),
|
||||
'dashicons-admin-media' => esc_html__( 'Media Icon', 'acf' ),
|
||||
'dashicons-admin-multisite' => esc_html__( 'Multisite Icon', 'acf' ),
|
||||
'dashicons-admin-network' => esc_html__( 'Network Icon', 'acf' ),
|
||||
'dashicons-admin-page' => esc_html__( 'Page Icon', 'acf' ),
|
||||
'dashicons-admin-plugins' => esc_html__( 'Plugins Icon', 'acf' ),
|
||||
'dashicons-admin-post' => esc_html__( 'Post Icon', 'acf' ),
|
||||
'dashicons-admin-settings' => esc_html__( 'Settings Icon', 'acf' ),
|
||||
'dashicons-admin-site' => esc_html__( 'Site Icon', 'acf' ),
|
||||
'dashicons-admin-site-alt' => esc_html__( 'Site (alt) Icon', 'acf' ),
|
||||
'dashicons-admin-site-alt2' => esc_html__( 'Site (alt2) Icon', 'acf' ),
|
||||
'dashicons-admin-site-alt3' => esc_html__( 'Site (alt3) Icon', 'acf' ),
|
||||
'dashicons-admin-tools' => esc_html__( 'Tools Icon', 'acf' ),
|
||||
'dashicons-admin-users' => esc_html__( 'Users Icon', 'acf' ),
|
||||
'dashicons-airplane' => esc_html__( 'Airplane Icon', 'acf' ),
|
||||
'dashicons-album' => esc_html__( 'Album Icon', 'acf' ),
|
||||
'dashicons-align-center' => esc_html__( 'Align Center Icon', 'acf' ),
|
||||
'dashicons-align-full-width' => esc_html__( 'Align Full Width Icon', 'acf' ),
|
||||
'dashicons-align-left' => esc_html__( 'Align Left Icon', 'acf' ),
|
||||
'dashicons-align-none' => esc_html__( 'Align None Icon', 'acf' ),
|
||||
'dashicons-align-pull-left' => esc_html__( 'Align Pull Left Icon', 'acf' ),
|
||||
'dashicons-align-pull-right' => esc_html__( 'Align Pull Right Icon', 'acf' ),
|
||||
'dashicons-align-right' => esc_html__( 'Align Right Icon', 'acf' ),
|
||||
'dashicons-align-wide' => esc_html__( 'Align Wide Icon', 'acf' ),
|
||||
'dashicons-amazon' => esc_html__( 'Amazon Icon', 'acf' ),
|
||||
'dashicons-analytics' => esc_html__( 'Analytics Icon', 'acf' ),
|
||||
'dashicons-archive' => esc_html__( 'Archive Icon', 'acf' ),
|
||||
'dashicons-arrow-down' => esc_html__( 'Arrow Down Icon', 'acf' ),
|
||||
'dashicons-arrow-down-alt' => esc_html__( 'Arrow Down (alt) Icon', 'acf' ),
|
||||
'dashicons-arrow-down-alt2' => esc_html__( 'Arrow Down (alt2) Icon', 'acf' ),
|
||||
'dashicons-arrow-left' => esc_html__( 'Arrow Left Icon', 'acf' ),
|
||||
'dashicons-arrow-left-alt' => esc_html__( 'Arrow Left (alt) Icon', 'acf' ),
|
||||
'dashicons-arrow-left-alt2' => esc_html__( 'Arrow Left (alt2) Icon', 'acf' ),
|
||||
'dashicons-arrow-right' => esc_html__( 'Arrow Right Icon', 'acf' ),
|
||||
'dashicons-arrow-right-alt' => esc_html__( 'Arrow Right (alt) Icon', 'acf' ),
|
||||
'dashicons-arrow-right-alt2' => esc_html__( 'Arrow Right (alt2) Icon', 'acf' ),
|
||||
'dashicons-arrow-up' => esc_html__( 'Arrow Up Icon', 'acf' ),
|
||||
'dashicons-arrow-up-alt' => esc_html__( 'Arrow Up (alt) Icon', 'acf' ),
|
||||
'dashicons-arrow-up-alt2' => esc_html__( 'Arrow Up (alt2) Icon', 'acf' ),
|
||||
'dashicons-art' => esc_html__( 'Art Icon', 'acf' ),
|
||||
'dashicons-awards' => esc_html__( 'Awards Icon', 'acf' ),
|
||||
'dashicons-backup' => esc_html__( 'Backup Icon', 'acf' ),
|
||||
'dashicons-bank' => esc_html__( 'Bank Icon', 'acf' ),
|
||||
'dashicons-beer' => esc_html__( 'Beer Icon', 'acf' ),
|
||||
'dashicons-bell' => esc_html__( 'Bell Icon', 'acf' ),
|
||||
'dashicons-block-default' => esc_html__( 'Block Default Icon', 'acf' ),
|
||||
'dashicons-book' => esc_html__( 'Book Icon', 'acf' ),
|
||||
'dashicons-book-alt' => esc_html__( 'Book (alt) Icon', 'acf' ),
|
||||
'dashicons-buddicons-activity' => esc_html__( 'Activity Icon', 'acf' ),
|
||||
'dashicons-buddicons-bbpress-logo' => esc_html__( 'bbPress Icon', 'acf' ),
|
||||
'dashicons-buddicons-buddypress-logo' => esc_html__( 'BuddyPress Icon', 'acf' ),
|
||||
'dashicons-buddicons-community' => esc_html__( 'Community Icon', 'acf' ),
|
||||
'dashicons-buddicons-forums' => esc_html__( 'Forums Icon', 'acf' ),
|
||||
'dashicons-buddicons-friends' => esc_html__( 'Friends Icon', 'acf' ),
|
||||
'dashicons-buddicons-groups' => esc_html__( 'Groups Icon', 'acf' ),
|
||||
'dashicons-buddicons-pm' => esc_html__( 'PM Icon', 'acf' ),
|
||||
'dashicons-buddicons-replies' => esc_html__( 'Replies Icon', 'acf' ),
|
||||
'dashicons-buddicons-topics' => esc_html__( 'Topics Icon', 'acf' ),
|
||||
'dashicons-buddicons-tracking' => esc_html__( 'Tracking Icon', 'acf' ),
|
||||
'dashicons-building' => esc_html__( 'Building Icon', 'acf' ),
|
||||
'dashicons-businessman' => esc_html__( 'Businessman Icon', 'acf' ),
|
||||
'dashicons-businessperson' => esc_html__( 'Businessperson Icon', 'acf' ),
|
||||
'dashicons-businesswoman' => esc_html__( 'Businesswoman Icon', 'acf' ),
|
||||
'dashicons-button' => esc_html__( 'Button Icon', 'acf' ),
|
||||
'dashicons-calculator' => esc_html__( 'Calculator Icon', 'acf' ),
|
||||
'dashicons-calendar' => esc_html__( 'Calendar Icon', 'acf' ),
|
||||
'dashicons-calendar-alt' => esc_html__( 'Calendar (alt) Icon', 'acf' ),
|
||||
'dashicons-camera' => esc_html__( 'Camera Icon', 'acf' ),
|
||||
'dashicons-camera-alt' => esc_html__( 'Camera (alt) Icon', 'acf' ),
|
||||
'dashicons-car' => esc_html__( 'Car Icon', 'acf' ),
|
||||
'dashicons-carrot' => esc_html__( 'Carrot Icon', 'acf' ),
|
||||
'dashicons-cart' => esc_html__( 'Cart Icon', 'acf' ),
|
||||
'dashicons-category' => esc_html__( 'Category Icon', 'acf' ),
|
||||
'dashicons-chart-area' => esc_html__( 'Chart Area Icon', 'acf' ),
|
||||
'dashicons-chart-bar' => esc_html__( 'Chart Bar Icon', 'acf' ),
|
||||
'dashicons-chart-line' => esc_html__( 'Chart Line Icon', 'acf' ),
|
||||
'dashicons-chart-pie' => esc_html__( 'Chart Pie Icon', 'acf' ),
|
||||
'dashicons-clipboard' => esc_html__( 'Clipboard Icon', 'acf' ),
|
||||
'dashicons-clock' => esc_html__( 'Clock Icon', 'acf' ),
|
||||
'dashicons-cloud' => esc_html__( 'Cloud Icon', 'acf' ),
|
||||
'dashicons-cloud-saved' => esc_html__( 'Cloud Saved Icon', 'acf' ),
|
||||
'dashicons-cloud-upload' => esc_html__( 'Cloud Upload Icon', 'acf' ),
|
||||
'dashicons-code-standards' => esc_html__( 'Code Standards Icon', 'acf' ),
|
||||
'dashicons-coffee' => esc_html__( 'Coffee Icon', 'acf' ),
|
||||
'dashicons-color-picker' => esc_html__( 'Color Picker Icon', 'acf' ),
|
||||
'dashicons-columns' => esc_html__( 'Columns Icon', 'acf' ),
|
||||
'dashicons-controls-back' => esc_html__( 'Back Icon', 'acf' ),
|
||||
'dashicons-controls-forward' => esc_html__( 'Forward Icon', 'acf' ),
|
||||
'dashicons-controls-pause' => esc_html__( 'Pause Icon', 'acf' ),
|
||||
'dashicons-controls-play' => esc_html__( 'Play Icon', 'acf' ),
|
||||
'dashicons-controls-repeat' => esc_html__( 'Repeat Icon', 'acf' ),
|
||||
'dashicons-controls-skipback' => esc_html__( 'Skip Back Icon', 'acf' ),
|
||||
'dashicons-controls-skipforward' => esc_html__( 'Skip Forward Icon', 'acf' ),
|
||||
'dashicons-controls-volumeoff' => esc_html__( 'Volume Off Icon', 'acf' ),
|
||||
'dashicons-controls-volumeon' => esc_html__( 'Volume On Icon', 'acf' ),
|
||||
'dashicons-cover-image' => esc_html__( 'Cover Image Icon', 'acf' ),
|
||||
'dashicons-dashboard' => esc_html__( 'Dashboard Icon', 'acf' ),
|
||||
'dashicons-database' => esc_html__( 'Database Icon', 'acf' ),
|
||||
'dashicons-database-add' => esc_html__( 'Database Add Icon', 'acf' ),
|
||||
'dashicons-database-export' => esc_html__( 'Database Export Icon', 'acf' ),
|
||||
'dashicons-database-import' => esc_html__( 'Database Import Icon', 'acf' ),
|
||||
'dashicons-database-remove' => esc_html__( 'Database Remove Icon', 'acf' ),
|
||||
'dashicons-database-view' => esc_html__( 'Database View Icon', 'acf' ),
|
||||
'dashicons-desktop' => esc_html__( 'Desktop Icon', 'acf' ),
|
||||
'dashicons-dismiss' => esc_html__( 'Dismiss Icon', 'acf' ),
|
||||
'dashicons-download' => esc_html__( 'Download Icon', 'acf' ),
|
||||
'dashicons-drumstick' => esc_html__( 'Drumstick Icon', 'acf' ),
|
||||
'dashicons-edit' => esc_html__( 'Edit Icon', 'acf' ),
|
||||
'dashicons-edit-large' => esc_html__( 'Edit Large Icon', 'acf' ),
|
||||
'dashicons-edit-page' => esc_html__( 'Edit Page Icon', 'acf' ),
|
||||
'dashicons-editor-aligncenter' => esc_html__( 'Align Center Icon', 'acf' ),
|
||||
'dashicons-editor-alignleft' => esc_html__( 'Align Left Icon', 'acf' ),
|
||||
'dashicons-editor-alignright' => esc_html__( 'Align Right Icon', 'acf' ),
|
||||
'dashicons-editor-bold' => esc_html__( 'Bold Icon', 'acf' ),
|
||||
'dashicons-editor-break' => esc_html__( 'Break Icon', 'acf' ),
|
||||
'dashicons-editor-code' => esc_html__( 'Code Icon', 'acf' ),
|
||||
'dashicons-editor-contract' => esc_html__( 'Contract Icon', 'acf' ),
|
||||
'dashicons-editor-customchar' => esc_html__( 'Custom Character Icon', 'acf' ),
|
||||
'dashicons-editor-expand' => esc_html__( 'Expand Icon', 'acf' ),
|
||||
'dashicons-editor-help' => esc_html__( 'Help Icon', 'acf' ),
|
||||
'dashicons-editor-indent' => esc_html__( 'Indent Icon', 'acf' ),
|
||||
'dashicons-editor-insertmore' => esc_html__( 'Insert More Icon', 'acf' ),
|
||||
'dashicons-editor-italic' => esc_html__( 'Italic Icon', 'acf' ),
|
||||
'dashicons-editor-justify' => esc_html__( 'Justify Icon', 'acf' ),
|
||||
'dashicons-editor-kitchensink' => esc_html__( 'Kitchen Sink Icon', 'acf' ),
|
||||
'dashicons-editor-ltr' => esc_html__( 'LTR Icon', 'acf' ),
|
||||
'dashicons-editor-ol' => esc_html__( 'Ordered List Icon', 'acf' ),
|
||||
'dashicons-editor-ol-rtl' => esc_html__( 'Ordered List RTL Icon', 'acf' ),
|
||||
'dashicons-editor-outdent' => esc_html__( 'Outdent Icon', 'acf' ),
|
||||
'dashicons-editor-paragraph' => esc_html__( 'Paragraph Icon', 'acf' ),
|
||||
'dashicons-editor-paste-text' => esc_html__( 'Paste Text Icon', 'acf' ),
|
||||
'dashicons-editor-paste-word' => esc_html__( 'Paste Word Icon', 'acf' ),
|
||||
'dashicons-editor-quote' => esc_html__( 'Quote Icon', 'acf' ),
|
||||
'dashicons-editor-removeformatting' => esc_html__( 'Remove Formatting Icon', 'acf' ),
|
||||
'dashicons-editor-rtl' => esc_html__( 'RTL Icon', 'acf' ),
|
||||
'dashicons-editor-spellcheck' => esc_html__( 'Spellcheck Icon', 'acf' ),
|
||||
'dashicons-editor-strikethrough' => esc_html__( 'Strikethrough Icon', 'acf' ),
|
||||
'dashicons-editor-table' => esc_html__( 'Table Icon', 'acf' ),
|
||||
'dashicons-editor-textcolor' => esc_html__( 'Text Color Icon', 'acf' ),
|
||||
'dashicons-editor-ul' => esc_html__( 'Unordered List Icon', 'acf' ),
|
||||
'dashicons-editor-underline' => esc_html__( 'Underline Icon', 'acf' ),
|
||||
'dashicons-editor-unlink' => esc_html__( 'Unlink Icon', 'acf' ),
|
||||
'dashicons-editor-video' => esc_html__( 'Video Icon', 'acf' ),
|
||||
'dashicons-ellipsis' => esc_html__( 'Ellipsis Icon', 'acf' ),
|
||||
'dashicons-email' => esc_html__( 'Email Icon', 'acf' ),
|
||||
'dashicons-email-alt' => esc_html__( 'Email (alt) Icon', 'acf' ),
|
||||
'dashicons-email-alt2' => esc_html__( 'Email (alt2) Icon', 'acf' ),
|
||||
'dashicons-embed-audio' => esc_html__( 'Embed Audio Icon', 'acf' ),
|
||||
'dashicons-embed-generic' => esc_html__( 'Embed Generic Icon', 'acf' ),
|
||||
'dashicons-embed-photo' => esc_html__( 'Embed Photo Icon', 'acf' ),
|
||||
'dashicons-embed-post' => esc_html__( 'Embed Post Icon', 'acf' ),
|
||||
'dashicons-embed-video' => esc_html__( 'Embed Video Icon', 'acf' ),
|
||||
'dashicons-excerpt-view' => esc_html__( 'Excerpt View Icon', 'acf' ),
|
||||
'dashicons-exit' => esc_html__( 'Exit Icon', 'acf' ),
|
||||
'dashicons-external' => esc_html__( 'External Icon', 'acf' ),
|
||||
'dashicons-facebook' => esc_html__( 'Facebook Icon', 'acf' ),
|
||||
'dashicons-facebook-alt' => esc_html__( 'Facebook (alt) Icon', 'acf' ),
|
||||
'dashicons-feedback' => esc_html__( 'Feedback Icon', 'acf' ),
|
||||
'dashicons-filter' => esc_html__( 'Filter Icon', 'acf' ),
|
||||
'dashicons-flag' => esc_html__( 'Flag Icon', 'acf' ),
|
||||
'dashicons-food' => esc_html__( 'Food Icon', 'acf' ),
|
||||
'dashicons-format-aside' => esc_html__( 'Aside Icon', 'acf' ),
|
||||
'dashicons-format-audio' => esc_html__( 'Audio Icon', 'acf' ),
|
||||
'dashicons-format-chat' => esc_html__( 'Chat Icon', 'acf' ),
|
||||
'dashicons-format-gallery' => esc_html__( 'Gallery Icon', 'acf' ),
|
||||
'dashicons-format-image' => esc_html__( 'Image Icon', 'acf' ),
|
||||
'dashicons-format-quote' => esc_html__( 'Quote Icon', 'acf' ),
|
||||
'dashicons-format-status' => esc_html__( 'Status Icon', 'acf' ),
|
||||
'dashicons-format-video' => esc_html__( 'Video Icon', 'acf' ),
|
||||
'dashicons-forms' => esc_html__( 'Forms Icon', 'acf' ),
|
||||
'dashicons-fullscreen-alt' => esc_html__( 'Fullscreen (alt) Icon', 'acf' ),
|
||||
'dashicons-fullscreen-exit-alt' => esc_html__( 'Fullscreen Exit (alt) Icon', 'acf' ),
|
||||
'dashicons-games' => esc_html__( 'Games Icon', 'acf' ),
|
||||
'dashicons-google' => esc_html__( 'Google Icon', 'acf' ),
|
||||
'dashicons-grid-view' => esc_html__( 'Grid View Icon', 'acf' ),
|
||||
'dashicons-groups' => esc_html__( 'Groups Icon', 'acf' ),
|
||||
'dashicons-hammer' => esc_html__( 'Hammer Icon', 'acf' ),
|
||||
'dashicons-heading' => esc_html__( 'Heading Icon', 'acf' ),
|
||||
'dashicons-heart' => esc_html__( 'Heart Icon', 'acf' ),
|
||||
'dashicons-hidden' => esc_html__( 'Hidden Icon', 'acf' ),
|
||||
'dashicons-hourglass' => esc_html__( 'Hourglass Icon', 'acf' ),
|
||||
'dashicons-html' => esc_html__( 'HTML Icon', 'acf' ),
|
||||
'dashicons-id' => esc_html__( 'ID Icon', 'acf' ),
|
||||
'dashicons-id-alt' => esc_html__( 'ID (alt) Icon', 'acf' ),
|
||||
'dashicons-image-crop' => esc_html__( 'Crop Icon', 'acf' ),
|
||||
'dashicons-image-filter' => esc_html__( 'Filter Icon', 'acf' ),
|
||||
'dashicons-image-flip-horizontal' => esc_html__( 'Flip Horizontal Icon', 'acf' ),
|
||||
'dashicons-image-flip-vertical' => esc_html__( 'Flip Vertical Icon', 'acf' ),
|
||||
'dashicons-image-rotate' => esc_html__( 'Rotate Icon', 'acf' ),
|
||||
'dashicons-image-rotate-left' => esc_html__( 'Rotate Left Icon', 'acf' ),
|
||||
'dashicons-image-rotate-right' => esc_html__( 'Rotate Right Icon', 'acf' ),
|
||||
'dashicons-images-alt' => esc_html__( 'Images (alt) Icon', 'acf' ),
|
||||
'dashicons-images-alt2' => esc_html__( 'Images (alt2) Icon', 'acf' ),
|
||||
'dashicons-index-card' => esc_html__( 'Index Card Icon', 'acf' ),
|
||||
'dashicons-info' => esc_html__( 'Info Icon', 'acf' ),
|
||||
'dashicons-info-outline' => esc_html__( 'Info Outline Icon', 'acf' ),
|
||||
'dashicons-insert' => esc_html__( 'Insert Icon', 'acf' ),
|
||||
'dashicons-insert-after' => esc_html__( 'Insert After Icon', 'acf' ),
|
||||
'dashicons-insert-before' => esc_html__( 'Insert Before Icon', 'acf' ),
|
||||
'dashicons-instagram' => esc_html__( 'Instagram Icon', 'acf' ),
|
||||
'dashicons-laptop' => esc_html__( 'Laptop Icon', 'acf' ),
|
||||
'dashicons-layout' => esc_html__( 'Layout Icon', 'acf' ),
|
||||
'dashicons-leftright' => esc_html__( 'Left Right Icon', 'acf' ),
|
||||
'dashicons-lightbulb' => esc_html__( 'Lightbulb Icon', 'acf' ),
|
||||
'dashicons-linkedin' => esc_html__( 'LinkedIn Icon', 'acf' ),
|
||||
'dashicons-list-view' => esc_html__( 'List View Icon', 'acf' ),
|
||||
'dashicons-location' => esc_html__( 'Location Icon', 'acf' ),
|
||||
'dashicons-location-alt' => esc_html__( 'Location (alt) Icon', 'acf' ),
|
||||
'dashicons-lock' => esc_html__( 'Lock Icon', 'acf' ),
|
||||
'dashicons-marker' => esc_html__( 'Marker Icon', 'acf' ),
|
||||
'dashicons-media-archive' => esc_html__( 'Archive Icon', 'acf' ),
|
||||
'dashicons-media-audio' => esc_html__( 'Audio Icon', 'acf' ),
|
||||
'dashicons-media-code' => esc_html__( 'Code Icon', 'acf' ),
|
||||
'dashicons-media-default' => esc_html__( 'Default Icon', 'acf' ),
|
||||
'dashicons-media-document' => esc_html__( 'Document Icon', 'acf' ),
|
||||
'dashicons-media-interactive' => esc_html__( 'Interactive Icon', 'acf' ),
|
||||
'dashicons-media-spreadsheet' => esc_html__( 'Spreadsheet Icon', 'acf' ),
|
||||
'dashicons-media-text' => esc_html__( 'Text Icon', 'acf' ),
|
||||
'dashicons-media-video' => esc_html__( 'Video Icon', 'acf' ),
|
||||
'dashicons-megaphone' => esc_html__( 'Megaphone Icon', 'acf' ),
|
||||
'dashicons-menu' => esc_html__( 'Menu Icon', 'acf' ),
|
||||
'dashicons-menu-alt' => esc_html__( 'Menu (alt) Icon', 'acf' ),
|
||||
'dashicons-menu-alt2' => esc_html__( 'Menu (alt2) Icon', 'acf' ),
|
||||
'dashicons-menu-alt3' => esc_html__( 'Menu (alt3) Icon', 'acf' ),
|
||||
'dashicons-microphone' => esc_html__( 'Microphone Icon', 'acf' ),
|
||||
'dashicons-migrate' => esc_html__( 'Migrate Icon', 'acf' ),
|
||||
'dashicons-minus' => esc_html__( 'Minus Icon', 'acf' ),
|
||||
'dashicons-money' => esc_html__( 'Money Icon', 'acf' ),
|
||||
'dashicons-money-alt' => esc_html__( 'Money (alt) Icon', 'acf' ),
|
||||
'dashicons-move' => esc_html__( 'Move Icon', 'acf' ),
|
||||
'dashicons-nametag' => esc_html__( 'Nametag Icon', 'acf' ),
|
||||
'dashicons-networking' => esc_html__( 'Networking Icon', 'acf' ),
|
||||
'dashicons-no' => esc_html__( 'No Icon', 'acf' ),
|
||||
'dashicons-no-alt' => esc_html__( 'No (alt) Icon', 'acf' ),
|
||||
'dashicons-open-folder' => esc_html__( 'Open Folder Icon', 'acf' ),
|
||||
'dashicons-palmtree' => esc_html__( 'Palm Tree Icon', 'acf' ),
|
||||
'dashicons-paperclip' => esc_html__( 'Paperclip Icon', 'acf' ),
|
||||
'dashicons-pdf' => esc_html__( 'PDF Icon', 'acf' ),
|
||||
'dashicons-performance' => esc_html__( 'Performance Icon', 'acf' ),
|
||||
'dashicons-pets' => esc_html__( 'Pets Icon', 'acf' ),
|
||||
'dashicons-phone' => esc_html__( 'Phone Icon', 'acf' ),
|
||||
'dashicons-pinterest' => esc_html__( 'Pinterest Icon', 'acf' ),
|
||||
'dashicons-playlist-audio' => esc_html__( 'Playlist Audio Icon', 'acf' ),
|
||||
'dashicons-playlist-video' => esc_html__( 'Playlist Video Icon', 'acf' ),
|
||||
'dashicons-plugins-checked' => esc_html__( 'Plugins Checked Icon', 'acf' ),
|
||||
'dashicons-plus' => esc_html__( 'Plus Icon', 'acf' ),
|
||||
'dashicons-plus-alt' => esc_html__( 'Plus (alt) Icon', 'acf' ),
|
||||
'dashicons-plus-alt2' => esc_html__( 'Plus (alt2) Icon', 'acf' ),
|
||||
'dashicons-podio' => esc_html__( 'Podio Icon', 'acf' ),
|
||||
'dashicons-portfolio' => esc_html__( 'Portfolio Icon', 'acf' ),
|
||||
'dashicons-post-status' => esc_html__( 'Post Status Icon', 'acf' ),
|
||||
'dashicons-pressthis' => esc_html__( 'Pressthis Icon', 'acf' ),
|
||||
'dashicons-printer' => esc_html__( 'Printer Icon', 'acf' ),
|
||||
'dashicons-privacy' => esc_html__( 'Privacy Icon', 'acf' ),
|
||||
'dashicons-products' => esc_html__( 'Products Icon', 'acf' ),
|
||||
'dashicons-randomize' => esc_html__( 'Randomize Icon', 'acf' ),
|
||||
'dashicons-reddit' => esc_html__( 'Reddit Icon', 'acf' ),
|
||||
'dashicons-redo' => esc_html__( 'Redo Icon', 'acf' ),
|
||||
'dashicons-remove' => esc_html__( 'Remove Icon', 'acf' ),
|
||||
'dashicons-rest-api' => esc_html__( 'REST API Icon', 'acf' ),
|
||||
'dashicons-rss' => esc_html__( 'RSS Icon', 'acf' ),
|
||||
'dashicons-saved' => esc_html__( 'Saved Icon', 'acf' ),
|
||||
'dashicons-schedule' => esc_html__( 'Schedule Icon', 'acf' ),
|
||||
'dashicons-screenoptions' => esc_html__( 'Screen Options Icon', 'acf' ),
|
||||
'dashicons-search' => esc_html__( 'Search Icon', 'acf' ),
|
||||
'dashicons-share' => esc_html__( 'Share Icon', 'acf' ),
|
||||
'dashicons-share-alt' => esc_html__( 'Share (alt) Icon', 'acf' ),
|
||||
'dashicons-share-alt2' => esc_html__( 'Share (alt2) Icon', 'acf' ),
|
||||
'dashicons-shield' => esc_html__( 'Shield Icon', 'acf' ),
|
||||
'dashicons-shield-alt' => esc_html__( 'Shield (alt) Icon', 'acf' ),
|
||||
'dashicons-shortcode' => esc_html__( 'Shortcode Icon', 'acf' ),
|
||||
'dashicons-slides' => esc_html__( 'Slides Icon', 'acf' ),
|
||||
'dashicons-smartphone' => esc_html__( 'Smartphone Icon', 'acf' ),
|
||||
'dashicons-smiley' => esc_html__( 'Smiley Icon', 'acf' ),
|
||||
'dashicons-sort' => esc_html__( 'Sort Icon', 'acf' ),
|
||||
'dashicons-sos' => esc_html__( 'Sos Icon', 'acf' ),
|
||||
'dashicons-spotify' => esc_html__( 'Spotify Icon', 'acf' ),
|
||||
'dashicons-star-empty' => esc_html__( 'Star Empty Icon', 'acf' ),
|
||||
'dashicons-star-filled' => esc_html__( 'Star Filled Icon', 'acf' ),
|
||||
'dashicons-star-half' => esc_html__( 'Star Half Icon', 'acf' ),
|
||||
'dashicons-sticky' => esc_html__( 'Sticky Icon', 'acf' ),
|
||||
'dashicons-store' => esc_html__( 'Store Icon', 'acf' ),
|
||||
'dashicons-superhero' => esc_html__( 'Superhero Icon', 'acf' ),
|
||||
'dashicons-superhero-alt' => esc_html__( 'Superhero (alt) Icon', 'acf' ),
|
||||
'dashicons-table-col-after' => esc_html__( 'Table Col After Icon', 'acf' ),
|
||||
'dashicons-table-col-before' => esc_html__( 'Table Col Before Icon', 'acf' ),
|
||||
'dashicons-table-col-delete' => esc_html__( 'Table Col Delete Icon', 'acf' ),
|
||||
'dashicons-table-row-after' => esc_html__( 'Table Row After Icon', 'acf' ),
|
||||
'dashicons-table-row-before' => esc_html__( 'Table Row Before Icon', 'acf' ),
|
||||
'dashicons-table-row-delete' => esc_html__( 'Table Row Delete Icon', 'acf' ),
|
||||
'dashicons-tablet' => esc_html__( 'Tablet Icon', 'acf' ),
|
||||
'dashicons-tag' => esc_html__( 'Tag Icon', 'acf' ),
|
||||
'dashicons-tagcloud' => esc_html__( 'Tagcloud Icon', 'acf' ),
|
||||
'dashicons-testimonial' => esc_html__( 'Testimonial Icon', 'acf' ),
|
||||
'dashicons-text' => esc_html__( 'Text Icon', 'acf' ),
|
||||
'dashicons-text-page' => esc_html__( 'Text Page Icon', 'acf' ),
|
||||
'dashicons-thumbs-down' => esc_html__( 'Thumbs Down Icon', 'acf' ),
|
||||
'dashicons-thumbs-up' => esc_html__( 'Thumbs Up Icon', 'acf' ),
|
||||
'dashicons-tickets' => esc_html__( 'Tickets Icon', 'acf' ),
|
||||
'dashicons-tickets-alt' => esc_html__( 'Tickets (alt) Icon', 'acf' ),
|
||||
'dashicons-tide' => esc_html__( 'Tide Icon', 'acf' ),
|
||||
'dashicons-translation' => esc_html__( 'Translation Icon', 'acf' ),
|
||||
'dashicons-trash' => esc_html__( 'Trash Icon', 'acf' ),
|
||||
'dashicons-twitch' => esc_html__( 'Twitch Icon', 'acf' ),
|
||||
'dashicons-twitter' => esc_html__( 'Twitter Icon', 'acf' ),
|
||||
'dashicons-twitter-alt' => esc_html__( 'Twitter (alt) Icon', 'acf' ),
|
||||
'dashicons-undo' => esc_html__( 'Undo Icon', 'acf' ),
|
||||
'dashicons-universal-access' => esc_html__( 'Universal Access Icon', 'acf' ),
|
||||
'dashicons-universal-access-alt' => esc_html__( 'Universal Access (alt) Icon', 'acf' ),
|
||||
'dashicons-unlock' => esc_html__( 'Unlock Icon', 'acf' ),
|
||||
'dashicons-update' => esc_html__( 'Update Icon', 'acf' ),
|
||||
'dashicons-update-alt' => esc_html__( 'Update (alt) Icon', 'acf' ),
|
||||
'dashicons-upload' => esc_html__( 'Upload Icon', 'acf' ),
|
||||
'dashicons-vault' => esc_html__( 'Vault Icon', 'acf' ),
|
||||
'dashicons-video-alt' => esc_html__( 'Video (alt) Icon', 'acf' ),
|
||||
'dashicons-video-alt2' => esc_html__( 'Video (alt2) Icon', 'acf' ),
|
||||
'dashicons-video-alt3' => esc_html__( 'Video (alt3) Icon', 'acf' ),
|
||||
'dashicons-visibility' => esc_html__( 'Visibility Icon', 'acf' ),
|
||||
'dashicons-warning' => esc_html__( 'Warning Icon', 'acf' ),
|
||||
'dashicons-welcome-add-page' => esc_html__( 'Add Page Icon', 'acf' ),
|
||||
'dashicons-welcome-comments' => esc_html__( 'Comments Icon', 'acf' ),
|
||||
'dashicons-welcome-learn-more' => esc_html__( 'Learn More Icon', 'acf' ),
|
||||
'dashicons-welcome-view-site' => esc_html__( 'View Site Icon', 'acf' ),
|
||||
'dashicons-welcome-widgets-menus' => esc_html__( 'Widgets Menus Icon', 'acf' ),
|
||||
'dashicons-welcome-write-blog' => esc_html__( 'Write Blog Icon', 'acf' ),
|
||||
'dashicons-whatsapp' => esc_html__( 'WhatsApp Icon', 'acf' ),
|
||||
'dashicons-wordpress' => esc_html__( 'WordPress Icon', 'acf' ),
|
||||
'dashicons-wordpress-alt' => esc_html__( 'WordPress (alt) Icon', 'acf' ),
|
||||
'dashicons-xing' => esc_html__( 'Xing Icon', 'acf' ),
|
||||
'dashicons-yes' => esc_html__( 'Yes Icon', 'acf' ),
|
||||
'dashicons-yes-alt' => esc_html__( 'Yes (alt) Icon', 'acf' ),
|
||||
'dashicons-youtube' => esc_html__( 'YouTube Icon', 'acf' ),
|
||||
);
|
||||
|
||||
return apply_filters( 'acf/fields/icon_picker/dashicons', $dashicons );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the schema used by the REST API.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $field The main field array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ): array {
|
||||
return array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'properties' => array(
|
||||
'type' => array(
|
||||
'description' => esc_html__( 'The type of icon to save.', 'acf' ),
|
||||
'type' => array( 'string' ),
|
||||
'required' => true,
|
||||
'enum' => array_keys( $this->get_tabs() ),
|
||||
),
|
||||
'value' => array(
|
||||
'description' => esc_html__( 'The value of icon to save.', 'acf' ),
|
||||
'type' => array( 'string', 'int' ),
|
||||
'required' => true,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates a value sent via the REST API.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param boolean $valid The current validity boolean.
|
||||
* @param array|null $value The value of the field.
|
||||
* @param array $field The main field array.
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( is_null( $value ) ) {
|
||||
if ( ! empty( $field['required'] ) ) {
|
||||
return new WP_Error(
|
||||
'rest_property_required',
|
||||
/* translators: %s - field name */
|
||||
sprintf( __( '%s is a required property of acf.', 'acf' ), $field['name'] )
|
||||
);
|
||||
} else {
|
||||
return $valid;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $value['type'] ) && 'media_library' === $value['type'] ) {
|
||||
$param = sprintf( '%s[%s][value]', $field['prefix'], $field['name'] );
|
||||
$data = array(
|
||||
'param' => $param,
|
||||
'value' => (int) $value['value'],
|
||||
);
|
||||
|
||||
if ( ! is_int( $value['value'] ) || 'attachment' !== get_post_type( $value['value'] ) ) {
|
||||
/* translators: %s - field/param name */
|
||||
$error = sprintf( __( '%s requires a valid attachment ID when type is set to media_library.', 'acf' ), $param );
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
}
|
||||
|
||||
acf_register_field_type( 'acf_field_icon_picker' );
|
||||
endif;
|
||||
@@ -0,0 +1,467 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_image' ) ) :
|
||||
|
||||
class acf_field_image extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'image';
|
||||
$this->label = __( 'Image', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'Uses the native WordPress media picker to upload, or choose images.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-image.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/image/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
'preview_size' => 'medium',
|
||||
'library' => 'all',
|
||||
'min_width' => 0,
|
||||
'min_height' => 0,
|
||||
'min_size' => 0,
|
||||
'max_width' => 0,
|
||||
'max_height' => 0,
|
||||
'max_size' => 0,
|
||||
'mime_types' => '',
|
||||
);
|
||||
|
||||
// filters
|
||||
add_filter( 'get_media_item_args', array( $this, 'get_media_item_args' ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// localize
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Select Image' => __( 'Select Image', 'acf' ),
|
||||
'Edit Image' => __( 'Edit Image', 'acf' ),
|
||||
'Update Image' => __( 'Update Image', 'acf' ),
|
||||
'All images' => __( 'All images', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field HTML.
|
||||
*
|
||||
* @date 23/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param array $field The field settings.
|
||||
* @return void
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
$uploader = acf_get_setting( 'uploader' );
|
||||
|
||||
// Enqueue uploader scripts
|
||||
if ( $uploader === 'wp' ) {
|
||||
acf_enqueue_uploader();
|
||||
}
|
||||
|
||||
// Elements and attributes.
|
||||
$value = '';
|
||||
$div_attrs = array(
|
||||
'class' => 'acf-image-uploader',
|
||||
'data-preview_size' => $field['preview_size'],
|
||||
'data-library' => $field['library'],
|
||||
'data-mime_types' => $field['mime_types'],
|
||||
'data-uploader' => $uploader,
|
||||
);
|
||||
$img_attrs = array(
|
||||
'src' => '',
|
||||
'alt' => '',
|
||||
'data-name' => 'image',
|
||||
);
|
||||
|
||||
// Detect value.
|
||||
if ( $field['value'] && is_numeric( $field['value'] ) ) {
|
||||
$image = wp_get_attachment_image_src( $field['value'], $field['preview_size'] );
|
||||
if ( $image ) {
|
||||
$value = $field['value'];
|
||||
$img_attrs['src'] = $image[0];
|
||||
$img_attrs['alt'] = get_post_meta( $field['value'], '_wp_attachment_image_alt', true );
|
||||
$div_attrs['class'] .= ' has-value';
|
||||
}
|
||||
}
|
||||
|
||||
// Add "preview size" max width and height style.
|
||||
// Apply max-width to wrap, and max-height to img for max compatibility with field widths.
|
||||
$size = acf_get_image_size( $field['preview_size'] );
|
||||
$size_w = $size['width'] ? $size['width'] . 'px' : '100%';
|
||||
$size_h = $size['height'] ? $size['height'] . 'px' : '100%';
|
||||
$img_attrs['style'] = sprintf( 'max-height: %s;', $size_h );
|
||||
|
||||
// Render HTML.
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div_attrs ); ?>>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<div class="show-if-value image-wrap" style="max-width: <?php echo esc_attr( $size_w ); ?>">
|
||||
<img <?php echo acf_esc_attrs( $img_attrs ); ?> />
|
||||
<div class="acf-actions -hover">
|
||||
<?php if ( $uploader !== 'basic' ) : ?>
|
||||
<a class="acf-icon -pencil dark" data-name="edit" href="#" title="<?php esc_attr_e( 'Edit', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php esc_attr_e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide-if-value">
|
||||
<?php if ( $uploader === 'basic' ) : ?>
|
||||
<?php if ( $field['value'] && ! is_numeric( $field['value'] ) ) : ?>
|
||||
<div class="acf-error-message"><p><?php echo acf_esc_html( $field['value'] ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
<label class="acf-basic-uploader">
|
||||
<?php
|
||||
acf_file_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'id' => $field['id'],
|
||||
'key' => $field['key'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
</label>
|
||||
<?php else : ?>
|
||||
<p><?php esc_html_e( 'No image selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php esc_html_e( 'Add Image', 'acf' ); ?></a></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'array' => __( 'Image Array', 'acf' ),
|
||||
'url' => __( 'Image URL', 'acf' ),
|
||||
'id' => __( 'Image ID', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Library', 'acf' ),
|
||||
'instructions' => __( 'Limit the media library choice', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'library',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'all' => __( 'All', 'acf' ),
|
||||
'uploadedTo' => __( 'Uploaded to post', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
// Clear numeric settings.
|
||||
$clear = array(
|
||||
'min_width',
|
||||
'min_height',
|
||||
'min_size',
|
||||
'max_width',
|
||||
'max_height',
|
||||
'max_size',
|
||||
);
|
||||
|
||||
foreach ( $clear as $k ) {
|
||||
if ( empty( $field[ $k ] ) ) {
|
||||
$field[ $k ] = '';
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum', 'acf' ),
|
||||
'hint' => __( 'Restrict which images can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'min_width',
|
||||
'prepend' => __( 'Width', 'acf' ),
|
||||
'append' => 'px',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'min_height',
|
||||
'prepend' => __( 'Height', 'acf' ),
|
||||
'append' => 'px',
|
||||
'_append' => 'min_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'min_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
'_append' => 'min_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum', 'acf' ),
|
||||
'hint' => __( 'Restrict which images can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'max_width',
|
||||
'prepend' => __( 'Width', 'acf' ),
|
||||
'append' => 'px',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'max_height',
|
||||
'prepend' => __( 'Height', 'acf' ),
|
||||
'append' => 'px',
|
||||
'_append' => 'max_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'max_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
'_append' => 'max_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allowed File Types', 'acf' ),
|
||||
'instructions' => __( 'Comma separated list. Leave blank for all types', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'mime_types',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Preview Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'preview_size',
|
||||
'choices' => acf_get_image_sizes(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if not numeric (error message)
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert to int
|
||||
$value = intval( $value );
|
||||
|
||||
// format
|
||||
if ( $field['return_format'] == 'url' ) {
|
||||
return wp_get_attachment_url( $value );
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
return acf_get_attachment( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 27/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param $vars (array)
|
||||
* @return $vars
|
||||
*/
|
||||
function get_media_item_args( $vars ) {
|
||||
|
||||
$vars['send'] = true;
|
||||
return( $vars );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
return acf_get_field_type( 'file' )->update_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will validate a basic file input
|
||||
*
|
||||
* @type function
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param boolean $valid The current validity status.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The name of the input in the POST object.
|
||||
* @return boolean The validity status.
|
||||
*/
|
||||
public function validate_value( $valid, $value, $field, $input ) {
|
||||
return acf_get_field_type( 'file' )->validate_value( $valid, $value, $field, $input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional validation for the image field when submitted via REST.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return acf_get_field_type( 'file' )->validate_rest_value( $valid, $value, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field The field array
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return acf_get_field_type( 'file' )->get_rest_schema( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value The field value
|
||||
* @param string|integer $post_id The post ID
|
||||
* @param array $field The field array
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_image' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_link' ) ) :
|
||||
|
||||
class acf_field_link extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'link';
|
||||
$this->label = __( 'Link', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'Allows you to specify a link and its properties such as title and target using the WordPress native link picker.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-link.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/link/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/5/17
|
||||
* @since 5.5.13
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function get_link( $value = '' ) {
|
||||
|
||||
// vars
|
||||
$link = array(
|
||||
'title' => '',
|
||||
'url' => '',
|
||||
'target' => '',
|
||||
);
|
||||
|
||||
// array (ACF 5.6.0)
|
||||
if ( is_array( $value ) ) {
|
||||
$link = array_merge( $link, $value );
|
||||
|
||||
// post id (ACF < 5.6.0)
|
||||
} elseif ( is_numeric( $value ) ) {
|
||||
$link['title'] = get_the_title( $value );
|
||||
$link['url'] = get_permalink( $value );
|
||||
|
||||
// string (ACF < 5.6.0)
|
||||
} elseif ( is_string( $value ) ) {
|
||||
$link['url'] = $value;
|
||||
}
|
||||
|
||||
// return
|
||||
return $link;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$div = array(
|
||||
'id' => $field['id'],
|
||||
'class' => $field['class'] . ' acf-link',
|
||||
);
|
||||
|
||||
// render scripts/styles
|
||||
acf_enqueue_uploader();
|
||||
|
||||
// get link
|
||||
$link = $this->get_link( $field['value'] );
|
||||
|
||||
// classes
|
||||
if ( $link['url'] ) {
|
||||
$div['class'] .= ' -value';
|
||||
}
|
||||
|
||||
if ( $link['target'] === '_blank' ) {
|
||||
$div['class'] .= ' -external';
|
||||
}
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
|
||||
<div class="acf-hidden">
|
||||
<a class="link-node" href="<?php echo esc_url( $link['url'] ); ?>" target="<?php echo esc_attr( $link['target'] ); ?>"><?php echo esc_html( $link['title'] ); ?></a>
|
||||
<?php foreach ( $link as $k => $v ) : ?>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'class' => "input-$k",
|
||||
'name' => $field['name'] . "[$k]",
|
||||
'value' => $v,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<a href="#" class="button" data-name="add" target=""><?php esc_html_e( 'Select Link', 'acf' ); ?></a>
|
||||
|
||||
<div class="link-wrap">
|
||||
<span class="link-title"><?php echo esc_html( $link['title'] ); ?></span>
|
||||
<a class="link-url" href="<?php echo esc_url( $link['url'] ); ?>" target="_blank"><?php echo esc_html( $link['url'] ); ?></a>
|
||||
<i class="acf-icon -link-ext acf-js-tooltip" title="<?php esc_attr_e( 'Opens in a new window/tab', 'acf' ); ?>"></i><a class="acf-icon -pencil -clear acf-js-tooltip" data-name="edit" href="#" title="<?php esc_attr_e( 'Edit', 'acf' ); ?>"></a><a class="acf-icon -cancel -clear acf-js-tooltip" data-name="remove" href="#" title="<?php esc_attr_e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'array' => __( 'Link Array', 'acf' ),
|
||||
'url' => __( 'Link URL', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// get link
|
||||
$link = $this->get_link( $value );
|
||||
|
||||
// format value
|
||||
if ( $field['return_format'] == 'url' ) {
|
||||
return $link['url'];
|
||||
}
|
||||
|
||||
// return link
|
||||
return $link;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// bail early if not required
|
||||
if ( ! $field['required'] ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// URL is required
|
||||
if ( empty( $value ) || empty( $value['url'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Check if value is an empty array and convert to empty string.
|
||||
if ( empty( $value ) || empty( $value['url'] ) ) {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'properties' => array(
|
||||
'title' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'url' => array(
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'format' => 'uri',
|
||||
),
|
||||
'target' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_link' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_message' ) ) :
|
||||
|
||||
class acf_field_message extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'message';
|
||||
$this->label = __( 'Message', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Used to display a message to editors alongside other fields. Useful for providing additional context or instructions around your fields.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-message.png';
|
||||
$this->supports = array(
|
||||
'required' => false,
|
||||
'bindings' => false,
|
||||
);
|
||||
$this->defaults = array(
|
||||
'message' => '',
|
||||
'esc_html' => 0,
|
||||
'new_lines' => 'wpautop',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$m = $field['message'];
|
||||
|
||||
// wptexturize (improves "quotes")
|
||||
$m = wptexturize( $m );
|
||||
|
||||
// esc_html
|
||||
if ( $field['esc_html'] ) {
|
||||
$m = esc_html( $m );
|
||||
}
|
||||
|
||||
// new lines
|
||||
if ( $field['new_lines'] == 'wpautop' ) {
|
||||
$m = wpautop( $m );
|
||||
} elseif ( $field['new_lines'] == 'br' ) {
|
||||
$m = nl2br( $m );
|
||||
}
|
||||
|
||||
// return
|
||||
echo acf_esc_html( $m );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Message', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'textarea',
|
||||
'name' => 'message',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'New Lines', 'acf' ),
|
||||
'instructions' => __( 'Controls how new lines are rendered', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'new_lines',
|
||||
'choices' => array(
|
||||
'wpautop' => __( 'Automatically add paragraphs', 'acf' ),
|
||||
'br' => __( 'Automatically add <br>', 'acf' ),
|
||||
'' => __( 'No Formatting', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Escape HTML', 'acf' ),
|
||||
'instructions' => __( 'Allow HTML markup to display as visible text instead of rendering', 'acf' ),
|
||||
'name' => 'esc_html',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
function translate_field( $field ) {
|
||||
|
||||
// translate
|
||||
$field['message'] = acf_translate( $field['message'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove instructions
|
||||
$field['instructions'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_message' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,320 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_number' ) ) :
|
||||
|
||||
class acf_field_number extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'number';
|
||||
$this->label = __( 'Number', 'acf' );
|
||||
$this->description = __( 'An input limited to numerical values.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-number.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/number/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'min' => '',
|
||||
'max' => '',
|
||||
'step' => '',
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'min', 'max', 'step', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
$html = '';
|
||||
|
||||
// step
|
||||
if ( ! $field['step'] ) {
|
||||
$field['step'] = 'any';
|
||||
}
|
||||
|
||||
// prepend
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-prepended';
|
||||
$html .= '<div class="acf-input-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
}
|
||||
|
||||
// append
|
||||
if ( $field['append'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-appended';
|
||||
$html .= '<div class="acf-input-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
}
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// render
|
||||
$html .= '<div class="acf-input-wrap">' . acf_get_text_input( $atts ) . '</div>';
|
||||
|
||||
// return
|
||||
echo $html; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by individual html functions above.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
|
||||
// default_value
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Step Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'step',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// remove ','
|
||||
if ( acf_str_exists( ',', $value ) ) {
|
||||
$value = str_replace( ',', '', $value );
|
||||
}
|
||||
|
||||
// if value is not numeric...
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
|
||||
// allow blank to be saved
|
||||
if ( ! empty( $value ) ) {
|
||||
$valid = __( 'Value must be a number', 'acf' );
|
||||
}
|
||||
|
||||
// return early
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// convert
|
||||
$value = floatval( $value );
|
||||
|
||||
// min
|
||||
if ( is_numeric( $field['min'] ) && $value < floatval( $field['min'] ) ) {
|
||||
$valid = sprintf( __( 'Value must be equal to or higher than %d', 'acf' ), $field['min'] );
|
||||
}
|
||||
|
||||
// max
|
||||
if ( is_numeric( $field['max'] ) && $value > floatval( $field['max'] ) ) {
|
||||
$valid = sprintf( __( 'Value must be equal to or lower than %d', 'acf' ), $field['max'] );
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// no formatting needed for empty value
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// remove ','
|
||||
if ( acf_str_exists( ',', $value ) ) {
|
||||
$value = str_replace( ',', '', $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'number', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
if ( ! empty( $field['min'] ) ) {
|
||||
$schema['minimum'] = (float) $field['min'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max'] ) ) {
|
||||
$schema['maximum'] = (float) $field['max'];
|
||||
}
|
||||
|
||||
if ( isset( $field['default_value'] ) && is_numeric( $field['default_value'] ) ) {
|
||||
$schema['default'] = (float) $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_number' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_oembed' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field_oembed extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'oembed';
|
||||
$this->label = __( 'oEmbed', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'An interactive component for embedding videos, images, tweets, audio and other content by making use of the native WordPress oEmbed functionality.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-oembed.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/oembed/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'width' => '',
|
||||
'height' => '',
|
||||
);
|
||||
$this->width = 640;
|
||||
$this->height = 390;
|
||||
$this->supports = array(
|
||||
'escaping_html' => true, // The OEmbed field only produces html safe content from format_value.
|
||||
);
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/oembed/search', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/oembed/search', array( $this, 'ajax_query' ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will prepare the field for input
|
||||
*
|
||||
* @type function
|
||||
* @date 14/2/17
|
||||
* @since 5.5.8
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return (int)
|
||||
*/
|
||||
function prepare_field( $field ) {
|
||||
|
||||
// defaults
|
||||
if ( ! $field['width'] ) {
|
||||
$field['width'] = $this->width;
|
||||
}
|
||||
if ( ! $field['height'] ) {
|
||||
$field['height'] = $this->height;
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to fetch the HTML for the provided URL using oEmbed.
|
||||
*
|
||||
* @date 24/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $url The URL that should be embedded.
|
||||
* @param integer|string $width Optional maxwidth value passed to the provider URL.
|
||||
* @param integer|string $height Optional maxheight value passed to the provider URL.
|
||||
* @return string|false The embedded HTML on success, false on failure.
|
||||
*/
|
||||
function wp_oembed_get( $url = '', $width = 0, $height = 0 ) {
|
||||
$embed = false;
|
||||
$res = array(
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
);
|
||||
|
||||
if ( function_exists( 'wp_oembed_get' ) ) {
|
||||
$embed = wp_oembed_get( $url, $res );
|
||||
}
|
||||
|
||||
// try shortcode
|
||||
if ( ! $embed ) {
|
||||
global $wp_embed;
|
||||
$embed = $wp_embed->shortcode( $res, $url );
|
||||
}
|
||||
|
||||
return $embed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AJAX results for the oEmbed field.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_query() {
|
||||
$args = acf_request_args(
|
||||
array(
|
||||
'nonce' => '',
|
||||
'field_key' => '',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
wp_send_json( $this->get_ajax_query( $_POST ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @type function
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param $options (array)
|
||||
* @return (array)
|
||||
*/
|
||||
function get_ajax_query( $args = array() ) {
|
||||
|
||||
// defaults
|
||||
$args = acf_parse_args(
|
||||
$args,
|
||||
array(
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $args['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// prepare field to correct width and height
|
||||
$field = $this->prepare_field( $field );
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'url' => $args['s'],
|
||||
'html' => $this->wp_oembed_get( $args['s'], $field['width'], $field['height'] ),
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the oEmbed field.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
$atts = array(
|
||||
'class' => 'acf-oembed',
|
||||
'data-nonce' => wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] ),
|
||||
);
|
||||
|
||||
if ( $field['value'] ) {
|
||||
$atts['class'] .= ' has-value';
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $atts ); ?>>
|
||||
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'class' => 'input-value',
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<div class="title">
|
||||
<?php
|
||||
acf_text_input(
|
||||
array(
|
||||
'class' => 'input-search',
|
||||
'value' => $field['value'],
|
||||
'placeholder' => __( 'Enter URL', 'acf' ),
|
||||
'autocomplete' => 'off',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<div class="acf-actions -hover">
|
||||
<a data-name="clear-button" href="#" class="acf-icon -cancel grey"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="canvas">
|
||||
<div class="canvas-media">
|
||||
<?php
|
||||
if ( $field['value'] ) {
|
||||
echo $this->wp_oembed_get( $field['value'], $field['width'], $field['height'] ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- wp_ombed_get generates HTML safe output.
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<i class="acf-icon -picture hide-if-value"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Embed Size', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'width',
|
||||
'prepend' => __( 'Width', 'acf' ),
|
||||
'append' => 'px',
|
||||
'placeholder' => $this->width,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Embed Size', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'height',
|
||||
'prepend' => __( 'Height', 'acf' ),
|
||||
'append' => 'px',
|
||||
'placeholder' => $this->height,
|
||||
'_append' => 'width',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template.
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database.
|
||||
* @param mixed $post_id The $post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return mixed the modified value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// prepare field to correct width and height
|
||||
$field = $this->prepare_field( $field );
|
||||
|
||||
// get oembed
|
||||
$value = $this->wp_oembed_get( $value, $field['width'], $field['height'] );
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
$schema['format'] = 'uri';
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_oembed' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_output' ) ) :
|
||||
|
||||
/**
|
||||
* This class and field type has been deprecated since ACF 6.3.2 and will not output anything.
|
||||
*/
|
||||
class acf_field_output extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'output';
|
||||
$this->label = 'output';
|
||||
$this->public = false;
|
||||
$this->defaults = array(
|
||||
'html' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The render field call. Deprecated since ACF 6.3.2.
|
||||
*
|
||||
* @param array $field The $field being edited
|
||||
* @return false
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
|
||||
// Deprecated since 6.3.2 and will be removed in a future release.
|
||||
_deprecated_function( __FUNCTION__, '6.3.2' );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_output' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,705 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_page_link' ) ) :
|
||||
|
||||
class acf_field_page_link extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'page_link';
|
||||
$this->label = __( 'Page Link', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'An interactive dropdown to select one or more posts, pages, custom post type items or archive URLs, with the option to search.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-page-link.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/page-link/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'post_type' => array(),
|
||||
'taxonomy' => array(),
|
||||
'allow_null' => 0,
|
||||
'multiple' => 0,
|
||||
'allow_archives' => 1,
|
||||
);
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/page_link/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/page_link/query', array( $this, 'ajax_query' ) );
|
||||
add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_page_link_conditional_choices' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters choices in page link conditions.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $choices The selected choice.
|
||||
* @param array $conditional_field The conditional field settings object.
|
||||
* @param string $rule_value The rule value.
|
||||
* @return array
|
||||
*/
|
||||
public function render_field_page_link_conditional_choices( $choices, $conditional_field, $rule_value ) {
|
||||
if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'page_link' ) {
|
||||
return $choices;
|
||||
}
|
||||
if ( ! empty( $rule_value ) ) {
|
||||
$post_title = get_the_title( $rule_value );
|
||||
$choices = array( $rule_value => $post_title );
|
||||
}
|
||||
return $choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AJAX results for the Page Link field.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_query() {
|
||||
$nonce = acf_request_arg( 'nonce', '' );
|
||||
$key = acf_request_arg( 'field_key', '' );
|
||||
$conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
|
||||
|
||||
if ( $conditional_logic ) {
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Use the standard ACF admin nonce.
|
||||
$nonce = '';
|
||||
$key = '';
|
||||
}
|
||||
|
||||
if ( ! acf_verify_ajax( $nonce, $key, ! $conditional_logic ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$_POST,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
'include' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$args = array();
|
||||
$s = false;
|
||||
$is_search = false;
|
||||
|
||||
// paged
|
||||
$args['posts_per_page'] = 20;
|
||||
$args['paged'] = $options['paged'];
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
// update vars
|
||||
$args['s'] = $s;
|
||||
$is_search = true;
|
||||
}
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// update $args
|
||||
if ( ! empty( $field['post_type'] ) ) {
|
||||
$args['post_type'] = acf_get_array( $field['post_type'] );
|
||||
} else {
|
||||
$args['post_type'] = acf_get_post_types();
|
||||
}
|
||||
|
||||
// post status
|
||||
if ( ! empty( $options['post_status'] ) ) {
|
||||
$args['post_status'] = acf_get_array( $options['post_status'] );
|
||||
} elseif ( ! empty( $field['post_status'] ) ) {
|
||||
$args['post_status'] = acf_get_array( $field['post_status'] );
|
||||
}
|
||||
|
||||
// create tax queries
|
||||
if ( ! empty( $field['taxonomy'] ) ) {
|
||||
|
||||
// append to $args
|
||||
$args['tax_query'] = array();
|
||||
|
||||
// decode terms
|
||||
$taxonomies = acf_decode_taxonomy_terms( $field['taxonomy'] );
|
||||
|
||||
// now create the tax queries
|
||||
foreach ( $taxonomies as $taxonomy => $terms ) {
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'slug',
|
||||
'terms' => $terms,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $options['include'] ) ) {
|
||||
$args['include'] = $options['include'];
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/page_link/query', $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/page_link/query/name=' . $field['name'], $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/page_link/query/key=' . $field['key'], $args, $field, $options['post_id'] );
|
||||
|
||||
// add archives to $results
|
||||
if ( $field['allow_archives'] && $args['paged'] == 1 ) {
|
||||
|
||||
// Generate unique list of URLs.
|
||||
$links = array();
|
||||
$links[] = home_url();
|
||||
foreach ( $args['post_type'] as $post_type ) {
|
||||
$links[] = get_post_type_archive_link( $post_type );
|
||||
}
|
||||
$links = array_filter( $links );
|
||||
$links = array_unique( $links );
|
||||
|
||||
// Convert list into choices.
|
||||
$children = array();
|
||||
foreach ( $links as $link ) {
|
||||
|
||||
// Ignore if search does not match.
|
||||
if ( $is_search && stripos( $link, $s ) === false ) {
|
||||
continue;
|
||||
}
|
||||
$children[] = array(
|
||||
'id' => $link,
|
||||
'text' => $link,
|
||||
);
|
||||
}
|
||||
if ( $children ) {
|
||||
$results[] = array(
|
||||
'text' => __( 'Archives', 'acf' ),
|
||||
'children' => $children,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// If there is an include set, we will unset search to avoid attempting to further filter by the search term.
|
||||
if ( isset( $args['include'] ) ) {
|
||||
unset( $args['s'] );
|
||||
}
|
||||
|
||||
// get posts grouped by post type
|
||||
$groups = acf_get_grouped_posts( $args );
|
||||
|
||||
// loop
|
||||
if ( ! empty( $groups ) ) {
|
||||
foreach ( array_keys( $groups ) as $group_title ) {
|
||||
|
||||
// vars
|
||||
$posts = acf_extract_var( $groups, $group_title );
|
||||
|
||||
// data
|
||||
$data = array(
|
||||
'text' => $group_title,
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
// convert post objects to post titles
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
$posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'], $is_search );
|
||||
}
|
||||
|
||||
// order posts by search
|
||||
if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
|
||||
$posts = acf_order_by_search( $posts, $args['s'] );
|
||||
}
|
||||
|
||||
// append to $data
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
$data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
|
||||
}
|
||||
|
||||
// append to $results
|
||||
$results[] = $data;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
acf_send_ajax_results(
|
||||
array(
|
||||
'results' => $results,
|
||||
'limit' => $args['posts_per_page'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an array containing id, text and maybe description data
|
||||
*
|
||||
* @type function
|
||||
* @date 7/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $id (mixed)
|
||||
* @param $text (string)
|
||||
* @return (array)
|
||||
*/
|
||||
function get_post_result( $id, $text ) {
|
||||
|
||||
// vars
|
||||
$result = array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
|
||||
// look for parent
|
||||
$search = '| ' . __( 'Parent', 'acf' ) . ':';
|
||||
$pos = strpos( $text, $search );
|
||||
|
||||
if ( $pos !== false ) {
|
||||
$result['description'] = substr( $text, $pos + 2 );
|
||||
$result['text'] = substr( $text, 0, $pos );
|
||||
}
|
||||
|
||||
// return
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function returns the HTML for a result
|
||||
*
|
||||
* @type function
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post (object)
|
||||
* @param $field (array)
|
||||
* @param $post_id (int) the post_id to which this value is saved to
|
||||
* @return (string)
|
||||
*/
|
||||
function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
|
||||
|
||||
// get post_id
|
||||
if ( ! $post_id ) {
|
||||
$post_id = acf_get_form_data( 'post_id' );
|
||||
}
|
||||
|
||||
// vars
|
||||
$title = acf_get_post_title( $post, $is_search );
|
||||
|
||||
// filters
|
||||
$title = apply_filters( 'acf/fields/page_link/result', $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/page_link/result/name=' . $field['_name'], $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/page_link/result/key=' . $field['key'], $title, $post, $field, $post_id );
|
||||
|
||||
// return
|
||||
return $title;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an array of posts for a given field value
|
||||
*
|
||||
* @type function
|
||||
* @date 13/06/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $value (array)
|
||||
* @return $value
|
||||
*/
|
||||
function get_posts( $value, $field ) {
|
||||
|
||||
// force value to array
|
||||
$value = acf_get_array( $value );
|
||||
|
||||
// get selected post ID's
|
||||
$post__in = array();
|
||||
|
||||
foreach ( $value as $k => $v ) {
|
||||
if ( is_numeric( $v ) ) {
|
||||
|
||||
// append to $post__in
|
||||
$post__in[] = (int) $v;
|
||||
}
|
||||
}
|
||||
|
||||
// bail early if no posts
|
||||
if ( empty( $post__in ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// get posts
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $post__in,
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
// override value with post
|
||||
$return = array();
|
||||
|
||||
// append to $return
|
||||
foreach ( $value as $k => $v ) {
|
||||
if ( is_numeric( $v ) ) {
|
||||
|
||||
// extract first post
|
||||
$post = array_shift( $posts );
|
||||
|
||||
// append
|
||||
if ( $post ) {
|
||||
$return[] = $post;
|
||||
}
|
||||
} else {
|
||||
$return[] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $return;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the Page Link field.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['choices'] = array();
|
||||
$field['nonce'] = wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] );
|
||||
|
||||
// populate choices if value exists
|
||||
if ( ! empty( $field['value'] ) ) {
|
||||
|
||||
// get posts
|
||||
$posts = $this->get_posts( $field['value'], $field );
|
||||
|
||||
// set choices
|
||||
if ( ! empty( $posts ) ) {
|
||||
foreach ( array_keys( $posts ) as $i ) {
|
||||
|
||||
// vars
|
||||
$post = acf_extract_var( $posts, $i );
|
||||
|
||||
if ( is_object( $post ) ) {
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $post->ID ] = $this->get_post_title( $post, $field );
|
||||
} else {
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $post ] = $post;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
acf_render_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_type',
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All post types', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Status', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_status',
|
||||
'choices' => acf_get_pretty_post_statuses(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'Any post status', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Taxonomy', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_terms(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All taxonomies', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Archives URLs', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_archives',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select Multiple', 'acf' ),
|
||||
'instructions' => 'Allow content editors to select multiple values',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// ACF4 null
|
||||
if ( $value === 'null' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// get posts
|
||||
$value = $this->get_posts( $value, $field );
|
||||
|
||||
// set choices
|
||||
foreach ( array_keys( $value ) as $i ) {
|
||||
|
||||
// vars
|
||||
$post = acf_extract_var( $value, $i );
|
||||
|
||||
// convert $post to permalink
|
||||
if ( is_object( $post ) ) {
|
||||
$post = get_permalink( $post );
|
||||
}
|
||||
|
||||
// append back to $value
|
||||
$value[ $i ] = $post;
|
||||
}
|
||||
|
||||
// convert back from array if neccessary
|
||||
if ( ! $field['multiple'] ) {
|
||||
$value = array_shift( $value );
|
||||
}
|
||||
|
||||
// return value
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_maybe_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_maybe_idval( $value );
|
||||
}
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates page link fields updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return acf_get_field_type( 'post_object' )->validate_rest_value( $valid, $value, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => array( 'integer' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( ! empty( $field['allow_archives'] ) ) {
|
||||
$schema['type'][] = 'string';
|
||||
$schema['items']['type'][] = 'string';
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
$links = array();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
foreach ( (array) $value as $object_id ) {
|
||||
if ( ! $post_type = get_post_type( $object_id ) or ! $post_type = get_post_type_object( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
$rest_base = acf_get_object_type_rest_base( $post_type );
|
||||
$links[] = array(
|
||||
'rel' => $post_type->name === 'attachment' ? 'acf:attachment' : 'acf:post',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_page_link' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,106 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_password' ) ) :
|
||||
|
||||
class acf_field_password extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'password';
|
||||
$this->label = __( 'Password', 'acf' );
|
||||
$this->description = __( 'An input for providing a password using a masked field.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-password.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/password/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
acf_get_field_type( 'text' )->render_field( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
// TODO: Delete this method?
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_password' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,761 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_post_object' ) ) :
|
||||
|
||||
class acf_field_post_object extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'post_object';
|
||||
$this->label = __( 'Post Object', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'An interactive and customizable UI for picking one or many posts, pages or post type items with the option to search. ', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-post-object.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/post-object/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'post_type' => array(),
|
||||
'taxonomy' => array(),
|
||||
'allow_null' => 0,
|
||||
'multiple' => 0,
|
||||
'return_format' => 'object',
|
||||
'ui' => 1,
|
||||
'bidirectional_target' => array(),
|
||||
);
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/post_object/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/post_object/query', array( $this, 'ajax_query' ) );
|
||||
add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_post_object_conditional_choices' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters choices in post object conditions.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $choices The selected choice.
|
||||
* @param array $conditional_field The conditional field settings object.
|
||||
* @param string $rule_value The rule value.
|
||||
* @return array
|
||||
*/
|
||||
public function render_field_post_object_conditional_choices( $choices, $conditional_field, $rule_value ) {
|
||||
if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'post_object' ) {
|
||||
return $choices;
|
||||
}
|
||||
if ( ! empty( $rule_value ) ) {
|
||||
$post_title = get_the_title( $rule_value );
|
||||
$choices = array( $rule_value => $post_title );
|
||||
}
|
||||
return $choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX query handler for post object fields.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_query() {
|
||||
$nonce = acf_request_arg( 'nonce', '' );
|
||||
$key = acf_request_arg( 'field_key', '' );
|
||||
$conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
|
||||
|
||||
if ( $conditional_logic ) {
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Use the standard ACF admin nonce.
|
||||
$nonce = '';
|
||||
$key = '';
|
||||
}
|
||||
|
||||
if ( ! acf_verify_ajax( $nonce, $key, ! $conditional_logic ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param array $options The options being queried for the ajax request.
|
||||
* @return array|boolean The AJAX response array, or false on failure.
|
||||
*/
|
||||
public function get_ajax_query( $options = array() ) {
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
'include' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$args = array();
|
||||
$s = false;
|
||||
$is_search = false;
|
||||
|
||||
// paged
|
||||
$args['posts_per_page'] = 20;
|
||||
$args['paged'] = $options['paged'];
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
// update vars
|
||||
$args['s'] = $s;
|
||||
$is_search = true;
|
||||
}
|
||||
|
||||
if ( ! empty( $options['include'] ) ) {
|
||||
$args['include'] = $options['include'];
|
||||
}
|
||||
|
||||
// post_type
|
||||
if ( ! empty( $field['post_type'] ) ) {
|
||||
$args['post_type'] = acf_get_array( $field['post_type'] );
|
||||
} else {
|
||||
$args['post_type'] = acf_get_post_types();
|
||||
}
|
||||
|
||||
// post status
|
||||
if ( ! empty( $options['post_status'] ) ) {
|
||||
$args['post_status'] = acf_get_array( $options['post_status'] );
|
||||
} elseif ( ! empty( $field['post_status'] ) ) {
|
||||
$args['post_status'] = acf_get_array( $field['post_status'] );
|
||||
}
|
||||
|
||||
// If there is an include set, we will unset search to avoid attempting to further filter by the search term.
|
||||
if ( isset( $args['include'] ) ) {
|
||||
unset( $args['s'] );
|
||||
}
|
||||
|
||||
// taxonomy
|
||||
if ( ! empty( $field['taxonomy'] ) ) {
|
||||
|
||||
// vars
|
||||
$terms = acf_decode_taxonomy_terms( $field['taxonomy'] );
|
||||
|
||||
// append to $args
|
||||
$args['tax_query'] = array();
|
||||
|
||||
// now create the tax queries
|
||||
foreach ( $terms as $k => $v ) {
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $k,
|
||||
'field' => 'slug',
|
||||
'terms' => $v,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/post_object/query', $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/post_object/query/name=' . $field['name'], $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/post_object/query/key=' . $field['key'], $args, $field, $options['post_id'] );
|
||||
|
||||
// get posts grouped by post type
|
||||
$groups = acf_get_grouped_posts( $args );
|
||||
|
||||
// bail early if no posts
|
||||
if ( empty( $groups ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( array_keys( $groups ) as $group_title ) {
|
||||
|
||||
// vars
|
||||
$posts = acf_extract_var( $groups, $group_title );
|
||||
|
||||
// data
|
||||
$data = array(
|
||||
'text' => $group_title,
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
// convert post objects to post titles
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
$posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'], $is_search, true );
|
||||
}
|
||||
|
||||
// order posts by search
|
||||
if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
|
||||
$posts = acf_order_by_search( $posts, $args['s'] );
|
||||
}
|
||||
|
||||
// append to $data
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
$data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
|
||||
}
|
||||
|
||||
// append to $results
|
||||
$results[] = $data;
|
||||
}
|
||||
|
||||
// optgroup or single
|
||||
$post_type = acf_get_array( $args['post_type'] );
|
||||
if ( count( $post_type ) == 1 ) {
|
||||
$results = $results[0]['children'];
|
||||
}
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
'limit' => $args['posts_per_page'],
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array containing id, text and maybe description data
|
||||
*
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param mixed $id The ID of the post result.
|
||||
* @param string $text The text for the response item.
|
||||
* @return array The combined result array.
|
||||
*/
|
||||
public function get_post_result( $id, $text ) {
|
||||
|
||||
// vars
|
||||
$result = array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
|
||||
// look for parent
|
||||
$search = '| ' . __( 'Parent', 'acf' ) . ':';
|
||||
$pos = strpos( $text, $search );
|
||||
|
||||
if ( $pos !== false ) {
|
||||
$result['description'] = substr( $text, $pos + 2 );
|
||||
$result['text'] = substr( $text, 0, $pos );
|
||||
}
|
||||
|
||||
// return
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function post object's filtered output post title
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param WP_Post $post The WordPress post.
|
||||
* @param array $field The field being output.
|
||||
* @param integer $post_id The post_id to which this value is saved to.
|
||||
* @param integer $is_search An int-as-boolean value for whether we're performing a search.
|
||||
* @param boolean $unescape Should we return an unescaped post title.
|
||||
* @return string A potentially user filtered post title for the post, which may contain unsafe HTML.
|
||||
*/
|
||||
public function get_post_title( $post, $field, $post_id = 0, $is_search = 0, $unescape = false ) {
|
||||
|
||||
// get post_id
|
||||
if ( ! $post_id ) {
|
||||
$post_id = acf_get_form_data( 'post_id' );
|
||||
}
|
||||
|
||||
// vars
|
||||
$title = acf_get_post_title( $post, $is_search );
|
||||
|
||||
// unescape for select2 output which handles the escaping.
|
||||
if ( $unescape ) {
|
||||
$title = html_entity_decode( $title );
|
||||
}
|
||||
|
||||
// filters
|
||||
$title = apply_filters( 'acf/fields/post_object/result', $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/post_object/result/name=' . $field['_name'], $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/post_object/result/key=' . $field['key'], $title, $post, $field, $post_id );
|
||||
|
||||
// return untrusted output.
|
||||
return $title;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for the post object field.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array holding all the field's data.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['nonce'] = wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] );
|
||||
$field['choices'] = array();
|
||||
|
||||
// load posts
|
||||
$posts = $this->get_posts( $field['value'], $field );
|
||||
|
||||
if ( $posts ) {
|
||||
foreach ( array_keys( $posts ) as $i ) {
|
||||
|
||||
// vars
|
||||
$post = acf_extract_var( $posts, $i );
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $post->ID ] = $this->get_post_title( $post, $field );
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
acf_render_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for post object field. This is rendered when editing.
|
||||
* The value of $field['name'] can be used (like below) to save extra data to the $field.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array holding all the field's data.
|
||||
*/
|
||||
public function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_type',
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All post types', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Status', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_status',
|
||||
'choices' => acf_get_pretty_post_statuses(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'Any post status', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Taxonomy', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_terms(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All taxonomies', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'object' => __( 'Post Object', 'acf' ),
|
||||
'id' => __( 'Post ID', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select Multiple', 'acf' ),
|
||||
'instructions' => 'Allow content editors to select multiple values',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Advanced" tab.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_advanced_settings( $field ) {
|
||||
acf_render_bidirectional_field_settings( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is applied to the $value after it is loaded from the db
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value found in the database
|
||||
* @param mixed $post_id The post_id from which the value was loaded
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return mixed $value
|
||||
*/
|
||||
public function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// ACF4 null
|
||||
if ( $value === 'null' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value found in the database
|
||||
* @param mixed $post_id The post_id from which the value was loaded
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return mixed $value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
$value = acf_get_numeric( $value );
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load posts if needed
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
$value = $this->get_posts( $value, $field );
|
||||
}
|
||||
|
||||
// convert back from array if neccessary
|
||||
if ( ! $field['multiple'] && is_array( $value ) ) {
|
||||
$value = current( $value );
|
||||
}
|
||||
|
||||
// return value
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters the field value before it is saved into the database.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which will be saved in the database.
|
||||
* @param integer $post_id The post_id of which the value will be saved.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return mixed $value The modified value.
|
||||
*/
|
||||
public function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
acf_update_bidirectional_values( array(), $post_id, $field );
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_idval( $value );
|
||||
}
|
||||
|
||||
acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field );
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an array of posts for a given field value
|
||||
*
|
||||
* @since 5.0
|
||||
*
|
||||
* @param mixed $value The value of the field.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return array $value An array of post objects.
|
||||
*/
|
||||
public function get_posts( $value, $field ) {
|
||||
|
||||
// numeric
|
||||
$value = acf_get_numeric( $value );
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get posts
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $value,
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
// return
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates post object fields updated via the REST API.
|
||||
*
|
||||
* @since 5.11
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( is_null( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array( 'param' => $param );
|
||||
$value = is_array( $value ) ? $value : array( $value );
|
||||
|
||||
$invalid_posts = array();
|
||||
$post_type_errors = array();
|
||||
$taxonomy_errors = array();
|
||||
|
||||
foreach ( $value as $post_id ) {
|
||||
if ( is_string( $post_id ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$post_type = get_post_type( $post_id );
|
||||
if ( ! $post_type ) {
|
||||
$invalid_posts[] = $post_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
is_array( $field['post_type'] ) &&
|
||||
! empty( $field['post_type'] ) &&
|
||||
! in_array( $post_type, $field['post_type'] )
|
||||
) {
|
||||
$post_type_errors[] = $post_id;
|
||||
}
|
||||
|
||||
if ( is_array( $field['taxonomy'] ) && ! empty( $field['taxonomy'] ) ) {
|
||||
$found = false;
|
||||
foreach ( $field['taxonomy'] as $taxonomy_term ) {
|
||||
$decoded = acf_decode_taxonomy_term( $taxonomy_term );
|
||||
if ( $decoded && is_object_in_term( $post_id, $decoded['taxonomy'], $decoded['term'] ) ) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $found ) {
|
||||
$taxonomy_errors[] = $post_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $invalid_posts ) ) {
|
||||
$error = sprintf(
|
||||
__( '%1$s must have a valid post ID.', 'acf' ),
|
||||
$param
|
||||
);
|
||||
$data['value'] = $invalid_posts;
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
if ( count( $post_type_errors ) ) {
|
||||
$error = sprintf(
|
||||
_n(
|
||||
'%1$s must be of post type %2$s.',
|
||||
'%1$s must be of one of the following post types: %2$s',
|
||||
count( $field['post_type'] ),
|
||||
'acf'
|
||||
),
|
||||
$param,
|
||||
count( $field['post_type'] ) > 1 ? implode( ', ', $field['post_type'] ) : $field['post_type'][0]
|
||||
);
|
||||
$data['value'] = $post_type_errors;
|
||||
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
if ( count( $taxonomy_errors ) ) {
|
||||
$error = sprintf(
|
||||
_n(
|
||||
'%1$s must have term %2$s.',
|
||||
'%1$s must have one of the following terms: %2$s',
|
||||
count( $field['taxonomy'] ),
|
||||
'acf'
|
||||
),
|
||||
$param,
|
||||
count( $field['taxonomy'] ) > 1 ? implode( ', ', $field['taxonomy'] ) : $field['taxonomy'][0]
|
||||
);
|
||||
$data['value'] = $taxonomy_errors;
|
||||
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @since 5.11
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* REST link attributes generator for this field.
|
||||
*
|
||||
* @since 5.11
|
||||
* @see \acf_field::get_rest_links()
|
||||
*
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id The post ID being queried.
|
||||
* @param array $field The field array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
$links = array();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
foreach ( (array) $value as $object_id ) {
|
||||
if ( ! $post_type = get_post_type( $object_id ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! $post_type_object = get_post_type_object( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rest_base = acf_get_object_type_rest_base( $post_type_object );
|
||||
$links[] = array(
|
||||
'rel' => $post_type_object->name === 'attachment' ? 'acf:attachment' : 'acf:post',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @since 5.11
|
||||
*
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id The post ID being queried.
|
||||
* @param array $field The field array.
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_post_object' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,457 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_radio' ) ) :
|
||||
|
||||
class acf_field_radio extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'radio';
|
||||
$this->label = __( 'Radio Button', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A group of radio button inputs that allows the user to make a single selection from values that you specify.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-radio-button.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/radio-button/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'layout' => 'vertical',
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'other_choice' => 0,
|
||||
'save_other_choice' => 0,
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'value',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field (array) the $field being rendered
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field (array) the $field being edited
|
||||
* @return n/a
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$e = '';
|
||||
$ul = array(
|
||||
'class' => 'acf-radio-list',
|
||||
'data-allow_null' => $field['allow_null'],
|
||||
'data-other_choice' => $field['other_choice'],
|
||||
);
|
||||
|
||||
// append to class
|
||||
$ul['class'] .= ' ' . ( $field['layout'] == 'horizontal' ? 'acf-hl' : 'acf-bl' );
|
||||
$ul['class'] .= ' ' . $field['class'];
|
||||
|
||||
// Determine selected value.
|
||||
$value = (string) $field['value'];
|
||||
|
||||
// 1. Selected choice.
|
||||
if ( isset( $field['choices'][ $value ] ) ) {
|
||||
$checked = (string) $value;
|
||||
|
||||
// 2. Custom choice.
|
||||
} elseif ( $field['other_choice'] && $value !== '' ) {
|
||||
$checked = 'other';
|
||||
|
||||
// 3. Empty choice.
|
||||
} elseif ( $field['allow_null'] ) {
|
||||
$checked = '';
|
||||
|
||||
// 4. Default to first choice.
|
||||
} else {
|
||||
$checked = (string) key( $field['choices'] );
|
||||
}
|
||||
|
||||
// other choice
|
||||
$other_input = false;
|
||||
if ( $field['other_choice'] ) {
|
||||
|
||||
// Define other input attrs.
|
||||
$other_input = array(
|
||||
'type' => 'text',
|
||||
'name' => $field['name'],
|
||||
'value' => '',
|
||||
'disabled' => 'disabled',
|
||||
'class' => 'acf-disabled',
|
||||
);
|
||||
|
||||
// Select other choice if value is not a valid choice.
|
||||
if ( $checked === 'other' ) {
|
||||
unset( $other_input['disabled'] );
|
||||
$other_input['value'] = $field['value'];
|
||||
}
|
||||
|
||||
// Ensure an 'other' choice is defined.
|
||||
if ( ! isset( $field['choices']['other'] ) ) {
|
||||
$field['choices']['other'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Bail early if no choices.
|
||||
if ( empty( $field['choices'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hiden input.
|
||||
$e .= acf_get_hidden_input( array( 'name' => $field['name'] ) );
|
||||
|
||||
// Open <ul>.
|
||||
$e .= '<ul ' . acf_esc_attrs( $ul ) . '>';
|
||||
|
||||
// Loop through choices.
|
||||
foreach ( $field['choices'] as $value => $label ) {
|
||||
$is_selected = false;
|
||||
|
||||
// Ensure value is a string.
|
||||
$value = (string) $value;
|
||||
|
||||
// Define input attrs.
|
||||
$attrs = array(
|
||||
'type' => 'radio',
|
||||
'id' => sanitize_title( $field['id'] . '-' . $value ),
|
||||
'name' => $field['name'],
|
||||
'value' => $value,
|
||||
);
|
||||
|
||||
// Check if selected.
|
||||
if ( esc_attr( $value ) === esc_attr( $checked ) ) {
|
||||
$attrs['checked'] = 'checked';
|
||||
$is_selected = true;
|
||||
}
|
||||
|
||||
// Check if is disabled.
|
||||
if ( isset( $field['disabled'] ) && acf_in_array( $value, $field['disabled'] ) ) {
|
||||
$attrs['disabled'] = 'disabled';
|
||||
}
|
||||
|
||||
// Additional HTML (the "Other" input).
|
||||
$additional_html = '';
|
||||
if ( $value === 'other' && $other_input ) {
|
||||
$additional_html = ' ' . acf_get_text_input( $other_input );
|
||||
}
|
||||
|
||||
// append
|
||||
$e .= '<li><label' . ( $is_selected ? ' class="selected"' : '' ) . '><input ' . acf_esc_attrs( $attrs ) . '/>' . acf_esc_html( $label ) . '</label>' . $additional_html . '</li>';
|
||||
}
|
||||
|
||||
// Close <ul>.
|
||||
$e .= '</ul>';
|
||||
|
||||
// Output HTML.
|
||||
echo $e; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped per attribute above.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
// Encode choices (convert from array).
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'type' => 'textarea',
|
||||
'name' => 'choices',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Other Choice', 'acf' ),
|
||||
'name' => 'other_choice',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Add 'other' choice to allow for custom values", 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Other Choice', 'acf' ),
|
||||
'name' => 'save_other_choice',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Save 'other' values to the field's choices", 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'other_choice',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Layout', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'vertical' => __( 'Vertical', 'acf' ),
|
||||
'horizontal' => __( 'Horizontal', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the field group ID (post_type = acf)
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
function update_field( $field ) {
|
||||
|
||||
// decode choices (convert to array)
|
||||
$field['choices'] = acf_decode_choices( $field['choices'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
* @todo Fix bug where $field was found via json and has no ID
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value (allow 0 to be saved)
|
||||
if ( ! $value && ! is_numeric( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// save_other_choice
|
||||
if ( $field['save_other_choice'] ) {
|
||||
|
||||
// value isn't in choices yet
|
||||
if ( ! isset( $field['choices'][ $value ] ) ) {
|
||||
|
||||
// get raw $field (may have been changed via repeater field)
|
||||
// if field is local, it won't have an ID
|
||||
$selector = $field['ID'] ? $field['ID'] : $field['key'];
|
||||
$field = acf_get_field( $selector );
|
||||
|
||||
// bail early if no ID (JSON only)
|
||||
if ( ! $field['ID'] ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// unslash (fixes serialize single quote issue)
|
||||
$value = wp_unslash( $value );
|
||||
|
||||
// sanitize (remove tags)
|
||||
$value = sanitize_text_field( $value );
|
||||
|
||||
// update $field
|
||||
$field['choices'][ $value ] = $value;
|
||||
|
||||
// save
|
||||
acf_update_field( $field );
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.2.9
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value found in the database
|
||||
* @param $post_id - the post_id from which the value was loaded from
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the value to be saved in te database
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// must be single value
|
||||
if ( is_array( $value ) ) {
|
||||
$value = array_pop( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
function translate_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'select' )->translate_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
return acf_get_field_type( 'select' )->format_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
// If other/custom choices are allowed, nothing else to do here.
|
||||
if ( ! empty( $field['other_choice'] ) ) {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
$schema['enum'] = acf_get_field_type( 'select' )->format_rest_choices( $field['choices'] );
|
||||
|
||||
if ( ! empty( $field['allow_null'] ) ) {
|
||||
$schema['enum'][] = null;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_radio' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_range' ) ) :
|
||||
|
||||
class acf_field_range extends acf_field_number {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'range';
|
||||
$this->label = __( 'Range', 'acf' );
|
||||
$this->description = __( 'An input for selecting a numerical value within a specified range using a range slider element.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-range.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/range/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'min' => '',
|
||||
'max' => '',
|
||||
'step' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'min', 'max', 'step' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
|
||||
// step
|
||||
if ( ! $field['step'] ) {
|
||||
$field['step'] = 1;
|
||||
}
|
||||
|
||||
// min / max
|
||||
if ( ! $field['min'] ) {
|
||||
$field['min'] = 0;
|
||||
}
|
||||
if ( ! $field['max'] ) {
|
||||
$field['max'] = 100;
|
||||
}
|
||||
|
||||
// allow for prev 'non numeric' value
|
||||
if ( ! is_numeric( $field['value'] ) ) {
|
||||
$field['value'] = 0;
|
||||
}
|
||||
|
||||
// constrain within max and min
|
||||
$field['value'] = max( $field['value'], $field['min'] );
|
||||
$field['value'] = min( $field['value'], $field['max'] );
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// open
|
||||
$html = '<div class="acf-range-wrap">';
|
||||
|
||||
// prepend
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
$html .= '<div class="acf-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
}
|
||||
|
||||
// range
|
||||
$html .= acf_get_text_input( $atts );
|
||||
|
||||
// Calculate input width based on the largest possible input character length.
|
||||
// Also take into account the step size for decimal steps minus - 1.5 chars for leading "0.".
|
||||
$len = max(
|
||||
strlen( strval( $field['min'] ) ),
|
||||
strlen( strval( $field['max'] ) )
|
||||
);
|
||||
if ( floatval( $atts['step'] ) < 1 ) {
|
||||
$len += strlen( strval( $field['step'] ) ) - 1.5;
|
||||
}
|
||||
|
||||
// input
|
||||
$html .= acf_get_text_input(
|
||||
array(
|
||||
'type' => 'number',
|
||||
'id' => $atts['id'] . '-alt',
|
||||
'value' => $atts['value'],
|
||||
'step' => $atts['step'],
|
||||
// 'min' => $atts['min'], // removed to avoid browser validation errors
|
||||
// 'max' => $atts['max'],
|
||||
'style' => 'width: ' . ( 1.8 + $len * 0.7 ) . 'em;',
|
||||
)
|
||||
);
|
||||
|
||||
// append
|
||||
if ( $field['append'] !== '' ) {
|
||||
$html .= '<div class="acf-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
}
|
||||
|
||||
// close
|
||||
$html .= '</div>';
|
||||
|
||||
// return
|
||||
echo $html; //phpcs:ignore WordPress.Security.EscapeOutput -- Only populated with already escaped HTML.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
'placeholder' => '0',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
'placeholder' => '100',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Step Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'step',
|
||||
'placeholder' => '1',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'number', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'minimum' => empty( $field['min'] ) ? 0 : (int) $field['min'],
|
||||
'maximum' => empty( $field['max'] ) ? 100 : (int) $field['max'],
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && is_numeric( $field['default_value'] ) ) {
|
||||
$schema['default'] = (int) $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_range' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,888 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_relationship' ) ) :
|
||||
|
||||
class acf_field_relationship extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'relationship';
|
||||
$this->label = __( 'Relationship', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'A dual-column interface to select one or more posts, pages, or custom post type items to create a relationship with the item that you\'re currently editing. Includes options to search and filter.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-relationship.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/relationship/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'post_type' => array(),
|
||||
'taxonomy' => array(),
|
||||
'min' => 0,
|
||||
'max' => 0,
|
||||
'filters' => array( 'search', 'post_type', 'taxonomy' ),
|
||||
'elements' => array(),
|
||||
'return_format' => 'object',
|
||||
'bidirectional_target' => array(),
|
||||
);
|
||||
add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_relation_conditional_choices' ), 10, 3 );
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/relationship/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/relationship/query', array( $this, 'ajax_query' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters choices in relation conditions.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $choices The selected choice.
|
||||
* @param array $conditional_field The conditional field settings object.
|
||||
* @param string $rule_value The rule value.
|
||||
* @return array
|
||||
*/
|
||||
public function render_field_relation_conditional_choices( $choices, $conditional_field, $rule_value ) {
|
||||
if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'relationship' ) {
|
||||
return $choices;
|
||||
}
|
||||
if ( ! empty( $rule_value ) ) {
|
||||
$post_title = get_the_title( $rule_value );
|
||||
$choices = array( $rule_value => $post_title );
|
||||
}
|
||||
return $choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// localize
|
||||
acf_localize_text(
|
||||
array(
|
||||
// 'Minimum values reached ( {min} values )' => __('Minimum values reached ( {min} values )', 'acf'),
|
||||
'Maximum values reached ( {max} values )' => __( 'Maximum values reached ( {max} values )', 'acf' ),
|
||||
'Loading' => __( 'Loading', 'acf' ),
|
||||
'No matches found' => __( 'No matches found', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AJAX results for the Relationship field.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_query() {
|
||||
$nonce = acf_request_arg( 'nonce', '' );
|
||||
$key = acf_request_arg( 'field_key', '' );
|
||||
$conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
|
||||
|
||||
if ( $conditional_logic ) {
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Use the standard ACF admin nonce.
|
||||
$nonce = '';
|
||||
$key = '';
|
||||
}
|
||||
|
||||
if ( ! acf_verify_ajax( $nonce, $key, ! $conditional_logic ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param array $options An array of options for the query.
|
||||
* @return array
|
||||
*/
|
||||
public function get_ajax_query( $options = array() ) {
|
||||
// defaults
|
||||
$options = wp_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
'post_type' => '',
|
||||
'include' => '',
|
||||
'taxonomy' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$args = array();
|
||||
$s = false;
|
||||
$is_search = false;
|
||||
|
||||
// paged
|
||||
$args['posts_per_page'] = 20;
|
||||
$args['paged'] = intval( $options['paged'] );
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' && empty( $options['include'] ) ) {
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
// update vars
|
||||
$args['s'] = $s;
|
||||
$is_search = true;
|
||||
}
|
||||
|
||||
// post_type
|
||||
if ( ! empty( $options['post_type'] ) ) {
|
||||
$args['post_type'] = acf_get_array( $options['post_type'] );
|
||||
} elseif ( ! empty( $field['post_type'] ) ) {
|
||||
$args['post_type'] = acf_get_array( $field['post_type'] );
|
||||
} else {
|
||||
$args['post_type'] = acf_get_post_types();
|
||||
}
|
||||
|
||||
// post status
|
||||
if ( ! empty( $options['post_status'] ) ) {
|
||||
$args['post_status'] = acf_get_array( $options['post_status'] );
|
||||
} elseif ( ! empty( $field['post_status'] ) ) {
|
||||
$args['post_status'] = acf_get_array( $field['post_status'] );
|
||||
}
|
||||
|
||||
// taxonomy
|
||||
if ( ! empty( $options['taxonomy'] ) ) {
|
||||
|
||||
// vars
|
||||
$term = acf_decode_taxonomy_term( $options['taxonomy'] );
|
||||
|
||||
// tax query
|
||||
$args['tax_query'] = array();
|
||||
|
||||
// append
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $term['taxonomy'],
|
||||
'field' => 'slug',
|
||||
'terms' => $term['term'],
|
||||
);
|
||||
} elseif ( ! empty( $field['taxonomy'] ) ) {
|
||||
|
||||
// vars
|
||||
$terms = acf_decode_taxonomy_terms( $field['taxonomy'] );
|
||||
|
||||
// append to $args
|
||||
$args['tax_query'] = array(
|
||||
'relation' => 'OR',
|
||||
);
|
||||
|
||||
// now create the tax queries
|
||||
foreach ( $terms as $k => $v ) {
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $k,
|
||||
'field' => 'slug',
|
||||
'terms' => $v,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $options['include'] ) ) {
|
||||
// If we have an include, we need to return only the selected posts.
|
||||
$args['post__in'] = array( $options['include'] );
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/relationship/query', $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/relationship/query/name=' . $field['name'], $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/relationship/query/key=' . $field['key'], $args, $field, $options['post_id'] );
|
||||
|
||||
// get posts grouped by post type
|
||||
$groups = acf_get_grouped_posts( $args );
|
||||
|
||||
// bail early if no posts
|
||||
if ( empty( $groups ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( array_keys( $groups ) as $group_title ) {
|
||||
|
||||
// vars
|
||||
$posts = acf_extract_var( $groups, $group_title );
|
||||
|
||||
// data
|
||||
$data = array(
|
||||
'text' => $group_title,
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
// convert post objects to post titles
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
$posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'] );
|
||||
}
|
||||
|
||||
// order posts by search
|
||||
if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
|
||||
$posts = acf_order_by_search( $posts, $args['s'] );
|
||||
}
|
||||
|
||||
// append to $data
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
$data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
|
||||
}
|
||||
|
||||
// append to $results
|
||||
$results[] = $data;
|
||||
}
|
||||
|
||||
// add as optgroup or results
|
||||
if ( count( $args['post_type'] ) == 1 ) {
|
||||
$results = $results[0]['children'];
|
||||
}
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
'limit' => $args['posts_per_page'],
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array containing id, text and maybe description data
|
||||
*
|
||||
* @type function
|
||||
* @date 7/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $id (mixed)
|
||||
* @param $text (string)
|
||||
* @return (array)
|
||||
*/
|
||||
function get_post_result( $id, $text ) {
|
||||
|
||||
// vars
|
||||
$result = array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
|
||||
// return
|
||||
return $result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function returns the HTML for a result
|
||||
*
|
||||
* @type function
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post (object)
|
||||
* @param $field (array)
|
||||
* @param $post_id (int) the post_id to which this value is saved to
|
||||
* @return (string)
|
||||
*/
|
||||
function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
|
||||
|
||||
// get post_id
|
||||
if ( ! $post_id ) {
|
||||
$post_id = acf_get_form_data( 'post_id' );
|
||||
}
|
||||
|
||||
// vars
|
||||
$title = acf_get_post_title( $post, $is_search );
|
||||
|
||||
// featured_image
|
||||
if ( acf_in_array( 'featured_image', $field['elements'] ) ) {
|
||||
|
||||
// vars
|
||||
$class = 'thumbnail';
|
||||
$thumbnail = acf_get_post_thumbnail( $post->ID, array( 17, 17 ) );
|
||||
|
||||
// icon
|
||||
if ( $thumbnail['type'] == 'icon' ) {
|
||||
$class .= ' -' . $thumbnail['type'];
|
||||
}
|
||||
|
||||
// append
|
||||
$title = '<div class="' . $class . '">' . $thumbnail['html'] . '</div>' . $title;
|
||||
}
|
||||
|
||||
// filters
|
||||
$title = apply_filters( 'acf/fields/relationship/result', $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/relationship/result/name=' . $field['_name'], $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/relationship/result/key=' . $field['key'], $title, $post, $field, $post_id );
|
||||
|
||||
// return
|
||||
return $title;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$post_type = acf_get_array( $field['post_type'] );
|
||||
$taxonomy = acf_get_array( $field['taxonomy'] );
|
||||
$filters = acf_get_array( $field['filters'] );
|
||||
|
||||
// filters
|
||||
$filter_count = count( $filters );
|
||||
$filter_post_type_choices = array();
|
||||
$filter_taxonomy_choices = array();
|
||||
|
||||
// post_type filter
|
||||
if ( in_array( 'post_type', $filters ) ) {
|
||||
$filter_post_type_choices = array(
|
||||
'' => __( 'Select post type', 'acf' ),
|
||||
) + acf_get_pretty_post_types( $post_type );
|
||||
}
|
||||
|
||||
// taxonomy filter
|
||||
if ( in_array( 'taxonomy', $filters ) ) {
|
||||
$term_choices = array();
|
||||
$filter_taxonomy_choices = array(
|
||||
'' => __( 'Select taxonomy', 'acf' ),
|
||||
);
|
||||
|
||||
// check for specific taxonomy setting
|
||||
if ( $taxonomy ) {
|
||||
$terms = acf_get_encoded_terms( $taxonomy );
|
||||
$term_choices = acf_get_choices_from_terms( $terms, 'slug' );
|
||||
|
||||
// if no terms were specified, find all terms
|
||||
} else {
|
||||
|
||||
// restrict taxonomies by the post_type selected
|
||||
$term_args = array();
|
||||
if ( $post_type ) {
|
||||
$term_args['taxonomy'] = acf_get_taxonomies(
|
||||
array(
|
||||
'post_type' => $post_type,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// get terms
|
||||
$terms = acf_get_grouped_terms( $term_args );
|
||||
$term_choices = acf_get_choices_from_grouped_terms( $terms, 'slug' );
|
||||
}
|
||||
|
||||
// append term choices
|
||||
$filter_taxonomy_choices = $filter_taxonomy_choices + $term_choices;
|
||||
}
|
||||
|
||||
// div attributes
|
||||
$atts = array(
|
||||
'id' => $field['id'],
|
||||
'class' => "acf-relationship {$field['class']}",
|
||||
'data-min' => $field['min'],
|
||||
'data-max' => $field['max'],
|
||||
'data-s' => '',
|
||||
'data-paged' => 1,
|
||||
'data-post_type' => '',
|
||||
'data-taxonomy' => '',
|
||||
'data-nonce' => wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] ),
|
||||
);
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $atts ); ?>>
|
||||
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => '',
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<?php
|
||||
|
||||
/* filters */
|
||||
if ( $filter_count ) :
|
||||
?>
|
||||
<div class="filters -f<?php echo esc_attr( $filter_count ); ?>">
|
||||
<?php
|
||||
|
||||
/* search */
|
||||
if ( in_array( 'search', $filters ) ) :
|
||||
?>
|
||||
<div class="filter -search">
|
||||
<?php
|
||||
acf_text_input(
|
||||
array(
|
||||
'placeholder' => __( 'Search...', 'acf' ),
|
||||
'data-filter' => 's',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
/* post_type */
|
||||
if ( in_array( 'post_type', $filters ) ) :
|
||||
?>
|
||||
<div class="filter -post_type">
|
||||
<?php
|
||||
acf_select_input(
|
||||
array(
|
||||
'choices' => $filter_post_type_choices,
|
||||
'data-filter' => 'post_type',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
/* post_type */
|
||||
if ( in_array( 'taxonomy', $filters ) ) :
|
||||
?>
|
||||
<div class="filter -taxonomy">
|
||||
<?php
|
||||
acf_select_input(
|
||||
array(
|
||||
'choices' => $filter_taxonomy_choices,
|
||||
'data-filter' => 'taxonomy',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="selection">
|
||||
<div class="choices">
|
||||
<ul class="acf-bl list choices-list"></ul>
|
||||
</div>
|
||||
<div class="values">
|
||||
<ul class="acf-bl list values-list">
|
||||
<?php
|
||||
if ( ! empty( $field['value'] ) ) :
|
||||
|
||||
// get posts
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $field['value'],
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
// loop
|
||||
foreach ( $posts as $post ) :
|
||||
?>
|
||||
<li>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'] . '[]',
|
||||
'value' => $post->ID,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<span tabindex="0" data-id="<?php echo esc_attr( $post->ID ); ?>" class="acf-rel-item acf-rel-item-remove">
|
||||
<?php echo acf_esc_html( $this->get_post_title( $post, $field ) ); ?>
|
||||
<a href="#" class="acf-icon -minus small dark" data-name="remove_item"></a>
|
||||
</span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_type',
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All post types', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Status', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_status',
|
||||
'choices' => acf_get_pretty_post_statuses(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'Any post status', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Taxonomy', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_terms(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All taxonomies', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filters', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'checkbox',
|
||||
'name' => 'filters',
|
||||
'choices' => array(
|
||||
'search' => __( 'Search', 'acf' ),
|
||||
'post_type' => __( 'Post Type', 'acf' ),
|
||||
'taxonomy' => __( 'Taxonomy', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'object' => __( 'Post Object', 'acf' ),
|
||||
'id' => __( 'Post ID', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
$field['min'] = empty( $field['min'] ) ? '' : $field['min'];
|
||||
$field['max'] = empty( $field['max'] ) ? '' : $field['max'];
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum Posts', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum Posts', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Elements', 'acf' ),
|
||||
'instructions' => __( 'Selected elements will be displayed in each result', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'elements',
|
||||
'choices' => array(
|
||||
'featured_image' => __( 'Featured Image', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Advanced" tab.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_advanced_settings( $field ) {
|
||||
acf_render_bidirectional_field_settings( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is applied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// force value to array
|
||||
$value = acf_get_array( $value );
|
||||
|
||||
// convert to int
|
||||
$value = array_map( 'intval', $value );
|
||||
|
||||
// load posts if needed
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
|
||||
// get posts
|
||||
$value = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $value,
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// default
|
||||
if ( empty( $value ) || ! is_array( $value ) ) {
|
||||
$value = array();
|
||||
}
|
||||
|
||||
// min
|
||||
if ( count( $value ) < $field['min'] ) {
|
||||
$valid = _n( '%1$s requires at least %2$s selection', '%1$s requires at least %2$s selections', $field['min'], 'acf' );
|
||||
$valid = sprintf( $valid, $field['label'], $field['min'] );
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters the field value before it is saved into the database.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which will be saved in the database.
|
||||
* @param integer $post_id The post_id of which the value will be saved.
|
||||
* @param array $field The field array holding all the field options.
|
||||
*
|
||||
* @return mixed $value The modified value.
|
||||
*/
|
||||
public function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
acf_update_bidirectional_values( array(), $post_id, $field );
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_idval( $value );
|
||||
}
|
||||
|
||||
acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field );
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates relationship fields updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return acf_get_field_type( 'post_object' )->validate_rest_value( $valid, $value, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( ! empty( $field['min'] ) ) {
|
||||
$schema['minItems'] = (int) $field['min'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max'] ) ) {
|
||||
$schema['maxItems'] = (int) $field['max'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
$links = array();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
foreach ( (array) $value as $object_id ) {
|
||||
if ( ! $post_type = get_post_type( $object_id ) or ! $post_type = get_post_type_object( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
$rest_base = acf_get_object_type_rest_base( $post_type );
|
||||
$links[] = array(
|
||||
'rel' => $post_type->name === 'attachment' ? 'acf:attachment' : 'acf:post',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_relationship' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,769 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_select' ) ) :
|
||||
|
||||
class acf_field_select extends acf_field {
|
||||
|
||||
/**
|
||||
* Sets up the field type data.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'select';
|
||||
$this->label = _x( 'Select', 'noun', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A dropdown list with a selection of choices that you specify.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-select.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/select/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'multiple' => 0,
|
||||
'allow_null' => 0,
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'ui' => 0,
|
||||
'ajax' => 0,
|
||||
'placeholder' => '',
|
||||
'return_format' => 'value',
|
||||
'create_options' => 0,
|
||||
'save_options' => 0,
|
||||
);
|
||||
|
||||
add_action( 'wp_ajax_acf/fields/select/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/select/query', array( $this, 'ajax_query' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues admin scripts for the Select field.
|
||||
*
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function input_admin_enqueue_scripts() {
|
||||
// Bail early if not enqueuing select2.
|
||||
if ( ! acf_get_setting( 'enqueue_select2' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
global $wp_scripts;
|
||||
|
||||
$min = defined( 'ACF_DEVELOPMENT_MODE' ) && ACF_DEVELOPMENT_MODE ? '' : '.min';
|
||||
$major = acf_get_setting( 'select2_version' );
|
||||
|
||||
// attempt to find 3rd party Select2 version
|
||||
// - avoid including v3 CSS when v4 JS is already enqueued.
|
||||
if ( isset( $wp_scripts->registered['select2'] ) ) {
|
||||
$major = (int) $wp_scripts->registered['select2']->ver;
|
||||
}
|
||||
|
||||
if ( $major === 3 ) {
|
||||
// Use v3 if necessary.
|
||||
$version = '3.5.2';
|
||||
$script = acf_get_url( "assets/inc/select2/3/select2{$min}.js" );
|
||||
$style = acf_get_url( 'assets/inc/select2/3/select2.css' );
|
||||
} else {
|
||||
// Default to v4.
|
||||
$version = '4.0.13';
|
||||
$script = acf_get_url( "assets/inc/select2/4/select2.full{$min}.js" );
|
||||
$style = acf_get_url( "assets/inc/select2/4/select2{$min}.css" );
|
||||
}
|
||||
|
||||
wp_enqueue_script( 'select2', $script, array( 'jquery' ), $version );
|
||||
wp_enqueue_style( 'select2', $style, '', $version );
|
||||
|
||||
acf_localize_data(
|
||||
array(
|
||||
'select2L10n' => array(
|
||||
'matches_1' => _x( 'One result is available, press enter to select it.', 'Select2 JS matches_1', 'acf' ),
|
||||
/* translators: %d - number of results available in select field */
|
||||
'matches_n' => _x( '%d results are available, use up and down arrow keys to navigate.', 'Select2 JS matches_n', 'acf' ),
|
||||
'matches_0' => _x( 'No matches found', 'Select2 JS matches_0', 'acf' ),
|
||||
'input_too_short_1' => _x( 'Please enter 1 or more characters', 'Select2 JS input_too_short_1', 'acf' ),
|
||||
/* translators: %d - number of characters to enter into select field input */
|
||||
'input_too_short_n' => _x( 'Please enter %d or more characters', 'Select2 JS input_too_short_n', 'acf' ),
|
||||
'input_too_long_1' => _x( 'Please delete 1 character', 'Select2 JS input_too_long_1', 'acf' ),
|
||||
/* translators: %d - number of characters that should be removed from select field */
|
||||
'input_too_long_n' => _x( 'Please delete %d characters', 'Select2 JS input_too_long_n', 'acf' ),
|
||||
'selection_too_long_1' => _x( 'You can only select 1 item', 'Select2 JS selection_too_long_1', 'acf' ),
|
||||
/* translators: %d - maximum number of items that can be selected in the select field */
|
||||
'selection_too_long_n' => _x( 'You can only select %d items', 'Select2 JS selection_too_long_n', 'acf' ),
|
||||
'load_more' => _x( 'Loading more results…', 'Select2 JS load_more', 'acf' ),
|
||||
'searching' => _x( 'Searching…', 'Select2 JS searching', 'acf' ),
|
||||
'load_fail' => _x( 'Loading failed', 'Select2 JS load_fail', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for getting Select field choices.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_query() {
|
||||
$nonce = acf_request_arg( 'nonce', '' );
|
||||
$key = acf_request_arg( 'field_key', '' );
|
||||
|
||||
$is_field_key = acf_is_field_key( $key );
|
||||
|
||||
// Back-compat for field settings.
|
||||
if ( ! $is_field_key ) {
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
$nonce = '';
|
||||
$key = '';
|
||||
}
|
||||
|
||||
if ( ! acf_verify_ajax( $nonce, $key, $is_field_key ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param array $options An array of options.
|
||||
* @return array A select2 compatible array of options.
|
||||
*/
|
||||
public function get_ajax_query( $options = array() ) {
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
$shortcut = apply_filters( 'acf/fields/select/query', array(), $options );
|
||||
$shortcut = apply_filters( 'acf/fields/select/query/key=' . $options['field_key'], $shortcut, $options );
|
||||
if ( ! empty( $shortcut ) ) {
|
||||
return $shortcut;
|
||||
}
|
||||
|
||||
// load field.
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get choices.
|
||||
$choices = acf_get_array( $field['choices'] );
|
||||
if ( empty( $field['choices'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
$s = null;
|
||||
|
||||
// search.
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = strval( $options['s'] );
|
||||
$s = wp_unslash( $s );
|
||||
}
|
||||
|
||||
foreach ( $field['choices'] as $k => $v ) {
|
||||
|
||||
// ensure $v is a string.
|
||||
$v = strval( $v );
|
||||
|
||||
// if searching, but doesn't exist.
|
||||
if ( is_string( $s ) && stripos( $v, $s ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append results.
|
||||
$results[] = array(
|
||||
'id' => $k,
|
||||
'text' => $v,
|
||||
);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the HTML interface for the field.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array holding all the field's data.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
$value = acf_get_array( $field['value'] );
|
||||
$choices = acf_get_array( $field['choices'] );
|
||||
|
||||
if ( empty( $field['placeholder'] ) ) {
|
||||
$field['placeholder'] = _x( 'Select', 'verb', 'acf' );
|
||||
}
|
||||
|
||||
// Add empty value (allows '' to be selected).
|
||||
if ( empty( $value ) ) {
|
||||
$value = array( '' );
|
||||
}
|
||||
|
||||
// prepend empty choice
|
||||
// - only for single selects
|
||||
// - have tried array_merge but this causes keys to re-index if is numeric (post ID's)
|
||||
if ( $field['allow_null'] && ! $field['multiple'] ) {
|
||||
$choices = array( '' => "- {$field['placeholder']} -" ) + $choices;
|
||||
}
|
||||
|
||||
// clean up choices if using ajax
|
||||
if ( $field['ui'] && $field['ajax'] ) {
|
||||
$minimal = array();
|
||||
foreach ( $value as $key ) {
|
||||
if ( isset( $choices[ $key ] ) ) {
|
||||
$minimal[ $key ] = $choices[ $key ];
|
||||
}
|
||||
}
|
||||
$choices = $minimal;
|
||||
}
|
||||
|
||||
$select = array(
|
||||
'id' => $field['id'],
|
||||
'class' => $field['class'],
|
||||
'name' => $field['name'],
|
||||
'data-ui' => $field['ui'],
|
||||
'data-ajax' => $field['ajax'],
|
||||
'data-multiple' => $field['multiple'],
|
||||
'data-placeholder' => $field['placeholder'],
|
||||
'data-allow_null' => $field['allow_null'],
|
||||
);
|
||||
|
||||
if ( ! empty( $field['aria-label'] ) ) {
|
||||
$select['aria-label'] = $field['aria-label'];
|
||||
}
|
||||
|
||||
if ( $field['multiple'] ) {
|
||||
$select['multiple'] = 'multiple';
|
||||
$select['size'] = 5;
|
||||
$select['name'] .= '[]';
|
||||
|
||||
// Reduce size to single line if UI.
|
||||
if ( $field['ui'] ) {
|
||||
$select['size'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $field['create_options'] ) && $field['ui'] ) {
|
||||
$select['data-create_options'] = true;
|
||||
}
|
||||
|
||||
// special atts
|
||||
if ( ! empty( $field['readonly'] ) ) {
|
||||
$select['readonly'] = 'readonly';
|
||||
}
|
||||
if ( ! empty( $field['disabled'] ) ) {
|
||||
$select['disabled'] = 'disabled';
|
||||
}
|
||||
if ( ! empty( $field['ajax_action'] ) ) {
|
||||
$select['data-ajax_action'] = $field['ajax_action'];
|
||||
}
|
||||
if ( ! empty( $field['nonce'] ) ) {
|
||||
$select['data-nonce'] = $field['nonce'];
|
||||
}
|
||||
if ( $field['ajax'] && empty( $field['nonce'] ) && acf_is_field_key( $field['key'] ) ) {
|
||||
$select['data-nonce'] = wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] );
|
||||
}
|
||||
if ( ! empty( $field['hide_search'] ) ) {
|
||||
$select['data-minimum-results-for-search'] = '-1';
|
||||
}
|
||||
|
||||
// Hidden input is needed to allow validation to see <select> element with no selected value.
|
||||
if ( $field['multiple'] || $field['ui'] ) {
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'id' => $field['id'] . '-input',
|
||||
'name' => $field['name'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$select['value'] = $value;
|
||||
$select['choices'] = $choices;
|
||||
|
||||
if ( ! empty( $field['create_options'] ) && $field['ui'] && is_array( $field['value'] ) ) {
|
||||
foreach ( $field['value'] as $value ) {
|
||||
// Already exists in choices.
|
||||
if ( isset( $field['choices'][ $value ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$option = esc_attr( $value );
|
||||
|
||||
$select['choices'][ $option ] = $option;
|
||||
}
|
||||
}
|
||||
|
||||
acf_select_input( $select );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "General" tab.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array holding all the field's data.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_settings( $field ) {
|
||||
|
||||
// encode choices (convert from array)
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_encode_choices( $field['default_value'], false );
|
||||
|
||||
// choices
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'name' => 'choices',
|
||||
'type' => 'textarea',
|
||||
)
|
||||
);
|
||||
|
||||
// default_value
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Enter each default value on a new line', 'acf' ),
|
||||
'name' => 'default_value',
|
||||
'type' => 'textarea',
|
||||
)
|
||||
);
|
||||
|
||||
// return_format
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => __( 'Specify the value returned', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select Multiple', 'acf' ),
|
||||
'instructions' => 'Allow content editors to select multiple values',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Stylized UI', 'acf' ),
|
||||
'instructions' => __( 'Use a stylized checkbox using select2', 'acf' ),
|
||||
'name' => 'ui',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Use AJAX to lazy load choices?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'ajax',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'conditions' => array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Create Options', 'acf' ),
|
||||
'instructions' => __( 'Allow content editors to create new options by typing in the Select input. Multiple options can be created from a comma separated string.', 'acf' ),
|
||||
'name' => 'create_options',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'conditions' => array(
|
||||
array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
array(
|
||||
'field' => 'multiple',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Options', 'acf' ),
|
||||
'instructions' => __( 'Save created options back to the "Choices" setting in the field definition.', 'acf' ),
|
||||
'name' => 'save_options',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'conditions' => array(
|
||||
array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
array(
|
||||
'field' => 'multiple',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
array(
|
||||
'field' => 'create_options',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $value after it is loaded from the db.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value found in the database.
|
||||
* @param integer|string $post_id The post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return mixed
|
||||
*/
|
||||
public function load_value( $value, $post_id, $field ) {
|
||||
// Return an array when field is set for multiple.
|
||||
if ( $field['multiple'] ) {
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return array();
|
||||
}
|
||||
return acf_array( $value );
|
||||
}
|
||||
|
||||
// Otherwise, return a single value.
|
||||
return acf_unarray( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $field before it is saved to the database.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return array
|
||||
*/
|
||||
public function update_field( $field ) {
|
||||
// Decode choices (convert to array).
|
||||
$field['choices'] = acf_decode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_decode_choices( $field['default_value'], true );
|
||||
|
||||
// Convert back to string for single selects.
|
||||
if ( ! $field['multiple'] ) {
|
||||
$field['default_value'] = acf_unarray( $field['default_value'] );
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $value before it is updated in the db.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which will be saved in the database.
|
||||
* @param integer|string $post_id The post_id of which the value will be saved.
|
||||
* @param array $field The field array holding all the field options.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function update_value( $value, $post_id, $field ) {
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - Parse each value as string for SQL LIKE queries.
|
||||
if ( is_array( $value ) ) {
|
||||
$value = array_map( 'strval', $value );
|
||||
}
|
||||
|
||||
// Save custom options back to the field definition if configured.
|
||||
if ( ! empty( $field['save_options'] ) && is_array( $value ) ) {
|
||||
// Get the raw field, using the ID if present or the key otherwise (i.e. when using JSON).
|
||||
$selector = $field['ID'] ? $field['ID'] : $field['key'];
|
||||
$field = acf_get_field( $selector );
|
||||
|
||||
// Bail if we don't have a valid field or field ID (JSON only).
|
||||
if ( empty( $field['ID'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
foreach ( $value as $v ) {
|
||||
// Ignore if the option already exists.
|
||||
if ( isset( $field['choices'][ $v ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unslash (fixes serialize single quote issue) and sanitize.
|
||||
$v = wp_unslash( $v );
|
||||
$v = sanitize_text_field( $v );
|
||||
|
||||
// Append to the field choices.
|
||||
$field['choices'][ $v ] = $v;
|
||||
}
|
||||
|
||||
acf_update_field( $field );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the field settings.
|
||||
*
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param array $field The main field array.
|
||||
* @return array
|
||||
*/
|
||||
public function translate_field( $field ) {
|
||||
$field['choices'] = acf_translate( $field['choices'] );
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters the $value after it is loaded from the db, and before it is returned to the template.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database.
|
||||
* @param integer|string $post_id The post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
if ( is_array( $value ) ) {
|
||||
foreach ( $value as $i => $val ) {
|
||||
$value[ $i ] = $this->format_value_single( $val, $post_id, $field );
|
||||
}
|
||||
} else {
|
||||
$value = $this->format_value_single( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the value when the select is not a multi-select.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value to format.
|
||||
* @param integer|string $post_id The post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_single( $value, $post_id, $field ) {
|
||||
// Bail early if is empty.
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
$label = acf_maybe_get( $field['choices'], $value, $value );
|
||||
|
||||
if ( $field['return_format'] === 'label' ) {
|
||||
$value = $label;
|
||||
} elseif ( $field['return_format'] === 'array' ) {
|
||||
$value = array(
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
);
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates select fields updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
// rest_validate_request_arg() handles the other types, we just worry about strings.
|
||||
if ( is_null( $value ) || is_array( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
$option_keys = array_diff(
|
||||
array_keys( $field['choices'] ),
|
||||
array_values( $field['choices'] )
|
||||
);
|
||||
|
||||
$allowed = empty( $option_keys ) ? $field['choices'] : $option_keys;
|
||||
|
||||
if ( ! in_array( $value, $allowed ) ) {
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array(
|
||||
'param' => $param,
|
||||
'value' => $value,
|
||||
);
|
||||
$error = sprintf(
|
||||
__( '%1$s is not one of %2$s', 'acf' ),
|
||||
$param,
|
||||
implode( ', ', $allowed )
|
||||
);
|
||||
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats the choices available for the REST API.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $choices The choices for the field.
|
||||
* @return array
|
||||
*/
|
||||
public function format_rest_choices( $choices ) {
|
||||
$keys = array_keys( $choices );
|
||||
$values = array_values( $choices );
|
||||
$int_choices = array();
|
||||
|
||||
if ( array_diff( $keys, $values ) ) {
|
||||
// User has specified custom keys.
|
||||
$choices = $keys;
|
||||
} else {
|
||||
// Default keys, same as value.
|
||||
$choices = $values;
|
||||
}
|
||||
|
||||
// Assume everything is a string by default.
|
||||
$choices = array_map( 'strval', $choices );
|
||||
|
||||
// Also allow integers if is_numeric().
|
||||
foreach ( $choices as $choice ) {
|
||||
if ( is_numeric( $choice ) ) {
|
||||
$int_choices[] = (int) $choice;
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge( $choices, $int_choices );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field The main field array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'string', 'array', 'int', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
'enum' => $this->format_rest_choices( $field['choices'] ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_select' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_separator' ) ) :
|
||||
|
||||
class acf_field_separator extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'separator';
|
||||
$this->label = __( 'Separator', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-separator.png';
|
||||
$this->supports = array( 'required' => false );
|
||||
$this->category = 'layout';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_separator' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,166 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_tab' ) ) :
|
||||
|
||||
class acf_field_tab extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'tab';
|
||||
$this->label = __( 'Tab', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Allows you to group fields into tabbed sections in the edit screen. Useful for keeping fields organized and structured.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-tabs.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/tab/', 'docs', 'field-type-selection' );
|
||||
$this->supports = array(
|
||||
'required' => false,
|
||||
'bindings' => false,
|
||||
);
|
||||
$this->defaults = array(
|
||||
'placement' => 'top',
|
||||
'endpoint' => 0, // added in 5.2.8
|
||||
'selected' => 0, // added in 6.3
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Output the HTML required for a tab.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array of the field data.
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
$atts = array(
|
||||
'href' => '',
|
||||
'class' => 'acf-tab-button',
|
||||
'data-placement' => $field['placement'],
|
||||
'data-endpoint' => $field['endpoint'],
|
||||
'data-key' => $field['key'],
|
||||
'data-selected' => $field['selected'],
|
||||
);
|
||||
|
||||
if ( isset( $field['unique_tab_key'] ) && ! empty( $field['unique_tab_key'] ) ) {
|
||||
$atts['data-unique-tab-key'] = $field['unique_tab_key'];
|
||||
}
|
||||
|
||||
if ( isset( $field['settings-type'] ) ) {
|
||||
$atts['data-settings-type'] = acf_slugify( $field['settings-type'] );
|
||||
$atts['class'] .= ' acf-settings-type-' . acf_slugify( $field['settings-type'] );
|
||||
}
|
||||
|
||||
if ( isset( $field['class'] ) && ! empty( $field['class'] ) ) {
|
||||
$atts['class'] .= ' ' . $field['class'];
|
||||
}
|
||||
|
||||
?>
|
||||
<a <?php echo acf_esc_attrs( $atts ); ?>><?php echo acf_esc_html( $field['label'] ); ?></a>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
|
||||
/*
|
||||
// message
|
||||
$message = '';
|
||||
$message .= '<p>' . __( 'Use "Tab Fields" to better organize your edit screen by grouping fields together.', 'acf') . '</p>';
|
||||
$message .= '<p>' . __( 'All fields following this "tab field" (or until another "tab field" is defined) will be grouped together using this field\'s label as the tab heading.','acf') . '</p>';
|
||||
|
||||
|
||||
// default_value
|
||||
acf_render_field_setting( $field, array(
|
||||
'label' => __('Instructions','acf'),
|
||||
'instructions' => '',
|
||||
'name' => 'notes',
|
||||
'type' => 'message',
|
||||
'message' => $message,
|
||||
));
|
||||
*/
|
||||
|
||||
// preview_size
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placement', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'placement',
|
||||
'choices' => array(
|
||||
'top' => __( 'Top aligned', 'acf' ),
|
||||
'left' => __( 'Left aligned', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// endpoint
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'New Tab Group', 'acf' ),
|
||||
'instructions' => __( 'Start a new group of tabs at this tab.', 'acf' ),
|
||||
'name' => 'endpoint',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove instructions
|
||||
$field['instructions'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_tab' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,960 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_taxonomy' ) ) :
|
||||
|
||||
class acf_field_taxonomy extends acf_field {
|
||||
|
||||
// vars
|
||||
var $save_post_terms = array();
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'taxonomy';
|
||||
$this->label = __( 'Taxonomy', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'Allows the selection of one or more taxonomy terms based on the criteria and options specified in the fields settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-taxonomy.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/taxonomy/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'taxonomy' => 'category',
|
||||
'field_type' => 'checkbox',
|
||||
'multiple' => 0,
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'id',
|
||||
'add_term' => 1, // 5.2.3
|
||||
'load_terms' => 0, // 5.2.7
|
||||
'save_terms' => 0, // 5.2.7
|
||||
'bidirectional_target' => array(),
|
||||
);
|
||||
|
||||
// Register filter variations.
|
||||
acf_add_filter_variations( 'acf/fields/taxonomy/query', array( 'name', 'key' ), 1 );
|
||||
acf_add_filter_variations( 'acf/fields/taxonomy/result', array( 'name', 'key' ), 2 );
|
||||
|
||||
// ajax
|
||||
add_action( 'wp_ajax_acf/fields/taxonomy/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/taxonomy/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_acf/fields/taxonomy/add_term', array( $this, 'ajax_add_term' ) );
|
||||
add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_taxonomy_conditional_choices' ), 10, 3 );
|
||||
|
||||
// actions
|
||||
add_action( 'acf/save_post', array( $this, 'save_post' ), 15, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns AJAX results for the Taxonomy field.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_query() {
|
||||
$nonce = acf_request_arg( 'nonce', '' );
|
||||
$key = acf_request_arg( 'field_key', '' );
|
||||
$conditional_logic = (bool) acf_request_arg( 'conditional_logic', false );
|
||||
|
||||
if ( $conditional_logic ) {
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Use the standard ACF admin nonce.
|
||||
$nonce = '';
|
||||
$key = '';
|
||||
}
|
||||
|
||||
if ( ! acf_verify_ajax( $nonce, $key, ! $conditional_logic ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
acf_send_ajax_results( $this->get_ajax_query( $_POST ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @type function
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param $options (array)
|
||||
* @return (array)
|
||||
*/
|
||||
function get_ajax_query( $options = array() ) {
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'term_id' => '',
|
||||
'include' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// if options include isset, then we are loading a specific term.
|
||||
if ( ! empty( $options['include'] ) ) {
|
||||
$options['term_id'] = $options['include'];
|
||||
// paged should be 1.
|
||||
$options['paged'] = 1;
|
||||
}
|
||||
|
||||
// Bail early if taxonomy does not exist.
|
||||
if ( ! taxonomy_exists( $field['taxonomy'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$results = array();
|
||||
$is_hierarchical = is_taxonomy_hierarchical( $field['taxonomy'] );
|
||||
$is_pagination = ( $options['paged'] > 0 );
|
||||
$is_search = false;
|
||||
$limit = 20;
|
||||
$offset = 20 * ( $options['paged'] - 1 );
|
||||
|
||||
$args = array(
|
||||
'taxonomy' => $field['taxonomy'],
|
||||
'hide_empty' => false,
|
||||
);
|
||||
|
||||
// Don't bother for hierarchial terms, we will need to load all terms anyway.
|
||||
if ( $is_pagination && ! $is_hierarchical ) {
|
||||
$args['number'] = $limit;
|
||||
$args['offset'] = $offset;
|
||||
}
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
$args['search'] = isset( $options['term_id'] ) && $options['term_id'] ? '' : $s;
|
||||
$is_search = true;
|
||||
}
|
||||
|
||||
$args = apply_filters( 'acf/fields/taxonomy/query', $args, $field, $options['post_id'] );
|
||||
|
||||
if ( ! empty( $options['include'] ) ) {
|
||||
// Limit search to a specific id if one is provided.
|
||||
$args['include'] = $options['include'];
|
||||
}
|
||||
|
||||
$terms = acf_get_terms( $args );
|
||||
|
||||
// Sort hierachial.
|
||||
if ( $is_hierarchical ) {
|
||||
$limit = acf_maybe_get( $args, 'number', $limit );
|
||||
$offset = acf_maybe_get( $args, 'offset', $offset );
|
||||
|
||||
$parent = acf_maybe_get( $args, 'parent', 0 );
|
||||
$parent = acf_maybe_get( $args, 'child_of', $parent );
|
||||
|
||||
// This will fail if a search has taken place because parents wont exist.
|
||||
if ( ! $is_search ) {
|
||||
$ordered_terms = _get_term_children( $parent, $terms, $field['taxonomy'] );
|
||||
// Check for empty array. Possible if parent did not exist within original data.
|
||||
if ( ! empty( $ordered_terms ) ) {
|
||||
$terms = $ordered_terms;
|
||||
}
|
||||
}
|
||||
|
||||
// Fake pagination.
|
||||
if ( $is_pagination && ! $options['include'] ) {
|
||||
$terms = array_slice( $terms, $offset, $limit );
|
||||
}
|
||||
}
|
||||
|
||||
// Append to r.
|
||||
foreach ( $terms as $term ) {
|
||||
|
||||
// Add to json.
|
||||
$results[] = array(
|
||||
'id' => $term->term_id,
|
||||
'text' => $this->get_term_title( $term, $field, $options['post_id'], true ),
|
||||
);
|
||||
}
|
||||
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
'limit' => $limit,
|
||||
);
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Term's title displayed in the field UI.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param WP_Term $term The term object.
|
||||
* @param array $field The field settings.
|
||||
* @param mixed $post_id The post_id being edited.
|
||||
* @param boolean $unescape Should we return an unescaped post title.
|
||||
* @return string
|
||||
*/
|
||||
function get_term_title( $term, $field, $post_id = 0, $unescape = false ) {
|
||||
$title = acf_get_term_title( $term );
|
||||
|
||||
// Default $post_id to current post being edited.
|
||||
$post_id = $post_id ? $post_id : acf_get_form_data( 'post_id' );
|
||||
|
||||
// unescape for select2 output which handles the escaping.
|
||||
if ( $unescape ) {
|
||||
$title = html_entity_decode( $title );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the term title.
|
||||
*
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $title The term title.
|
||||
* @param WP_Term $term The term object.
|
||||
* @param array $field The field settings.
|
||||
* @param (int|string) $post_id The post_id being edited.
|
||||
*/
|
||||
return apply_filters( 'acf/fields/taxonomy/result', $title, $term, $field, $post_id );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an array of terms for a given field value
|
||||
*
|
||||
* @type function
|
||||
* @date 13/06/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $value (array)
|
||||
* @return $value
|
||||
*/
|
||||
function get_terms( $value, $taxonomy = 'category' ) {
|
||||
|
||||
// load terms in 1 query to save multiple DB calls from following code
|
||||
if ( count( $value ) > 1 ) {
|
||||
$terms = acf_get_terms(
|
||||
array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'include' => $value,
|
||||
'hide_empty' => false,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// update value to include $post
|
||||
foreach ( array_keys( $value ) as $i ) {
|
||||
$value[ $i ] = get_term( $value[ $i ], $taxonomy );
|
||||
}
|
||||
|
||||
// filter out null values
|
||||
$value = array_filter( $value );
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value found in the database
|
||||
* @param $post_id - the post_id from which the value was loaded from
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the value to be saved in te database
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// get valid terms
|
||||
$value = acf_get_valid_terms( $value, $field['taxonomy'] );
|
||||
|
||||
// load_terms
|
||||
if ( $field['load_terms'] ) {
|
||||
|
||||
// Decode $post_id for $type and $id.
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
$type = $decoded['type'];
|
||||
$id = $decoded['id'];
|
||||
|
||||
if ( $type === 'block' ) {
|
||||
// Get parent block...
|
||||
}
|
||||
|
||||
// get terms
|
||||
$term_ids = wp_get_object_terms(
|
||||
$id,
|
||||
$field['taxonomy'],
|
||||
array(
|
||||
'fields' => 'ids',
|
||||
'orderby' => 'none',
|
||||
)
|
||||
);
|
||||
|
||||
// bail early if no terms
|
||||
if ( empty( $term_ids ) || is_wp_error( $term_ids ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sort
|
||||
if ( ! empty( $value ) ) {
|
||||
$order = array();
|
||||
|
||||
foreach ( $term_ids as $i => $v ) {
|
||||
$order[ $i ] = array_search( $v, $value );
|
||||
}
|
||||
|
||||
array_multisort( $order, $term_ids );
|
||||
}
|
||||
|
||||
// update value
|
||||
$value = $term_ids;
|
||||
}
|
||||
|
||||
// convert back from array if neccessary
|
||||
if ( $field['field_type'] == 'select' || $field['field_type'] == 'radio' ) {
|
||||
$value = array_shift( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Filters the field value before it is saved into the database.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which will be saved in the database.
|
||||
* @param integer $post_id The post_id of which the value will be saved.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return mixed $value The modified value.
|
||||
*/
|
||||
public function update_value( $value, $post_id, $field ) {
|
||||
|
||||
if ( is_array( $value ) ) {
|
||||
$value = array_filter( $value );
|
||||
}
|
||||
|
||||
acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field, 'term' );
|
||||
|
||||
// save_terms if enabled.
|
||||
if ( $field['save_terms'] ) {
|
||||
|
||||
// vars
|
||||
$taxonomy = $field['taxonomy'];
|
||||
|
||||
// force value to array.
|
||||
$term_ids = acf_get_array( $value );
|
||||
|
||||
// convert to int.
|
||||
$term_ids = array_map( 'intval', $term_ids );
|
||||
|
||||
// get existing term id's (from a previously saved field).
|
||||
$old_term_ids = isset( $this->save_post_terms[ $taxonomy ] ) ? $this->save_post_terms[ $taxonomy ] : array();
|
||||
|
||||
// append
|
||||
$this->save_post_terms[ $taxonomy ] = array_merge( $old_term_ids, $term_ids );
|
||||
|
||||
// if called directly from frontend update_field().
|
||||
if ( ! did_action( 'acf/save_post' ) ) {
|
||||
$this->save_post( $post_id );
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will save any terms in the save_post_terms array
|
||||
*
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param mixed $post_id The ACF post ID to save to.
|
||||
* @return void
|
||||
*/
|
||||
public function save_post( $post_id ) {
|
||||
// Check for saved terms.
|
||||
if ( ! empty( $this->save_post_terms ) ) {
|
||||
/**
|
||||
* Determine object ID allowing for non "post" $post_id (user, taxonomy, etc).
|
||||
* Although not fully supported by WordPress, non "post" objects may use the term relationships table.
|
||||
* Sharing taxonomies across object types is discouraged, but unique taxonomies work well.
|
||||
* Note: Do not attempt to restrict to "post" only. This has been attempted in 5.8.9 and later reverted.
|
||||
*/
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
$type = $decoded['type'];
|
||||
$id = $decoded['id'];
|
||||
|
||||
if ( $type === 'block' ) {
|
||||
// Get parent block...
|
||||
}
|
||||
|
||||
// Loop over taxonomies and save terms.
|
||||
foreach ( $this->save_post_terms as $taxonomy => $term_ids ) {
|
||||
wp_set_object_terms( $id, $term_ids, $taxonomy, false );
|
||||
}
|
||||
|
||||
// Reset storage.
|
||||
$this->save_post_terms = array();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// force value to array
|
||||
$value = acf_get_array( $value );
|
||||
|
||||
// load posts if needed
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
|
||||
// get posts
|
||||
$value = $this->get_terms( $value, $field['taxonomy'] );
|
||||
}
|
||||
|
||||
// convert back from array if neccessary
|
||||
if ( $field['field_type'] == 'select' || $field['field_type'] == 'radio' ) {
|
||||
$value = array_shift( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Taxonomy field.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
// force value to array
|
||||
$field['value'] = acf_get_array( $field['value'] );
|
||||
|
||||
$nonce = wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] );
|
||||
|
||||
// vars
|
||||
$div = array(
|
||||
'class' => 'acf-taxonomy-field',
|
||||
'data-save' => $field['save_terms'],
|
||||
'data-ftype' => $field['field_type'],
|
||||
'data-taxonomy' => $field['taxonomy'],
|
||||
'data-allow_null' => $field['allow_null'],
|
||||
'data-nonce' => $nonce,
|
||||
);
|
||||
// get taxonomy
|
||||
$taxonomy = get_taxonomy( $field['taxonomy'] );
|
||||
|
||||
// bail early if taxonomy does not exist
|
||||
if ( ! $taxonomy ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php if ( $field['add_term'] && current_user_can( $taxonomy->cap->manage_terms ) ) : ?>
|
||||
<div class="acf-actions -hover">
|
||||
<a href="#" class="acf-icon -plus acf-js-tooltip small" data-name="add" title="<?php echo esc_attr( $taxonomy->labels->add_new_item ); ?>"></a>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
if ( $field['field_type'] == 'select' ) {
|
||||
$field['multiple'] = 0;
|
||||
|
||||
$this->render_field_select( $field, $nonce );
|
||||
} elseif ( $field['field_type'] == 'multi_select' ) {
|
||||
$field['multiple'] = 1;
|
||||
|
||||
$this->render_field_select( $field, $nonce );
|
||||
} elseif ( $field['field_type'] == 'radio' ) {
|
||||
$this->render_field_checkbox( $field );
|
||||
} elseif ( $field['field_type'] == 'checkbox' ) {
|
||||
$this->render_field_checkbox( $field );
|
||||
}
|
||||
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_select( $field, $nonce ) {
|
||||
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['nonce'] = $nonce;
|
||||
$field['choices'] = array();
|
||||
|
||||
// value
|
||||
if ( ! empty( $field['value'] ) ) {
|
||||
|
||||
// get terms
|
||||
$terms = $this->get_terms( $field['value'], $field['taxonomy'] );
|
||||
|
||||
// set choices
|
||||
if ( ! empty( $terms ) ) {
|
||||
foreach ( array_keys( $terms ) as $i ) {
|
||||
|
||||
// vars
|
||||
$term = acf_extract_var( $terms, $i );
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $term->term_id ] = $this->get_term_title( $term, $field );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render select
|
||||
acf_render_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field an array holding all the field's data.
|
||||
*/
|
||||
public function render_field_checkbox( $field ) {
|
||||
|
||||
// hidden input.
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => $field['name'],
|
||||
)
|
||||
);
|
||||
|
||||
// checkbox saves an array.
|
||||
if ( $field['field_type'] == 'checkbox' ) {
|
||||
$field['name'] .= '[]';
|
||||
}
|
||||
|
||||
// taxonomy.
|
||||
$taxonomy_obj = get_taxonomy( $field['taxonomy'] );
|
||||
|
||||
// include walker.
|
||||
acf_include( 'includes/walkers/class-acf-walker-taxonomy-field.php' );
|
||||
|
||||
// vars.
|
||||
$args = array(
|
||||
'taxonomy' => $field['taxonomy'],
|
||||
'show_option_none' => sprintf( _x( 'No %s', 'No Terms', 'acf' ), $taxonomy_obj->labels->name ),
|
||||
'hide_empty' => false,
|
||||
'style' => 'none',
|
||||
'walker' => new ACF_Taxonomy_Field_Walker( $field ),
|
||||
);
|
||||
|
||||
// filter for 3rd party customization.
|
||||
$args = apply_filters( 'acf/fields/taxonomy/wp_list_categories', $args, $field );
|
||||
$args = apply_filters( 'acf/fields/taxonomy/wp_list_categories/name=' . $field['_name'], $args, $field );
|
||||
$args = apply_filters( 'acf/fields/taxonomy/wp_list_categories/key=' . $field['key'], $args, $field );
|
||||
|
||||
?>
|
||||
<div class="categorychecklist-holder">
|
||||
<ul class="acf-checkbox-list acf-bl">
|
||||
<?php wp_list_categories( $args ); ?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Taxonomy', 'acf' ),
|
||||
'instructions' => __( 'Select the taxonomy to be displayed', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_labels(),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Create Terms', 'acf' ),
|
||||
'instructions' => __( 'Allow new terms to be created whilst editing', 'acf' ),
|
||||
'name' => 'add_term',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Terms', 'acf' ),
|
||||
'instructions' => __( 'Connect selected terms to the post', 'acf' ),
|
||||
'name' => 'save_terms',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Load Terms', 'acf' ),
|
||||
'instructions' => __( 'Load value from posts terms', 'acf' ),
|
||||
'name' => 'load_terms',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'object' => __( 'Term Object', 'acf' ),
|
||||
'id' => __( 'Term ID', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Appearance', 'acf' ),
|
||||
'instructions' => __( 'Select the appearance of this field', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'field_type',
|
||||
'optgroup' => true,
|
||||
'choices' => array(
|
||||
__( 'Multiple Values', 'acf' ) => array(
|
||||
'checkbox' => __( 'Checkbox', 'acf' ),
|
||||
'multi_select' => __( 'Multi Select', 'acf' ),
|
||||
),
|
||||
__( 'Single Value', 'acf' ) => array(
|
||||
'radio' => __( 'Radio Buttons', 'acf' ),
|
||||
'select' => _x( 'Select', 'noun', 'acf' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'conditions' => array(
|
||||
'field' => 'field_type',
|
||||
'operator' => '!=',
|
||||
'value' => 'checkbox',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Advanced" tab.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_advanced_settings( $field ) {
|
||||
acf_render_bidirectional_field_settings( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters choices in taxonomy conditions.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $choices The selected choice.
|
||||
* @param array $conditional_field The conditional field settings object.
|
||||
* @param string $rule_value The rule value.
|
||||
* @return mixed
|
||||
*/
|
||||
public function render_field_taxonomy_conditional_choices( $choices, $conditional_field, $rule_value ) {
|
||||
if ( is_array( $conditional_field ) && $conditional_field['type'] === 'taxonomy' ) {
|
||||
if ( ! empty( $rule_value ) ) {
|
||||
$term = get_term( $rule_value );
|
||||
$choices = array( $rule_value => $term->name );
|
||||
}
|
||||
}
|
||||
return $choices;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* AJAX handler for adding Taxonomy field terms.
|
||||
*
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_add_term() {
|
||||
$args = acf_request_args(
|
||||
array(
|
||||
'nonce' => '',
|
||||
'field_key' => '',
|
||||
'term_name' => '',
|
||||
'term_parent' => '',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $args['field_key'] );
|
||||
if ( ! $field ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// vars
|
||||
$taxonomy_obj = get_taxonomy( $field['taxonomy'] );
|
||||
$taxonomy_label = $taxonomy_obj->labels->singular_name;
|
||||
|
||||
// validate cap
|
||||
// note: this situation should never occur due to condition of the add new button
|
||||
if ( ! current_user_can( $taxonomy_obj->cap->manage_terms ) ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'error' => sprintf( __( 'User unable to add new %s', 'acf' ), $taxonomy_label ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// save?
|
||||
if ( $args['term_name'] ) {
|
||||
|
||||
// exists
|
||||
if ( term_exists( $args['term_name'], $field['taxonomy'], $args['term_parent'] ) ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'error' => sprintf( __( '%s already exists', 'acf' ), $taxonomy_label ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// vars
|
||||
$extra = array();
|
||||
if ( $args['term_parent'] ) {
|
||||
$extra['parent'] = (int) $args['term_parent'];
|
||||
}
|
||||
|
||||
// insert
|
||||
$data = wp_insert_term( $args['term_name'], $field['taxonomy'], $extra );
|
||||
|
||||
// error
|
||||
if ( is_wp_error( $data ) ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'error' => $data->get_error_message(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// load term
|
||||
$term = get_term( $data['term_id'] );
|
||||
|
||||
// prepend ancenstors count to term name
|
||||
$prefix = '';
|
||||
$ancestors = get_ancestors( $term->term_id, $term->taxonomy );
|
||||
if ( ! empty( $ancestors ) ) {
|
||||
$prefix = str_repeat( '- ', count( $ancestors ) );
|
||||
}
|
||||
|
||||
// success
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'message' => sprintf( __( '%s added', 'acf' ), $taxonomy_label ),
|
||||
'term_id' => $term->term_id,
|
||||
'term_name' => $term->name,
|
||||
'term_label' => $prefix . $term->name,
|
||||
'term_parent' => $term->parent,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
||||
<form method="post">
|
||||
<?php
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Name', 'acf' ),
|
||||
'name' => 'term_name',
|
||||
'type' => 'text',
|
||||
)
|
||||
);
|
||||
|
||||
if ( is_taxonomy_hierarchical( $field['taxonomy'] ) ) {
|
||||
$choices = array();
|
||||
$response = $this->get_ajax_query( $args );
|
||||
|
||||
if ( $response ) {
|
||||
foreach ( $response['results'] as $v ) {
|
||||
$choices[ $v['id'] ] = $v['text'];
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Parent', 'acf' ),
|
||||
'name' => 'term_parent',
|
||||
'type' => 'select',
|
||||
'allow_null' => 1,
|
||||
'ui' => 0,
|
||||
'choices' => $choices,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
||||
<p class="acf-submit">
|
||||
<button class="acf-submit-button button button-primary" type="submit"><?php esc_html_e( 'Add', 'acf' ); ?></button>
|
||||
</p>
|
||||
</form><?php
|
||||
|
||||
// die
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( in_array( $field['field_type'], array( 'radio', 'select' ) ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
$links = array();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
foreach ( (array) $value as $object_id ) {
|
||||
$term = get_term( $object_id );
|
||||
if ( ! $term instanceof WP_Term ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rest_base = acf_get_object_type_rest_base( get_taxonomy( $term->taxonomy ) );
|
||||
if ( ! $rest_base ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$links[] = array(
|
||||
'rel' => 'acf:term',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
'taxonomy' => $term->taxonomy,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_taxonomy' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_text' ) ) :
|
||||
|
||||
class acf_field_text extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'text';
|
||||
$this->label = __( 'Text', 'acf' );
|
||||
$this->description = __( 'A basic text input, useful for storing single string values.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-text.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/text/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'maxlength' => '',
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
$html = '';
|
||||
|
||||
// Prepend text.
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-prepended';
|
||||
$html .= '<div class="acf-input-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
}
|
||||
|
||||
// Append text.
|
||||
if ( $field['append'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-appended';
|
||||
$html .= '<div class="acf-input-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
}
|
||||
|
||||
// Input.
|
||||
$input_attrs = array();
|
||||
foreach ( array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'maxlength', 'pattern', 'readonly', 'disabled', 'required' ) as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$input_attrs[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $field['input-data'] ) && is_array( $field['input-data'] ) ) {
|
||||
foreach ( $field['input-data'] as $name => $attr ) {
|
||||
$input_attrs[ 'data-' . $name ] = $attr;
|
||||
}
|
||||
}
|
||||
|
||||
$html .= '<div class="acf-input-wrap">' . acf_get_text_input( acf_filter_attrs( $input_attrs ) ) . '</div>';
|
||||
|
||||
// Display.
|
||||
echo $html; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- only safe HTML output generated and escaped by functions above.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Character Limit', 'acf' ),
|
||||
'instructions' => __( 'Leave blank for no limit', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'maxlength',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* Validates a field's value.
|
||||
*
|
||||
* @date 29/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param (bool|string) Whether the value is vaid or not.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The HTML input name.
|
||||
* @return (bool|string)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// Check maxlength
|
||||
if ( $field['maxlength'] && ( acf_strlen( $value ) > $field['maxlength'] ) ) {
|
||||
return sprintf( __( 'Value must not exceed %d characters', 'acf' ), $field['maxlength'] );
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( ! empty( $field['maxlength'] ) ) {
|
||||
$schema['maxLength'] = (int) $field['maxlength'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_text' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_textarea' ) ) :
|
||||
|
||||
class acf_field_textarea extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'textarea';
|
||||
$this->label = __( 'Text Area', 'acf' );
|
||||
$this->description = __( 'A basic textarea input for storing paragraphs of text.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-textarea.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/textarea/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'new_lines' => '',
|
||||
'maxlength' => '',
|
||||
'placeholder' => '',
|
||||
'rows' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'id', 'class', 'name', 'value', 'placeholder', 'rows', 'maxlength' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
|
||||
// rows
|
||||
if ( ! $field['rows'] ) {
|
||||
$field['rows'] = 8;
|
||||
}
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// return
|
||||
acf_textarea_input( $atts );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'textarea',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Character Limit', 'acf' ),
|
||||
'instructions' => __( 'Leave blank for no limit', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'maxlength',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Rows', 'acf' ),
|
||||
'instructions' => __( 'Sets the textarea height', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'rows',
|
||||
'placeholder' => 8,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'New Lines', 'acf' ),
|
||||
'instructions' => __( 'Controls how new lines are rendered', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'new_lines',
|
||||
'choices' => array(
|
||||
'wpautop' => __( 'Automatically add paragraphs', 'acf' ),
|
||||
'br' => __( 'Automatically add <br>', 'acf' ),
|
||||
'' => __( 'No Formatting', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is applied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value or not for template
|
||||
if ( empty( $value ) || ! is_string( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// new lines
|
||||
if ( $field['new_lines'] == 'wpautop' ) {
|
||||
$value = wpautop( $value );
|
||||
} elseif ( $field['new_lines'] == 'br' ) {
|
||||
$value = nl2br( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* Validates a field's value.
|
||||
*
|
||||
* @date 29/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param (bool|string) Whether the value is vaid or not.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The HTML input name.
|
||||
* @return (bool|string)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// Check maxlength.
|
||||
if ( $field['maxlength'] && ( acf_strlen( $value ) > $field['maxlength'] ) ) {
|
||||
return sprintf( __( 'Value must not exceed %d characters', 'acf' ), $field['maxlength'] );
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( ! empty( $field['maxlength'] ) ) {
|
||||
$schema['maxLength'] = (int) $field['maxlength'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_textarea' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,195 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_time_picker' ) ) :
|
||||
|
||||
class acf_field_time_picker extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'time_picker';
|
||||
$this->label = __( 'Time Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for picking a time. The time format can be customized using the field settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-time.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/time-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'display_format' => 'g:i a',
|
||||
'return_format' => 'g:i a',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// Set value.
|
||||
$display_value = '';
|
||||
|
||||
if ( $field['value'] ) {
|
||||
$display_value = acf_format_date( $field['value'], $field['display_format'] );
|
||||
}
|
||||
|
||||
// Elements.
|
||||
$div = array(
|
||||
'class' => 'acf-time-picker acf-input-wrap',
|
||||
'data-time_format' => acf_convert_time_to_js( $field['display_format'] ),
|
||||
);
|
||||
$hidden_input = array(
|
||||
'id' => $field['id'],
|
||||
'class' => 'input-alt',
|
||||
'type' => 'hidden',
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
);
|
||||
$text_input = array(
|
||||
'class' => $field['class'] . ' input',
|
||||
'type' => 'text',
|
||||
'value' => $display_value,
|
||||
);
|
||||
foreach ( array( 'readonly', 'disabled' ) as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$hidden_input[ $k ] = $k;
|
||||
$text_input[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// Output.
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
$g_i_a = date_i18n( 'g:i a' );
|
||||
$H_i_s = date_i18n( 'H:i:s' );
|
||||
|
||||
echo '<div class="acf-field-settings-split">';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Display Format', 'acf' ),
|
||||
'hint' => __( 'The format displayed when editing a post', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'display_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'g:i a' => '<span>' . $g_i_a . '</span><code>g:i a</code>',
|
||||
'H:i:s' => '<span>' . $H_i_s . '</span><code>H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'hint' => __( 'The format returned via template functions', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'g:i a' => '<span>' . $g_i_a . '</span><code>g:i a</code>',
|
||||
'H:i:s' => '<span>' . $H_i_s . '</span><code>H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
return acf_format_date( $value, $field['return_format'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is applied to the $field after it is loaded from the database
|
||||
* and ensures the return and display values are set.
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.11.0
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @return array
|
||||
*/
|
||||
public function load_field( $field ) {
|
||||
if ( empty( $field['display_format'] ) ) {
|
||||
$field['display_format'] = $this->defaults['display_format'];
|
||||
}
|
||||
|
||||
if ( empty( $field['return_format'] ) ) {
|
||||
$field['return_format'] = $this->defaults['return_format'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'description' => 'A `H:i:s` formatted time string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_time_picker' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_true_false' ) ) :
|
||||
|
||||
class acf_field_true_false extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'true_false';
|
||||
$this->label = __( 'True / False', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A toggle that allows you to pick a value of 1 or 0 (on or off, true or false, etc). Can be presented as a stylized switch or checkbox.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-true-false.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/true-false/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => 0,
|
||||
'message' => '',
|
||||
'ui' => 0,
|
||||
'ui_on_text' => '',
|
||||
'ui_off_text' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$input = array(
|
||||
'type' => 'checkbox',
|
||||
'id' => $field['id'],
|
||||
'name' => $field['name'],
|
||||
'value' => '1',
|
||||
'class' => $field['class'],
|
||||
'autocomplete' => 'off',
|
||||
);
|
||||
|
||||
$hidden = array(
|
||||
'name' => $field['name'],
|
||||
'value' => 0,
|
||||
);
|
||||
|
||||
$active = $field['value'] ? true : false;
|
||||
$switch = '';
|
||||
|
||||
// checked
|
||||
if ( $active ) {
|
||||
$input['checked'] = 'checked';
|
||||
}
|
||||
|
||||
// ui
|
||||
if ( $field['ui'] ) {
|
||||
|
||||
// vars
|
||||
if ( $field['ui_on_text'] === '' ) {
|
||||
$field['ui_on_text'] = __( 'Yes', 'acf' );
|
||||
}
|
||||
if ( $field['ui_off_text'] === '' ) {
|
||||
$field['ui_off_text'] = __( 'No', 'acf' );
|
||||
}
|
||||
|
||||
// update input
|
||||
$input['class'] .= ' acf-switch-input';
|
||||
// $input['style'] = 'display:none;';
|
||||
$switch .= '<div class="acf-switch' . ( $active ? ' -on' : '' ) . '">';
|
||||
$switch .= '<span class="acf-switch-on">' . $field['ui_on_text'] . '</span>';
|
||||
$switch .= '<span class="acf-switch-off">' . $field['ui_off_text'] . '</span>';
|
||||
$switch .= '<div class="acf-switch-slider"></div>';
|
||||
$switch .= '</div>';
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="acf-true-false">
|
||||
<?php acf_hidden_input( $hidden ); ?>
|
||||
<label>
|
||||
<input <?php echo acf_esc_attrs( $input ); ?>/>
|
||||
<?php
|
||||
if ( $switch ) {
|
||||
echo acf_esc_html( $switch );}
|
||||
?>
|
||||
<?php
|
||||
if ( $field['message'] ) :
|
||||
?>
|
||||
<span class="message"><?php echo acf_esc_html( $field['message'] ); ?></span><?php endif; ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Message', 'acf' ),
|
||||
'instructions' => __( 'Displays text alongside the checkbox', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'message',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'On Text', 'acf' ),
|
||||
'instructions' => __( 'Text shown when active', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'ui_on_text',
|
||||
'placeholder' => __( 'Yes', 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Off Text', 'acf' ),
|
||||
'instructions' => __( 'Text shown when inactive', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'ui_off_text',
|
||||
'placeholder' => __( 'No', 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Stylized UI', 'acf' ),
|
||||
'instructions' => __( 'Use a stylized checkbox using select2', 'acf' ),
|
||||
'type' => 'true_false',
|
||||
'name' => 'ui',
|
||||
'ui' => 1,
|
||||
'class' => 'acf-field-object-true-false-ui',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
return empty( $value ) ? false : true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// bail early if not required
|
||||
if ( ! $field['required'] ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// value may be '0'
|
||||
if ( ! $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
function translate_field( $field ) {
|
||||
|
||||
// translate
|
||||
$field['message'] = acf_translate( $field['message'] );
|
||||
$field['ui_on_text'] = acf_translate( $field['ui_on_text'] );
|
||||
$field['ui_off_text'] = acf_translate( $field['ui_off_text'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'boolean', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = (bool) $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return (bool) $value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_true_false' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_url' ) ) :
|
||||
|
||||
/**
|
||||
* The URL field class.
|
||||
*/
|
||||
class acf_field_url extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function initialize() {
|
||||
// vars
|
||||
$this->name = 'url';
|
||||
$this->label = __( 'URL', 'acf' );
|
||||
$this->description = __( 'A text input specifically designed for storing web addresses.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-url.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/url/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'placeholder' => '',
|
||||
);
|
||||
$this->supports = array(
|
||||
'escaping_html' => true,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array holding all the field's data.
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// render
|
||||
$html = '<div class="acf-input-wrap acf-url">';
|
||||
$html .= '<i class="acf-icon -globe -small"></i>' . acf_get_text_input( $atts );
|
||||
$html .= '</div>';
|
||||
|
||||
// return
|
||||
echo $html; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- safe HTML, escaped by acf_get_text_input.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field An array holding all the field's data.
|
||||
*/
|
||||
public function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validate the fields value is correctly formatted as a URL
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $valid The current validity of the field value. Boolean true if valid, a validation error message string if not.
|
||||
* @param string $value The value of the field.
|
||||
* @param array $field Field object array.
|
||||
* @param string $input The form input name for this field.
|
||||
* @return mixed Boolean true if valid, a validation error message string if not.
|
||||
*/
|
||||
public function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// bail early if empty
|
||||
if ( empty( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
if ( strpos( $value, '://' ) !== false ) {
|
||||
|
||||
// url
|
||||
} elseif ( strpos( $value, '//' ) === 0 ) {
|
||||
|
||||
// protocol relative url
|
||||
} else {
|
||||
$valid = __( 'Value must be a valid URL', 'acf' );
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is applied to the $value after it is loaded from the db, and before it is returned to the template
|
||||
*
|
||||
* @since 6.2.6
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database.
|
||||
* @param mixed $post_id The $post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @param boolean $escape_html Should the field return a HTML safe formatted value.
|
||||
* @return mixed $value The modified value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field, $escape_html ) {
|
||||
if ( $escape_html ) {
|
||||
return esc_url( $value );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field The field object.
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
$schema['format'] = 'uri';
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_url' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,661 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'ACF_Field_User' ) ) :
|
||||
|
||||
class ACF_Field_User extends ACF_Field {
|
||||
|
||||
/**
|
||||
* Initializes the field type.
|
||||
*
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*/
|
||||
function initialize() {
|
||||
$this->name = 'user';
|
||||
$this->label = __( 'User', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'Allows the selection of one or more users which can be used to create relationships between data objects.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-user.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/user/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'role' => '',
|
||||
'multiple' => 0,
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'array',
|
||||
'bidirectional_target' => array(),
|
||||
);
|
||||
|
||||
// Register filter variations.
|
||||
acf_add_filter_variations( 'acf/fields/user/query', array( 'name', 'key' ), 1 );
|
||||
acf_add_filter_variations( 'acf/fields/user/result', array( 'name', 'key' ), 2 );
|
||||
acf_add_filter_variations( 'acf/fields/user/search_columns', array( 'name', 'key' ), 3 );
|
||||
add_filter( 'acf/conditional_logic/choices', array( $this, 'render_field_user_conditional_choices' ), 10, 3 );
|
||||
|
||||
// Add AJAX query.
|
||||
add_action( 'wp_ajax_acf/fields/user/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/user/query', array( $this, 'ajax_query' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters choices in user conditions.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $choices The selected choice.
|
||||
* @param array $conditional_field The conditional field settings object.
|
||||
* @param string $rule_value The rule value.
|
||||
* @return array
|
||||
*/
|
||||
public function render_field_user_conditional_choices( $choices, $conditional_field, $rule_value ) {
|
||||
if ( ! is_array( $conditional_field ) || $conditional_field['type'] !== 'user' ) {
|
||||
return $choices;
|
||||
}
|
||||
if ( ! empty( $rule_value ) ) {
|
||||
$user = acf_get_users(
|
||||
array(
|
||||
'include' => array( $rule_value ),
|
||||
)
|
||||
);
|
||||
|
||||
$user_result = acf_get_user_result( $user[0] );
|
||||
$choices = array( $user_result['id'] => $user_result['text'] );
|
||||
}
|
||||
|
||||
return $choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings HTML.
|
||||
*
|
||||
* @date 23/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param array $field The ACF field.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Role', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'role',
|
||||
'choices' => acf_get_user_role_labels(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All user roles', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'array' => __( 'User Array', 'acf' ),
|
||||
'object' => __( 'User Object', 'acf' ),
|
||||
'id' => __( 'User ID', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select Multiple', 'acf' ),
|
||||
'instructions' => 'Allow content editors to select multiple values',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Advanced" tab.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field_advanced_settings( $field ) {
|
||||
acf_render_bidirectional_field_settings( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field input HTML.
|
||||
*
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param array $field The ACF field.
|
||||
* @return void
|
||||
*/
|
||||
public function render_field( $field ) {
|
||||
// Change Field into a select.
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['choices'] = array();
|
||||
$field['nonce'] = wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] );
|
||||
|
||||
// Populate choices.
|
||||
if ( $field['value'] ) {
|
||||
|
||||
// Clean value into an array of IDs.
|
||||
$user_ids = array_map( 'intval', acf_array( $field['value'] ) );
|
||||
|
||||
// Find users in database (ensures all results are real).
|
||||
$users = acf_get_users(
|
||||
array(
|
||||
'include' => $user_ids,
|
||||
)
|
||||
);
|
||||
|
||||
// Append.
|
||||
if ( $users ) {
|
||||
foreach ( $users as $user ) {
|
||||
$field['choices'][ $user->ID ] = $this->get_result( $user, $field );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render.
|
||||
acf_render_field( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the result text for a given WP_User object.
|
||||
*
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param WP_User $user The WP_User object.
|
||||
* @param array $field The ACF field related to this query.
|
||||
* @param (int|string) $post_id The post_id being edited.
|
||||
* @return string
|
||||
*/
|
||||
function get_result( $user, $field, $post_id = 0 ) {
|
||||
|
||||
// Get user result item.
|
||||
$item = acf_get_user_result( $user );
|
||||
|
||||
// Default $post_id to current post being edited.
|
||||
$post_id = $post_id ? $post_id : acf_get_form_data( 'post_id' );
|
||||
|
||||
/**
|
||||
* Filters the result text.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $args The query args.
|
||||
* @param array $field The ACF field related to this query.
|
||||
* @param (int|string) $post_id The post_id being edited.
|
||||
*/
|
||||
return apply_filters( 'acf/fields/user/result', $item['text'], $user, $field, $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the field value after it is loaded from the database.
|
||||
*
|
||||
* @date 23/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param mixed $value The field value.
|
||||
* @param mixed $post_id The post ID where the value is saved.
|
||||
* @param array $field The field array containing all settings.
|
||||
* @return mixed
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// Add compatibility for version 4.
|
||||
if ( $value === 'null' ) {
|
||||
return false;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the field value after it is loaded from the database but before it is returned to the front-end API.
|
||||
*
|
||||
* @date 23/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param mixed $value The field value.
|
||||
* @param mixed $post_id The post ID where the value is saved.
|
||||
* @param array $field The field array containing all settings.
|
||||
* @return mixed
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( ! $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clean value into an array of IDs.
|
||||
$user_ids = array_map( 'intval', acf_array( $value ) );
|
||||
|
||||
// Find users in database (ensures all results are real).
|
||||
$users = acf_get_users(
|
||||
array(
|
||||
'include' => $user_ids,
|
||||
)
|
||||
);
|
||||
|
||||
// Bail early if no users found.
|
||||
if ( ! $users ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Format values using field settings.
|
||||
$value = array();
|
||||
foreach ( $users as $user ) {
|
||||
|
||||
// Return object.
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
$item = $user;
|
||||
|
||||
// Return array.
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
$item = array(
|
||||
'ID' => $user->ID,
|
||||
'user_firstname' => $user->user_firstname,
|
||||
'user_lastname' => $user->user_lastname,
|
||||
'nickname' => $user->nickname,
|
||||
'user_nicename' => $user->user_nicename,
|
||||
'display_name' => $user->display_name,
|
||||
'user_email' => $user->user_email,
|
||||
'user_url' => $user->user_url,
|
||||
'user_registered' => $user->user_registered,
|
||||
'user_description' => $user->user_description,
|
||||
'user_avatar' => get_avatar( $user->ID ),
|
||||
);
|
||||
|
||||
// Return ID.
|
||||
} else {
|
||||
$item = $user->ID;
|
||||
}
|
||||
|
||||
// Append item
|
||||
$value[] = $item;
|
||||
}
|
||||
|
||||
// Convert to single.
|
||||
if ( ! $field['multiple'] ) {
|
||||
$value = array_shift( $value );
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the field value before it is saved into the database.
|
||||
*
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param mixed $value The field value.
|
||||
* @param mixed $post_id The post ID where the value is saved.
|
||||
* @param array $field The field array containing all settings.
|
||||
* @return mixed $value The modified value.
|
||||
*/
|
||||
public function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
acf_update_bidirectional_values( array(), $post_id, $field, 'user' );
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_idval( $value );
|
||||
}
|
||||
|
||||
acf_update_bidirectional_values( acf_get_array( $value ), $post_id, $field, 'user' );
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for the AJAX query request.
|
||||
*
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function ajax_query() {
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
// Modify Request args.
|
||||
if ( isset( $_REQUEST['s'] ) ) {
|
||||
$_REQUEST['search'] = sanitize_text_field( $_REQUEST['s'] );
|
||||
}
|
||||
if ( isset( $_REQUEST['paged'] ) ) {
|
||||
$_REQUEST['page'] = absint( $_REQUEST['paged'] );
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
|
||||
// Add query hooks.
|
||||
add_action( 'acf/ajax/query_users/init', array( $this, 'ajax_query_init' ), 10, 2 );
|
||||
add_filter( 'acf/ajax/query_users/args', array( $this, 'ajax_query_args' ), 10, 3 );
|
||||
add_filter( 'acf/ajax/query_users/result', array( $this, 'ajax_query_result' ), 10, 3 );
|
||||
add_filter( 'acf/ajax/query_users/search_columns', array( $this, 'ajax_query_search_columns' ), 10, 4 );
|
||||
// Simulate AJAX request.
|
||||
acf_get_instance( 'ACF_Ajax_Query_Users' )->request();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs during the AJAX query initialization.
|
||||
*
|
||||
* @date 9/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $request The query request.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
* @return void
|
||||
*/
|
||||
function ajax_query_init( $request, $query ) {
|
||||
// Require field and make sure it's a user field.
|
||||
if ( ! $query->field || $query->field['type'] !== $this->name ) {
|
||||
$query->send( new WP_Error( 'acf_missing_field', __( 'Error loading field.', 'acf' ), array( 'status' => 404 ) ) );
|
||||
}
|
||||
|
||||
// Verify that this is a legitimate request using a separate nonce from the main AJAX nonce.
|
||||
$nonce = acf_request_arg( 'nonce', '' );
|
||||
$key = acf_request_arg( 'field_key', '' );
|
||||
|
||||
if ( ! acf_verify_ajax( $nonce, $key, true ) ) {
|
||||
$query->send( new WP_Error( 'acf_invalid_request', __( 'Invalid request.', 'acf' ), array( 'status' => 404 ) ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the AJAX query args.
|
||||
*
|
||||
* @date 9/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $args The query args.
|
||||
* @param array $request The query request.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
* @return array
|
||||
*/
|
||||
function ajax_query_args( $args, $request, $query ) {
|
||||
|
||||
// Add specific roles.
|
||||
if ( $query->field['role'] ) {
|
||||
$args['role__in'] = acf_array( $query->field['role'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the query args.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $args The query args.
|
||||
* @param array $field The ACF field related to this query.
|
||||
* @param (int|string) $post_id The post_id being edited.
|
||||
*/
|
||||
return apply_filters( 'acf/fields/user/query', $args, $query->field, $query->post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the WP_User_Query search columns.
|
||||
*
|
||||
* @date 9/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $columns An array of column names to be searched.
|
||||
* @param string $search The search term.
|
||||
* @param WP_User_Query $WP_User_Query The WP_User_Query instance.
|
||||
* @return array
|
||||
*/
|
||||
function ajax_query_search_columns( $columns, $search, $WP_User_Query, $query ) {
|
||||
|
||||
/**
|
||||
* Filters the column names to be searched.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $columns An array of column names to be searched.
|
||||
* @param string $search The search term.
|
||||
* @param WP_User_Query $WP_User_Query The WP_User_Query instance.
|
||||
* @param array $field The ACF field related to this query.
|
||||
*/
|
||||
return apply_filters( 'acf/fields/user/search_columns', $columns, $search, $WP_User_Query, $query->field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the AJAX Query result.
|
||||
*
|
||||
* @date 9/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $item The choice id and text.
|
||||
* @param WP_User $user The user object.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
* @return array
|
||||
*/
|
||||
function ajax_query_result( $item, $user, $query ) {
|
||||
|
||||
/**
|
||||
* Filters the result text.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param string The result text.
|
||||
* @param WP_User $user The user object.
|
||||
* @param array $field The ACF field related to this query.
|
||||
* @param (int|string) $post_id The post_id being edited.
|
||||
*/
|
||||
$item['text'] = apply_filters( 'acf/fields/user/result', $item['text'], $user, $query->field, $query->post_id );
|
||||
return $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of data formatted for use in a select2 AJAX response.
|
||||
*
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
* @deprecated 5.8.9
|
||||
*
|
||||
* @param array $args An array of query args.
|
||||
* @return array
|
||||
*/
|
||||
function get_ajax_query( $options = array() ) {
|
||||
_deprecated_function( __FUNCTION__, '5.8.9' );
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the WP_User_Query search columns.
|
||||
*
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
* @deprecated 5.8.9
|
||||
*
|
||||
* @param array $columns An array of column names to be searched.
|
||||
* @param string $search The search term.
|
||||
* @param WP_User_Query $WP_User_Query The WP_User_Query instance.
|
||||
* @return array
|
||||
*/
|
||||
function user_search_columns( $columns, $search, $WP_User_Query ) {
|
||||
_deprecated_function( __FUNCTION__, '5.8.9' );
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates user fields updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( is_null( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array( 'param' => $param );
|
||||
$value = is_array( $value ) ? $value : array( $value );
|
||||
|
||||
$invalid_users = array();
|
||||
$insufficient_roles = array();
|
||||
|
||||
foreach ( $value as $user_id ) {
|
||||
$user_data = get_userdata( $user_id );
|
||||
if ( ! $user_data ) {
|
||||
$invalid_users[] = $user_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $field['role'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$has_roles = count( array_intersect( $field['role'], $user_data->roles ) );
|
||||
if ( ! $has_roles ) {
|
||||
$insufficient_roles[] = $user_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $invalid_users ) ) {
|
||||
$error = sprintf(
|
||||
__( '%1$s must have a valid user ID.', 'acf' ),
|
||||
$param
|
||||
);
|
||||
$data['value'] = $invalid_users;
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
if ( count( $insufficient_roles ) ) {
|
||||
$error = sprintf(
|
||||
_n(
|
||||
'%1$s must have a user with the %2$s role.',
|
||||
'%1$s must have a user with one of the following roles: %2$s',
|
||||
count( $field['role'] ),
|
||||
'acf'
|
||||
),
|
||||
$param,
|
||||
count( $field['role'] ) > 1 ? implode( ', ', $field['role'] ) : $field['role'][0]
|
||||
);
|
||||
$data['value'] = $insufficient_roles;
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
$links = array();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
foreach ( (array) $value as $object_id ) {
|
||||
$links[] = array(
|
||||
'rel' => 'acf:user',
|
||||
'href' => rest_url( '/wp/v2/users/' . $object_id ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'ACF_Field_User' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,417 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_wysiwyg' ) ) :
|
||||
|
||||
class acf_field_wysiwyg extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'wysiwyg';
|
||||
$this->label = __( 'WYSIWYG Editor', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'Displays the WordPress WYSIWYG editor as seen in Posts and Pages allowing for a rich text-editing experience that also allows for multimedia content.', 'acf' ) . ' ' . __( 'We do not recommend using this field in ACF Blocks.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-wysiwyg.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/wysiwyg-editor/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'tabs' => 'all',
|
||||
'toolbar' => 'full',
|
||||
'media_upload' => 1,
|
||||
'default_value' => '',
|
||||
'delay' => 0,
|
||||
);
|
||||
$this->supports = array(
|
||||
'escaping_html' => true,
|
||||
);
|
||||
|
||||
// add acf_the_content filters
|
||||
$this->add_filters();
|
||||
|
||||
// actions
|
||||
add_action( 'acf/enqueue_uploader', array( $this, 'acf_enqueue_uploader' ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will add filters to 'acf_the_content'
|
||||
*
|
||||
* @type function
|
||||
* @date 20/09/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function add_filters() {
|
||||
|
||||
// WordPress 5.5 introduced new function for applying image tags.
|
||||
$wp_filter_content_tags = function_exists( 'wp_filter_content_tags' ) ? 'wp_filter_content_tags' : 'wp_make_content_images_responsive';
|
||||
|
||||
// Mimic filters added to "the_content" in "wp-includes/default-filters.php".
|
||||
add_filter( 'acf_the_content', 'capital_P_dangit', 11 );
|
||||
// add_filter( 'acf_the_content', 'do_blocks', 9 ); Not yet supported.
|
||||
add_filter( 'acf_the_content', 'wptexturize' );
|
||||
add_filter( 'acf_the_content', 'convert_smilies', 20 );
|
||||
add_filter( 'acf_the_content', 'wpautop' );
|
||||
add_filter( 'acf_the_content', 'shortcode_unautop' );
|
||||
// add_filter( 'acf_the_content', 'prepend_attachment' ); Causes double image on attachment page.
|
||||
add_filter( 'acf_the_content', $wp_filter_content_tags );
|
||||
add_filter( 'acf_the_content', 'do_shortcode', 11 );
|
||||
|
||||
// Mimic filters added to "the_content" in "wp-includes/class-wp-embed.php"
|
||||
if ( isset( $GLOBALS['wp_embed'] ) ) {
|
||||
add_filter( 'acf_the_content', array( $GLOBALS['wp_embed'], 'run_shortcode' ), 8 );
|
||||
add_filter( 'acf_the_content', array( $GLOBALS['wp_embed'], 'autoembed' ), 8 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an array of toolbars for the WYSIWYG field
|
||||
*
|
||||
* @type function
|
||||
* @date 18/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return (array)
|
||||
*/
|
||||
function get_toolbars() {
|
||||
|
||||
// vars
|
||||
$editor_id = 'acf_content';
|
||||
$toolbars = array();
|
||||
|
||||
// mce buttons (Full)
|
||||
$mce_buttons = array( 'formatselect', 'bold', 'italic', 'bullist', 'numlist', 'blockquote', 'alignleft', 'aligncenter', 'alignright', 'link', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' );
|
||||
$mce_buttons_2 = array( 'strikethrough', 'hr', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' );
|
||||
|
||||
// mce buttons (Basic)
|
||||
$teeny_mce_buttons = array( 'bold', 'italic', 'underline', 'blockquote', 'strikethrough', 'bullist', 'numlist', 'alignleft', 'aligncenter', 'alignright', 'undo', 'redo', 'link', 'fullscreen' );
|
||||
|
||||
// Full
|
||||
$toolbars['Full'] = array(
|
||||
1 => apply_filters( 'mce_buttons', $mce_buttons, $editor_id ),
|
||||
2 => apply_filters( 'mce_buttons_2', $mce_buttons_2, $editor_id ),
|
||||
3 => apply_filters( 'mce_buttons_3', array(), $editor_id ),
|
||||
4 => apply_filters( 'mce_buttons_4', array(), $editor_id ),
|
||||
);
|
||||
|
||||
// Basic
|
||||
$toolbars['Basic'] = array(
|
||||
1 => apply_filters( 'teeny_mce_buttons', $teeny_mce_buttons, $editor_id ),
|
||||
);
|
||||
|
||||
// Filter for 3rd party
|
||||
$toolbars = apply_filters( 'acf/fields/wysiwyg/toolbars', $toolbars );
|
||||
|
||||
// return
|
||||
return $toolbars;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Registers toolbars data for the WYSIWYG field.
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function acf_enqueue_uploader() {
|
||||
|
||||
// vars
|
||||
$data = array();
|
||||
$toolbars = $this->get_toolbars();
|
||||
|
||||
// loop
|
||||
if ( $toolbars ) {
|
||||
foreach ( $toolbars as $label => $rows ) {
|
||||
|
||||
// vars
|
||||
$key = $label;
|
||||
$key = sanitize_title( $key );
|
||||
$key = str_replace( '-', '_', $key );
|
||||
|
||||
// append
|
||||
$data[ $key ] = array();
|
||||
|
||||
if ( $rows ) {
|
||||
foreach ( $rows as $i => $row ) {
|
||||
$data[ $key ][ $i ] = implode( ',', $row );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'toolbars' => $data,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param array $field An array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// enqueue
|
||||
acf_enqueue_uploader();
|
||||
|
||||
// vars
|
||||
$id = uniqid( 'acf-editor-' );
|
||||
$default_editor = 'html';
|
||||
$show_tabs = true;
|
||||
|
||||
// get height
|
||||
$height = acf_get_user_setting( 'wysiwyg_height', 300 );
|
||||
$height = max( $height, 300 ); // minimum height is 300
|
||||
|
||||
// detect mode
|
||||
if ( ! user_can_richedit() ) {
|
||||
$show_tabs = false;
|
||||
} elseif ( $field['tabs'] == 'visual' ) {
|
||||
|
||||
// case: visual tab only
|
||||
$default_editor = 'tinymce';
|
||||
$show_tabs = false;
|
||||
} elseif ( $field['tabs'] == 'text' ) {
|
||||
|
||||
// case: text tab only
|
||||
$show_tabs = false;
|
||||
} elseif ( wp_default_editor() == 'tinymce' ) {
|
||||
|
||||
// case: both tabs
|
||||
$default_editor = 'tinymce';
|
||||
}
|
||||
|
||||
// must be logged in to upload
|
||||
if ( ! current_user_can( 'upload_files' ) ) {
|
||||
$field['media_upload'] = 0;
|
||||
}
|
||||
|
||||
// mode
|
||||
$switch_class = ( $default_editor === 'html' ) ? 'html-active' : 'tmce-active';
|
||||
|
||||
// filter
|
||||
add_filter( 'acf_the_editor_content', 'format_for_editor', 10, 2 );
|
||||
|
||||
$field['value'] = is_string( $field['value'] ) ? $field['value'] : '';
|
||||
$field['value'] = apply_filters( 'acf_the_editor_content', $field['value'], $default_editor );
|
||||
|
||||
// attr
|
||||
$wrap = array(
|
||||
'id' => 'wp-' . $id . '-wrap',
|
||||
'class' => 'acf-editor-wrap wp-core-ui wp-editor-wrap ' . $switch_class,
|
||||
'data-toolbar' => $field['toolbar'],
|
||||
);
|
||||
|
||||
// delay
|
||||
if ( $field['delay'] ) {
|
||||
$wrap['class'] .= ' delay';
|
||||
}
|
||||
|
||||
// vars
|
||||
$textarea = acf_get_textarea_input(
|
||||
array(
|
||||
'id' => $id,
|
||||
'class' => 'wp-editor-area',
|
||||
'name' => $field['name'],
|
||||
'style' => $height ? "height:{$height}px;" : '',
|
||||
'value' => '%s',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $wrap ); ?>>
|
||||
<div id="wp-<?php echo esc_attr( $id ); ?>-editor-tools" class="wp-editor-tools hide-if-no-js">
|
||||
<?php if ( $field['media_upload'] ) : ?>
|
||||
<div id="wp-<?php echo esc_attr( $id ); ?>-media-buttons" class="wp-media-buttons">
|
||||
<?php
|
||||
if ( ! function_exists( 'media_buttons' ) ) {
|
||||
require ABSPATH . 'wp-admin/includes/media.php';
|
||||
}
|
||||
do_action( 'media_buttons', $id );
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php if ( user_can_richedit() && $show_tabs ) : ?>
|
||||
<div class="wp-editor-tabs">
|
||||
<button id="<?php echo esc_attr( $id ); ?>-tmce" class="wp-switch-editor switch-tmce" data-wp-editor-id="<?php echo esc_attr( $id ); ?>" type="button"><?php esc_html_e( 'Visual', 'acf' ); ?></button>
|
||||
<button id="<?php echo esc_attr( $id ); ?>-html" class="wp-switch-editor switch-html" data-wp-editor-id="<?php echo esc_attr( $id ); ?>" type="button"><?php echo esc_html_x( 'Text', 'Name for the Text editor tab (formerly HTML)', 'acf' ); ?></button>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div id="wp-<?php echo esc_attr( $id ); ?>-editor-container" class="wp-editor-container">
|
||||
<?php if ( $field['delay'] ) : ?>
|
||||
<div class="acf-editor-toolbar"><?php esc_html_e( 'Click to initialize TinyMCE', 'acf' ); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php printf( $textarea, $field['value'] ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped by format_for_editor(). ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'textarea',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
$toolbars = $this->get_toolbars();
|
||||
$choices = array();
|
||||
|
||||
if ( ! empty( $toolbars ) ) {
|
||||
foreach ( $toolbars as $k => $v ) {
|
||||
$label = $k;
|
||||
$name = sanitize_title( $label );
|
||||
$name = str_replace( '-', '_', $name );
|
||||
|
||||
$choices[ $name ] = $label;
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Tabs', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'tabs',
|
||||
'choices' => array(
|
||||
'all' => __( 'Visual & Text', 'acf' ),
|
||||
'visual' => __( 'Visual Only', 'acf' ),
|
||||
'text' => __( 'Text Only', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Toolbar', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'toolbar',
|
||||
'choices' => $choices,
|
||||
'conditions' => array(
|
||||
'field' => 'tabs',
|
||||
'operator' => '!=',
|
||||
'value' => 'text',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Show Media Upload Buttons', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'media_upload',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Delay Initialization', 'acf' ),
|
||||
'instructions' => __( 'TinyMCE will not be initialized until field is clicked', 'acf' ),
|
||||
'name' => 'delay',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'conditions' => array(
|
||||
'field' => 'tabs',
|
||||
'operator' => '!=',
|
||||
'value' => 'text',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* This filter is applied to the $value after it is loaded from the db, and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
*
|
||||
* @param mixed $value The value which was loaded from the database.
|
||||
* @param mixed $post_id The $post_id from which the value was loaded.
|
||||
* @param array $field The field array holding all the field options.
|
||||
* @param boolean $escape_html Should the field return a HTML safe formatted value.
|
||||
* @return mixed $value The modified value
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field, $escape_html ) {
|
||||
// Bail early if no value or not a string.
|
||||
if ( empty( $value ) || ! is_string( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
if ( $escape_html ) {
|
||||
add_filter( 'acf_the_content', 'acf_esc_html', 1 );
|
||||
}
|
||||
|
||||
$value = apply_filters( 'acf_the_content', $value );
|
||||
|
||||
if ( $escape_html ) {
|
||||
remove_filter( 'acf_the_content', 'acf_esc_html', 1 );
|
||||
}
|
||||
|
||||
// Follow the_content function in /wp-includes/post-template.php
|
||||
return str_replace( ']]>', ']]>', $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_wysiwyg' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,371 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field {
|
||||
|
||||
// field information properties.
|
||||
public $name = '';
|
||||
public $label = '';
|
||||
public $category = 'basic';
|
||||
public $description = '';
|
||||
public $doc_url = false;
|
||||
public $tutorial_url = false;
|
||||
public $preview_image = false;
|
||||
public $pro = false;
|
||||
public $defaults = array();
|
||||
public $l10n = array();
|
||||
public $public = true;
|
||||
public $show_in_rest = true;
|
||||
public $supports = array(
|
||||
'escaping_html' => false, // Set true when a field handles its own HTML escaping in format_value
|
||||
'required' => true,
|
||||
);
|
||||
|
||||
/**
|
||||
* Initializes the `acf_field` class. To initialize a field type that is
|
||||
* extending this class, use the `initialize()` method in the child class instead.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
// Initialize the field type.
|
||||
$this->initialize();
|
||||
|
||||
// Register info about the field type.
|
||||
acf_register_field_type_info(
|
||||
array(
|
||||
'label' => $this->label,
|
||||
'name' => $this->name,
|
||||
'category' => $this->category,
|
||||
'description' => $this->description,
|
||||
'doc_url' => $this->doc_url,
|
||||
'tutorial_url' => $this->tutorial_url,
|
||||
'preview_image' => $this->preview_image,
|
||||
'pro' => $this->pro,
|
||||
'public' => $this->public,
|
||||
)
|
||||
);
|
||||
|
||||
// value
|
||||
$this->add_field_filter( 'acf/load_value', array( $this, 'load_value' ), 10, 3 );
|
||||
$this->add_field_filter( 'acf/update_value', array( $this, 'update_value' ), 10, 3 );
|
||||
$this->add_field_filter( 'acf/format_value', array( $this, 'format_value' ), 10, 4 );
|
||||
$this->add_field_filter( 'acf/validate_value', array( $this, 'validate_value' ), 10, 4 );
|
||||
$this->add_field_action( 'acf/delete_value', array( $this, 'delete_value' ), 10, 3 );
|
||||
|
||||
// field
|
||||
$this->add_field_filter( 'acf/validate_rest_value', array( $this, 'validate_rest_value' ), 10, 3 );
|
||||
$this->add_field_filter( 'acf/validate_field', array( $this, 'validate_field' ), 10, 1 );
|
||||
$this->add_field_filter( 'acf/load_field', array( $this, 'load_field' ), 10, 1 );
|
||||
$this->add_field_filter( 'acf/update_field', array( $this, 'update_field' ), 10, 1 );
|
||||
$this->add_field_filter( 'acf/duplicate_field', array( $this, 'duplicate_field' ), 10, 1 );
|
||||
$this->add_field_action( 'acf/delete_field', array( $this, 'delete_field' ), 10, 1 );
|
||||
$this->add_field_action( 'acf/render_field', array( $this, 'render_field' ), 9, 1 );
|
||||
$this->add_field_action( 'acf/render_field_settings', array( $this, 'render_field_settings' ), 9, 1 );
|
||||
$this->add_field_filter( 'acf/prepare_field', array( $this, 'prepare_field' ), 10, 1 );
|
||||
$this->add_field_filter( 'acf/translate_field', array( $this, 'translate_field' ), 10, 1 );
|
||||
|
||||
// input actions
|
||||
$this->add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'input_admin_enqueue_scripts' ), 10, 0 );
|
||||
$this->add_action( 'acf/input/admin_head', array( $this, 'input_admin_head' ), 10, 0 );
|
||||
$this->add_action( 'acf/input/form_data', array( $this, 'input_form_data' ), 10, 1 );
|
||||
$this->add_filter( 'acf/input/admin_l10n', array( $this, 'input_admin_l10n' ), 10, 1 );
|
||||
$this->add_action( 'acf/input/admin_footer', array( $this, 'input_admin_footer' ), 10, 1 );
|
||||
|
||||
// field group actions
|
||||
$this->add_action( 'acf/field_group/admin_enqueue_scripts', array( $this, 'field_group_admin_enqueue_scripts' ), 10, 0 );
|
||||
$this->add_action( 'acf/field_group/admin_head', array( $this, 'field_group_admin_head' ), 10, 0 );
|
||||
$this->add_action( 'acf/field_group/admin_footer', array( $this, 'field_group_admin_footer' ), 10, 0 );
|
||||
|
||||
// Add field global settings configurable by supports on specific field types.
|
||||
$this->add_field_action( 'acf/field_group/render_field_settings_tab/validation', array( $this, 'render_required_setting' ), 5 );
|
||||
$this->add_field_action( 'acf/field_group/render_field_settings_tab/presentation', array( $this, 'render_bindings_setting' ), 5 );
|
||||
|
||||
foreach ( acf_get_combined_field_type_settings_tabs() as $tab_key => $tab_label ) {
|
||||
$this->add_field_action( "acf/field_group/render_field_settings_tab/{$tab_key}", array( $this, "render_field_{$tab_key}_settings" ), 9, 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the field type. Overridden in child classes.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*/
|
||||
public function initialize() {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a function `is_callable()` before adding the filter, since
|
||||
* classes that extend `acf_field` might not implement all filters.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $tag The name of the filter to add the callback to.
|
||||
* @param string $function_to_add The callback to be run when the filter is applied.
|
||||
* @param integer $priority The priority to add the filter on.
|
||||
* @param integer $accepted_args The number of args to pass to the function.
|
||||
* @return void
|
||||
*/
|
||||
public function add_filter( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
// Bail early if not callable.
|
||||
if ( ! is_callable( $function_to_add ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a filter specific to the current field type.
|
||||
*
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param string $tag The name of the filter to add the callback to.
|
||||
* @param string $function_to_add The callback to be run when the filter is applied.
|
||||
* @param integer $priority The priority to add the filter on.
|
||||
* @param integer $accepted_args The number of args to pass to the function.
|
||||
* @return void
|
||||
*/
|
||||
public function add_field_filter( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
// Append the field type name to the tag before adding the filter.
|
||||
$tag .= '/type=' . $this->name;
|
||||
$this->add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks a function `is_callable()` before adding the action, since
|
||||
* classes that extend `acf_field` might not implement all actions.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $tag The name of the action to add the callback to.
|
||||
* @param string $function_to_add The callback to be run when the action is ran.
|
||||
* @param integer $priority The priority to add the action on.
|
||||
* @param integer $accepted_args The number of args to pass to the function.
|
||||
* @return void
|
||||
*/
|
||||
public function add_action( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
// Bail early if not callable
|
||||
if ( ! is_callable( $function_to_add ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an action specific to the current field type.
|
||||
*
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param string $tag The name of the action to add the callback to.
|
||||
* @param string $function_to_add The callback to be run when the action is ran.
|
||||
* @param integer $priority The priority to add the action on.
|
||||
* @param integer $accepted_args The number of args to pass to the function.
|
||||
* @return void
|
||||
*/
|
||||
public function add_field_action( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
// Append the field type name to the tag before adding the action.
|
||||
$tag .= '/type=' . $this->name;
|
||||
$this->add_action( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends default settings to a field.
|
||||
* Runs on `acf/validate_field/type={$this->name}`.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
public function validate_field( $field ) {
|
||||
// Bail early if no defaults.
|
||||
if ( ! is_array( $this->defaults ) ) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
// Merge in defaults but keep order of $field keys.
|
||||
foreach ( $this->defaults as $k => $v ) {
|
||||
if ( ! isset( $field[ $k ] ) ) {
|
||||
$field[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Append l10n text translations to an array which is later passed to JS.
|
||||
* Runs on `acf/input/admin_l10n`.
|
||||
*
|
||||
* @since 3.6
|
||||
*
|
||||
* @param array $l10n
|
||||
* @return array $l10n
|
||||
*/
|
||||
public function input_admin_l10n( $l10n ) {
|
||||
// Bail early if no defaults.
|
||||
if ( empty( $this->l10n ) ) {
|
||||
return $l10n;
|
||||
}
|
||||
|
||||
// Append.
|
||||
$l10n[ $this->name ] = $this->l10n;
|
||||
|
||||
return $l10n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional validation for fields being updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of links for addition to the REST API response. Each link is an array and must have both `rel` and
|
||||
* `href` keys. The `href` key must be a REST API resource URL. If a link is marked as `embeddable`, the `_embed` URL
|
||||
* parameter will trigger WordPress to dispatch an internal sub request and load the object within the same request
|
||||
* under the `_embedded` response property.
|
||||
*
|
||||
* e.g;
|
||||
* [
|
||||
* [
|
||||
* 'rel' => 'acf:post',
|
||||
* 'href' => 'https://example.com/wp-json/wp/v2/posts/497',
|
||||
* 'embeddable' => true,
|
||||
* ],
|
||||
* [
|
||||
* 'rel' => 'acf:user',
|
||||
* 'href' => 'https://example.com/wp-json/wp/v2/users/2',
|
||||
* 'embeddable' => true,
|
||||
* ],
|
||||
* ]
|
||||
*
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the "Required" setting on the field type "Validation" settings tab.
|
||||
*
|
||||
* @since 6.2.5
|
||||
*
|
||||
* @param array $field The field type being rendered.
|
||||
* @return void
|
||||
*/
|
||||
public function render_required_setting( $field ) {
|
||||
$supports_required = acf_field_type_supports( $field['type'], 'required', true );
|
||||
|
||||
// Only prevent rendering if explicitly disabled.
|
||||
if ( ! $supports_required ) {
|
||||
return;
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Required', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'required',
|
||||
'ui' => 1,
|
||||
'class' => 'field-required',
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the "Allow in Bindings" setting on the field type "Presentation" settings tab.
|
||||
*
|
||||
* @since 6.3.6
|
||||
*
|
||||
* @param array $field The field type being rendered.
|
||||
* @return void
|
||||
*/
|
||||
public function render_bindings_setting( $field ) {
|
||||
$supports_bindings = acf_field_type_supports( $field['type'], 'bindings', true );
|
||||
|
||||
// Only prevent rendering if explicitly disabled.
|
||||
if ( ! $supports_bindings ) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* translators: %s A "Learn More" link to documentation explaining the setting further. */
|
||||
$binding_string = esc_html__( 'Allow content editors to access and display the field value in the editor UI using Block Bindings or the ACF Shortcode. %s', 'acf' );
|
||||
$binding_url = '<a target="_blank" href="' . acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/bindings-security/', 'docs', 'field-settings' ) . '">' . esc_html__( 'Learn more.', 'acf' ) . '</a>';
|
||||
$binding_instructions = sprintf(
|
||||
$binding_string,
|
||||
$binding_url
|
||||
);
|
||||
|
||||
// This field setting has unique behavior. If the value isn't defined on the field object, it defaults to true, but for new fields or when changing field types, it defaults to off.
|
||||
if ( ! isset( $field['allow_in_bindings'] ) ) {
|
||||
if ( empty( $field['ID'] ) || doing_action( 'wp_ajax_acf/field_group/render_field_settings' ) ) {
|
||||
$field['allow_in_bindings'] = false;
|
||||
} else {
|
||||
$field['allow_in_bindings'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Access to Value in Editor UI', 'acf' ),
|
||||
'instructions' => $binding_instructions,
|
||||
'type' => 'true_false',
|
||||
'name' => 'allow_in_bindings',
|
||||
'ui' => 1,
|
||||
'class' => 'field-show-in-bindings',
|
||||
),
|
||||
true
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
Reference in New Issue
Block a user