edit pages
This commit is contained in:
@ -0,0 +1,150 @@
|
||||
<?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->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
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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 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,326 @@
|
||||
<?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',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render_field()
|
||||
*
|
||||
* Creates the field's input HTML
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field settings array
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
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_attr( $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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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,623 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_checkbox' ) ) :
|
||||
|
||||
class acf_field_checkbox extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' ),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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_attr( $ul ) . '>' . "\n" . $li . '</ul>' . "\n";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_choices
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @date 09/12/2022
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param bool $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 bool
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* render_field_toggle
|
||||
*
|
||||
* 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";
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_custom
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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,293 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_color_picker' ) ) :
|
||||
|
||||
class acf_field_color_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.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' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
$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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
* @date 15/12/20
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $post_id
|
||||
* @param array $field
|
||||
*
|
||||
* @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,329 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_date_picker' ) ) :
|
||||
|
||||
class acf_field_date_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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' );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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
|
||||
*/
|
||||
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 `Ymd` formatted date string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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,294 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_date_and_time_picker' ) ) :
|
||||
|
||||
class acf_field_date_and_time_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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_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
|
||||
*/
|
||||
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,198 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_email' ) ) :
|
||||
|
||||
class acf_field_email extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 bool $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 bool|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,543 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_file' ) ) :
|
||||
|
||||
class acf_field_file extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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 _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 _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 _e( 'Edit', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php _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 _e( 'No file selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php _e( 'Add File', 'acf' ); ?></a></p>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_media_item_args
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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;
|
||||
}
|
||||
|
||||
// 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 bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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|int $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,388 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_google_map' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field_google_map extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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 _e( 'Search', 'acf' ); ?>"></a>
|
||||
<a href="#" data-name="clear" class="acf-icon -cancel grey" title="<?php _e( 'Clear location', 'acf' ); ?>"></a>
|
||||
<a href="#" data-name="locate" class="acf-icon -location grey" title="<?php _e( 'Find current location', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
|
||||
<input class="search" type="text" placeholder="<?php _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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 ) {
|
||||
|
||||
// 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|int $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,683 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field__group' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field__group extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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->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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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 ) {
|
||||
|
||||
// vars
|
||||
$sub_fields = acf_get_fields( $field );
|
||||
|
||||
// append
|
||||
if ( $sub_fields ) {
|
||||
$field['sub_fields'] = $sub_fields;
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 '';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* prepare_field_for_db
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_block
|
||||
*
|
||||
* 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 -' . $label_placement . ' -border">';
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_render_field_wrap( $sub_field );
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_table
|
||||
*
|
||||
* 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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 _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' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* duplicate_field()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* delete_value
|
||||
*
|
||||
* 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 int|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,486 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_image' ) ) :
|
||||
|
||||
class acf_field_image extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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 _e( 'Edit', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php _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 _e( 'No image selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php _e( 'Add Image', 'acf' ); ?></a></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_media_item_args
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 ) {
|
||||
|
||||
return acf_get_field_type( 'file' )->update_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
return acf_get_field_type( 'file' )->validate_value( $valid, $value, $field, $input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional validation for the image field when submitted via REST.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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
|
||||
* @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
|
||||
* @param string|int $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_image' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,301 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_link' ) ) :
|
||||
|
||||
class acf_field_link extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_link
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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';
|
||||
}
|
||||
|
||||
/*
|
||||
<textarea id="<?php echo esc_attr($field['id']); ?>-textarea"><?php
|
||||
echo esc_textarea('<a href="'.$link['url'].'" target="'.$link['target'].'">'.$link['title'].'</a>');
|
||||
?></textarea>*/
|
||||
?>
|
||||
<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 _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 _e( 'Opens in a new window/tab', 'acf' ); ?>"></i><a class="acf-icon -pencil -clear acf-js-tooltip" data-name="edit" href="#" title="<?php _e( 'Edit', 'acf' ); ?>"></a><a class="acf-icon -cancel -clear acf-js-tooltip" data-name="remove" href="#" title="<?php _e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// bail early if not required
|
||||
if ( ! $field['required'] ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// URL is required
|
||||
if ( empty( $value ) || empty( $value['url'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 ) {
|
||||
|
||||
// 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,183 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_message' ) ) :
|
||||
|
||||
class acf_field_message extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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->defaults = array(
|
||||
'message' => '',
|
||||
'esc_html' => 0,
|
||||
'new_lines' => 'wpautop',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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,335 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_number' ) ) :
|
||||
|
||||
class acf_field_number extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 ) {
|
||||
|
||||
// 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|int $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,333 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_oembed' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field_oembed extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* prepare_field
|
||||
*
|
||||
* 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 int|string $width Optional maxwidth value passed to the provider URL.
|
||||
* @param int|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;
|
||||
}
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
wp_send_json( $response );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// atts
|
||||
$atts = array(
|
||||
'class' => 'acf-oembed',
|
||||
);
|
||||
|
||||
// <strong><?php _e("Error.", 'acf'); </strong> _e("No embed found for the given URL.", 'acf');
|
||||
|
||||
// value
|
||||
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'] );
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<i class="acf-icon -picture hide-if-value"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
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,69 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_output' ) ) :
|
||||
|
||||
class acf_field_output extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'output';
|
||||
$this->label = 'output';
|
||||
$this->public = false;
|
||||
$this->defaults = array(
|
||||
'html' => false,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// bail early if no html
|
||||
if ( ! $field['html'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// html
|
||||
if ( is_string( $field['html'] ) && ! function_exists( $field['html'] ) ) {
|
||||
echo $field['html'];
|
||||
|
||||
// function
|
||||
} else {
|
||||
call_user_func_array( $field['html'], array( $field ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_output' );
|
||||
endif; // class_exists check
|
@ -0,0 +1,693 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_page_link' ) ) :
|
||||
|
||||
class acf_field_page_link extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$_POST,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_result
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_title
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_posts
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['choices'] = array();
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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 bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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 int|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|int $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,114 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_password' ) ) :
|
||||
|
||||
class acf_field_password extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
acf_get_field_type( 'text' )->render_field( $field );
|
||||
}
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,758 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_post_object' ) ) :
|
||||
|
||||
class acf_field_post_object 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 = '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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* 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() ) {
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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'] );
|
||||
}
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_result
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_title
|
||||
*
|
||||
* 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/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
|
||||
return $title;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( '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
|
||||
*/
|
||||
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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// ACF4 null
|
||||
if ( $value === 'null' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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 ) {
|
||||
|
||||
// numeric
|
||||
$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 int $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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_posts
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// 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.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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.
|
||||
*
|
||||
* @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 int|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 ) ) {
|
||||
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.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_post_object' );
|
||||
endif; // class_exists check
|
@ -0,0 +1,481 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_radio' ) ) :
|
||||
|
||||
class acf_field_radio extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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_attr( $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_attr( $attrs ) . '/>' . acf_esc_html( $label ) . '</label>' . $additional_html . '</li>';
|
||||
}
|
||||
|
||||
// Close <ul>.
|
||||
$e .= '</ul>';
|
||||
|
||||
// Output HTML.
|
||||
echo $e;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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,282 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_range' ) ) :
|
||||
|
||||
class acf_field_range extends acf_field_number {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'min', 'max', 'step' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
$html = '';
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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|int $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,889 @@
|
||||
<?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(),
|
||||
);
|
||||
|
||||
// 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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* 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() ) {
|
||||
|
||||
// defaults
|
||||
$options = wp_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
'post_type' => '',
|
||||
'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'] !== '' ) {
|
||||
|
||||
// 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_result
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_title
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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' => '',
|
||||
);
|
||||
|
||||
?>
|
||||
<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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 int $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 bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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 int|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|int $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,747 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_select' ) ) :
|
||||
|
||||
class acf_field_select extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = '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',
|
||||
);
|
||||
|
||||
// ajax
|
||||
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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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_select2' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// globals
|
||||
global $wp_scripts, $wp_styles;
|
||||
|
||||
// vars
|
||||
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
$major = acf_get_setting( 'select2_version' );
|
||||
$version = '';
|
||||
$script = '';
|
||||
$style = '';
|
||||
|
||||
// attempt to find 3rd party Select2 version
|
||||
// - avoid including v3 CSS when v4 JS is already enququed
|
||||
if ( isset( $wp_scripts->registered['select2'] ) ) {
|
||||
$major = (int) $wp_scripts->registered['select2']->ver;
|
||||
}
|
||||
|
||||
// v4
|
||||
if ( $major == 4 ) {
|
||||
$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" );
|
||||
|
||||
// v3
|
||||
} else {
|
||||
$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' );
|
||||
}
|
||||
|
||||
// enqueue
|
||||
wp_enqueue_script( 'select2', $script, array( 'jquery' ), $version );
|
||||
wp_enqueue_style( 'select2', $style, '', $version );
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'select2L10n' => array(
|
||||
'matches_1' => _x( 'One result is available, press enter to select it.', 'Select2 JS matches_1', 'acf' ),
|
||||
'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' ),
|
||||
'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' ),
|
||||
'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' ),
|
||||
'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_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// convert
|
||||
$value = acf_get_array( $field['value'] );
|
||||
$choices = acf_get_array( $field['choices'] );
|
||||
|
||||
// placeholder
|
||||
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;
|
||||
}
|
||||
|
||||
// vars
|
||||
$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'];
|
||||
}
|
||||
|
||||
// multiple
|
||||
if ( $field['multiple'] ) {
|
||||
$select['multiple'] = 'multiple';
|
||||
$select['size'] = 5;
|
||||
$select['name'] .= '[]';
|
||||
|
||||
// Reduce size to single line if UI.
|
||||
if ( $field['ui'] ) {
|
||||
$select['size'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// 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['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'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $field['query_nonce'] ) ) {
|
||||
$select['data-query-nonce'] = $field['query_nonce'];
|
||||
}
|
||||
|
||||
// append
|
||||
$select['value'] = $value;
|
||||
$select['choices'] = $choices;
|
||||
|
||||
// render
|
||||
acf_select_input( $select );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 );
|
||||
|
||||
// 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
|
||||
*/
|
||||
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' => __( '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,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* 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 );
|
||||
|
||||
// Convert back to string for single selects.
|
||||
if ( ! $field['multiple'] ) {
|
||||
$field['default_value'] = acf_unarray( $field['default_value'] );
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_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.
|
||||
// - Parse each value as string for SQL LIKE queries.
|
||||
if ( is_array( $value ) ) {
|
||||
$value = array_map( 'strval', $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* 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['choices'] = acf_translate( $field['choices'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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 ) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
function format_value_single( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if is empty
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// vars
|
||||
$label = acf_maybe_get( $field['choices'], $value, $value );
|
||||
|
||||
// value
|
||||
if ( $field['return_format'] == 'value' ) {
|
||||
|
||||
// do nothing
|
||||
|
||||
// label
|
||||
} elseif ( $field['return_format'] == 'label' ) {
|
||||
$value = $label;
|
||||
|
||||
// array
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
$value = array(
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
);
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates select fields updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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,82 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_separator' ) ) :
|
||||
|
||||
class acf_field_separator extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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->category = 'layout';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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 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,169 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_tab' ) ) :
|
||||
|
||||
class acf_field_tab extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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->defaults = array(
|
||||
'placement' => 'top',
|
||||
'endpoint' => 0, // added in 5.2.8
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array(
|
||||
'href' => '',
|
||||
'class' => 'acf-tab-button',
|
||||
'data-placement' => $field['placement'],
|
||||
'data-endpoint' => $field['endpoint'],
|
||||
'data-key' => $field['key'],
|
||||
);
|
||||
|
||||
if ( isset( $field['settings-type'] ) ) {
|
||||
$atts['class'] .= ' acf-settings-type-' . acf_slugify( $field['settings-type'] );
|
||||
}
|
||||
|
||||
?>
|
||||
<a <?php echo acf_esc_attrs( $atts ); ?>><?php echo acf_esc_html( $field['label'] ); ?></a>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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_tab' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,970 @@
|
||||
<?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' ) );
|
||||
|
||||
// actions
|
||||
add_action( 'acf/save_post', array( $this, 'save_post' ), 15, 1 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* 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() ) {
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 0,
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if taxonomy does not exist
|
||||
if ( ! taxonomy_exists( $field['taxonomy'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vars
|
||||
$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
|
||||
$args = array(
|
||||
'taxonomy' => $field['taxonomy'],
|
||||
'hide_empty' => false,
|
||||
);
|
||||
|
||||
// pagination
|
||||
// - 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'] ) );
|
||||
|
||||
// update vars
|
||||
$args['search'] = $s;
|
||||
$is_search = true;
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/taxonomy/query', $args, $field, $options['post_id'] );
|
||||
|
||||
// get terms
|
||||
$terms = acf_get_terms( $args );
|
||||
|
||||
// sort into hierachial order!
|
||||
if ( $is_hierarchical ) {
|
||||
|
||||
// update vars
|
||||
$limit = acf_maybe_get( $args, 'number', $limit );
|
||||
$offset = acf_maybe_get( $args, 'offset', $offset );
|
||||
|
||||
// get parent
|
||||
$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 ) {
|
||||
|
||||
// order terms
|
||||
$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 ) {
|
||||
$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'] ),
|
||||
);
|
||||
}
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
'limit' => $limit,
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the Term's title displayed in the field UI.
|
||||
*
|
||||
* @date 1/11/2013
|
||||
* @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.
|
||||
* @return string
|
||||
*/
|
||||
function get_term_title( $term, $field, $post_id = 0 ) {
|
||||
$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' );
|
||||
|
||||
/**
|
||||
* 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_terms
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_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 int $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
|
||||
*
|
||||
* @date 26/11/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param int $post_id
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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( $field ) {
|
||||
|
||||
// force value to array
|
||||
$field['value'] = acf_get_array( $field['value'] );
|
||||
|
||||
// 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'],
|
||||
);
|
||||
|
||||
// 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 );
|
||||
} elseif ( $field['field_type'] == 'multi_select' ) {
|
||||
$field['multiple'] = 1;
|
||||
|
||||
$this->render_field_select( $field );
|
||||
} elseif ( $field['field_type'] == 'radio' ) {
|
||||
$this->render_field_checkbox( $field );
|
||||
} elseif ( $field['field_type'] == 'checkbox' ) {
|
||||
$this->render_field_checkbox( $field );
|
||||
}
|
||||
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_select()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
|
||||
/*
|
||||
* ajax_add_term
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 17/04/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_add_term() {
|
||||
|
||||
// verify nonce
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// vars
|
||||
$args = wp_parse_args(
|
||||
$_POST,
|
||||
array(
|
||||
'nonce' => '',
|
||||
'field_key' => '',
|
||||
'term_name' => '',
|
||||
'term_parent' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// 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 _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 int|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,216 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_text' ) ) :
|
||||
|
||||
class acf_field_text extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
$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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,255 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_textarea' ) ) :
|
||||
|
||||
class acf_field_textarea extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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 );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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,210 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_time_picker' ) ) :
|
||||
|
||||
class acf_field_time_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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>';
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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_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
|
||||
*/
|
||||
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 `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,319 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_true_false' ) ) :
|
||||
|
||||
class acf_field_true_false extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// 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_attr( $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
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_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
|
||||
* @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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// bail early if not required
|
||||
if ( ! $field['required'] ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// value may be '0'
|
||||
if ( ! $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* 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|int $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,179 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_url' ) ) :
|
||||
|
||||
class acf_field_url extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = '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' => '',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
$html = '';
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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_url' );
|
||||
endif; // class_exists check
|
@ -0,0 +1,634 @@
|
||||
<?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 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' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @date 23/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param array $field The ACF field.
|
||||
* @return void
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// Change Field into a select.
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['choices'] = array();
|
||||
$field['query_nonce'] = wp_create_nonce( 'acf/fields/user/query' . $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 fiven 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.
|
||||
if ( ! isset( $_REQUEST['user_query_nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_REQUEST['user_query_nonce'] ), 'acf/fields/user/query' . $query->field['key'] ) ) {
|
||||
$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 bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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 int|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|int $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,432 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_wysiwyg' ) ) :
|
||||
|
||||
class acf_field_wysiwyg extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_filters
|
||||
*
|
||||
* 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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_toolbars
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_enqueue_uploader
|
||||
*
|
||||
* 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 echo __( '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 _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 _e( 'Click to initialize TinyMCE', 'acf' ); ?></div>
|
||||
<?php endif; ?>
|
||||
<?php printf( $textarea, $field['value'] ); ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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,354 @@
|
||||
<?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
|
||||
);
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* This function will initialize the field type
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function __construct() {
|
||||
|
||||
// initialize
|
||||
$this->initialize();
|
||||
|
||||
// register info
|
||||
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 );
|
||||
|
||||
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 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* This function will initialize the field type
|
||||
*
|
||||
* @type function
|
||||
* @date 27/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function initialize() {
|
||||
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_filter
|
||||
*
|
||||
* This function checks if the function is_callable before adding the filter
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $tag (string)
|
||||
* @param $function_to_add (string)
|
||||
* @param $priority (int)
|
||||
* @param $accepted_args (int)
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function add_filter( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
|
||||
// bail early if no callable
|
||||
if ( ! is_callable( $function_to_add ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add
|
||||
add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_field_filter
|
||||
*
|
||||
* This function will add a field type specific filter
|
||||
*
|
||||
* @type function
|
||||
* @date 29/09/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $tag (string)
|
||||
* @param $function_to_add (string)
|
||||
* @param $priority (int)
|
||||
* @param $accepted_args (int)
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function add_field_filter( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
|
||||
// append
|
||||
$tag .= '/type=' . $this->name;
|
||||
|
||||
// add
|
||||
$this->add_filter( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_action
|
||||
*
|
||||
* This function checks if the function is_callable before adding the action
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $tag (string)
|
||||
* @param $function_to_add (string)
|
||||
* @param $priority (int)
|
||||
* @param $accepted_args (int)
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function add_action( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
|
||||
// bail early if no callable
|
||||
if ( ! is_callable( $function_to_add ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add
|
||||
add_action( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* add_field_action
|
||||
*
|
||||
* This function will add a field type specific filter
|
||||
*
|
||||
* @type function
|
||||
* @date 29/09/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $tag (string)
|
||||
* @param $function_to_add (string)
|
||||
* @param $priority (int)
|
||||
* @param $accepted_args (int)
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function add_field_action( $tag = '', $function_to_add = '', $priority = 10, $accepted_args = 1 ) {
|
||||
|
||||
// append
|
||||
$tag .= '/type=' . $this->name;
|
||||
|
||||
// add
|
||||
$this->add_action( $tag, $function_to_add, $priority, $accepted_args );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_field
|
||||
*
|
||||
* This function will append default settings to a field
|
||||
*
|
||||
* @type filter ("acf/validate_field/type={$this->name}")
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field (array)
|
||||
*/
|
||||
|
||||
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
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* admin_l10n
|
||||
*
|
||||
* This function will append l10n text translations to an array which is later passed to JS
|
||||
*
|
||||
* @type filter ("acf/input/admin_l10n")
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $l10n (array)
|
||||
* @return $l10n (array)
|
||||
*/
|
||||
|
||||
function input_admin_l10n( $l10n ) {
|
||||
|
||||
// bail early if no defaults
|
||||
if ( empty( $this->l10n ) ) {
|
||||
return $l10n;
|
||||
}
|
||||
|
||||
// append
|
||||
$l10n[ $this->name ] = $this->l10n;
|
||||
|
||||
// return
|
||||
return $l10n;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add additional validation for fields being updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param mixed $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|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|int $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|int $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return $value;
|
||||
}
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
Reference in New Issue
Block a user