edit pages

This commit is contained in:
razusrest
2024-04-18 17:45:44 +05:45
parent f4e3b7c750
commit 46f1b89d3d
3923 changed files with 1838473 additions and 156 deletions

View File

@ -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
?>

View File

@ -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

View File

@ -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

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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 &lt;br&gt;', '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

View File

@ -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

View File

@ -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
?>

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
?>

View File

@ -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&hellip;', 'Select2 JS load_more', 'acf' ),
'searching' => _x( 'Searching&hellip;', '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

View File

@ -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

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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

View File

@ -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 &lt;br&gt;', '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

View File

@ -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
?>

View File

@ -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
?>

View File

@ -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

View File

@ -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

View File

@ -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( ']]>', ']]&gt;', $value );
}
}
// initialize
acf_register_field_type( 'acf_field_wysiwyg' );
endif; // class_exists check
?>

View File

@ -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