initial commit

This commit is contained in:
2024-04-29 13:12:44 +05:45
commit 34887303c5
19300 changed files with 5268802 additions and 0 deletions

View File

@@ -0,0 +1,168 @@
<?php
// Register store for form data.
acf_register_store( 'form' );
/**
* acf_set_form_data
*
* Sets data about the current form.
*
* @date 6/10/13
* @since 5.0.0
*
* @param string $name The store name.
* @param array $data Array of data to start the store with.
* @return ACF_Data
*/
function acf_set_form_data( $name = '', $data = false ) {
return acf_get_store( 'form' )->set( $name, $data );
}
/**
* acf_get_form_data
*
* Gets data about the current form.
*
* @date 6/10/13
* @since 5.0.0
*
* @param string $name The store name.
* @return mixed
*/
function acf_get_form_data( $name = '' ) {
return acf_get_store( 'form' )->get( $name );
}
/**
* acf_form_data
*
* Called within a form to set important information and render hidden inputs.
*
* @date 15/10/13
* @since 5.0.0
*
* @param void
* @return void
*/
function acf_form_data( $data = array() ) {
// Apply defaults.
$data = wp_parse_args(
$data,
array(
/** @type string The current screen (post, user, taxonomy, etc). */
'screen' => 'post',
/** @type int|string The ID of current post being edited. */
'post_id' => 0,
/** @type bool Enables AJAX validation. */
'validation' => true,
)
);
// Create nonce using screen.
$data['nonce'] = wp_create_nonce( $data['screen'] );
// Append "changed" input used within "_wp_post_revision_fields" action.
$data['changed'] = 0;
// Set data.
acf_set_form_data( $data );
// Render HTML.
?>
<div id="acf-form-data" class="acf-hidden">
<?php
// Create hidden inputs from $data
foreach ( $data as $name => $value ) {
acf_hidden_input(
array(
'id' => '_acf_' . $name,
'name' => '_acf_' . $name,
'value' => $value,
)
);
}
/**
* Fires within the #acf-form-data element to add extra HTML.
*
* @date 15/10/13
* @since 5.0.0
*
* @param array $data The form data.
*/
do_action( 'acf/form_data', $data );
do_action( 'acf/input/form_data', $data );
?>
</div>
<?php
}
/**
* acf_save_post
*
* Saves the $_POST data.
*
* @date 15/10/13
* @since 5.0.0
*
* @param int|string $post_id The post id.
* @param array $values An array of values to override $_POST.
* @return bool True if save was successful.
*/
function acf_save_post( $post_id = 0, $values = null ) {
// Override $_POST data with $values.
if ( $values !== null ) {
$_POST['acf'] = $values;
}
// Bail early if no data to save.
if ( empty( $_POST['acf'] ) ) {
return false;
}
// Set form data (useful in various filters/actions).
acf_set_form_data( 'post_id', $post_id );
// Filter $_POST data for users without the 'unfiltered_html' capability.
if ( ! acf_allow_unfiltered_html() ) {
$_POST['acf'] = wp_kses_post_deep( $_POST['acf'] );
}
// Do generic action.
do_action( 'acf/save_post', $post_id );
// Return true.
return true;
}
/**
* _acf_do_save_post
*
* Private function hooked into 'acf/save_post' to actually save the $_POST data.
* This allows developers to hook in before and after ACF has actually saved the data.
*
* @date 11/1/19
* @since 5.7.10
*
* @param int|string $post_id The post id.
* @return void
*/
function _acf_do_save_post( $post_id = 0 ) {
// Check and update $_POST data.
if ( $_POST['acf'] ) {
acf_update_values( $_POST['acf'], $post_id );
}
}
// Run during generic action.
add_action( 'acf/save_post', '_acf_do_save_post' );

View File

@@ -0,0 +1,470 @@
<?php
/*
* acf_is_empty
*
* Returns true if the value provided is considered "empty". Allows numbers such as 0.
*
* @date 6/7/16
* @since 5.4.0
*
* @param mixed $var The value to check.
* @return bool
*/
function acf_is_empty( $var ) {
return ( ! $var && ! is_numeric( $var ) );
}
/**
* acf_not_empty
*
* Returns true if the value provided is considered "not empty". Allows numbers such as 0.
*
* @date 15/7/19
* @since 5.8.1
*
* @param mixed $var The value to check.
* @return bool
*/
function acf_not_empty( $var ) {
return ( $var || is_numeric( $var ) );
}
/**
* acf_uniqid
*
* Returns a unique numeric based id.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $prefix The id prefix. Defaults to 'acf'.
* @return string
*/
function acf_uniqid( $prefix = 'acf' ) {
// Instantiate global counter.
global $acf_uniqid;
if ( ! isset( $acf_uniqid ) ) {
$acf_uniqid = 1;
}
// Return id.
return $prefix . '-' . $acf_uniqid++;
}
/**
* acf_merge_attributes
*
* Merges together two arrays but with extra functionality to append class names.
*
* @date 22/1/19
* @since 5.7.10
*
* @param array $array1 An array of attributes.
* @param array $array2 An array of attributes.
* @return array
*/
function acf_merge_attributes( $array1, $array2 ) {
// Merge together attributes.
$array3 = array_merge( $array1, $array2 );
// Append together special attributes.
foreach ( array( 'class', 'style' ) as $key ) {
if ( isset( $array1[ $key ] ) && isset( $array2[ $key ] ) ) {
$array3[ $key ] = trim( $array1[ $key ] ) . ' ' . trim( $array2[ $key ] );
}
}
// Return.
return $array3;
}
/**
* acf_cache_key
*
* Returns a filtered cache key.
*
* @date 25/1/19
* @since 5.7.11
*
* @param string $key The cache key.
* @return string
*/
function acf_cache_key( $key = '' ) {
/**
* Filters the cache key.
*
* @date 25/1/19
* @since 5.7.11
*
* @param string $key The cache key.
* @param string $original_key The original cache key.
*/
return apply_filters( 'acf/get_cache_key', $key, $key );
}
/**
* acf_request_args
*
* Returns an array of $_REQUEST values using the provided defaults.
*
* @date 28/2/19
* @since 5.7.13
*
* @param array $args An array of args.
* @return array
*/
function acf_request_args( $args = array() ) {
foreach ( $args as $k => $v ) {
$args[ $k ] = isset( $_REQUEST[ $k ] ) ? $_REQUEST[ $k ] : $args[ $k ];
}
return $args;
}
/**
* Returns a single $_REQUEST arg with fallback.
*
* @date 23/10/20
* @since 5.9.2
*
* @param string $key The property name.
* @param mixed $default The default value to fallback to.
* @return mixed
*/
function acf_request_arg( $name = '', $default = null ) {
return isset( $_REQUEST[ $name ] ) ? $_REQUEST[ $name ] : $default;
}
// Register store.
acf_register_store( 'filters' );
/**
* acf_enable_filter
*
* Enables a filter with the given name.
*
* @date 14/7/16
* @since 5.4.0
*
* @param string name The modifer name.
* @return void
*/
function acf_enable_filter( $name = '' ) {
acf_get_store( 'filters' )->set( $name, true );
}
/**
* acf_disable_filter
*
* Disables a filter with the given name.
*
* @date 14/7/16
* @since 5.4.0
*
* @param string name The modifer name.
* @return void
*/
function acf_disable_filter( $name = '' ) {
acf_get_store( 'filters' )->set( $name, false );
}
/**
* acf_is_filter_enabled
*
* Returns the state of a filter for the given name.
*
* @date 14/7/16
* @since 5.4.0
*
* @param string name The modifer name.
* @return array
*/
function acf_is_filter_enabled( $name = '' ) {
return acf_get_store( 'filters' )->get( $name );
}
/**
* acf_get_filters
*
* Returns an array of filters in their current state.
*
* @date 14/7/16
* @since 5.4.0
*
* @param void
* @return array
*/
function acf_get_filters() {
return acf_get_store( 'filters' )->get();
}
/**
* acf_set_filters
*
* Sets an array of filter states.
*
* @date 14/7/16
* @since 5.4.0
*
* @param array $filters An Array of modifers
* @return array
*/
function acf_set_filters( $filters = array() ) {
acf_get_store( 'filters' )->set( $filters );
}
/**
* acf_disable_filters
*
* Disables all filters and returns the previous state.
*
* @date 14/7/16
* @since 5.4.0
*
* @param void
* @return array
*/
function acf_disable_filters() {
// Get state.
$prev_state = acf_get_filters();
// Set all modifers as false.
acf_set_filters( array_map( '__return_false', $prev_state ) );
// Return prev state.
return $prev_state;
}
/**
* acf_enable_filters
*
* Enables all or an array of specific filters and returns the previous state.
*
* @date 14/7/16
* @since 5.4.0
*
* @param array $filters An Array of modifers
* @return array
*/
function acf_enable_filters( $filters = array() ) {
// Get state.
$prev_state = acf_get_filters();
// Allow specific filters to be enabled.
if ( $filters ) {
acf_set_filters( $filters );
// Set all modifers as true.
} else {
acf_set_filters( array_map( '__return_true', $prev_state ) );
}
// Return prev state.
return $prev_state;
}
/**
* acf_idval
*
* Parses the provided value for an ID.
*
* @date 29/3/19
* @since 5.7.14
*
* @param mixed $value A value to parse.
* @return int
*/
function acf_idval( $value ) {
// Check if value is numeric.
if ( is_numeric( $value ) ) {
return (int) $value;
// Check if value is array.
} elseif ( is_array( $value ) ) {
return (int) isset( $value['ID'] ) ? $value['ID'] : 0;
// Check if value is object.
} elseif ( is_object( $value ) ) {
return (int) isset( $value->ID ) ? $value->ID : 0;
}
// Return default.
return 0;
}
/**
* acf_maybe_idval
*
* Checks value for potential id value.
*
* @date 6/4/19
* @since 5.7.14
*
* @param mixed $value A value to parse.
* @return mixed
*/
function acf_maybe_idval( $value ) {
if ( $id = acf_idval( $value ) ) {
return $id;
}
return $value;
}
/**
* acf_numval
*
* Casts the provided value as eiter an int or float using a simple hack.
*
* @date 11/4/19
* @since 5.7.14
*
* @param mixed $value A value to parse.
* @return (int|float)
*/
function acf_numval( $value ) {
return ( intval( $value ) == floatval( $value ) ) ? intval( $value ) : floatval( $value );
}
/**
* acf_idify
*
* Returns an id attribute friendly string.
*
* @date 24/12/17
* @since 5.6.5
*
* @param string $str The string to convert.
* @return string
*/
function acf_idify( $str = '' ) {
return str_replace( array( '][', '[', ']' ), array( '-', '-', '' ), strtolower( $str ) );
}
/**
* acf_slugify
*
* Returns a slug friendly string.
*
* @date 24/12/17
* @since 5.6.5
*
* @param string $str The string to convert.
* @param string $glue The glue between each slug piece.
* @return string
*/
function acf_slugify( $str = '', $glue = '-' ) {
return str_replace( array( '_', '-', '/', ' ' ), $glue, strtolower( $str ) );
}
/**
* Returns a string with correct full stop punctuation.
*
* @date 12/7/19
* @since 5.8.2
*
* @param string $str The string to format.
* @return string
*/
function acf_punctify( $str = '' ) {
if ( substr( trim( strip_tags( $str ) ), -1 ) !== '.' ) {
return trim( $str ) . '.';
}
return trim( $str );
}
/**
* acf_did
*
* Returns true if ACF already did an event.
*
* @date 30/8/19
* @since 5.8.1
*
* @param string $name The name of the event.
* @return bool
*/
function acf_did( $name ) {
// Return true if already did the event (preventing event).
if ( acf_get_data( "acf_did_$name" ) ) {
return true;
// Otherwise, update store and return false (alowing event).
} else {
acf_set_data( "acf_did_$name", true );
return false;
}
}
/**
* Returns the length of a string that has been submitted via $_POST.
*
* Uses the following process:
* 1. Unslash the string because posted values will be slashed.
* 2. Decode special characters because wp_kses() will normalize entities.
* 3. Treat line-breaks as a single character instead of two.
* 4. Use mb_strlen() to accomodate special characters.
*
* @date 04/06/2020
* @since 5.9.0
*
* @param string $str The string to review.
* @return int
*/
function acf_strlen( $str ) {
return mb_strlen( str_replace( "\r\n", "\n", wp_specialchars_decode( wp_unslash( $str ) ) ) );
}
/**
* Returns a value with default fallback.
*
* @date 6/4/20
* @since 5.9.0
*
* @param mixed $value The value.
* @param mixed $default_value The default value.
* @return mixed
*/
function acf_with_default( $value, $default_value ) {
return $value ? $value : $default_value;
}
/**
* Returns the current priority of a running action.
*
* @date 14/07/2020
* @since 5.9.0
*
* @param string $action The action name.
* @return int|bool
*/
function acf_doing_action( $action ) {
global $wp_filter;
if ( isset( $wp_filter[ $action ] ) ) {
return $wp_filter[ $action ]->current_priority();
}
return false;
}
/**
* Returns the current URL.
*
* @date 23/01/2015
* @since 5.1.5
*
* @param void
* @return string
*/
function acf_get_current_url() {
// Ensure props exist to avoid PHP Notice during CLI commands.
if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
return ( is_ssl() ? 'https' : 'http' ) . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
return '';
}

View File

@@ -0,0 +1,230 @@
<?php
// Register store.
acf_register_store( 'hook-variations' );
/**
* acf_add_filter_variations
*
* Registers variations for the given filter.
*
* @date 26/1/19
* @since 5.7.11
*
* @param string $filter The filter name.
* @param array $variations An array variation keys.
* @param int $index The param index to find variation values.
* @return void
*/
function acf_add_filter_variations( $filter = '', $variations = array(), $index = 0 ) {
// Store replacement data.
acf_get_store( 'hook-variations' )->set(
$filter,
array(
'type' => 'filter',
'variations' => $variations,
'index' => $index,
)
);
// Add generic handler.
// Use a priotiry of 10, and accepted args of 10 (ignored by WP).
add_filter( $filter, '_acf_apply_hook_variations', 10, 10 );
}
/**
* acf_add_action_variations
*
* Registers variations for the given action.
*
* @date 26/1/19
* @since 5.7.11
*
* @param string $action The action name.
* @param array $variations An array variation keys.
* @param int $index The param index to find variation values.
* @return void
*/
function acf_add_action_variations( $action = '', $variations = array(), $index = 0 ) {
// Store replacement data.
acf_get_store( 'hook-variations' )->set(
$action,
array(
'type' => 'action',
'variations' => $variations,
'index' => $index,
)
);
// Add generic handler.
// Use a priotiry of 10, and accepted args of 10 (ignored by WP).
add_action( $action, '_acf_apply_hook_variations', 10, 10 );
}
/**
* _acf_apply_hook_variations
*
* Applys hook variations during apply_filters() or do_action().
*
* @date 25/1/19
* @since 5.7.11
*
* @param mixed
* @return mixed
*/
function _acf_apply_hook_variations() {
// Get current filter.
$filter = current_filter();
// Get args provided.
$args = func_get_args();
// Get variation information.
$variations = acf_get_store( 'hook-variations' )->get( $filter );
extract( $variations );
// Find field in args using index.
$field = $args[ $index ];
// Loop over variations and apply filters.
foreach ( $variations as $variation ) {
// Get value from field.
// First look for "backup" value ("_name", "_key").
if ( isset( $field[ "_$variation" ] ) ) {
$value = $field[ "_$variation" ];
} elseif ( isset( $field[ $variation ] ) ) {
$value = $field[ $variation ];
} else {
continue;
}
// Apply filters.
if ( $type === 'filter' ) {
$args[0] = apply_filters_ref_array( "$filter/$variation=$value", $args );
// Or do action.
} else {
do_action_ref_array( "$filter/$variation=$value", $args );
}
}
// Return first arg.
return $args[0];
}
// Register store.
acf_register_store( 'deprecated-hooks' );
/**
* acf_add_deprecated_filter
*
* Registers a deprecated filter to run during the replacement.
*
* @date 25/1/19
* @since 5.7.11
*
* @param string $deprecated The deprecated hook.
* @param string $version The version this hook was deprecated.
* @param string $replacement The replacement hook.
* @return void
*/
function acf_add_deprecated_filter( $deprecated, $version, $replacement ) {
// Store replacement data.
acf_get_store( 'deprecated-hooks' )->append(
array(
'type' => 'filter',
'deprecated' => $deprecated,
'replacement' => $replacement,
'version' => $version,
)
);
// Add generic handler.
// Use a priotiry of 10, and accepted args of 10 (ignored by WP).
add_filter( $replacement, '_acf_apply_deprecated_hook', 10, 10 );
}
/**
* acf_add_deprecated_action
*
* Registers a deprecated action to run during the replacement.
*
* @date 25/1/19
* @since 5.7.11
*
* @param string $deprecated The deprecated hook.
* @param string $version The version this hook was deprecated.
* @param string $replacement The replacement hook.
* @return void
*/
function acf_add_deprecated_action( $deprecated, $version, $replacement ) {
// Store replacement data.
acf_get_store( 'deprecated-hooks' )->append(
array(
'type' => 'action',
'deprecated' => $deprecated,
'replacement' => $replacement,
'version' => $version,
)
);
// Add generic handler.
// Use a priotiry of 10, and accepted args of 10 (ignored by WP).
add_filter( $replacement, '_acf_apply_deprecated_hook', 10, 10 );
}
/**
* _acf_apply_deprecated_hook
*
* Applys a deprecated filter during apply_filters() or do_action().
*
* @date 25/1/19
* @since 5.7.11
*
* @param mixed
* @return mixed
*/
function _acf_apply_deprecated_hook() {
// Get current hook.
$hook = current_filter();
// Get args provided.
$args = func_get_args();
// Get deprecated items for this hook.
$items = acf_get_store( 'deprecated-hooks' )->query( array( 'replacement' => $hook ) );
// Loop over results.
foreach ( $items as $item ) {
// Extract data.
extract( $item );
// Check if anyone is hooked into this deprecated hook.
if ( has_filter( $deprecated ) ) {
// Log warning.
// _deprecated_hook( $deprecated, $version, $hook );
// Apply filters.
if ( $type === 'filter' ) {
$args[0] = apply_filters_ref_array( $deprecated, $args );
// Or do action.
} else {
do_action_ref_array( $deprecated, $args );
}
}
}
// Return first arg.
return $args[0];
}

View File

@@ -0,0 +1,497 @@
<?php
/**
* acf_filter_attrs
*
* Filters out empty attrs from the provided array.
*
* @date 11/6/19
* @since 5.8.1
*
* @param array $attrs The array of attrs.
* @return array
*/
function acf_filter_attrs( $attrs ) {
// Filter out empty attrs but allow "0" values.
$filtered = array_filter( $attrs, 'acf_not_empty' );
// Correct specific attributes (required="required").
foreach ( array( 'required', 'readonly', 'disabled', 'multiple' ) as $key ) {
unset( $filtered[ $key ] );
if ( ! empty( $attrs[ $key ] ) ) {
$filtered[ $key ] = $key;
}
}
return $filtered;
}
/**
* acf_esc_attrs
*
* Generated valid HTML from an array of attrs.
*
* @date 11/6/19
* @since 5.8.1
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_esc_attrs( $attrs ) {
$html = '';
// Loop over attrs and validate data types.
foreach ( $attrs as $k => $v ) {
// String (but don't trim value).
if ( is_string( $v ) && ( $k !== 'value' ) ) {
$v = trim( $v );
// Boolean
} elseif ( is_bool( $v ) ) {
$v = $v ? 1 : 0;
// Object
} elseif ( is_array( $v ) || is_object( $v ) ) {
$v = json_encode( $v );
}
// Generate HTML.
$html .= sprintf( ' %s="%s"', esc_attr( $k ), esc_attr( $v ) );
}
// Return trimmed.
return trim( $html );
}
/**
* Sanitizes text content and strips out disallowed HTML.
*
* This function emulates `wp_kses_post()` with a context of "acf" for extensibility.
*
* @date 16/4/21
* @since 5.9.6
*
* @param string $string
* @return string
*/
function acf_esc_html( $string = '' ) {
return wp_kses( (string) $string, 'acf' );
}
/**
* Private callback for the "wp_kses_allowed_html" filter used to return allowed HTML for "acf" context.
*
* @date 16/4/21
* @since 5.9.6
*
* @param array $tags An array of allowed tags.
* @param string $context The context name.
* @return array.
*/
function _acf_kses_allowed_html( $tags, $context ) {
global $allowedposttags;
if ( $context === 'acf' ) {
return $allowedposttags;
}
return $tags;
}
add_filter( 'wp_kses_allowed_html', '_acf_kses_allowed_html', 0, 2 );
/**
* acf_html_input
*
* Returns the HTML of an input.
*
* @date 13/6/19
* @since 5.8.1
*
* @param array $attrs The array of attrs.
* @return string
*/
// function acf_html_input( $attrs = array() ) {
// return sprintf( '<input %s/>', acf_esc_attrs($attrs) );
// }
/**
* acf_hidden_input
*
* Renders the HTML of a hidden input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_hidden_input( $attrs = array() ) {
echo acf_get_hidden_input( $attrs );
}
/**
* acf_get_hidden_input
*
* Returns the HTML of a hidden input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_hidden_input( $attrs = array() ) {
return sprintf( '<input type="hidden" %s/>', acf_esc_attrs( $attrs ) );
}
/**
* acf_text_input
*
* Renders the HTML of a text input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_text_input( $attrs = array() ) {
echo acf_get_text_input( $attrs );
}
/**
* acf_get_text_input
*
* Returns the HTML of a text input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_text_input( $attrs = array() ) {
$attrs = wp_parse_args(
$attrs,
array(
'type' => 'text',
)
);
if ( isset( $attrs['value'] ) && is_string( $attrs['value'] ) ) {
$attrs['value'] = htmlspecialchars( $attrs['value'] );
}
return sprintf( '<input %s/>', acf_esc_attrs( $attrs ) );
}
/**
* acf_file_input
*
* Renders the HTML of a file input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_file_input( $attrs = array() ) {
echo acf_get_file_input( $attrs );
}
/**
* acf_get_file_input
*
* Returns the HTML of a file input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_file_input( $attrs = array() ) {
return sprintf( '<input type="file" %s/>', acf_esc_attrs( $attrs ) );
}
/**
* acf_textarea_input
*
* Renders the HTML of a textarea input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_textarea_input( $attrs = array() ) {
echo acf_get_textarea_input( $attrs );
}
/**
* acf_get_textarea_input
*
* Returns the HTML of a textarea input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_textarea_input( $attrs = array() ) {
$value = '';
if ( isset( $attrs['value'] ) ) {
$value = $attrs['value'];
unset( $attrs['value'] );
}
return sprintf( '<textarea %s>%s</textarea>', acf_esc_attrs( $attrs ), esc_textarea( $value ) );
}
/**
* acf_checkbox_input
*
* Renders the HTML of a checkbox input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_checkbox_input( $attrs = array() ) {
echo acf_get_checkbox_input( $attrs );
}
/**
* acf_get_checkbox_input
*
* Returns the HTML of a checkbox input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_checkbox_input( $attrs = array() ) {
// Allow radio or checkbox type.
$attrs = wp_parse_args(
$attrs,
array(
'type' => 'checkbox',
)
);
// Get label.
$label = '';
if ( isset( $attrs['label'] ) ) {
$label = $attrs['label'];
unset( $attrs['label'] );
}
// Render.
$checked = isset( $attrs['checked'] );
return '<label' . ( $checked ? ' class="selected"' : '' ) . '><input ' . acf_esc_attr( $attrs ) . '/> ' . acf_esc_html( $label ) . '</label>';
}
/**
* acf_radio_input
*
* Renders the HTML of a radio input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_radio_input( $attrs = array() ) {
echo acf_get_radio_input( $attrs );
}
/**
* acf_get_radio_input
*
* Returns the HTML of a radio input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_radio_input( $attrs = array() ) {
$attrs['type'] = 'radio';
return acf_get_checkbox_input( $attrs );
}
/**
* acf_select_input
*
* Renders the HTML of a select input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_select_input( $attrs = array() ) {
echo acf_get_select_input( $attrs );
}
/**
* acf_select_input
*
* Returns the HTML of a select input.
*
* @date 3/02/2014
* @since 5.0.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_get_select_input( $attrs = array() ) {
$value = (array) acf_extract_var( $attrs, 'value' );
$choices = (array) acf_extract_var( $attrs, 'choices' );
return sprintf(
'<select %s>%s</select>',
acf_esc_attrs( $attrs ),
acf_walk_select_input( $choices, $value )
);
}
/**
* acf_walk_select_input
*
* Returns the HTML of a select input's choices.
*
* @date 27/6/17
* @since 5.6.0
*
* @param array $choices The choices to walk through.
* @param array $values The selected choices.
* @param array $depth The current walk depth.
* @return string
*/
function acf_walk_select_input( $choices = array(), $values = array(), $depth = 0 ) {
$html = '';
// Sanitize values for 'selected' matching (only once).
if ( $depth == 0 ) {
$values = array_map( 'esc_attr', $values );
}
// Loop over choices and append to html.
if ( $choices ) {
foreach ( $choices as $value => $label ) {
// Multiple (optgroup)
if ( is_array( $label ) ) {
$html .= sprintf(
'<optgroup label="%s">%s</optgroup>',
esc_attr( $value ),
acf_walk_select_input( $label, $values, $depth + 1 )
);
// single (option)
} else {
$attrs = array(
'value' => $value,
);
// If is selected.
$pos = array_search( esc_attr( $value ), $values );
if ( $pos !== false ) {
$attrs['selected'] = 'selected';
$attrs['data-i'] = $pos;
}
$html .= sprintf( '<option %s>%s</option>', acf_esc_attr( $attrs ), esc_html( $label ) );
}
}
}
return $html;
}
/**
* acf_clean_atts
*
* See acf_filter_attrs().
*
* @date 3/10/17
* @since 5.6.3
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_clean_atts( $attrs ) {
return acf_filter_attrs( $attrs );
}
/**
* acf_esc_atts
*
* See acf_esc_attrs().
*
* @date 27/6/17
* @since 5.6.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_esc_atts( $attrs ) {
return acf_esc_attrs( $attrs );
}
/**
* acf_esc_attr
*
* See acf_esc_attrs().
*
* @date 13/6/19
* @since 5.8.1
* @deprecated 5.6.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_esc_attr( $attrs ) {
return acf_esc_attrs( $attrs );
}
/**
* acf_esc_attr_e
*
* See acf_esc_attrs().
*
* @date 13/6/19
* @since 5.8.1
* @deprecated 5.6.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_esc_attr_e( $attrs ) {
echo acf_esc_attrs( $attrs );
}
/**
* acf_esc_atts_e
*
* See acf_esc_attrs().
*
* @date 13/6/19
* @since 5.8.1
* @deprecated 5.6.0
*
* @param array $attrs The array of attrs.
* @return string
*/
function acf_esc_atts_e( $attrs ) {
echo acf_esc_attrs( $attrs );
}

View File

@@ -0,0 +1,382 @@
<?php
/**
* acf_get_meta
*
* Returns an array of "ACF only" meta for the given post_id.
*
* @date 9/10/18
* @since 5.8.0
*
* @param mixed $post_id The post_id for this data.
* @return array
*/
function acf_get_meta( $post_id = 0 ) {
// Allow filter to short-circuit load_value logic.
$null = apply_filters( 'acf/pre_load_meta', null, $post_id );
if ( $null !== null ) {
return ( $null === '__return_null' ) ? null : $null;
}
// Decode $post_id for $type and $id.
extract( acf_decode_post_id( $post_id ) );
// Determine CRUD function.
// - Relies on decoded post_id result to identify option or meta types.
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
if ( $type === 'option' ) {
$allmeta = acf_get_option_meta( $id );
} else {
$allmeta = get_metadata( $type, $id, '' );
}
// Loop over meta and check that a reference exists for each value.
$meta = array();
if ( $allmeta ) {
foreach ( $allmeta as $key => $value ) {
// If a reference exists for this value, add it to the meta array.
if ( isset( $allmeta[ "_$key" ] ) ) {
$meta[ $key ] = $allmeta[ $key ][0];
$meta[ "_$key" ] = $allmeta[ "_$key" ][0];
}
}
}
// Unserialized results (get_metadata does not unserialize if $key is empty).
$meta = array_map( 'maybe_unserialize', $meta );
/**
* Filters the $meta array after it has been loaded.
*
* @date 25/1/19
* @since 5.7.11
*
* @param array $meta The arary of loaded meta.
* @param string $post_id The $post_id for this meta.
*/
return apply_filters( 'acf/load_meta', $meta, $post_id );
}
/**
* acf_get_option_meta
*
* Returns an array of meta for the given wp_option name prefix in the same format as get_post_meta().
*
* @date 9/10/18
* @since 5.8.0
*
* @param string $prefix The wp_option name prefix.
* @return array
*/
function acf_get_option_meta( $prefix = '' ) {
// Globals.
global $wpdb;
// Vars.
$meta = array();
$search = "{$prefix}_%";
$_search = "_{$prefix}_%";
// Escape underscores for LIKE.
$search = str_replace( '_', '\_', $search );
$_search = str_replace( '_', '\_', $_search );
// Query database for results.
$rows = $wpdb->get_results(
$wpdb->prepare(
"SELECT *
FROM $wpdb->options
WHERE option_name LIKE %s
OR option_name LIKE %s",
$search,
$_search
),
ARRAY_A
);
// Loop over results and append meta (removing the $prefix from the option name).
$len = strlen( "{$prefix}_" );
foreach ( $rows as $row ) {
$meta[ substr( $row['option_name'], $len ) ][] = $row['option_value'];
}
// Return results.
return $meta;
}
/**
* acf_get_metadata
*
* Retrieves specific metadata from the database.
*
* @date 16/10/2015
* @since 5.2.3
*
* @param (int|string) $post_id The post id.
* @param string $name The meta name.
* @param bool $hidden If the meta is hidden (starts with an underscore).
* @return mixed
*/
function acf_get_metadata( $post_id = 0, $name = '', $hidden = false ) {
// Allow filter to short-circuit logic.
$null = apply_filters( 'acf/pre_load_metadata', null, $post_id, $name, $hidden );
if ( $null !== null ) {
return ( $null === '__return_null' ) ? null : $null;
}
// Decode $post_id for $type and $id.
extract( acf_decode_post_id( $post_id ) );
// Hidden meta uses an underscore prefix.
$prefix = $hidden ? '_' : '';
// Bail early if no $id (possible during new acf_form).
if ( ! $id ) {
return null;
}
// Determine CRUD function.
// - Relies on decoded post_id result to identify option or meta types.
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
if ( $type === 'option' ) {
return get_option( "{$prefix}{$id}_{$name}", null );
} else {
$meta = get_metadata( $type, $id, "{$prefix}{$name}", false );
return isset( $meta[0] ) ? $meta[0] : null;
}
}
/**
* acf_update_metadata
*
* Updates metadata in the database.
*
* @date 16/10/2015
* @since 5.2.3
*
* @param (int|string) $post_id The post id.
* @param string $name The meta name.
* @param mixed $value The meta value.
* @param bool $hidden If the meta is hidden (starts with an underscore).
* @return (int|bool) Meta ID if the key didn't exist, true on successful update, false on failure.
*/
function acf_update_metadata( $post_id = 0, $name = '', $value = '', $hidden = false ) {
// Allow filter to short-circuit logic.
$pre = apply_filters( 'acf/pre_update_metadata', null, $post_id, $name, $value, $hidden );
if ( $pre !== null ) {
return $pre;
}
// Decode $post_id for $type and $id.
extract( acf_decode_post_id( $post_id ) );
// Hidden meta uses an underscore prefix.
$prefix = $hidden ? '_' : '';
// Bail early if no $id (possible during new acf_form).
if ( ! $id ) {
return false;
}
// Determine CRUD function.
// - Relies on decoded post_id result to identify option or meta types.
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
if ( $type === 'option' ) {
$value = wp_unslash( $value );
$autoload = (bool) acf_get_setting( 'autoload' );
return update_option( "{$prefix}{$id}_{$name}", $value, $autoload );
} else {
return update_metadata( $type, $id, "{$prefix}{$name}", $value );
}
}
/**
* acf_delete_metadata
*
* Deletes metadata from the database.
*
* @date 16/10/2015
* @since 5.2.3
*
* @param (int|string) $post_id The post id.
* @param string $name The meta name.
* @param bool $hidden If the meta is hidden (starts with an underscore).
* @return bool
*/
function acf_delete_metadata( $post_id = 0, $name = '', $hidden = false ) {
// Allow filter to short-circuit logic.
$pre = apply_filters( 'acf/pre_delete_metadata', null, $post_id, $name, $hidden );
if ( $pre !== null ) {
return $pre;
}
// Decode $post_id for $type and $id.
extract( acf_decode_post_id( $post_id ) );
// Hidden meta uses an underscore prefix.
$prefix = $hidden ? '_' : '';
// Bail early if no $id (possible during new acf_form).
if ( ! $id ) {
return false;
}
// Determine CRUD function.
// - Relies on decoded post_id result to identify option or meta types.
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
if ( $type === 'option' ) {
return delete_option( "{$prefix}{$id}_{$name}" );
} else {
return delete_metadata( $type, $id, "{$prefix}{$name}" );
}
}
/**
* acf_copy_postmeta
*
* Copies meta from one post to another. Useful for saving and restoring revisions.
*
* @date 25/06/2016
* @since 5.3.8
*
* @param (int|string) $from_post_id The post id to copy from.
* @param (int|string) $to_post_id The post id to paste to.
* @return void
*/
function acf_copy_metadata( $from_post_id = 0, $to_post_id = 0 ) {
// Get all postmeta.
$meta = acf_get_meta( $from_post_id );
// Check meta.
if ( $meta ) {
// Slash data. WP expects all data to be slashed and will unslash it (fixes '\' character issues).
$meta = wp_slash( $meta );
// Loop over meta.
foreach ( $meta as $name => $value ) {
acf_update_metadata( $to_post_id, $name, $value );
}
}
}
/**
* acf_copy_postmeta
*
* Copies meta from one post to another. Useful for saving and restoring revisions.
*
* @date 25/06/2016
* @since 5.3.8
* @deprecated 5.7.11
*
* @param int $from_post_id The post id to copy from.
* @param int $to_post_id The post id to paste to.
* @return void
*/
function acf_copy_postmeta( $from_post_id = 0, $to_post_id = 0 ) {
return acf_copy_metadata( $from_post_id, $to_post_id );
}
/**
* acf_get_meta_field
*
* Returns a field using the provided $id and $post_id parameters.
* Looks for a reference to help loading the correct field via name.
*
* @date 21/1/19
* @since 5.7.10
*
* @param string $key The meta name (field name).
* @param (int|string) $post_id The post_id where this field's value is saved.
* @return (array|false) The field array.
*/
function acf_get_meta_field( $key = 0, $post_id = 0 ) {
// Try reference.
$field_key = acf_get_reference( $key, $post_id );
if ( $field_key ) {
$field = acf_get_field( $field_key );
if ( $field ) {
$field['name'] = $key;
return $field;
}
}
// Return false.
return false;
}
/**
* acf_get_metaref
*
* Retrieves reference metadata from the database.
*
* @date 16/10/2015
* @since 5.2.3
*
* @param (int|string) $post_id The post id.
* @param string type The reference type (fields|groups).
* @param string $name An optional specific name
* @return mixed
*/
function acf_get_metaref( $post_id = 0, $type = 'fields', $name = '' ) {
// Load existing meta.
$meta = acf_get_metadata( $post_id, "_acf_$type" );
// Handle no meta.
if ( ! $meta ) {
return $name ? '' : array();
}
// Return specific reference.
if ( $name ) {
return isset( $meta[ $name ] ) ? $meta[ $name ] : '';
// Or return all references.
} else {
return $meta;
}
}
/**
* acf_update_metaref
*
* Updates reference metadata in the database.
*
* @date 16/10/2015
* @since 5.2.3
*
* @param (int|string) $post_id The post id.
* @param string type The reference type (fields|groups).
* @param array $references An array of references.
* @return (int|bool) Meta ID if the key didn't exist, true on successful update, false on failure.
*/
function acf_update_metaref( $post_id = 0, $type = 'fields', $references = array() ) {
// Get current references.
$current = acf_get_metaref( $post_id, $type );
// Merge in new references.
$references = array_merge( $current, $references );
// Simplify groups
if ( $type === 'groups' ) {
$references = array_values( $references );
}
// Remove duplicate references.
$references = array_unique( $references );
// Update metadata.
return acf_update_metadata( $post_id, "_acf_$type", $references );
}

View File

@@ -0,0 +1,40 @@
<?php
/**
* Returns available templates for each post type.
*
* @date 29/8/17
* @since 5.6.2
*
* @param void
* @return array
*/
function acf_get_post_templates() {
// Check store.
$cache = acf_get_data( 'post_templates' );
if ( $cache !== null ) {
return $cache;
}
// Initialize templates with default placeholder for pages.
$post_templates = array();
$post_templates['page'] = array();
// Loop over post types and append their templates.
if ( method_exists( 'WP_Theme', 'get_page_templates' ) ) {
$post_types = get_post_types();
foreach ( $post_types as $post_type ) {
$templates = wp_get_theme()->get_page_templates( null, $post_type );
if ( $templates ) {
$post_templates[ $post_type ] = $templates;
}
}
}
// Update store.
acf_set_data( 'post_templates', $post_templates );
// Return templates.
return $post_templates;
}

View File

@@ -0,0 +1,119 @@
<?php
/**
* acf_get_users
*
* Similar to the get_users() function but with extra functionality.
*
* @date 9/1/19
* @since 5.7.10
*
* @param array $args The query args.
* @return array
*/
function acf_get_users( $args = array() ) {
// Get users.
$users = get_users( $args );
// Maintain order.
if ( $users && $args['include'] ) {
// Generate order array.
$order = array();
foreach ( $users as $i => $user ) {
$order[ $i ] = array_search( $user->ID, $args['include'] );
}
// Sort results.
array_multisort( $order, $users );
}
// Return
return $users;
}
/**
* acf_get_user_result
*
* Returns a result containing "id" and "text" for the given user.
*
* @date 21/5/19
* @since 5.8.1
*
* @param WP_User $user The user object.
* @return array
*/
function acf_get_user_result( $user ) {
// Vars.
$id = $user->ID;
$text = $user->user_login;
// Add name.
if ( $user->first_name && $user->last_name ) {
$text .= " ({$user->first_name} {$user->last_name})";
} elseif ( $user->first_name ) {
$text .= " ({$user->first_name})";
}
return compact( 'id', 'text' );
}
/**
* acf_get_user_role_labels
*
* Returns an array of user roles in the format "name => label".
*
* @date 20/5/19
* @since 5.8.1
*
* @param array $roles A specific array of roles.
* @return array
*/
function acf_get_user_role_labels( $roles = array() ) {
$all_roles = wp_roles()->get_names();
// Load all roles if none provided.
if ( empty( $roles ) ) {
$roles = array_keys( $all_roles );
}
// Loop over roles and populare labels.
$lables = array();
foreach ( $roles as $role ) {
if ( isset( $all_roles[ $role ] ) ) {
$lables[ $role ] = translate_user_role( $all_roles[ $role ] );
}
}
// Return labels.
return $lables;
}
/**
* acf_allow_unfiltered_html
*
* Returns true if the current user is allowed to save unfiltered HTML.
*
* @date 9/1/19
* @since 5.7.10
*
* @param void
* @return bool
*/
function acf_allow_unfiltered_html() {
// Check capability.
$allow_unfiltered_html = current_user_can( 'unfiltered_html' );
/**
* Filters whether the current user is allowed to save unfiltered HTML.
*
* @date 9/1/19
* @since 5.7.10
*
* @param bool allow_unfiltered_html The result.
*/
return apply_filters( 'acf/allow_unfiltered_html', $allow_unfiltered_html );
}

View File

@@ -0,0 +1,158 @@
<?php
// Globals.
global $acf_stores, $acf_instances;
// Initialize plaeholders.
$acf_stores = array();
$acf_instances = array();
/**
* acf_new_instance
*
* Creates a new instance of the given class and stores it in the instances data store.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $class The class name.
* @return object The instance.
*/
function acf_new_instance( $class = '' ) {
global $acf_instances;
return $acf_instances[ $class ] = new $class();
}
/**
* acf_get_instance
*
* Returns an instance for the given class.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $class The class name.
* @return object The instance.
*/
function acf_get_instance( $class = '' ) {
global $acf_instances;
if ( ! isset( $acf_instances[ $class ] ) ) {
$acf_instances[ $class ] = new $class();
}
return $acf_instances[ $class ];
}
/**
* acf_register_store
*
* Registers a data store.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $name The store name.
* @param array $data Array of data to start the store with.
* @return ACF_Data
*/
function acf_register_store( $name = '', $data = false ) {
// Create store.
$store = new ACF_Data( $data );
// Register store.
global $acf_stores;
$acf_stores[ $name ] = $store;
// Return store.
return $store;
}
/**
* acf_get_store
*
* Returns a data store.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $name The store name.
* @return ACF_Data
*/
function acf_get_store( $name = '' ) {
global $acf_stores;
return isset( $acf_stores[ $name ] ) ? $acf_stores[ $name ] : false;
}
/**
* acf_switch_stores
*
* Triggered when switching between sites on a multisite installation.
*
* @date 13/2/19
* @since 5.7.11
*
* @param int $site_id New blog ID.
* @param int prev_blog_id Prev blog ID.
* @return void
*/
function acf_switch_stores( $site_id, $prev_site_id ) {
// Loop over stores and call switch_site().
global $acf_stores;
foreach ( $acf_stores as $store ) {
$store->switch_site( $site_id, $prev_site_id );
}
}
add_action( 'switch_blog', 'acf_switch_stores', 10, 2 );
/**
* acf_get_path
*
* Returns the plugin path to a specified file.
*
* @date 28/9/13
* @since 5.0.0
*
* @param string $filename The specified file.
* @return string
*/
function acf_get_path( $filename = '' ) {
return ACF_PATH . ltrim( $filename, '/' );
}
/**
* acf_get_url
*
* Returns the plugin url to a specified file.
* This function also defines the ACF_URL constant.
*
* @date 12/12/17
* @since 5.6.8
*
* @param string $filename The specified file.
* @return string
*/
function acf_get_url( $filename = '' ) {
if ( ! defined( 'ACF_URL' ) ) {
define( 'ACF_URL', acf_get_setting( 'url' ) );
}
return ACF_URL . ltrim( $filename, '/' );
}
/*
* acf_include
*
* Includes a file within the ACF plugin.
*
* @date 10/3/14
* @since 5.0.0
*
* @param string $filename The specified file.
* @return void
*/
function acf_include( $filename = '' ) {
$file_path = acf_get_path( $filename );
if ( file_exists( $file_path ) ) {
include_once $file_path;
}
}

View File

@@ -0,0 +1,324 @@
<?php
// Register store.
acf_register_store( 'values' )->prop( 'multisite', true );
/**
* acf_get_reference
*
* Retrieves the field key for a given field name and post_id.
*
* @date 26/1/18
* @since 5.6.5
*
* @param string $field_name The name of the field. eg 'sub_heading'.
* @param mixed $post_id The post_id of which the value is saved against.
* @return string The field key.
*/
function acf_get_reference( $field_name, $post_id ) {
// Allow filter to short-circuit load_value logic.
$reference = apply_filters( 'acf/pre_load_reference', null, $field_name, $post_id );
if ( $reference !== null ) {
return $reference;
}
// Get hidden meta for this field name.
$reference = acf_get_metadata( $post_id, $field_name, true );
/**
* Filters the reference value.
*
* @date 25/1/19
* @since 5.7.11
*
* @param string $reference The reference value.
* @param string $field_name The field name.
* @param (int|string) $post_id The post ID where meta is stored.
*/
return apply_filters( 'acf/load_reference', $reference, $field_name, $post_id );
}
/**
* Retrieves the value for a given field and post_id.
*
* @date 28/09/13
* @since 5.0.0
*
* @param int|string $post_id The post id.
* @param array $field The field array.
* @return mixed
*/
function acf_get_value( $post_id, $field ) {
// Allow filter to short-circuit load_value logic.
$value = apply_filters( 'acf/pre_load_value', null, $post_id, $field );
if ( $value !== null ) {
return $value;
}
// Get field name.
$field_name = $field['name'];
// Check store.
$store = acf_get_store( 'values' );
if ( $store->has( "$post_id:$field_name" ) ) {
return $store->get( "$post_id:$field_name" );
}
// Load value from database.
$value = acf_get_metadata( $post_id, $field_name );
// Use field's default_value if no meta was found.
if ( $value === null && isset( $field['default_value'] ) ) {
$value = $field['default_value'];
}
/**
* Filters the $value after it has been loaded.
*
* @date 28/09/13
* @since 5.0.0
*
* @param mixed $value The value to preview.
* @param string $post_id The post ID for this value.
* @param array $field The field array.
*/
$value = apply_filters( 'acf/load_value', $value, $post_id, $field );
// Update store.
$store->set( "$post_id:$field_name", $value );
// Return value.
return $value;
}
// Register variation.
acf_add_filter_variations( 'acf/load_value', array( 'type', 'name', 'key' ), 2 );
/**
* acf_format_value
*
* Returns a formatted version of the provided value.
*
* @date 28/09/13
* @since 5.0.0
*
* @param mixed $value The field value.
* @param (int|string) $post_id The post id.
* @param array $field The field array.
* @return mixed.
*/
function acf_format_value( $value, $post_id, $field ) {
// Allow filter to short-circuit load_value logic.
$check = apply_filters( 'acf/pre_format_value', null, $value, $post_id, $field );
if ( $check !== null ) {
return $check;
}
// Get field name.
$field_name = $field['name'];
// Check store.
$store = acf_get_store( 'values' );
if ( $store->has( "$post_id:$field_name:formatted" ) ) {
return $store->get( "$post_id:$field_name:formatted" );
}
/**
* Filters the $value for use in a template function.
*
* @date 28/09/13
* @since 5.0.0
*
* @param mixed $value The value to preview.
* @param string $post_id The post ID for this value.
* @param array $field The field array.
*/
$value = apply_filters( 'acf/format_value', $value, $post_id, $field );
// Update store.
$store->set( "$post_id:$field_name:formatted", $value );
// Return value.
return $value;
}
// Register variation.
acf_add_filter_variations( 'acf/format_value', array( 'type', 'name', 'key' ), 2 );
/**
* acf_update_value
*
* Updates the value for a given field and post_id.
*
* @date 28/09/13
* @since 5.0.0
*
* @param mixed $value The new value.
* @param (int|string) $post_id The post id.
* @param array $field The field array.
* @return bool.
*/
function acf_update_value( $value, $post_id, $field ) {
// Allow filter to short-circuit update_value logic.
$check = apply_filters( 'acf/pre_update_value', null, $value, $post_id, $field );
if ( $check !== null ) {
return $check;
}
/**
* Filters the $value before it is updated.
*
* @date 28/09/13
* @since 5.0.0
*
* @param mixed $value The value to update.
* @param string $post_id The post ID for this value.
* @param array $field The field array.
* @param mixed $original The original value before modification.
*/
$value = apply_filters( 'acf/update_value', $value, $post_id, $field, $value );
// Allow null to delete value.
if ( $value === null ) {
return acf_delete_value( $post_id, $field );
}
// Update meta.
$return = acf_update_metadata( $post_id, $field['name'], $value );
// Update reference.
acf_update_metadata( $post_id, $field['name'], $field['key'], true );
// Delete stored data.
acf_flush_value_cache( $post_id, $field['name'] );
// Return update status.
return $return;
}
// Register variation.
acf_add_filter_variations( 'acf/update_value', array( 'type', 'name', 'key' ), 2 );
/**
* acf_update_values
*
* Updates an array of values.
*
* @date 26/2/19
* @since 5.7.13
*
* @param array values The array of values.
* @param (int|string) $post_id The post id.
* @return void
*/
function acf_update_values( $values, $post_id ) {
// Loop over values.
foreach ( $values as $key => $value ) {
// Get field.
$field = acf_get_field( $key );
// Update value.
if ( $field ) {
acf_update_value( $value, $post_id, $field );
}
}
}
/**
* acf_flush_value_cache
*
* Deletes all cached data for this value.
*
* @date 22/1/19
* @since 5.7.10
*
* @param (int|string) $post_id The post id.
* @param string $field_name The field name.
* @return void
*/
function acf_flush_value_cache( $post_id = 0, $field_name = '' ) {
// Delete stored data.
acf_get_store( 'values' )
->remove( "$post_id:$field_name" )
->remove( "$post_id:$field_name:formatted" );
}
/**
* acf_delete_value
*
* Deletes the value for a given field and post_id.
*
* @date 28/09/13
* @since 5.0.0
*
* @param (int|string) $post_id The post id.
* @param array $field The field array.
* @return bool.
*/
function acf_delete_value( $post_id, $field ) {
/**
* Fires before a value is deleted.
*
* @date 28/09/13
* @since 5.0.0
*
* @param string $post_id The post ID for this value.
* @param mixed $name The meta name.
* @param array $field The field array.
*/
do_action( 'acf/delete_value', $post_id, $field['name'], $field );
// Delete meta.
$return = acf_delete_metadata( $post_id, $field['name'] );
// Delete reference.
acf_delete_metadata( $post_id, $field['name'], true );
// Delete stored data.
acf_flush_value_cache( $post_id, $field['name'] );
// Return delete status.
return $return;
}
// Register variation.
acf_add_filter_variations( 'acf/delete_value', array( 'type', 'name', 'key' ), 2 );
/**
* acf_preview_value
*
* Return a human friendly 'preview' for a given field value.
*
* @date 28/09/13
* @since 5.0.0
*
* @param mixed $value The new value.
* @param (int|string) $post_id The post id.
* @param array $field The field array.
* @return bool.
*/
function acf_preview_value( $value, $post_id, $field ) {
/**
* Filters the $value before used in HTML.
*
* @date 24/10/16
* @since 5.5.0
*
* @param mixed $value The value to preview.
* @param string $post_id The post ID for this value.
* @param array $field The field array.
*/
return apply_filters( 'acf/preview_value', $value, $post_id, $field );
}
// Register variation.
acf_add_filter_variations( 'acf/preview_value', array( 'type', 'name', 'key' ), 2 );

View File

@@ -0,0 +1,218 @@
<?php
/**
* Returns a WordPress object type.
*
* @date 1/4/20
* @since 5.9.0
*
* @param string $object_type The object type (post, term, user, etc).
* @param string $object_subtype Optional object subtype (post type, taxonomy).
* @return object
*/
function acf_get_object_type( $object_type, $object_subtype = '' ) {
$props = array(
'type' => $object_type,
'subtype' => $object_subtype,
'name' => '',
'label' => '',
'icon' => '',
);
// Set unique identifier as name.
if ( $object_subtype ) {
$props['name'] = "$object_type/$object_subtype";
} else {
$props['name'] = $object_type;
}
// Set label and icon.
switch ( $object_type ) {
case 'post':
if ( $object_subtype ) {
$post_type = get_post_type_object( $object_subtype );
if ( $post_type ) {
$props['label'] = $post_type->labels->name;
$props['icon'] = acf_with_default( $post_type->menu_icon, 'dashicons-admin-post' );
} else {
return false;
}
} else {
$props['label'] = __( 'Posts', 'acf' );
$props['icon'] = 'dashicons-admin-post';
}
break;
case 'term':
if ( $object_subtype ) {
$taxonomy = get_taxonomy( $object_subtype );
if ( $taxonomy ) {
$props['label'] = $taxonomy->labels->name;
} else {
return false;
}
} else {
$props['label'] = __( 'Taxonomies', 'acf' );
}
$props['icon'] = 'dashicons-tag';
break;
case 'attachment':
$props['label'] = __( 'Attachments', 'acf' );
$props['icon'] = 'dashicons-admin-media';
break;
case 'comment':
$props['label'] = __( 'Comments', 'acf' );
$props['icon'] = 'dashicons-admin-comments';
break;
case 'widget':
$props['label'] = __( 'Widgets', 'acf' );
$props['icon'] = 'dashicons-screenoptions';
break;
case 'menu':
$props['label'] = __( 'Menus', 'acf' );
$props['icon'] = 'dashicons-admin-appearance';
break;
case 'menu_item':
$props['label'] = __( 'Menu items', 'acf' );
$props['icon'] = 'dashicons-admin-appearance';
break;
case 'user':
$props['label'] = __( 'Users', 'acf' );
$props['icon'] = 'dashicons-admin-users';
break;
case 'option':
$props['label'] = __( 'Options', 'acf' );
$props['icon'] = 'dashicons-admin-generic';
break;
case 'block':
$props['label'] = __( 'Blocks', 'acf' );
$props['icon'] = acf_version_compare( 'wp', '>=', '5.5' ) ? 'dashicons-block-default' : 'dashicons-layout';
break;
default:
return false;
}
// Convert to object.
$object = (object) $props;
/**
* Filters the object type.
*
* @date 6/4/20
* @since 5.9.0
*
* @param object $object The object props.
* @param string $object_type The object type (post, term, user, etc).
* @param string $object_subtype Optional object subtype (post type, taxonomy).
*/
return apply_filters( 'acf/get_object_type', $object, $object_type, $object_subtype );
}
/**
* Decodes a post_id value such as 1 or "user_1" into an array containing the type and ID.
*
* @date 25/1/19
* @since 5.7.11
*
* @param (int|string) $post_id The post id.
* @return array
*/
function acf_decode_post_id( $post_id = 0 ) {
$type = '';
$id = 0;
// Interpret numeric value (123).
if ( is_numeric( $post_id ) ) {
$type = 'post';
$id = $post_id;
// Interpret string value ("user_123" or "option").
} elseif ( is_string( $post_id ) ) {
$i = strrpos( $post_id, '_' );
if ( $i > 0 ) {
$type = substr( $post_id, 0, $i );
$id = substr( $post_id, $i + 1 );
} else {
$type = $post_id;
$id = '';
}
// Handle incorrect param type.
} else {
return compact( 'type', 'id' );
}
// Validate props based on param format.
$format = $type . '_' . ( is_numeric( $id ) ? '%d' : '%s' );
switch ( $format ) {
case 'post_%d':
$type = 'post';
$id = absint( $id );
break;
case 'term_%d':
$type = 'term';
$id = absint( $id );
break;
case 'attachment_%d':
$type = 'post';
$id = absint( $id );
break;
case 'comment_%d':
$type = 'comment';
$id = absint( $id );
break;
case 'widget_%s':
case 'widget_%d':
$type = 'option';
$id = $post_id;
break;
case 'menu_%d':
$type = 'term';
$id = absint( $id );
break;
case 'menu_item_%d':
$type = 'post';
$id = absint( $id );
break;
case 'user_%d':
$type = 'user';
$id = absint( $id );
break;
case 'block_%s':
$type = 'block';
$id = $post_id;
break;
case 'option_%s':
$type = 'option';
$id = $post_id;
break;
case 'blog_%d':
case 'site_%d':
// Allow backwards compatibility for custom taxonomies.
$type = taxonomy_exists( $type ) ? 'term' : 'blog';
$id = absint( $id );
break;
default:
// Check for taxonomy name.
if ( taxonomy_exists( $type ) && is_numeric( $id ) ) {
$type = 'term';
$id = absint( $id );
break;
}
// Treat unknown post_id format as an option.
$type = 'option';
$id = $post_id;
break;
}
/**
* Filters the decoded post_id information.
*
* @date 25/1/19
* @since 5.7.11
*
* @param array $props An array containing "type" and "id" information.
* @param (int|string) $post_id The post id.
*/
return apply_filters( 'acf/decode_post_id', compact( 'type', 'id' ), $post_id );
}

View File

@@ -0,0 +1,820 @@
<?php
/*
* ACF Admin Field Group Class
*
* All the logic for editing a field group
*
* @class acf_admin_field_group
* @package ACF
* @subpackage Admin
*/
if ( ! class_exists( 'acf_admin_field_group' ) ) :
class acf_admin_field_group {
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'current_screen', array( $this, 'current_screen' ) );
add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
// ajax
add_action( 'wp_ajax_acf/field_group/render_field_settings', array( $this, 'ajax_render_field_settings' ) );
add_action( 'wp_ajax_acf/field_group/render_location_rule', array( $this, 'ajax_render_location_rule' ) );
add_action( 'wp_ajax_acf/field_group/move_field', array( $this, 'ajax_move_field' ) );
// filters
add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
add_filter( 'use_block_editor_for_post_type', array( $this, 'use_block_editor_for_post_type' ), 10, 2 );
}
/**
* use_block_editor_for_post_type
*
* Prevents the block editor from loading when editing an ACF field group.
*
* @date 7/12/18
* @since 5.8.0
*
* @param bool $use_block_editor Whether the post type can be edited or not. Default true.
* @param string $post_type The post type being checked.
* @return bool
*/
function use_block_editor_for_post_type( $use_block_editor, $post_type ) {
if ( $post_type === 'acf-field-group' ) {
return false;
}
return $use_block_editor;
}
/*
* post_updated_messages
*
* This function will customize the message shown when editing a field group
*
* @type action (post_updated_messages)
* @date 30/04/2014
* @since 5.0.0
*
* @param $messages (array)
* @return $messages
*/
function post_updated_messages( $messages ) {
// append to messages
$messages['acf-field-group'] = array(
0 => '', // Unused. Messages start at index 1.
1 => __( 'Field group updated.', 'acf' ),
2 => __( 'Field group updated.', 'acf' ),
3 => __( 'Field group deleted.', 'acf' ),
4 => __( 'Field group updated.', 'acf' ),
5 => false, // field group does not support revisions
6 => __( 'Field group published.', 'acf' ),
7 => __( 'Field group saved.', 'acf' ),
8 => __( 'Field group submitted.', 'acf' ),
9 => __( 'Field group scheduled for.', 'acf' ),
10 => __( 'Field group draft updated.', 'acf' ),
);
// return
return $messages;
}
/*
* current_screen
*
* This function is fired when loading the admin page before HTML has been rendered.
*
* @type action (current_screen)
* @date 21/07/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function current_screen() {
// validate screen
if ( ! acf_is_screen( 'acf-field-group' ) ) {
return;
}
// disable filters to ensure ACF loads raw data from DB
acf_disable_filters();
// enqueue scripts
acf_enqueue_scripts();
// actions
add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'acf/input/admin_head', array( $this, 'admin_head' ) );
add_action( 'acf/input/form_data', array( $this, 'form_data' ) );
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ) );
// filters
add_filter( 'acf/input/admin_l10n', array( $this, 'admin_l10n' ) );
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 30/06/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_enqueue_scripts() {
// no autosave
wp_dequeue_script( 'autosave' );
// custom scripts
wp_enqueue_style( 'acf-field-group' );
wp_enqueue_script( 'acf-field-group' );
// localize text
acf_localize_text(
array(
'The string "field_" may not be used at the start of a field name' => __( 'The string "field_" may not be used at the start of a field name', 'acf' ),
'This field cannot be moved until its changes have been saved' => __( 'This field cannot be moved until its changes have been saved', 'acf' ),
'Field group title is required' => __( 'Field group title is required', 'acf' ),
'Move to trash. Are you sure?' => __( 'Move to trash. Are you sure?', 'acf' ),
'No toggle fields available' => __( 'No toggle fields available', 'acf' ),
'Move Custom Field' => __( 'Move Custom Field', 'acf' ),
'Checked' => __( 'Checked', 'acf' ),
'(no label)' => __( '(no label)', 'acf' ),
'(this field)' => __( '(this field)', 'acf' ),
'copy' => __( 'copy', 'acf' ),
'or' => __( 'or', 'acf' ),
'Show this field group if' => __( 'Show this field group if', 'acf' ),
'Null' => __( 'Null', 'acf' ),
// Conditions
'Has any value' => __( 'Has any value', 'acf' ),
'Has no value' => __( 'Has no value', 'acf' ),
'Value is equal to' => __( 'Value is equal to', 'acf' ),
'Value is not equal to' => __( 'Value is not equal to', 'acf' ),
'Value matches pattern' => __( 'Value matches pattern', 'acf' ),
'Value contains' => __( 'Value contains', 'acf' ),
'Value is greater than' => __( 'Value is greater than', 'acf' ),
'Value is less than' => __( 'Value is less than', 'acf' ),
'Selection is greater than' => __( 'Selection is greater than', 'acf' ),
'Selection is less than' => __( 'Selection is less than', 'acf' ),
// Pro-only fields
'Repeater (Pro only)' => __( 'Repeater (Pro only)', 'acf' ),
'Flexibly Content (Pro only)' => __( 'Flexible Content (Pro only)', 'acf' ),
'Clone (Pro only)' => __( 'Clone (Pro only)', 'acf' ),
'Gallery (Pro only)' => __( 'Gallery (Pro only)', 'acf' ),
)
);
// localize data
acf_localize_data(
array(
'fieldTypes' => acf_get_field_types_info(),
)
);
// 3rd party hook
do_action( 'acf/field_group/admin_enqueue_scripts' );
}
/*
* admin_head
*
* This function will setup all functionality for the field group edit page to work
*
* @type action (admin_head)
* @date 23/06/12
* @since 3.1.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function admin_head() {
// global
global $post, $field_group;
// set global var
$field_group = acf_get_field_group( $post->ID );
// metaboxes
add_meta_box( 'acf-field-group-fields', __( 'Fields', 'acf' ), array( $this, 'mb_fields' ), 'acf-field-group', 'normal', 'high' );
add_meta_box( 'acf-field-group-locations', __( 'Location', 'acf' ), array( $this, 'mb_locations' ), 'acf-field-group', 'normal', 'high' );
add_meta_box( 'acf-field-group-options', __( 'Settings', 'acf' ), array( $this, 'mb_options' ), 'acf-field-group', 'normal', 'high' );
// actions
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
// filters
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
// 3rd party hook
do_action( 'acf/field_group/admin_head' );
}
/*
* edit_form_after_title
*
* This action will allow ACF to render metaboxes after the title
*
* @type action
* @date 17/08/13
*
* @param n/a
* @return n/a
*/
function edit_form_after_title() {
// globals
global $post;
// render post data
acf_form_data(
array(
'screen' => 'field_group',
'post_id' => $post->ID,
'delete_fields' => 0,
'validation' => 0,
)
);
}
/*
* form_data
*
* This function will add extra HTML to the acf form data element
*
* @type function
* @date 31/05/2016
* @since 5.3.8
*
* @param n/a
* @return n/a
*/
function form_data( $args ) {
// do action
do_action( 'acf/field_group/form_data', $args );
}
/*
* admin_l10n
*
* This function will append extra l10n strings to the acf JS object
*
* @type function
* @date 31/05/2016
* @since 5.3.8
*
* @param $l10n (array)
* @return $l10n
*/
function admin_l10n( $l10n ) {
return apply_filters( 'acf/field_group/admin_l10n', $l10n );
}
/*
* admin_footer
*
* description
*
* @type function
* @date 11/01/2016
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
function admin_footer() {
// 3rd party hook
do_action( 'acf/field_group/admin_footer' );
}
/*
* screen_settings
*
* description
*
* @type function
* @date 26/01/13
* @since 3.6.0
*
* @param $current (string)
* @return $current
*/
function screen_settings( $html ) {
// vars
$checked = acf_get_user_setting( 'show_field_keys' ) ? 'checked="checked"' : '';
// append
$html .= '<div id="acf-append-show-on-screen" class="acf-hidden">';
$html .= '<label for="acf-field-key-hide"><input id="acf-field-key-hide" type="checkbox" value="1" name="show_field_keys" ' . $checked . ' /> ' . __( 'Field Keys', 'acf' ) . '</label>';
$html .= '</div>';
// return
return $html;
}
/*
* post_submitbox_misc_actions
*
* This function will customize the publish metabox
*
* @type function
* @date 17/07/2015
* @since 5.2.9
*
* @param n/a
* @return n/a
*/
function post_submitbox_misc_actions() {
global $field_group;
$status_label = $field_group['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Disabled', 'post status', 'acf' );
?>
<script type="text/javascript">
(function($) {
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
})(jQuery);
</script>
<?php
}
/*
* save_post
*
* This function will save all the field group data
*
* @type function
* @date 23/06/12
* @since 1.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function save_post( $post_id, $post ) {
// do not save if this is an auto save routine
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// bail early if not acf-field-group
if ( $post->post_type !== 'acf-field-group' ) {
return $post_id;
}
// only save once! WordPress save's a revision as well.
if ( wp_is_post_revision( $post_id ) ) {
return $post_id;
}
// verify nonce
if ( ! acf_verify_nonce( 'field_group' ) ) {
return $post_id;
}
// Bail early if request came from an unauthorised user.
if ( ! current_user_can( acf_get_setting( 'capability' ) ) ) {
return $post_id;
}
// disable filters to ensure ACF loads raw data from DB
acf_disable_filters();
// save fields
if ( ! empty( $_POST['acf_fields'] ) ) {
// loop
foreach ( $_POST['acf_fields'] as $field ) {
// vars
$specific = false;
$save = acf_extract_var( $field, 'save' );
// only saved field if has changed
if ( $save == 'meta' ) {
$specific = array(
'menu_order',
'post_parent',
);
}
// set parent
if ( ! $field['parent'] ) {
$field['parent'] = $post_id;
}
// save field
acf_update_field( $field, $specific );
}
}
// delete fields
if ( $_POST['_acf_delete_fields'] ) {
// clean
$ids = explode( '|', $_POST['_acf_delete_fields'] );
$ids = array_map( 'intval', $ids );
// loop
foreach ( $ids as $id ) {
// bai early if no id
if ( ! $id ) {
continue;
}
// delete
acf_delete_field( $id );
}
}
// add args
$_POST['acf_field_group']['ID'] = $post_id;
$_POST['acf_field_group']['title'] = $_POST['post_title'];
// save field group
acf_update_field_group( $_POST['acf_field_group'] );
// return
return $post_id;
}
/*
* mb_fields
*
* This function will render the HTML for the medtabox 'acf-field-group-fields'
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param N/A
* @return N/A
*/
function mb_fields() {
// global
global $field_group;
// get fields
$view = array(
'fields' => acf_get_fields( $field_group ),
'parent' => 0,
);
// load view
acf_get_view( 'field-group-fields', $view );
}
/*
* mb_options
*
* This function will render the HTML for the medtabox 'acf-field-group-options'
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param N/A
* @return N/A
*/
function mb_options() {
// global
global $field_group;
// field key (leave in for compatibility)
if ( ! acf_is_field_group_key( $field_group['key'] ) ) {
$field_group['key'] = uniqid( 'group_' );
}
// view
acf_get_view( 'field-group-options' );
}
/*
* mb_locations
*
* This function will render the HTML for the medtabox 'acf-field-group-locations'
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param N/A
* @return N/A
*/
function mb_locations() {
// global
global $field_group;
// UI needs at lease 1 location rule
if ( empty( $field_group['location'] ) ) {
$field_group['location'] = array(
// group 0
array(
// rule 0
array(
'param' => 'post_type',
'operator' => '==',
'value' => 'post',
),
),
);
}
// view
acf_get_view( 'field-group-locations' );
}
/*
* ajax_render_location_rule
*
* This function can be accessed via an AJAX action and will return the result from the render_location_value function
*
* @type function (ajax)
* @date 30/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function ajax_render_location_rule() {
// validate
if ( ! acf_verify_ajax() ) {
die();
}
// verify user capability
if ( ! acf_current_user_can_admin() ) {
die();
}
// validate rule
$rule = acf_validate_location_rule( $_POST['rule'] );
// view
acf_get_view(
'html-location-rule',
array(
'rule' => $rule,
)
);
// die
die();
}
/*
* ajax_render_field_settings
*
* This function will return HTML containing the field's settings based on it's new type
*
* @type function (ajax)
* @date 30/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function ajax_render_field_settings() {
// validate
if ( ! acf_verify_ajax() ) {
die();
}
// verify user capability
if ( ! acf_current_user_can_admin() ) {
die();
}
// vars
$field = acf_maybe_get_POST( 'field' );
// check
if ( ! $field ) {
die();
}
// set prefix
$field['prefix'] = acf_maybe_get_POST( 'prefix' );
// validate
$field = acf_get_valid_field( $field );
// render
do_action( "acf/render_field_settings/type={$field['type']}", $field );
// return
die();
}
/*
* ajax_move_field
*
* description
*
* @type function
* @date 20/01/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function ajax_move_field() {
// disable filters to ensure ACF loads raw data from DB
acf_disable_filters();
$args = acf_parse_args(
$_POST,
array(
'nonce' => '',
'post_id' => 0,
'field_id' => 0,
'field_group_id' => 0,
)
);
// verify nonce
if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) ) {
die();
}
// verify user capability
if ( ! acf_current_user_can_admin() ) {
die();
}
// confirm?
if ( $args['field_id'] && $args['field_group_id'] ) {
// vars
$field = acf_get_field( $args['field_id'] );
$field_group = acf_get_field_group( $args['field_group_id'] );
// update parent
$field['parent'] = $field_group['ID'];
// remove conditional logic
$field['conditional_logic'] = 0;
// update field
acf_update_field( $field );
// Output HTML.
$link = '<a href="' . admin_url( 'post.php?post=' . $field_group['ID'] . '&action=edit' ) . '" target="_blank">' . esc_html( $field_group['title'] ) . '</a>';
echo '' .
'<p><strong>' . __( 'Move Complete.', 'acf' ) . '</strong></p>' .
'<p>' . sprintf(
acf_punctify( __( 'The %1$s field can now be found in the %2$s field group', 'acf' ) ),
esc_html( $field['label'] ),
$link
) . '</p>' .
'<a href="#" class="button button-primary acf-close-popup">' . __( 'Close Window', 'acf' ) . '</a>';
die();
}
// get all field groups
$field_groups = acf_get_field_groups();
$choices = array();
// check
if ( ! empty( $field_groups ) ) {
// loop
foreach ( $field_groups as $field_group ) {
// bail early if no ID
if ( ! $field_group['ID'] ) {
continue;
}
// bail ealry if is current
if ( $field_group['ID'] == $args['post_id'] ) {
continue;
}
// append
$choices[ $field_group['ID'] ] = $field_group['title'];
}
}
// render options
$field = acf_get_valid_field(
array(
'type' => 'select',
'name' => 'acf_field_group',
'choices' => $choices,
)
);
echo '<p>' . __( 'Please select the destination for this field', 'acf' ) . '</p>';
echo '<form id="acf-move-field-form">';
// render
acf_render_field_wrap( $field );
echo '<button type="submit" class="button button-primary">' . __( 'Move Field', 'acf' ) . '</button>';
echo '</form>';
// die
die();
}
}
// initialize
new acf_admin_field_group();
endif;
?>

View File

@@ -0,0 +1,885 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Field_Groups' ) ) :
class ACF_Admin_Field_Groups {
/**
* Array of field groups availbale for sync.
*
* @since 5.9.0
* @var array
*/
public $sync = array();
/**
* The current view (post_status).
*
* @since 5.9.0
* @var string
*/
public $view = '';
/**
* Constructor.
*
* @date 5/03/2014
* @since 5.0.0
*
* @param void
* @return void
*/
public function __construct() {
// Add hooks.
add_action( 'load-edit.php', array( $this, 'handle_redirection' ) );
add_action( 'current_screen', array( $this, 'current_screen' ) );
// Handle post status change events.
add_action( 'trashed_post', array( $this, 'trashed_post' ) );
add_action( 'untrashed_post', array( $this, 'untrashed_post' ) );
add_action( 'deleted_post', array( $this, 'deleted_post' ) );
}
/**
* Returns the Field Groups admin URL.
*
* @date 27/3/20
* @since 5.9.0
*
* @param string $params Extra URL params.
* @return string
*/
public function get_admin_url( $params = '' ) {
return admin_url( "edit.php?post_type=acf-field-group{$params}" );
}
/**
* Returns the Field Groups admin URL taking into account the current view.
*
* @date 27/3/20
* @since 5.9.0
*
* @param string $params Extra URL params.
* @return string
*/
public function get_current_admin_url( $params = '' ) {
return $this->get_admin_url( ( $this->view ? '&post_status=' . $this->view : '' ) . $params );
}
/**
* Redirects users from ACF 4.0 admin page.
*
* @date 17/9/18
* @since 5.7.6
*
* @param void
* @return void
*/
public function handle_redirection() {
if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'acf' ) {
wp_redirect( $this->get_admin_url() );
exit;
}
}
/**
* Constructor for the Field Groups admin page.
*
* @date 21/07/2014
* @since 5.0.0
*
* @param void
* @return void
*/
public function current_screen() {
// Bail early if not Field Groups admin page.
if ( ! acf_is_screen( 'edit-acf-field-group' ) ) {
return;
}
// Get the current view.
$this->view = isset( $_GET['post_status'] ) ? sanitize_text_field( $_GET['post_status'] ) : '';
// Setup and check for custom actions..
$this->setup_sync();
$this->check_sync();
$this->check_duplicate();
// Modify publish post status text and order.
global $wp_post_statuses;
$wp_post_statuses['publish']->label_count = _n_noop( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', 'acf' );
$wp_post_statuses['trash'] = acf_extract_var( $wp_post_statuses, 'trash' );
// Add hooks.
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
add_filter( 'views_edit-acf-field-group', array( $this, 'admin_table_views' ), 10, 1 );
add_filter( 'manage_acf-field-group_posts_columns', array( $this, 'admin_table_columns' ), 10, 1 );
add_action( 'manage_acf-field-group_posts_custom_column', array( $this, 'admin_table_columns_html' ), 10, 2 );
add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
add_filter( 'bulk_actions-edit-acf-field-group', array( $this, 'admin_table_bulk_actions' ), 10, 1 );
add_action( 'admin_footer', array( $this, 'admin_footer' ), 1 );
if ( $this->view !== 'trash' ) {
add_filter( 'page_row_actions', array( $this, 'page_row_actions' ), 10, 2 );
}
// Add hooks for "sync" view.
if ( $this->view === 'sync' ) {
add_action( 'admin_footer', array( $this, 'admin_footer__sync' ), 1 );
}
}
/**
* Sets up the field groups ready for sync.
*
* @date 17/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function setup_sync() {
// Review local json field groups.
if ( acf_get_local_json_files() ) {
// Get all groups in a single cached query to check if sync is available.
$all_field_groups = acf_get_field_groups();
foreach ( $all_field_groups as $field_group ) {
// Extract vars.
$local = acf_maybe_get( $field_group, 'local' );
$modified = acf_maybe_get( $field_group, 'modified' );
$private = acf_maybe_get( $field_group, 'private' );
// Ignore if is private.
if ( $private ) {
continue;
// Ignore not local "json".
} elseif ( $local !== 'json' ) {
continue;
// Append to sync if not yet in database.
} elseif ( ! $field_group['ID'] ) {
$this->sync[ $field_group['key'] ] = $field_group;
// Append to sync if "json" modified time is newer than database.
} elseif ( $modified && $modified > get_post_modified_time( 'U', true, $field_group['ID'] ) ) {
$this->sync[ $field_group['key'] ] = $field_group;
}
}
}
}
/**
* Enqueues admin scripts.
*
* @date 18/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function admin_enqueue_scripts() {
acf_enqueue_script( 'acf' );
// Localize text.
acf_localize_text(
array(
'Review local JSON changes' => __( 'Review local JSON changes', 'acf' ),
'Loading diff' => __( 'Loading diff', 'acf' ),
'Sync changes' => __( 'Sync changes', 'acf' ),
)
);
}
/**
* Modifies the admin body class.
*
* @date 18/4/20
* @since 5.9.0
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
$classes .= ' acf-admin-field-groups';
if ( $this->view ) {
$classes .= " view-{$this->view}";
}
return $classes;
}
/**
* returns the disabled post state HTML.
*
* @date 17/4/20
* @since 5.9.0
*
* @param void
* @return string
*/
public function get_disabled_post_state() {
return '<span class="dashicons dashicons-hidden"></span> ' . _x( 'Disabled', 'post status', 'acf' );
}
/**
* Adds the "disabled" post state for the admin table title.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $post_states An array of post display states.
* @param WP_Post $post The current post object.
* @return array
*/
public function display_post_states( $post_states, $post ) {
if ( $post->post_status === 'acf-disabled' ) {
$post_states['acf-disabled'] = $this->get_disabled_post_state();
}
return $post_states;
}
/**
* Customizes the admin table columns.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $columns The columns array.
* @return array
*/
public function admin_table_columns( $_columns ) {
$columns = array(
'cb' => $_columns['cb'],
'title' => $_columns['title'],
'acf-description' => __( 'Description', 'acf' ),
'acf-key' => __( 'Key', 'acf' ),
'acf-location' => __( 'Location', 'acf' ),
'acf-count' => __( 'Fields', 'acf' ),
);
if ( acf_get_local_json_files() ) {
$columns['acf-json'] = __( 'Local JSON', 'acf' );
}
return $columns;
}
/**
* Renders the admin table column HTML
*
* @date 1/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param int $post_id The current post ID.
* @return void
*/
public function admin_table_columns_html( $column_name, $post_id ) {
$field_group = acf_get_field_group( $post_id );
if ( $field_group ) {
$this->render_admin_table_column( $column_name, $field_group );
}
}
/**
* Renders a specific admin table column.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param array $field_group The field group.
* @return void
*/
public function render_admin_table_column( $column_name, $field_group ) {
switch ( $column_name ) {
// Key.
case 'acf-key':
echo esc_html( $field_group['key'] );
break;
// Description.
case 'acf-description':
if ( $field_group['description'] ) {
echo '<span class="acf-description">' . acf_esc_html( $field_group['description'] ) . '</span>';
}
break;
// Location.
case 'acf-location':
$this->render_admin_table_column_locations( $field_group );
break;
// Count.
case 'acf-count':
echo esc_html( acf_get_field_count( $field_group ) );
break;
// Local JSON.
case 'acf-json':
$this->render_admin_table_column_local_status( $field_group );
break;
}
}
/**
* Displays a visual representation of the field group's locations.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $field_group The field group.
* @return void
*/
public function render_admin_table_column_locations( $field_group ) {
$objects = array();
// Loop over location rules and determine connected object types.
if ( $field_group['location'] ) {
foreach ( $field_group['location'] as $i => $rules ) {
// Determine object types for each rule.
foreach ( $rules as $j => $rule ) {
// Get location type and subtype for the current rule.
$location = acf_get_location_rule( $rule['param'] );
$location_object_type = '';
$location_object_subtype = '';
if ( $location ) {
$location_object_type = $location->get_object_type( $rule );
$location_object_subtype = $location->get_object_subtype( $rule );
}
$rules[ $j ]['object_type'] = $location_object_type;
$rules[ $j ]['object_subtype'] = $location_object_subtype;
}
// Now that each $rule conains object type data...
$object_types = array_column( $rules, 'object_type' );
$object_types = array_filter( $object_types );
$object_types = array_values( $object_types );
if ( $object_types ) {
$object_type = $object_types[0];
} else {
continue;
}
$object_subtypes = array_column( $rules, 'object_subtype' );
$object_subtypes = array_filter( $object_subtypes );
$object_subtypes = array_values( $object_subtypes );
$object_subtypes = array_map( 'acf_array', $object_subtypes );
if ( count( $object_subtypes ) > 1 ) {
$object_subtypes = call_user_func_array( 'array_intersect', $object_subtypes );
$object_subtypes = array_values( $object_subtypes );
} elseif ( $object_subtypes ) {
$object_subtypes = $object_subtypes[0];
} else {
$object_subtypes = array( '' );
}
// Append to objects.
foreach ( $object_subtypes as $object_subtype ) {
$object = acf_get_object_type( $object_type, $object_subtype );
if ( $object ) {
$objects[ $object->name ] = $object;
}
}
}
}
// Reset keys.
$objects = array_values( $objects );
// Display.
$html = '';
if ( $objects ) {
$limit = 3;
$total = count( $objects );
// Icon.
$html .= '<span class="dashicons ' . $objects[0]->icon . ( $total > 1 ? ' acf-multi-dashicon' : '' ) . '"></span> ';
// Labels.
$labels = array_column( $objects, 'label' );
$labels = array_slice( $labels, 0, 3 );
$html .= implode( ', ', $labels );
// More.
if ( $total > $limit ) {
$html .= ', ...';
}
} else {
$html = '<span class="dashicons dashicons-businesswoman"></span> ' . __( 'Various', 'acf' );
}
// Filter.
echo acf_esc_html( $html );
}
/**
* Returns a human readable file location.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $file The full file path.
* @return string
*/
public function get_human_readable_file_location( $file ) {
// Generate friendly file path.
$theme_path = get_stylesheet_directory();
if ( strpos( $file, $theme_path ) !== false ) {
$rel_file = str_replace( $theme_path, '', $file );
$located = sprintf( __( 'Located in theme: %s', 'acf' ), $rel_file );
} elseif ( strpos( $file, WP_PLUGIN_DIR ) !== false ) {
$rel_file = str_replace( WP_PLUGIN_DIR, '', $file );
$located = sprintf( __( 'Located in plugin: %s', 'acf' ), $rel_file );
} else {
$rel_file = str_replace( ABSPATH, '', $file );
$located = sprintf( __( 'Located in: %s', 'acf' ), $rel_file );
}
return $located;
}
/**
* Displays the local JSON status of a field group.
*
* @date 14/4/20
* @since 5.9.0
*
* @param type $var Description. Default.
* @return type Description.
*/
public function render_admin_table_column_local_status( $field_group ) {
$json = acf_get_local_json_files();
if ( isset( $json[ $field_group['key'] ] ) ) {
$file = $json[ $field_group['key'] ];
if ( isset( $this->sync[ $field_group['key'] ] ) ) {
$url = $this->get_admin_url( '&acfsync=' . $field_group['key'] . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
echo '<strong>' . __( 'Sync available', 'acf' ) . '</strong>';
if ( $field_group['ID'] ) {
echo '<div class="row-actions">
<span class="sync"><a href="' . esc_url( $url ) . '">' . __( 'Sync', 'acf' ) . '</a> | </span>
<span class="review"><a href="#" data-event="review-sync" data-id="' . esc_attr( $field_group['ID'] ) . '" data-href="' . esc_url( $url ) . '">' . __( 'Review changes', 'acf' ) . '</a></span>
</div>';
} else {
echo '<div class="row-actions">
<span class="sync"><a href="' . esc_url( $url ) . '">' . __( 'Import', 'acf' ) . '</a></span>
</div>';
}
} else {
echo __( 'Saved', 'acf' );
}
} else {
echo '<span class="acf-secondary-text">' . __( 'Awaiting save', 'acf' ) . '</span>';
}
}
/**
* Customizes the page row actions visible on hover.
*
* @date 14/4/20
* @since 5.9.0
*
* @param array $actions The array of actions HTML.
* @param WP_Post $post The post.
* @return array
*/
public function page_row_actions( $actions, $post ) {
// Remove "Quick Edit" action.
unset( $actions['inline'], $actions['inline hide-if-no-js'] );
// Append "Duplicate" action.
$duplicate_action_url = $this->get_admin_url( '&acfduplicate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
$actions['acfduplicate'] = '<a href="' . esc_url( $duplicate_action_url ) . '" aria-label="' . esc_attr__( 'Duplicate this item', 'acf' ) . '">' . __( 'Duplicate', 'acf' ) . '</a>';
// Return actions in custom order.
$order = array( 'edit', 'acfduplicate', 'trash' );
return array_merge( array_flip( $order ), $actions );
}
/**
* Modifies the admin table bulk actions dropdown.
*
* @date 15/4/20
* @since 5.9.0
*
* @param array $actions The actions array.
* @return array
*/
public function admin_table_bulk_actions( $actions ) {
// Add "duplicate" action.
if ( $this->view !== 'sync' ) {
$actions['acfduplicate'] = __( 'Duplicate', 'acf' );
}
// Add "Sync" action.
if ( $this->sync ) {
if ( $this->view === 'sync' ) {
$actions = array();
}
$actions['acfsync'] = __( 'Sync changes', 'acf' );
}
return $actions;
}
/**
* Checks for the custom "duplicate" action.
*
* @date 15/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function check_duplicate() {
// Display notice on success redirect.
if ( isset( $_GET['acfduplicatecomplete'] ) ) {
$ids = array_map( 'intval', explode( ',', $_GET['acfduplicatecomplete'] ) );
// Generate text.
$text = sprintf(
_n( 'Field group duplicated.', '%s field groups duplicated.', count( $ids ), 'acf' ),
count( $ids )
);
// Append links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
acf_add_admin_notice( $text, 'success' );
return;
}
// Find items to duplicate.
$ids = array();
if ( isset( $_GET['acfduplicate'] ) ) {
$ids[] = intval( $_GET['acfduplicate'] );
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfduplicate' ) {
$ids = array_map( 'intval', $_GET['post'] );
}
if ( $ids ) {
check_admin_referer( 'bulk-posts' );
// Duplicate field groups and generate array of new IDs.
$new_ids = array();
foreach ( $ids as $id ) {
$field_group = acf_duplicate_field_group( $id );
$new_ids[] = $field_group['ID'];
}
// Redirect.
wp_redirect( $this->get_admin_url( '&acfduplicatecomplete=' . implode( ',', $new_ids ) ) );
exit;
}
}
/**
* Checks for the custom "acfsync" action.
*
* @date 15/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function check_sync() {
// Display notice on success redirect.
if ( isset( $_GET['acfsynccomplete'] ) ) {
$ids = array_map( 'intval', explode( ',', $_GET['acfsynccomplete'] ) );
// Generate text.
$text = sprintf(
_n( 'Field group synchronised.', '%s field groups synchronised.', count( $ids ), 'acf' ),
count( $ids )
);
// Append links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
acf_add_admin_notice( $text, 'success' );
return;
}
// Find items to sync.
$keys = array();
if ( isset( $_GET['acfsync'] ) ) {
$keys[] = sanitize_text_field( $_GET['acfsync'] );
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfsync' ) {
$keys = array_map( 'sanitize_text_field', $_GET['post'] );
}
if ( $keys && $this->sync ) {
check_admin_referer( 'bulk-posts' );
// Disabled "Local JSON" controller to prevent the .json file from being modified during import.
acf_update_setting( 'json', false );
// Sync field groups and generate array of new IDs.
$files = acf_get_local_json_files();
$new_ids = array();
foreach ( $this->sync as $key => $field_group ) {
if ( $field_group['key'] && in_array( $field_group['key'], $keys ) ) {
// Import.
} elseif ( $field_group['ID'] && in_array( $field_group['ID'], $keys ) ) {
// Import.
} else {
// Ignore.
continue;
}
$local_field_group = json_decode( file_get_contents( $files[ $key ] ), true );
$local_field_group['ID'] = $field_group['ID'];
$result = acf_import_field_group( $local_field_group );
$new_ids[] = $result['ID'];
}
// Redirect.
wp_redirect( $this->get_current_admin_url( '&acfsynccomplete=' . implode( ',', $new_ids ) ) );
exit;
}
}
/**
* Customizes the admin table subnav.
*
* @date 17/4/20
* @since 5.9.0
*
* @param array $views The available views.
* @return array
*/
public function admin_table_views( $views ) {
global $wp_list_table, $wp_query;
// Count items.
$count = count( $this->sync );
// Append "sync" link to subnav.
if ( $count ) {
$views['sync'] = sprintf(
'<a %s href="%s">%s <span class="count">(%s)</span></a>',
( $this->view === 'sync' ? 'class="current"' : '' ),
esc_url( $this->get_admin_url( '&post_status=sync' ) ),
esc_html( __( 'Sync available', 'acf' ) ),
$count
);
}
// Modify table pagination args to match JSON data.
if ( $this->view === 'sync' ) {
$wp_list_table->set_pagination_args(
array(
'total_items' => $count,
'total_pages' => 1,
'per_page' => $count,
)
);
$wp_query->post_count = 1; // At least one post is needed to render bulk drop-down.
}
return $views;
}
/**
* Prints scripts into the admin footer.
*
* @date 20/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
function admin_footer() {
?>
<script type="text/javascript">
(function($){
// Displays a modal comparing local changes.
function reviewSync( props ) {
var modal = acf.newModal({
title: acf.__('Review local JSON changes'),
content: '<p class="acf-modal-feedback"><i class="acf-loading"></i> ' + acf.__('Loading diff') + '</p>',
toolbar: '<a href="' + props.href + '" class="button button-primary button-sync-changes disabled">' + acf.__('Sync changes') + '</a>',
});
// Call AJAX.
var xhr = $.ajax({
url: acf.get('ajaxurl'),
method: 'POST',
dataType: 'json',
data: acf.prepareForAjax({
action: 'acf/ajax/local_json_diff',
id: props.id
})
})
.done(function( data, textStatus, jqXHR ) {
modal.content( data.html );
modal.$('.button-sync-changes').removeClass('disabled');
})
.fail(function( jqXHR, textStatus, errorThrown ) {
if( error = acf.getXhrError(jqXHR) ) {
modal.content( '<p class="acf-modal-feedback error">' + error + '</p>' );
}
});
}
// Add event listener.
$(document).on('click', 'a[data-event="review-sync"]', function( e ){
e.preventDefault();
reviewSync( $(this).data() );
});
})(jQuery);
</script>
<?php
}
/**
* Customizes the admin table HTML when viewing "sync" post_status.
*
* @date 17/4/20
* @since 5.9.0
*
* @param array $views The available views.
* @return array
*/
public function admin_footer__sync() {
global $wp_list_table;
// Get table columns.
$columns = $wp_list_table->get_columns();
$hidden = get_hidden_columns( $wp_list_table->screen );
?>
<div style="display: none;">
<table>
<tbody id="acf-the-list">
<?php
foreach ( $this->sync as $k => $field_group ) {
echo '<tr>';
foreach ( $columns as $column_name => $column_label ) {
$el = 'td';
if ( $column_name === 'cb' ) {
$el = 'th';
$classes = 'check-column';
$column_label = '';
} elseif ( $column_name === 'title' ) {
$classes = "$column_name column-$column_name column-primary";
} else {
$classes = "$column_name column-$column_name";
}
if ( in_array( $column_name, $hidden, true ) ) {
$classes .= ' hidden';
}
echo "<$el class=\"$classes\" data-colname=\"$column_label\">";
switch ( $column_name ) {
// Checkbox.
case 'cb':
echo '<label for="cb-select-' . esc_attr( $k ) . '" class="screen-reader-text">' . esc_html( sprintf( __( 'Select %s', 'acf' ), $field_group['title'] ) ) . '</label>';
echo '<input id="cb-select-' . esc_attr( $k ) . '" type="checkbox" value="' . esc_attr( $k ) . '" name="post[]">';
break;
// Title.
case 'title':
$post_state = '';
if ( ! $field_group['active'] ) {
$post_state = ' — <span class="post-state">' . $this->get_disabled_post_state() . '</span>';
}
echo '<strong><span class="row-title">' . esc_html( $field_group['title'] ) . '</span>' . $post_state . '</strong>';
echo '<div class="row-actions"><span class="file acf-secondary-text">' . $this->get_human_readable_file_location( $field_group['local_file'] ) . '</span></div>';
echo '<button type="button" class="toggle-row"><span class="screen-reader-text">Show more details</span></button>';
break;
// All other columns.
default:
$this->render_admin_table_column( $column_name, $field_group );
break;
}
echo "</$el>";
}
echo '</tr>';
}
?>
</tbody>
</table>
</div>
<script type="text/javascript">
(function($){
$('#the-list').html( $('#acf-the-list').children() );
})(jQuery);
</script>
<?php
}
/**
* Fires when trashing a field group post.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function trashed_post( $post_id ) {
if ( get_post_type( $post_id ) === 'acf-field-group' ) {
acf_trash_field_group( $post_id );
}
}
/**
* Fires when untrashing a field group post.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function untrashed_post( $post_id ) {
if ( get_post_type( $post_id ) === 'acf-field-group' ) {
acf_untrash_field_group( $post_id );
}
}
/**
* Fires when deleting a field group post.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function deleted_post( $post_id ) {
if ( get_post_type( $post_id ) === 'acf-field-group' ) {
acf_delete_field_group( $post_id );
}
}
}
// Instantiate.
acf_new_instance( 'ACF_Admin_Field_Groups' );
endif; // class_exists check

View File

@@ -0,0 +1,140 @@
<?php
/**
* ACF Admin Notices
*
* Functions and classes to manage admin notices.
*
* @date 10/1/19
* @since 5.7.10
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Register notices store.
acf_register_store( 'notices' );
/**
* ACF_Admin_Notice
*
* Class used to create an admin notice.
*
* @date 10/1/19
* @since 5.7.10
*/
if ( ! class_exists( 'ACF_Admin_Notice' ) ) :
class ACF_Admin_Notice extends ACF_Data {
/** @var array Storage for data. */
var $data = array(
/** @type string Text displayed in notice. */
'text' => '',
/** @type string The type of notice (warning, error, success, info). */
'type' => 'info',
/** @type bool If the notice can be dismissed. */
'dismissible' => true,
);
/**
* render
*
* Renders the notice HTML.
*
* @date 27/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function render() {
$notice_text = $this->get( 'text' );
$notice_type = $this->get( 'type' );
$is_dismissible = $this->get( 'dismissible' );
printf(
'<div class="acf-admin-notice notice notice-%s %s">%s</div>',
esc_attr( $notice_type ),
$is_dismissible ? 'is-dismissible' : '',
acf_esc_html( wpautop( acf_punctify( $notice_text ) ) )
);
}
}
endif; // class_exists check
/**
* acf_new_admin_notice
*
* Instantiates and returns a new model.
*
* @date 23/12/18
* @since 5.8.0
*
* @param array $data Optional data to set.
* @return ACF_Admin_Notice
*/
function acf_new_admin_notice( $data = false ) {
// Create notice.
$instance = new ACF_Admin_Notice( $data );
// Register notice.
acf_get_store( 'notices' )->set( $instance->cid, $instance );
// Return notice.
return $instance;
}
/**
* acf_render_admin_notices
*
* Renders all admin notices HTML.
*
* @date 10/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function acf_render_admin_notices() {
// Get notices.
$notices = acf_get_store( 'notices' )->get_data();
// Loop over notices and render.
if ( $notices ) {
foreach ( $notices as $notice ) {
$notice->render();
}
}
}
// Render notices during admin action.
add_action( 'admin_notices', 'acf_render_admin_notices', 99 );
/**
* acf_add_admin_notice
*
* Creates and returns a new notice.
*
* @date 17/10/13
* @since 5.0.0
*
* @param string $text The admin notice text.
* @param string $class The type of notice (warning, error, success, info).
* @return ACF_Admin_Notice
*/
function acf_add_admin_notice( $text = '', $type = 'info' ) {
return acf_new_admin_notice(
array(
'text' => $text,
'type' => $type,
)
);
}

View File

@@ -0,0 +1,347 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'acf_admin_tools' ) ) :
class acf_admin_tools {
/** @var array Contains an array of admin tool instances */
var $tools = array();
/** @var string The active tool */
var $active = '';
/**
* __construct
*
* This function will setup the class functionality
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
}
/**
* register_tool
*
* This function will store a tool tool class
*
* @date 10/10/17
* @since 5.6.3
*
* @param string $class
* @return n/a
*/
function register_tool( $class ) {
$instance = new $class();
$this->tools[ $instance->name ] = $instance;
}
/**
* get_tool
*
* This function will return a tool tool class
*
* @date 10/10/17
* @since 5.6.3
*
* @param string $name
* @return n/a
*/
function get_tool( $name ) {
return isset( $this->tools[ $name ] ) ? $this->tools[ $name ] : null;
}
/**
* get_tools
*
* This function will return an array of all tools
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return array
*/
function get_tools() {
return $this->tools;
}
/*
* admin_menu
*
* This function will add the ACF menu item to the WP admin
*
* @type action (admin_menu)
* @date 28/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_menu() {
// bail early if no show_admin
if ( ! acf_get_setting( 'show_admin' ) ) {
return;
}
// add page
$page = add_submenu_page( 'edit.php?post_type=acf-field-group', __( 'Tools', 'acf' ), __( 'Tools', 'acf' ), acf_get_setting( 'capability' ), 'acf-tools', array( $this, 'html' ) );
// actions
add_action( 'load-' . $page, array( $this, 'load' ) );
}
/**
* load
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function load() {
// disable filters (default to raw data)
acf_disable_filters();
// include tools
$this->include_tools();
// check submit
$this->check_submit();
// load acf scripts
acf_enqueue_scripts();
}
/**
* include_tools
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function include_tools() {
// include
acf_include( 'includes/admin/tools/class-acf-admin-tool.php' );
acf_include( 'includes/admin/tools/class-acf-admin-tool-export.php' );
acf_include( 'includes/admin/tools/class-acf-admin-tool-import.php' );
// action
do_action( 'acf/include_admin_tools' );
}
/**
* check_submit
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function check_submit() {
// loop
foreach ( $this->get_tools() as $tool ) {
// load
$tool->load();
// submit
if ( acf_verify_nonce( $tool->name ) ) {
$tool->submit();
}
}
}
/**
* html
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
// vars
$screen = get_current_screen();
$active = acf_maybe_get_GET( 'tool' );
// view
$view = array(
'screen_id' => $screen->id,
'active' => $active,
);
// register metaboxes
foreach ( $this->get_tools() as $tool ) {
// check active
if ( $active && $active !== $tool->name ) {
continue;
}
// add metabox
add_meta_box( 'acf-admin-tool-' . $tool->name, acf_esc_html( $tool->title ), array( $this, 'metabox_html' ), $screen->id, 'normal', 'default', array( 'tool' => $tool->name ) );
}
// view
acf_get_view( 'html-admin-tools', $view );
}
/**
* meta_box_html
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function metabox_html( $post, $metabox ) {
// vars
$tool = $this->get_tool( $metabox['args']['tool'] );
?>
<form method="post">
<?php $tool->html(); ?>
<?php acf_nonce_input( $tool->name ); ?>
</form>
<?php
}
}
// initialize
acf()->admin_tools = new acf_admin_tools();
endif; // class_exists check
/*
* acf_register_admin_tool
*
* alias of acf()->admin_tools->register_tool()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_register_admin_tool( $class ) {
return acf()->admin_tools->register_tool( $class );
}
/*
* acf_get_admin_tools_url
*
* This function will return the admin URL to the tools page
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_admin_tools_url() {
return admin_url( 'edit.php?post_type=acf-field-group&page=acf-tools' );
}
/*
* acf_get_admin_tool_url
*
* This function will return the admin URL to the tools page
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_admin_tool_url( $tool = '' ) {
return acf_get_admin_tools_url() . '&tool=' . $tool;
}
?>

View File

@@ -0,0 +1,246 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Upgrade' ) ) :
class ACF_Admin_Upgrade {
/**
* __construct
*
* Sets up the class functionality.
*
* @date 31/7/18
* @since 5.7.2
*
* @param void
* @return void
*/
function __construct() {
// actions
add_action( 'admin_menu', array( $this, 'admin_menu' ), 20 );
if ( is_multisite() ) {
add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ), 20 );
}
}
/**
* admin_menu
*
* Setus up logic if DB Upgrade is needed on a single site.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function admin_menu() {
// check if upgrade is avaialble
if ( acf_has_upgrade() ) {
// add notice
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
// add page
$page = add_submenu_page( 'index.php', __( 'Upgrade Database', 'acf' ), __( 'Upgrade Database', 'acf' ), acf_get_setting( 'capability' ), 'acf-upgrade', array( $this, 'admin_html' ) );
// actions
add_action( 'load-' . $page, array( $this, 'admin_load' ) );
}
}
/**
* network_admin_menu
*
* Sets up admin logic if DB Upgrade is required on a multi site.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function network_admin_menu() {
// Vars.
$upgrade = false;
// Loop over sites and check for upgrades.
$sites = get_sites( array( 'number' => 0 ) );
if ( $sites ) {
// Unhook action to avoid memory issue (as seen in wp-includes/ms-site.php).
remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );
foreach ( $sites as $site ) {
// Switch site.
switch_to_blog( $site->blog_id );
// Check for upgrade.
$site_upgrade = acf_has_upgrade();
// Restore site.
// Ideally, we would switch back to the original site at after looping, however,
// the restore_current_blog() is needed to modify global vars.
restore_current_blog();
// Check if upgrade was found.
if ( $site_upgrade ) {
$upgrade = true;
break;
}
}
add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
}
// Bail early if no upgrade is needed.
if ( ! $upgrade ) {
return;
}
// Add notice.
add_action( 'network_admin_notices', array( $this, 'network_admin_notices' ) );
// Add page.
$page = add_submenu_page(
'index.php',
__( 'Upgrade Database', 'acf' ),
__( 'Upgrade Database', 'acf' ),
acf_get_setting( 'capability' ),
'acf-upgrade-network',
array( $this, 'network_admin_html' )
);
add_action( "load-$page", array( $this, 'network_admin_load' ) );
}
/**
* admin_load
*
* Runs during the loading of the admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_load() {
// remove prompt
remove_action( 'admin_notices', array( $this, 'admin_notices' ) );
// Enqueue core script.
acf_enqueue_script( 'acf' );
}
/**
* network_admin_load
*
* Runs during the loading of the network admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param type $var Description. Default.
* @return type Description.
*/
function network_admin_load() {
// remove prompt
remove_action( 'network_admin_notices', array( $this, 'network_admin_notices' ) );
// Enqueue core script.
acf_enqueue_script( 'acf' );
}
/**
* admin_notices
*
* Displays the DB Upgrade prompt.
*
* @date 23/8/18
* @since 5.7.3
*
* @param void
* @return void
*/
function admin_notices() {
// vars
$view = array(
'button_text' => __( 'Upgrade Database', 'acf' ),
'button_url' => admin_url( 'index.php?page=acf-upgrade' ),
'confirm' => true,
);
// view
acf_get_view( 'html-notice-upgrade', $view );
}
/**
* network_admin_notices
*
* Displays the DB Upgrade prompt on a multi site.
*
* @date 23/8/18
* @since 5.7.3
*
* @param void
* @return void
*/
function network_admin_notices() {
// vars
$view = array(
'button_text' => __( 'Review sites & upgrade', 'acf' ),
'button_url' => network_admin_url( 'index.php?page=acf-upgrade-network' ),
'confirm' => false,
);
// view
acf_get_view( 'html-notice-upgrade', $view );
}
/**
* admin_html
*
* Displays the HTML for the admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function admin_html() {
acf_get_view( 'html-admin-page-upgrade' );
}
/**
* network_admin_html
*
* Displays the HTML for the network upgrade admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function network_admin_html() {
acf_get_view( 'html-admin-page-upgrade-network' );
}
}
// instantiate
acf_new_instance( 'ACF_Admin_Upgrade' );
endif; // class_exists check

View File

@@ -0,0 +1,209 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin' ) ) :
class ACF_Admin {
/**
* Constructor.
*
* @date 23/06/12
* @since 5.0.0
*
* @param void
* @return void
*/
function __construct() {
// Add actions.
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
add_action( 'current_screen', array( $this, 'current_screen' ) );
}
/**
* Adds the ACF menu item.
*
* @date 28/09/13
* @since 5.0.0
*
* @param void
* @return void
*/
function admin_menu() {
// Bail early if ACF is hidden.
if ( ! acf_get_setting( 'show_admin' ) ) {
return;
}
// Vars.
$slug = 'edit.php?post_type=acf-field-group';
$cap = acf_get_setting( 'capability' );
// Add menu items.
add_menu_page( __( 'Custom Fields', 'acf' ), __( 'Custom Fields', 'acf' ), $cap, $slug, false, 'dashicons-welcome-widgets-menus', 80 );
add_submenu_page( $slug, __( 'Field Groups', 'acf' ), __( 'Field Groups', 'acf' ), $cap, $slug );
add_submenu_page( $slug, __( 'Add New', 'acf' ), __( 'Add New', 'acf' ), $cap, 'post-new.php?post_type=acf-field-group' );
}
/**
* Enqueues global admin styling.
*
* @date 28/09/13
* @since 5.0.0
*
* @param void
* @return void
*/
function admin_enqueue_scripts() {
wp_enqueue_style( 'acf-global' );
}
/**
* Appends custom admin body classes.
*
* @date 5/11/19
* @since 5.8.7
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
function admin_body_class( $classes ) {
global $wp_version;
// Determine body class version.
$wp_minor_version = floatval( $wp_version );
if ( $wp_minor_version >= 5.3 ) {
$classes .= ' acf-admin-5-3';
} else {
$classes .= ' acf-admin-3-8';
}
// Add browser for specific CSS.
$classes .= ' acf-browser-' . acf_get_browser();
// Return classes.
return $classes;
}
/**
* Adds custom functionality to "ACF" admin pages.
*
* @date 7/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
function current_screen( $screen ) {
// Determine if the current page being viewed is "ACF" related.
if ( isset( $screen->post_type ) && $screen->post_type === 'acf-field-group' ) {
add_action( 'in_admin_header', array( $this, 'in_admin_header' ) );
add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
$this->setup_help_tab();
}
}
/**
* Sets up the admin help tab.
*
* @date 20/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function setup_help_tab() {
$screen = get_current_screen();
// Overview tab.
$screen->add_help_tab(
array(
'id' => 'overview',
'title' => __( 'Overview', 'acf' ),
'content' =>
'<p><strong>' . __( 'Overview', 'acf' ) . '</strong></p>' .
'<p>' . __( 'The Advanced Custom Fields plugin provides a visual form builder to customize WordPress edit screens with extra fields, and an intuitive API to display custom field values in any theme template file.', 'acf' ) . '</p>' .
'<p>' . sprintf(
__( 'Before creating your first Field Group, we recommend first reading our <a href="%s" target="_blank">Getting started</a> guide to familiarize yourself with the plugin\'s philosophy and best practises.', 'acf' ),
'https://www.advancedcustomfields.com/resources/getting-started-with-acf/'
) . '</p>' .
'<p>' . __( 'Please use the Help & Support tab to get in touch should you find yourself requiring assistance.', 'acf' ) . '</p>' .
'',
)
);
// Help tab.
$screen->add_help_tab(
array(
'id' => 'help',
'title' => __( 'Help & Support', 'acf' ),
'content' =>
'<p><strong>' . __( 'Help & Support', 'acf' ) . '</strong></p>' .
'<p>' . __( 'We are fanatical about support, and want you to get the best out of your website with ACF. If you run into any difficulties, there are several places you can find help:', 'acf' ) . '</p>' .
'<ul>' .
'<li>' . sprintf(
__( '<a href="%s" target="_blank">Documentation</a>. Our extensive documentation contains references and guides for most situations you may encounter.', 'acf' ),
'https://www.advancedcustomfields.com/resources/'
) . '</li>' .
'<li>' . sprintf(
__( '<a href="%s" target="_blank">Discussions</a>. We have an active and friendly community on our Community Forums who may be able to help you figure out the how-tos of the ACF world.', 'acf' ),
'https://support.advancedcustomfields.com/'
) . '</li>' .
'<li>' . sprintf(
__( '<a href="%s" target="_blank">Help Desk</a>. The support professionals on our Help Desk will assist with your more in depth, technical challenges.', 'acf' ),
'https://www.advancedcustomfields.com/support/'
) . '</li>' .
'</ul>',
)
);
// Sidebar.
$screen->set_help_sidebar(
'<p><strong>' . __( 'Information', 'acf' ) . '</strong></p>' .
'<p><span class="dashicons dashicons-admin-plugins"></span> ' . sprintf( __( 'Version %s', 'acf' ), ACF_VERSION ) . '</p>' .
'<p><span class="dashicons dashicons-wordpress"></span> <a href="https://wordpress.org/plugins/advanced-custom-fields/" target="_blank">' . __( 'View details', 'acf' ) . '</a></p>' .
'<p><span class="dashicons dashicons-admin-home"></span> <a href="https://www.advancedcustomfields.com/" target="_blank" target="_blank">' . __( 'Visit website', 'acf' ) . '</a></p>' .
''
);
}
/**
* Renders the admin navigation element.
*
* @date 27/3/20
* @since 5.9.0
*
* @param void
* @return void
*/
function in_admin_header() {
acf_get_view( 'html-admin-navigation' );
}
/**
* Modifies the admin footer text.
*
* @date 7/4/20
* @since 5.9.0
*
* @param string $text The admin footer text.
* @return string
*/
function admin_footer_text( $text ) {
// Use RegExp to append "ACF" after the <a> element allowing translations to read correctly.
return preg_replace( '/(<a[\S\s]+?\/a>)/', '$1 ' . __( 'and', 'acf' ) . ' <a href="https://www.advancedcustomfields.com" target="_blank">ACF</a>', $text, 1 );
}
}
// Instantiate.
acf_new_instance( 'ACF_Admin' );
endif; // class_exists check

View File

@@ -0,0 +1,580 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Tool_Export' ) ) :
class ACF_Admin_Tool_Export extends ACF_Admin_Tool {
/** @var string View context */
var $view = '';
/** @var array Export data */
var $json = '';
/**
* initialize
*
* This function will initialize the admin tool
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function initialize() {
// vars
$this->name = 'export';
$this->title = __( 'Export Field Groups', 'acf' );
// active
if ( $this->is_active() ) {
$this->title .= ' - ' . __( 'Generate PHP', 'acf' );
}
}
/**
* submit
*
* This function will run when the tool's form has been submit
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit() {
// vars
$action = acf_maybe_get_POST( 'action' );
// download
if ( $action === 'download' ) {
$this->submit_download();
// generate
} elseif ( $action === 'generate' ) {
$this->submit_generate();
}
}
/**
* submit_download
*
* description
*
* @date 17/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit_download() {
// vars
$json = $this->get_selected();
// validate
if ( $json === false ) {
return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
}
// headers
$file_name = 'acf-export-' . date( 'Y-m-d' ) . '.json';
header( 'Content-Description: File Transfer' );
header( "Content-Disposition: attachment; filename={$file_name}" );
header( 'Content-Type: application/json; charset=utf-8' );
// return
echo acf_json_encode( $json );
die;
}
/**
* submit_generate
*
* description
*
* @date 17/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit_generate() {
// vars
$keys = $this->get_selected_keys();
// validate
if ( ! $keys ) {
return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
}
// url
$url = add_query_arg( 'keys', implode( '+', $keys ), $this->get_url() );
// redirect
wp_redirect( $url );
exit;
}
/**
* load
*
* description
*
* @date 21/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function load() {
// active
if ( $this->is_active() ) {
// get selected keys
$selected = $this->get_selected_keys();
// add notice
if ( $selected ) {
$count = count( $selected );
$text = sprintf( _n( 'Exported 1 field group.', 'Exported %s field groups.', $count, 'acf' ), $count );
acf_add_admin_notice( $text, 'success' );
}
}
}
/**
* html
*
* This function will output the metabox HTML
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
// single (generate PHP)
if ( $this->is_active() ) {
$this->html_single();
// archive
} else {
$this->html_archive();
}
}
/**
* html_field_selection
*
* description
*
* @date 24/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_field_selection() {
// vars
$choices = array();
$selected = $this->get_selected_keys();
$field_groups = acf_get_field_groups();
// loop
if ( $field_groups ) {
foreach ( $field_groups as $field_group ) {
$choices[ $field_group['key'] ] = esc_html( $field_group['title'] );
}
}
// render
acf_render_field_wrap(
array(
'label' => __( 'Select Field Groups', 'acf' ),
'type' => 'checkbox',
'name' => 'keys',
'prefix' => false,
'value' => $selected,
'toggle' => true,
'choices' => $choices,
)
);
}
/**
* html_panel_selection
*
* description
*
* @date 21/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_panel_selection() {
?>
<div class="acf-panel acf-panel-selection">
<h3 class="acf-panel-title"><?php _e( 'Select Field Groups', 'acf' ); ?> <i class="dashicons dashicons-arrow-right"></i></h3>
<div class="acf-panel-inside">
<?php $this->html_field_selection(); ?>
</div>
</div>
<?php
}
/**
* html_panel_settings
*
* description
*
* @date 21/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_panel_settings() {
?>
<div class="acf-panel acf-panel-settings">
<h3 class="acf-panel-title"><?php _e( 'Settings', 'acf' ); ?> <i class="dashicons dashicons-arrow-right"></i></h3>
<div class="acf-panel-inside">
<?php
/*
acf_render_field_wrap(array(
'label' => __('Empty settings', 'acf'),
'type' => 'select',
'name' => 'minimal',
'prefix' => false,
'value' => '',
'choices' => array(
'all' => __('Include all settings', 'acf'),
'minimal' => __('Ignore empty settings', 'acf'),
)
));
*/
?>
</div>
</div>
<?php
}
/**
* html_archive
*
* description
*
* @date 20/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_archive() {
?>
<p><?php _e( 'Select the field groups you would like to export and then select your export method. Use the download button to export to a .json file which you can then import to another ACF installation. Use the generate button to export to PHP code which you can place in your theme.', 'acf' ); ?></p>
<div class="acf-fields">
<?php $this->html_field_selection(); ?>
</div>
<p class="acf-submit">
<button type="submit" name="action" class="button button-primary" value="download"><?php _e( 'Export File', 'acf' ); ?></button>
<button type="submit" name="action" class="button" value="generate"><?php _e( 'Generate PHP', 'acf' ); ?></button>
</p>
<?php
}
/**
* html_single
*
* description
*
* @date 20/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_single() {
?>
<div class="acf-postbox-columns">
<div class="acf-postbox-main">
<?php $this->html_generate(); ?>
</div>
<div class="acf-postbox-side">
<?php $this->html_panel_selection(); ?>
<p class="acf-submit">
<button type="submit" name="action" class="button button-primary" value="generate"><?php _e( 'Generate PHP', 'acf' ); ?></button>
</p>
</div>
</div>
<?php
}
/**
* html_generate
*
* description
*
* @date 17/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_generate() {
// prevent default translation and fake __() within string
acf_update_setting( 'l10n_var_export', true );
// vars
$json = $this->get_selected();
$str_replace = array(
' ' => "\t",
"'!!__(!!\'" => "__('",
"!!\', !!\'" => "', '",
"!!\')!!'" => "')",
'array (' => 'array(',
);
$preg_replace = array(
'/([\t\r\n]+?)array/' => 'array',
'/[0-9]+ => array/' => 'array',
);
?>
<p><?php _e( "The following code can be used to register a local version of the selected field group(s). A local field group can provide many benefits such as faster load times, version control & dynamic fields/settings. Simply copy and paste the following code to your theme's functions.php file or include it within an external file.", 'acf' ); ?></p>
<textarea id="acf-export-textarea" readonly="true">
<?php
echo "if( function_exists('acf_add_local_field_group') ):" . "\r\n" . "\r\n";
foreach ( $json as $field_group ) {
// code
$code = var_export( $field_group, true );
// change double spaces to tabs
$code = str_replace( array_keys( $str_replace ), array_values( $str_replace ), $code );
// correctly formats "=> array("
$code = preg_replace( array_keys( $preg_replace ), array_values( $preg_replace ), $code );
// esc_textarea
$code = esc_textarea( $code );
// echo
echo "acf_add_local_field_group({$code});" . "\r\n" . "\r\n";
}
echo 'endif;';
?>
</textarea>
<p class="acf-submit">
<a class="button" id="acf-export-copy"><?php _e( 'Copy to clipboard', 'acf' ); ?></a>
</p>
<script type="text/javascript">
(function($){
// vars
var $a = $('#acf-export-copy');
var $textarea = $('#acf-export-textarea');
// remove $a if 'copy' is not supported
if( !document.queryCommandSupported('copy') ) {
return $a.remove();
}
// event
$a.on('click', function( e ){
// prevent default
e.preventDefault();
// select
$textarea.get(0).select();
// try
try {
// copy
var copy = document.execCommand('copy');
if( !copy ) return;
// tooltip
acf.newTooltip({
text: "<?php _e( 'Copied', 'acf' ); ?>",
timeout: 250,
target: $(this),
});
} catch (err) {
// do nothing
}
});
})(jQuery);
</script>
<?php
}
/**
* get_selected_keys
*
* This function will return an array of field group keys that have been selected
*
* @date 20/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_selected_keys() {
// check $_POST
if ( $keys = acf_maybe_get_POST( 'keys' ) ) {
return (array) $keys;
}
// check $_GET
if ( $keys = acf_maybe_get_GET( 'keys' ) ) {
$keys = str_replace( ' ', '+', $keys );
return explode( '+', $keys );
}
// return
return false;
}
/**
* get_selected
*
* This function will return the JSON data for given $_POST args
*
* @date 17/10/17
* @since 5.6.3
*
* @param n/a
* @return array
*/
function get_selected() {
// vars
$selected = $this->get_selected_keys();
$json = array();
// bail early if no keys
if ( ! $selected ) {
return false;
}
// construct JSON
foreach ( $selected as $key ) {
// load field group
$field_group = acf_get_field_group( $key );
// validate field group
if ( empty( $field_group ) ) {
continue;
}
// load fields
$field_group['fields'] = acf_get_fields( $field_group );
// prepare for export
$field_group = acf_prepare_field_group_for_export( $field_group );
// add to json array
$json[] = $field_group;
}
// return
return $json;
}
}
// initialize
acf_register_admin_tool( 'ACF_Admin_Tool_Export' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,161 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Tool_Import' ) ) :
class ACF_Admin_Tool_Import extends ACF_Admin_Tool {
/**
* initialize
*
* This function will initialize the admin tool
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function initialize() {
// vars
$this->name = 'import';
$this->title = __( 'Import Field Groups', 'acf' );
$this->icon = 'dashicons-upload';
}
/**
* html
*
* This function will output the metabox HTML
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
?>
<p><?php _e( 'Select the Advanced Custom Fields JSON file you would like to import. When you click the import button below, ACF will import the field groups.', 'acf' ); ?></p>
<div class="acf-fields">
<?php
acf_render_field_wrap(
array(
'label' => __( 'Select File', 'acf' ),
'type' => 'file',
'name' => 'acf_import_file',
'value' => false,
'uploader' => 'basic',
)
);
?>
</div>
<p class="acf-submit">
<input type="submit" class="button button-primary" value="<?php _e( 'Import File', 'acf' ); ?>" />
</p>
<?php
}
/**
* submit
*
* This function will run when the tool's form has been submit
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit() {
// Check file size.
if ( empty( $_FILES['acf_import_file']['size'] ) ) {
return acf_add_admin_notice( __( 'No file selected', 'acf' ), 'warning' );
}
// Get file data.
$file = $_FILES['acf_import_file'];
// Check errors.
if ( $file['error'] ) {
return acf_add_admin_notice( __( 'Error uploading file. Please try again', 'acf' ), 'warning' );
}
// Check file type.
if ( pathinfo( $file['name'], PATHINFO_EXTENSION ) !== 'json' ) {
return acf_add_admin_notice( __( 'Incorrect file type', 'acf' ), 'warning' );
}
// Read JSON.
$json = file_get_contents( $file['tmp_name'] );
$json = json_decode( $json, true );
// Check if empty.
if ( ! $json || ! is_array( $json ) ) {
return acf_add_admin_notice( __( 'Import file empty', 'acf' ), 'warning' );
}
// Ensure $json is an array of groups.
if ( isset( $json['key'] ) ) {
$json = array( $json );
}
// Remeber imported field group ids.
$ids = array();
// Loop over json
foreach ( $json as $field_group ) {
// Search database for existing field group.
$post = acf_get_field_group_post( $field_group['key'] );
if ( $post ) {
$field_group['ID'] = $post->ID;
}
// Import field group.
$field_group = acf_import_field_group( $field_group );
// append message
$ids[] = $field_group['ID'];
}
// Count number of imported field groups.
$total = count( $ids );
// Generate text.
$text = sprintf( _n( 'Imported 1 field group', 'Imported %s field groups', $total, 'acf' ), $total );
// Add links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice
acf_add_admin_notice( $text, 'success' );
}
}
// initialize
acf_register_admin_tool( 'ACF_Admin_Tool_Import' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,194 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Tool' ) ) :
class ACF_Admin_Tool {
/** @var string Tool name */
var $name = '';
/** @var string Tool title */
var $title = '';
/** @var string Dashicon slug */
// var $icon = '';
/** @var boolean Redirect form to single */
// var $redirect = false;
/**
* get_name
*
* This function will return the Tool's name
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_name() {
return $this->name;
}
/**
* get_title
*
* This function will return the Tool's title
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_title() {
return $this->title;
}
/**
* get_url
*
* This function will return the Tool's title
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_url() {
return acf_get_admin_tool_url( $this->name );
}
/**
* is_active
*
* This function will return true if the tool is active
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return bool
*/
function is_active() {
return acf_maybe_get_GET( 'tool' ) === $this->name;
}
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 27/6/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// initialize
$this->initialize();
}
/**
* initialize
*
* This function will initialize the admin tool
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function initialize() {
/* do nothing */
}
/**
* load
*
* This function is called during the admin page load
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function load() {
/* do nothing */
}
/**
* html
*
* This function will output the metabox HTML
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
}
/**
* submit
*
* This function will run when the tool's form has been submit
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit() {
}
}
endif; // class_exists check

View File

@@ -0,0 +1,177 @@
<?php
// vars
$disabled = false;
// empty
if ( empty( $field['conditional_logic'] ) ) {
$disabled = true;
$field['conditional_logic'] = array(
// group 0
array(
// rule 0
array(),
),
);
}
?>
<tr class="acf-field acf-field-true-false acf-field-setting-conditional_logic" data-type="true_false" data-name="conditional_logic">
<td class="acf-label">
<label><?php _e( 'Conditional Logic', 'acf' ); ?></label>
</td>
<td class="acf-input">
<?php
acf_render_field(
array(
'type' => 'true_false',
'name' => 'conditional_logic',
'prefix' => $field['prefix'],
'value' => $disabled ? 0 : 1,
'ui' => 1,
'class' => 'conditions-toggle',
)
);
?>
<div class="rule-groups"
<?php
if ( $disabled ) :
?>
style="display:none;"<?php endif; ?>>
<?php
foreach ( $field['conditional_logic'] as $group_id => $group ) :
// validate
if ( empty( $group ) ) {
continue;
}
// vars
// $group_id must be completely different to $rule_id to avoid JS issues
$group_id = "group_{$group_id}";
$h4 = ( $group_id == 'group_0' ) ? __( 'Show this field if', 'acf' ) : __( 'or', 'acf' );
?>
<div class="rule-group" data-id="<?php echo $group_id; ?>">
<h4><?php echo $h4; ?></h4>
<table class="acf-table -clear">
<tbody>
<?php
foreach ( $group as $rule_id => $rule ) :
// valid rule
$rule = wp_parse_args(
$rule,
array(
'field' => '',
'operator' => '',
'value' => '',
)
);
// vars
// $group_id must be completely different to $rule_id to avoid JS issues
$rule_id = "rule_{$rule_id}";
$prefix = "{$field['prefix']}[conditional_logic][{$group_id}][{$rule_id}]";
// data attributes
$attributes = array(
'data-id' => $rule_id,
'data-field' => $rule['field'],
'data-operator' => $rule['operator'],
'data-value' => $rule['value'],
);
?>
<tr class="rule" <?php acf_esc_attr_e( $attributes ); ?>>
<td class="param">
<?php
acf_render_field(
array(
'type' => 'select',
'prefix' => $prefix,
'name' => 'field',
'class' => 'condition-rule-field',
'disabled' => $disabled,
'value' => $rule['field'],
'choices' => array(
$rule['field'] => $rule['field'],
),
)
);
?>
</td>
<td class="operator">
<?php
acf_render_field(
array(
'type' => 'select',
'prefix' => $prefix,
'name' => 'operator',
'class' => 'condition-rule-operator',
'disabled' => $disabled,
'value' => $rule['operator'],
'choices' => array(
$rule['operator'] => $rule['operator'],
),
)
);
?>
</td>
<td class="value">
<?php
// create field
acf_render_field(
array(
'type' => 'select',
'prefix' => $prefix,
'name' => 'value',
'class' => 'condition-rule-value',
'disabled' => $disabled,
'value' => $rule['value'],
'choices' => array(
$rule['value'] => $rule['value'],
),
)
);
?>
</td>
<td class="add">
<a href="#" class="button add-conditional-rule"><?php _e( 'and', 'acf' ); ?></a>
</td>
<td class="remove">
<a href="#" class="acf-icon -minus remove-conditional-rule"></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endforeach; ?>
<h4><?php _e( 'or', 'acf' ); ?></h4>
<a href="#" class="button add-conditional-group"><?php _e( 'Add rule group', 'acf' ); ?></a>
</div>
</td>
</tr>

View File

@@ -0,0 +1,224 @@
<?php
// Define input name prefix using unique identifier.
$input_prefix = 'acf_fields[' . $field['ID'] . ']';
$input_id = acf_idify( $input_prefix );
// Update field props.
$field['prefix'] = $input_prefix;
// Elements.
$div_attrs = array(
'class' => 'acf-field-object acf-field-object-' . acf_slugify( $field['type'] ),
'data-id' => $field['ID'],
'data-key' => $field['key'],
'data-type' => $field['type'],
);
// Misc template vars.
$field_label = acf_get_field_label( $field, 'admin' );
$field_type_label = acf_get_field_type_label( $field['type'] );
?>
<div <?php echo acf_esc_attr( $div_attrs ); ?>>
<div class="meta">
<?php
$meta_inputs = array(
'ID' => $field['ID'],
'key' => $field['key'],
'parent' => $field['parent'],
'menu_order' => $i,
'save' => '',
);
foreach ( $meta_inputs as $k => $v ) :
acf_hidden_input(
array(
'name' => $input_prefix . '[' . $k . ']',
'value' => $v,
'id' => $input_id . '-' . $k,
)
);
endforeach;
?>
</div>
<div class="handle">
<ul class="acf-hl acf-tbody">
<li class="li-field-order">
<span class="acf-icon acf-sortable-handle" title="<?php _e( 'Drag to reorder', 'acf' ); ?>"><?php echo ( $i + 1 ); ?></span>
</li>
<li class="li-field-label">
<strong>
<a class="edit-field" title="<?php _e( 'Edit field', 'acf' ); ?>" href="#"><?php echo acf_esc_html( $field_label ); ?></a>
</strong>
<div class="row-options">
<a class="edit-field" title="<?php _e( 'Edit field', 'acf' ); ?>" href="#"><?php _e( 'Edit', 'acf' ); ?></a>
<a class="duplicate-field" title="<?php _e( 'Duplicate field', 'acf' ); ?>" href="#"><?php _e( 'Duplicate', 'acf' ); ?></a>
<a class="move-field" title="<?php _e( 'Move field to another group', 'acf' ); ?>" href="#"><?php _e( 'Move', 'acf' ); ?></a>
<a class="delete-field" title="<?php _e( 'Delete field', 'acf' ); ?>" href="#"><?php _e( 'Delete', 'acf' ); ?></a>
</div>
</li>
<?php // whitespace before field name looks odd but fixes chrome bug selecting all text in row ?>
<li class="li-field-name"> <?php echo esc_html( $field['name'] ); ?></li>
<li class="li-field-key"> <?php echo esc_html( $field['key'] ); ?></li>
<li class="li-field-type"> <?php echo esc_html( $field_type_label ); ?></li>
</ul>
</div>
<div class="settings">
<table class="acf-table">
<tbody class="acf-field-settings">
<?php
// label
acf_render_field_setting(
$field,
array(
'label' => __( 'Field Label', 'acf' ),
'instructions' => __( 'This is the name which will appear on the EDIT page', 'acf' ),
'name' => 'label',
'type' => 'text',
'class' => 'field-label',
),
true
);
// name
acf_render_field_setting(
$field,
array(
'label' => __( 'Field Name', 'acf' ),
'instructions' => __( 'Single word, no spaces. Underscores and dashes allowed', 'acf' ),
'name' => 'name',
'type' => 'text',
'class' => 'field-name',
),
true
);
// type
acf_render_field_setting(
$field,
array(
'label' => __( 'Field Type', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'type',
'choices' => acf_get_grouped_field_types(),
'class' => 'field-type',
),
true
);
// instructions
acf_render_field_setting(
$field,
array(
'label' => __( 'Instructions', 'acf' ),
'instructions' => __( 'Instructions for authors. Shown when submitting data', 'acf' ),
'type' => 'textarea',
'name' => 'instructions',
'rows' => 5,
),
true
);
// required
acf_render_field_setting(
$field,
array(
'label' => __( 'Required?', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'required',
'ui' => 1,
'class' => 'field-required',
),
true
);
// 3rd party settings
do_action( 'acf/render_field_settings', $field );
// type specific settings
do_action( "acf/render_field_settings/type={$field['type']}", $field );
// conditional logic
acf_get_view( 'field-group-field-conditional-logic', array( 'field' => $field ) );
// wrapper
acf_render_field_wrap(
array(
'label' => __( 'Wrapper Attributes', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'width',
'prefix' => $field['prefix'] . '[wrapper]',
'value' => $field['wrapper']['width'],
'prepend' => __( 'width', 'acf' ),
'append' => '%',
'wrapper' => array(
'data-name' => 'wrapper',
'class' => 'acf-field-setting-wrapper',
),
),
'tr'
);
acf_render_field_wrap(
array(
'label' => '',
'instructions' => '',
'type' => 'text',
'name' => 'class',
'prefix' => $field['prefix'] . '[wrapper]',
'value' => $field['wrapper']['class'],
'prepend' => __( 'class', 'acf' ),
'wrapper' => array(
'data-append' => 'wrapper',
),
),
'tr'
);
acf_render_field_wrap(
array(
'label' => '',
'instructions' => '',
'type' => 'text',
'name' => 'id',
'prefix' => $field['prefix'] . '[wrapper]',
'value' => $field['wrapper']['id'],
'prepend' => __( 'id', 'acf' ),
'wrapper' => array(
'data-append' => 'wrapper',
),
),
'tr'
);
?>
<tr class="acf-field acf-field-save">
<td class="acf-label"></td>
<td class="acf-input">
<ul class="acf-hl">
<li>
<a class="button edit-field" title="<?php _e( 'Close Field', 'acf' ); ?>" href="#"><?php _e( 'Close Field', 'acf' ); ?></a>
</li>
</ul>
</td>
</tr>
</tbody>
</table>
</div>
</div>

View File

@@ -0,0 +1,76 @@
<div class="acf-field-list-wrap">
<ul class="acf-hl acf-thead">
<li class="li-field-order"><?php _e( 'Order', 'acf' ); ?></li>
<li class="li-field-label"><?php _e( 'Label', 'acf' ); ?></li>
<li class="li-field-name"><?php _e( 'Name', 'acf' ); ?></li>
<li class="li-field-key"><?php _e( 'Key', 'acf' ); ?></li>
<li class="li-field-type"><?php _e( 'Type', 'acf' ); ?></li>
</ul>
<div class="acf-field-list
<?php
if ( ! $fields ) {
echo ' -empty'; }
?>
">
<div class="no-fields-message">
<?php _e( 'No fields. Click the <strong>+ Add Field</strong> button to create your first field.', 'acf' ); ?>
</div>
<?php
if ( $fields ) :
foreach ( $fields as $i => $field ) :
acf_get_view(
'field-group-field',
array(
'field' => $field,
'i' => $i,
)
);
endforeach;
endif;
?>
</div>
<ul class="acf-hl acf-tfoot">
<li class="acf-fr">
<a href="#" class="button button-primary button-large add-field"><?php _e( '+ Add Field', 'acf' ); ?></a>
</li>
</ul>
<?php
if ( ! $parent ) :
// get clone
$clone = acf_get_valid_field(
array(
'ID' => 'acfcloneindex',
'key' => 'acfcloneindex',
'label' => __( 'New Field', 'acf' ),
'name' => 'new_field',
'type' => 'text',
)
);
?>
<script type="text/html" id="tmpl-acf-field">
<?php
acf_get_view(
'field-group-field',
array(
'field' => $clone,
'i' => 0,
)
);
?>
</script>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,52 @@
<?php
// global
global $field_group;
?>
<div class="acf-field">
<div class="acf-label">
<label><?php _e( 'Rules', 'acf' ); ?></label>
<p class="description"><?php _e( 'Create a set of rules to determine which edit screens will use these advanced custom fields', 'acf' ); ?></p>
</div>
<div class="acf-input">
<div class="rule-groups">
<?php
foreach ( $field_group['location'] as $i => $group ) :
// bail ealry if no group
if ( empty( $group ) ) {
return;
}
// view
acf_get_view(
'html-location-group',
array(
'group' => $group,
'group_id' => "group_{$i}",
)
);
endforeach;
?>
<h4><?php _e( 'or', 'acf' ); ?></h4>
<a href="#" class="button add-location-group"><?php _e( 'Add rule group', 'acf' ); ?></a>
</div>
</div>
</div>
<script type="text/javascript">
if( typeof acf !== 'undefined' ) {
acf.newPostbox({
'id': 'acf-field-group-locations',
'label': 'left'
});
}
</script>

View File

@@ -0,0 +1,171 @@
<?php
// global
global $field_group;
// active
acf_render_field_wrap(
array(
'label' => __( 'Active', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'active',
'prefix' => 'acf_field_group',
'value' => $field_group['active'],
'ui' => 1,
// 'ui_on_text' => __('Active', 'acf'),
// 'ui_off_text' => __('Inactive', 'acf'),
)
);
// style
acf_render_field_wrap(
array(
'label' => __( 'Style', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'style',
'prefix' => 'acf_field_group',
'value' => $field_group['style'],
'choices' => array(
'default' => __( 'Standard (WP metabox)', 'acf' ),
'seamless' => __( 'Seamless (no metabox)', 'acf' ),
),
)
);
// position
acf_render_field_wrap(
array(
'label' => __( 'Position', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'position',
'prefix' => 'acf_field_group',
'value' => $field_group['position'],
'choices' => array(
'acf_after_title' => __( 'High (after title)', 'acf' ),
'normal' => __( 'Normal (after content)', 'acf' ),
'side' => __( 'Side', 'acf' ),
),
'default_value' => 'normal',
)
);
// label_placement
acf_render_field_wrap(
array(
'label' => __( 'Label placement', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'label_placement',
'prefix' => 'acf_field_group',
'value' => $field_group['label_placement'],
'choices' => array(
'top' => __( 'Top aligned', 'acf' ),
'left' => __( 'Left aligned', 'acf' ),
),
)
);
// instruction_placement
acf_render_field_wrap(
array(
'label' => __( 'Instruction placement', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'instruction_placement',
'prefix' => 'acf_field_group',
'value' => $field_group['instruction_placement'],
'choices' => array(
'label' => __( 'Below labels', 'acf' ),
'field' => __( 'Below fields', 'acf' ),
),
)
);
// menu_order
acf_render_field_wrap(
array(
'label' => __( 'Order No.', 'acf' ),
'instructions' => __( 'Field groups with a lower order will appear first', 'acf' ),
'type' => 'number',
'name' => 'menu_order',
'prefix' => 'acf_field_group',
'value' => $field_group['menu_order'],
)
);
// description
acf_render_field_wrap(
array(
'label' => __( 'Description', 'acf' ),
'instructions' => __( 'Shown in field group list', 'acf' ),
'type' => 'text',
'name' => 'description',
'prefix' => 'acf_field_group',
'value' => $field_group['description'],
)
);
// hide on screen
$choices = array(
'permalink' => __( 'Permalink', 'acf' ),
'the_content' => __( 'Content Editor', 'acf' ),
'excerpt' => __( 'Excerpt', 'acf' ),
'custom_fields' => __( 'Custom Fields', 'acf' ),
'discussion' => __( 'Discussion', 'acf' ),
'comments' => __( 'Comments', 'acf' ),
'revisions' => __( 'Revisions', 'acf' ),
'slug' => __( 'Slug', 'acf' ),
'author' => __( 'Author', 'acf' ),
'format' => __( 'Format', 'acf' ),
'page_attributes' => __( 'Page Attributes', 'acf' ),
'featured_image' => __( 'Featured Image', 'acf' ),
'categories' => __( 'Categories', 'acf' ),
'tags' => __( 'Tags', 'acf' ),
'send-trackbacks' => __( 'Send Trackbacks', 'acf' ),
);
if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
unset( $choices['custom_fields'] );
}
acf_render_field_wrap(
array(
'label' => __( 'Hide on screen', 'acf' ),
'instructions' => __( '<b>Select</b> items to <b>hide</b> them from the edit screen.', 'acf' ) . '<br /><br />' . __( "If multiple field groups appear on an edit screen, the first field group's options will be used (the one with the lowest order number)", 'acf' ),
'type' => 'checkbox',
'name' => 'hide_on_screen',
'prefix' => 'acf_field_group',
'value' => $field_group['hide_on_screen'],
'toggle' => true,
'choices' => $choices,
)
);
// 3rd party settings
do_action( 'acf/render_field_group_settings', $field_group );
?>
<div class="acf-hidden">
<input type="hidden" name="acf_field_group[key]" value="<?php echo $field_group['key']; ?>" />
</div>
<script type="text/javascript">
if( typeof acf !== 'undefined' ) {
acf.newPostbox({
'id': 'acf-field-group-options',
'label': 'left'
});
}
</script>

View File

@@ -0,0 +1,93 @@
<?php
/**
* The template for displaying admin navigation.
*
* @date 27/3/20
* @since 5.9.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $submenu, $parent_file, $submenu_file, $plugin_page, $pagenow;
// Vars.
$parent_slug = 'edit.php?post_type=acf-field-group';
// Generate array of navigation items.
$tabs = array();
if ( isset( $submenu[ $parent_slug ] ) ) {
foreach ( $submenu[ $parent_slug ] as $i => $sub_item ) {
// Check user can access page.
if ( ! current_user_can( $sub_item[1] ) ) {
continue;
}
// Ignore "Add New".
if ( $i === 1 ) {
continue;
}
// Define tab.
$tab = array(
'text' => $sub_item[0],
'url' => $sub_item[2],
);
// Convert submenu slug "test" to "$parent_slug&page=test".
if ( ! strpos( $sub_item[2], '.php' ) ) {
$tab['url'] = add_query_arg( array( 'page' => $sub_item[2] ), $parent_slug );
}
// Detect active state.
if ( $submenu_file === $sub_item[2] || $plugin_page === $sub_item[2] ) {
$tab['is_active'] = true;
}
// Special case for "Add New" page.
if ( $i === 0 && $submenu_file === 'post-new.php?post_type=acf-field-group' ) {
$tab['is_active'] = true;
}
$tabs[] = $tab;
}
}
/**
* Filters the admin navigation tabs.
*
* @date 27/3/20
* @since 5.9.0
*
* @param array $tabs The array of navigation tabs.
*/
$tabs = apply_filters( 'acf/admin/toolbar', $tabs );
// Bail early if set to false.
if ( $tabs === false ) {
return;
}
?>
<div class="acf-admin-toolbar">
<h2><i class="acf-tab-icon dashicons dashicons-welcome-widgets-menus"></i> <?php echo acf_get_setting( 'name' ); ?></h2>
<?php
foreach ( $tabs as $tab ) {
printf(
'<a class="acf-tab%s" href="%s">%s</a>',
! empty( $tab['is_active'] ) ? ' is-active' : '',
esc_url( $tab['url'] ),
acf_esc_html( $tab['text'] )
);
}
?>
<?php if ( ! defined( 'ACF_PRO' ) || ! ACF_PRO ) : ?>
<a target="_blank" href="https://www.advancedcustomfields.com/pro/?utm_source=ACF%2BFree&utm_medium=insideplugin&utm_campaign=ACF%2Bupgrade" class="btn-upgrade">
<img src="<?php echo acf_get_url( 'assets/images/icon-upgrade-pro.svg' ); ?>" />
<p><?php _e( 'Upgrade to Pro', 'acf' ); ?></p>
</a>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,196 @@
<?php
/**
* Network Admin Database Upgrade
*
* Shows the databse upgrade process.
*
* @date 24/8/18
* @since 5.7.4
* @param void
*/
?>
<style type="text/css">
/* hide steps */
.show-on-complete {
display: none;
}
</style>
<div id="acf-upgrade-wrap" class="wrap">
<h1><?php _e( 'Upgrade Database', 'acf' ); ?></h1>
<p><?php echo sprintf( __( 'The following sites require a DB upgrade. Check the ones you want to update and then click %s.', 'acf' ), '"' . __( 'Upgrade Sites', 'acf' ) . '"' ); ?></p>
<p><input type="submit" name="upgrade" value="<?php _e( 'Upgrade Sites', 'acf' ); ?>" class="button" id="upgrade-sites"></p>
<table class="wp-list-table widefat">
<thead>
<tr>
<td class="manage-column check-column" scope="col">
<input type="checkbox" id="sites-select-all">
</td>
<th class="manage-column" scope="col" style="width:33%;">
<label for="sites-select-all"><?php _e( 'Site', 'acf' ); ?></label>
</th>
<th><?php _e( 'Description', 'acf' ); ?></th>
</tr>
</thead>
<tfoot>
<tr>
<td class="manage-column check-column" scope="col">
<input type="checkbox" id="sites-select-all-2">
</td>
<th class="manage-column" scope="col">
<label for="sites-select-all-2"><?php _e( 'Site', 'acf' ); ?></label>
</th>
<th><?php _e( 'Description', 'acf' ); ?></th>
</tr>
</tfoot>
<tbody id="the-list">
<?php
$sites = acf_get_sites();
if ( $sites ) :
foreach ( $sites as $i => $site ) :
// switch blog
switch_to_blog( $site['blog_id'] );
?>
<tr
<?php
if ( $i % 2 == 0 ) :
?>
class="alternate"<?php endif; ?>>
<th class="check-column" scope="row">
<?php if ( acf_has_upgrade() ) : ?>
<input type="checkbox" value="<?php echo $site['blog_id']; ?>" name="checked[]">
<?php endif; ?>
</th>
<td>
<strong><?php echo get_bloginfo( 'name' ); ?></strong><br /><?php echo home_url(); ?>
</td>
<td>
<?php if ( acf_has_upgrade() ) : ?>
<span class="response"><?php printf( __( 'Site requires database upgrade from %1$s to %2$s', 'acf' ), acf_get_db_version(), ACF_VERSION ); ?></span>
<?php else : ?>
<?php _e( 'Site is up to date', 'acf' ); ?>
<?php endif; ?>
</td>
</tr>
<?php
// restore
restore_current_blog();
endforeach;
endif;
?>
</tbody>
</table>
<p><input type="submit" name="upgrade" value="<?php _e( 'Upgrade Sites', 'acf' ); ?>" class="button" id="upgrade-sites-2"></p>
<p class="show-on-complete"><?php echo sprintf( __( 'Database Upgrade complete. <a href="%s">Return to network dashboard</a>', 'acf' ), network_admin_url() ); ?></p>
<script type="text/javascript">
(function($) {
var upgrader = new acf.Model({
events: {
'click #upgrade-sites': 'onClick',
'click #upgrade-sites-2': 'onClick'
},
$inputs: function(){
return $('#the-list input:checked');
},
onClick: function( e, $el ){
// prevent default
e.preventDefault();
// bail early if no selection
if( !this.$inputs().length ) {
return alert('<?php _e( 'Please select at least one site to upgrade.', 'acf' ); ?>');
}
// confirm action
if( !confirm("<?php _e( 'It is strongly recommended that you backup your database before proceeding. Are you sure you wish to run the updater now?', 'acf' ); ?>") ) {
return;
}
// upgrade
this.upgrade();
},
upgrade: function(){
// vars
var $inputs = this.$inputs();
// bail early if no sites selected
if( !$inputs.length ) {
return this.complete();
}
// disable buttons
$('.button').prop('disabled', true);
// vars
var $input = $inputs.first();
var $row = $input.closest('tr');
var text = '';
var success = false;
// show loading
$row.find('.response').html('<i class="acf-loading"></i></span> <?php printf( __( 'Upgrading data to version %s', 'acf' ), ACF_VERSION ); ?>');
// send ajax request to upgrade DB
$.ajax({
url: acf.get('ajaxurl'),
dataType: 'json',
type: 'post',
data: acf.prepareForAjax({
action: 'acf/ajax/upgrade',
blog_id: $input.val()
}),
success: function( json ){
success = true;
$input.remove();
text = '<?php _e( 'Upgrade complete.', 'acf' ); ?>';
},
error: function( jqXHR, textStatus, errorThrown ){
text = '<?php _e( 'Upgrade failed.', 'acf' ); ?>';
if( error = acf.getXhrError(jqXHR) ) {
text += ' <code>' + error + '</code>';
}
},
complete: this.proxy(function(){
// display text
$row.find('.response').html( text );
// if successful upgrade, proceed to next site. Otherwise, skip to complete.
if( success ) {
this.upgrade();
} else {
this.complete();
}
})
});
},
complete: function(){
// enable buttons
$('.button').prop('disabled', false);
// show message
$('.show-on-complete').show();
}
});
})(jQuery);
</script>
</div>

View File

@@ -0,0 +1,97 @@
<?php
/**
* Admin Database Upgrade
*
* Shows the databse upgrade process.
*
* @date 24/8/18
* @since 5.7.4
* @param void
*/
?>
<style type="text/css">
/* hide steps */
.step-1,
.step-2,
.step-3 {
display: none;
}
</style>
<div id="acf-upgrade-wrap" class="wrap">
<h1><?php _e( 'Upgrade Database', 'acf' ); ?></h1>
<?php if ( acf_has_upgrade() ) : ?>
<p><?php _e( 'Reading upgrade tasks...', 'acf' ); ?></p>
<p class="step-1"><i class="acf-loading"></i> <?php printf( __( 'Upgrading data to version %s', 'acf' ), ACF_VERSION ); ?></p>
<p class="step-2"></p>
<p class="step-3"><?php echo sprintf( __( 'Database upgrade complete. <a href="%s">See what\'s new</a>', 'acf' ), admin_url( 'edit.php?post_type=acf-field-group' ) ); ?></p>
<script type="text/javascript">
(function($) {
var upgrader = new acf.Model({
initialize: function(){
// allow user to read message for 1 second
this.setTimeout( this.upgrade, 1000 );
},
upgrade: function(){
// show step 1
$('.step-1').show();
// vars
var response = '';
var success = false;
// send ajax request to upgrade DB
$.ajax({
url: acf.get('ajaxurl'),
dataType: 'json',
type: 'post',
data: acf.prepareForAjax({
action: 'acf/ajax/upgrade'
}),
success: function( json ){
success = true;
},
error: function( jqXHR, textStatus, errorThrown ){
response = '<?php _e( 'Upgrade failed.', 'acf' ); ?>';
if( error = acf.getXhrError(jqXHR) ) {
response += ' <code>' + error + '</code>';
}
},
complete: this.proxy(function(){
// remove spinner
$('.acf-loading').hide();
// display response
if( response ) {
$('.step-2').show().html( response );
}
// display success
if( success ) {
$('.step-3').show();
}
})
});
}
});
})(jQuery);
</script>
<?php else : ?>
<p><?php _e( 'No updates available.', 'acf' ); ?></p>
<?php endif; ?>
</div>

View File

@@ -0,0 +1,30 @@
<?php
/**
* html-admin-tools
*
* View to output admin tools for both archive and single
*
* @date 20/10/17
* @since 5.6.3
*
* @param string $screen_id The screen ID used to display metaboxes
* @param string $active The active Tool
* @return n/a
*/
$class = $active ? 'single' : 'grid';
?>
<div class="wrap" id="acf-admin-tools">
<h1><?php _e( 'Tools', 'acf' ); ?> <?php
if ( $active ) :
?>
<a class="page-title-action" href="<?php echo acf_get_admin_tools_url(); ?>"><?php _e( 'Back to all tools', 'acf' ); ?></a><?php endif; ?></h1>
<div class="acf-meta-box-wrap -<?php echo $class; ?>">
<?php do_meta_boxes( $screen_id, 'normal', '' ); ?>
</div>
</div>

View File

@@ -0,0 +1,30 @@
<div class="rule-group" data-id="<?php echo $group_id; ?>">
<h4><?php echo ( $group_id == 'group_0' ) ? __( 'Show this field group if', 'acf' ) : __( 'or', 'acf' ); ?></h4>
<table class="acf-table -clear">
<tbody>
<?php
foreach ( $group as $i => $rule ) :
// validate rule
$rule = acf_validate_location_rule( $rule );
// append id and group
$rule['id'] = "rule_{$i}";
$rule['group'] = $group_id;
// view
acf_get_view(
'html-location-rule',
array(
'rule' => $rule,
)
);
endforeach;
?>
</tbody>
</table>
</div>

View File

@@ -0,0 +1,97 @@
<?php
// vars
$prefix = 'acf_field_group[location][' . $rule['group'] . '][' . $rule['id'] . ']';
?>
<tr data-id="<?php echo $rule['id']; ?>">
<td class="param">
<?php
// vars
$choices = acf_get_location_rule_types();
// array
if ( is_array( $choices ) ) {
acf_render_field(
array(
'type' => 'select',
'name' => 'param',
'prefix' => $prefix,
'value' => $rule['param'],
'choices' => $choices,
'class' => 'refresh-location-rule',
)
);
}
?>
</td>
<td class="operator">
<?php
// vars
$choices = acf_get_location_rule_operators( $rule );
// array
if ( is_array( $choices ) ) {
acf_render_field(
array(
'type' => 'select',
'name' => 'operator',
'prefix' => $prefix,
'value' => $rule['operator'],
'choices' => $choices,
)
);
// custom
} else {
echo $choices;
}
?>
</td>
<td class="value">
<?php
// vars
$choices = acf_get_location_rule_values( $rule );
// array
if ( is_array( $choices ) ) {
acf_render_field(
array(
'type' => 'select',
'name' => 'value',
'prefix' => $prefix,
'value' => $rule['value'],
'choices' => $choices,
)
);
// custom
} else {
echo $choices;
}
?>
</td>
<td class="add">
<a href="#" class="button add-location-rule"><?php _e( 'and', 'acf' ); ?></a>
</td>
<td class="remove">
<a href="#" class="acf-icon -minus remove-location-rule"></a>
</td>
</tr>

View File

@@ -0,0 +1,50 @@
<?php
// calculate add-ons (non pro only)
$plugins = array();
if ( ! acf_get_setting( 'pro' ) ) {
if ( is_plugin_active( 'acf-repeater/acf-repeater.php' ) ) {
$plugins[] = __( 'Repeater', 'acf' );
}
if ( is_plugin_active( 'acf-flexible-content/acf-flexible-content.php' ) ) {
$plugins[] = __( 'Flexible Content', 'acf' );
}
if ( is_plugin_active( 'acf-gallery/acf-gallery.php' ) ) {
$plugins[] = __( 'Gallery', 'acf' );
}
if ( is_plugin_active( 'acf-options-page/acf-options-page.php' ) ) {
$plugins[] = __( 'Options Page', 'acf' );
}
}
?>
<div id="acf-upgrade-notice" class="notice">
<div class="col-content">
<img src="<?php echo acf_get_url( 'assets/images/acf-logo.png' ); ?>" />
<h2><?php _e( 'Database Upgrade Required', 'acf' ); ?></h2>
<p><?php printf( __( 'Thank you for updating to %1$s v%2$s!', 'acf' ), acf_get_setting( 'name' ), acf_get_setting( 'version' ) ); ?><br /><?php _e( 'This version contains improvements to your database and requires an upgrade.', 'acf' ); ?></p>
<?php if ( ! empty( $plugins ) ) : ?>
<p><?php printf( __( 'Please also check all premium add-ons (%s) are updated to the latest version.', 'acf' ), implode( ', ', $plugins ) ); ?></p>
<?php endif; ?>
</div>
<div class="col-actions">
<a id="acf-upgrade-button" href="<?php echo $button_url; ?>" class="button button-primary button-hero"><?php echo $button_text; ?></a>
</div>
</div>
<?php if ( $confirm ) : ?>
<script type="text/javascript">
(function($) {
$("#acf-upgrade-button").on("click", function(){
return confirm("<?php _e( 'It is strongly recommended that you backup your database before proceeding. Are you sure you wish to run the updater now?', 'acf' ); ?>");
});
})(jQuery);
</script>
<?php endif; ?>

View File

@@ -0,0 +1,103 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax_Check_Screen' ) ) :
class ACF_Ajax_Check_Screen extends ACF_Ajax {
/** @var string The AJAX action name. */
var $action = 'acf/ajax/check_screen';
/** @var bool Prevents access for non-logged in users. */
var $public = false;
/**
* get_response
*
* Returns the response data to sent back.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return mixed The response data or WP_Error.
*/
function get_response( $request ) {
// vars
$args = wp_parse_args(
$this->request,
array(
'screen' => '',
'post_id' => 0,
'ajax' => true,
'exists' => array(),
)
);
// vars
$response = array(
'results' => array(),
'style' => '',
);
// get field groups
$field_groups = acf_get_field_groups( $args );
// loop through field groups
if ( $field_groups ) {
foreach ( $field_groups as $i => $field_group ) {
// vars
$item = array(
'id' => 'acf-' . $field_group['key'],
'key' => $field_group['key'],
'title' => $field_group['title'],
'position' => $field_group['position'],
'style' => $field_group['style'],
'label' => $field_group['label_placement'],
'edit' => acf_get_field_group_edit_link( $field_group['ID'] ),
'html' => '',
);
// append html if doesnt already exist on page
if ( ! in_array( $field_group['key'], $args['exists'] ) ) {
// load fields
$fields = acf_get_fields( $field_group );
// get field HTML
ob_start();
// render
acf_render_fields( $fields, $args['post_id'], 'div', $field_group['instruction_placement'] );
$item['html'] = ob_get_clean();
}
// append
$response['results'][] = $item;
}
// Get style from first field group.
$response['style'] = acf_get_field_group_style( $field_groups[0] );
}
// Custom metabox order.
if ( $this->get( 'screen' ) == 'post' ) {
$response['sorted'] = get_user_option( 'meta-box-order_' . $this->get( 'post_type' ) );
}
// return
return $response;
}
}
acf_new_instance( 'ACF_Ajax_Check_Screen' );
endif; // class_exists check

View File

@@ -0,0 +1,82 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax_Local_JSON_Diff' ) ) :
class ACF_Ajax_Local_JSON_Diff extends ACF_Ajax {
/** @var string The AJAX action name. */
var $action = 'acf/ajax/local_json_diff';
/** @var bool Prevents access for non-logged in users. */
var $public = false;
/**
* get_response
*
* Returns the response data to sent back.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return mixed The response data or WP_Error.
*/
function get_response( $request ) {
$json = array();
// Extract props.
$id = isset( $request['id'] ) ? intval( $request['id'] ) : 0;
// Bail ealry if missing props.
if ( ! $id ) {
return new WP_Error( 'acf_invalid_param', __( 'Invalid field group parameter(s).', 'acf' ), array( 'status' => 404 ) );
}
// Disable filters and load field group directly from database.
acf_disable_filters();
$field_group = acf_get_field_group( $id );
if ( ! $field_group ) {
return new WP_Error( 'acf_invalid_id', __( 'Invalid field group ID.', 'acf' ), array( 'status' => 404 ) );
}
$field_group['fields'] = acf_get_fields( $field_group );
$field_group['modified'] = get_post_modified_time( 'U', true, $field_group['ID'] );
$field_group = acf_prepare_field_group_for_export( $field_group );
// Load local field group file.
$files = acf_get_local_json_files();
$key = $field_group['key'];
if ( ! isset( $files[ $key ] ) ) {
return new WP_Error( 'acf_cannot_compare', __( 'Sorry, this field group is unavailable for diff comparison.', 'acf' ), array( 'status' => 404 ) );
}
$local_field_group = json_decode( file_get_contents( $files[ $key ] ), true );
// Render diff HTML.
$date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
$date_template = __( 'Last updated: %s', 'acf' );
$json['html'] = '
<div class="acf-diff">
<div class="acf-diff-title">
<div class="acf-diff-title-left">
<strong>' . __( 'Original field group', 'acf' ) . '</strong>
<span>' . sprintf( $date_template, wp_date( $date_format, $field_group['modified'] ) ) . '</span>
</div>
<div class="acf-diff-title-right">
<strong>' . __( 'JSON field group (newer)', 'acf' ) . '</strong>
<span>' . sprintf( $date_template, wp_date( $date_format, $local_field_group['modified'] ) ) . '</span>
</div>
</div>
<div class="acf-diff-content">
' . wp_text_diff( acf_json_encode( $field_group ), acf_json_encode( $local_field_group ) ) . '
</div>
</div>';
return $json;
}
}
acf_new_instance( 'ACF_Ajax_Local_JSON_Diff' );
endif; // class_exists check

View File

@@ -0,0 +1,275 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax_Query_Users' ) ) :
class ACF_Ajax_Query_Users extends ACF_Ajax_Query {
/** @var string The AJAX action name. */
var $action = 'acf/ajax/query_users';
/**
* init_request
*
* Called at the beginning of a request to setup properties.
*
* @date 23/5/19
* @since 5.8.1
*
* @param array $request The request args.
* @return void
*/
function init_request( $request ) {
parent::init_request( $request );
// Customize query.
add_filter( 'user_search_columns', array( $this, 'filter_search_columns' ), 10, 3 );
/**
* Fires when a request is made.
*
* @date 21/5/19
* @since 5.8.1
*
* @param array $request The query request.
* @param ACF_Ajax_Query $query The query object.
*/
do_action( 'acf/ajax/query_users/init', $request, $this );
}
/**
* get_args
*
* Returns an array of args for this query.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return array
*/
function get_args( $request ) {
$args = parent::get_args( $request );
$args['number'] = $this->per_page;
$args['paged'] = $this->page;
if ( $this->is_search ) {
$args['search'] = "*{$this->search}*";
}
/**
* Filters the query args.
*
* @date 21/5/19
* @since 5.8.1
*
* @param array $args The query args.
* @param array $request The query request.
* @param ACF_Ajax_Query $query The query object.
*/
return apply_filters( 'acf/ajax/query_users/args', $args, $request, $this );
}
/**
* Prepares args for the get_results() method.
*
* @date 23/3/20
* @since 5.8.9
*
* @param array args The query args.
* @return array
*/
function prepare_args( $args ) {
// Parse pagination args that may have been modified.
if ( isset( $args['users_per_page'] ) ) {
$this->per_page = intval( $args['users_per_page'] );
unset( $args['users_per_page'] );
} elseif ( isset( $args['number'] ) ) {
$this->per_page = intval( $args['number'] );
}
if ( isset( $args['paged'] ) ) {
$this->page = intval( $args['paged'] );
unset( $args['paged'] );
}
// Set pagination args for fine control.
$args['number'] = $this->per_page;
$args['offset'] = $this->per_page * ( $this->page - 1 );
$args['count_total'] = true;
return $args;
}
/**
* get_results
*
* Returns an array of results for the given args.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array args The query args.
* @return array
*/
function get_results( $args ) {
$results = array();
// Prepare args for quey.
$args = $this->prepare_args( $args );
// Get result groups.
if ( ! empty( $args['role__in'] ) ) {
$roles = acf_get_user_role_labels( $args['role__in'] );
} else {
$roles = acf_get_user_role_labels();
}
// Return a flat array of results when searching or when queriying one group only.
if ( $this->is_search || count( $roles ) === 1 ) {
// Query users and append to results.
$wp_user_query = new WP_User_Query( $args );
$users = (array) $wp_user_query->get_results();
$total_users = $wp_user_query->get_total();
foreach ( $users as $user ) {
$results[] = $this->get_result( $user );
}
// Determine if more results exist.
// As this query does not return grouped results, the calculation can be exact (">").
$this->more = ( $total_users > count( $users ) + $args['offset'] );
// Otherwise, group results via role.
} else {
// Unset args that will interfer with query results.
unset( $args['role__in'], $args['role__not_in'] );
// Loop over each role.
foreach ( $roles as $role => $role_label ) {
// Query users (for this role only).
$args['role'] = $role;
$wp_user_query = new WP_User_Query( $args );
$users = (array) $wp_user_query->get_results();
$total_users = $wp_user_query->get_total();
// acf_log( $args );
// acf_log( '- ', count($users) );
// acf_log( '- ', $total_users );
// If users were found for this query...
if ( $users ) {
// Append optgroup of results.
$role_results = array();
foreach ( $users as $user ) {
$role_results[] = $this->get_result( $user );
}
$results[] = array(
'text' => $role_label,
'children' => $role_results,
);
// End loop when enough results have been found.
if ( count( $users ) === $args['number'] ) {
// Determine if more results exist.
// As this query does return grouped results, the calculation is best left fuzzy to avoid querying the next group (">=").
$this->more = ( $total_users >= count( $users ) + $args['offset'] );
break;
// Otherwise, modify the args so that the next query can continue on correctly.
} else {
$args['offset'] = 0;
$args['number'] -= count( $users );
}
// If no users were found (for the current pagination args), but there were users found for previous pages...
// Modify the args so that the next query is offset slightly less (the number of total users) and can continue on correctly.
} elseif ( $total_users ) {
$args['offset'] -= $total_users;
continue;
// Ignore roles that will never return a result.
} else {
continue;
}
}
}
/**
* Filters the query results.
*
* @date 21/5/19
* @since 5.8.1
*
* @param array $results The query results.
* @param array $args The query args.
* @param ACF_Ajax_Query $query The query object.
*/
return apply_filters( 'acf/ajax/query_users/results', $results, $args, $this );
}
/**
* get_result
*
* Returns a single result for the given item object.
*
* @date 31/7/18
* @since 5.7.2
*
* @param mixed $item A single item from the queried results.
* @return string
*/
function get_result( $user ) {
$item = acf_get_user_result( $user );
/**
* Filters the result item.
*
* @date 21/5/19
* @since 5.8.1
*
* @param array $item The choice id and text.
* @param ACF_User $user The user object.
* @param ACF_Ajax_Query $query The query object.
*/
return apply_filters( 'acf/ajax/query_users/result', $item, $user, $this );
}
/**
* 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 filter_search_columns( $columns, $search, $WP_User_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 ACF_Ajax_Query $query The query object.
*/
return apply_filters( 'acf/ajax/query_users/search_columns', $columns, $search, $WP_User_Query, $this );
}
}
acf_new_instance( 'ACF_Ajax_Query_Users' );
endif; // class_exists check

View File

@@ -0,0 +1,152 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax_Query' ) ) :
class ACF_Ajax_Query extends ACF_Ajax {
/** @var bool Prevents access for non-logged in users. */
var $public = true;
/** @var int The page of results to return. */
var $page = 1;
/** @var int The number of results per page. */
var $per_page = 20;
/** @var bool Signifies whether or not this AJAX query has more pages to load. */
var $more = false;
/** @var string The searched term. */
var $search = '';
/** @var bool Signifies whether the current query is a search. */
var $is_search = false;
/** @var (int|string) The post_id being edited. */
var $post_id = 0;
/** @var array The ACF field related to this query. */
var $field = false;
/**
* get_response
*
* Returns the response data to sent back.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return (array|WP_Error) The response data or WP_Error.
*/
function get_response( $request ) {
// Init request.
$this->init_request( $request );
// Get query args.
$args = $this->get_args( $request );
// Get query results.
$results = $this->get_results( $args );
if ( is_wp_error( $results ) ) {
return $results;
}
// Return response.
return array(
'results' => $results,
'more' => $this->more,
);
}
/**
* init_request
*
* Called at the beginning of a request to setup properties.
*
* @date 23/5/19
* @since 5.8.1
*
* @param array $request The request args.
* @return void
*/
function init_request( $request ) {
// Get field for this query.
if ( isset( $request['field_key'] ) ) {
$this->field = acf_get_field( $request['field_key'] );
}
// Update query properties.
if ( isset( $request['page'] ) ) {
$this->page = intval( $request['page'] );
}
if ( isset( $request['per_page'] ) ) {
$this->per_page = intval( $request['per_page'] );
}
if ( isset( $request['search'] ) && acf_not_empty( $request['search'] ) ) {
$this->search = sanitize_text_field( $request['search'] );
$this->is_search = true;
}
if ( isset( $request['post_id'] ) ) {
$this->post_id = $request['post_id'];
}
}
/**
* get_args
*
* Returns an array of args for this query.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return array
*/
function get_args( $request ) {
// Allow for custom "query" arg.
if ( isset( $request['query'] ) ) {
return (array) $request['query'];
}
return array();
}
/**
* get_items
*
* Returns an array of results for the given args.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array args The query args.
* @return array
*/
function get_results( $args ) {
return array();
}
/**
* get_item
*
* Returns a single result for the given item object.
*
* @date 31/7/18
* @since 5.7.2
*
* @param mixed $item A single item from the queried results.
* @return array An array containing "id" and "text".
*/
function get_result( $item ) {
return false;
}
}
endif; // class_exists check

View File

@@ -0,0 +1,56 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax_Upgrade' ) ) :
class ACF_Ajax_Upgrade extends ACF_Ajax {
/** @var string The AJAX action name */
var $action = 'acf/ajax/upgrade';
/**
* get_response
*
* Returns the response data to sent back.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return mixed The response data or WP_Error.
*/
function get_response( $request ) {
// Switch blog.
if ( isset( $request['blog_id'] ) ) {
switch_to_blog( $request['blog_id'] );
}
// Bail early if no upgrade avaiable.
if ( ! acf_has_upgrade() ) {
return new WP_Error( 'upgrade_error', __( 'No updates available.', 'acf' ) );
}
// Listen for output.
ob_start();
// Run upgrades.
acf_upgrade_all();
// Store output.
$error = ob_get_clean();
// Return error or success.
if ( $error ) {
return new WP_Error( 'upgrade_error', $error );
}
return true;
}
}
acf_new_instance( 'ACF_Ajax_Upgrade' );
endif; // class_exists check

View File

@@ -0,0 +1,43 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax_User_Setting' ) ) :
class ACF_Ajax_User_Setting extends ACF_Ajax {
/** @var string The AJAX action name. */
var $action = 'acf/ajax/user_setting';
/** @var bool Prevents access for non-logged in users. */
var $public = true;
/**
* get_response
*
* Returns the response data to sent back.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return mixed The response data or WP_Error.
*/
function get_response( $request ) {
// update
if ( $this->has( 'value' ) ) {
return acf_update_user_setting( $this->get( 'name' ), $this->get( 'value' ) );
// get
} else {
return acf_get_user_setting( $this->get( 'name' ) );
}
}
}
acf_new_instance( 'ACF_Ajax_User_Setting' );
endif; // class_exists check

View File

@@ -0,0 +1,232 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Ajax' ) ) :
class ACF_Ajax {
/** @var string The AJAX action name. */
var $action = '';
/** @var array The $_REQUEST data. */
var $request;
/** @var bool Prevents access for non-logged in users. */
var $public = false;
/**
* __construct
*
* Sets up the class functionality.
*
* @date 31/7/18
* @since 5.7.2
*
* @param void
* @return void
*/
function __construct() {
$this->initialize();
$this->add_actions();
}
/**
* has
*
* Returns true if the request has data for the given key.
*
* @date 31/7/18
* @since 5.7.2
*
* @param string $key The data key.
* @return boolean
*/
function has( $key = '' ) {
return isset( $this->request[ $key ] );
}
/**
* get
*
* Returns request data for the given key.
*
* @date 31/7/18
* @since 5.7.2
*
* @param string $key The data key.
* @return mixed
*/
function get( $key = '' ) {
return isset( $this->request[ $key ] ) ? $this->request[ $key ] : null;
}
/**
* Sets request data for the given key.
*
* @date 31/7/18
* @since 5.7.2
*
* @param string $key The data key.
* @param mixed $value The data value.
* @return ACF_Ajax
*/
function set( $key = '', $value = null ) {
$this->request[ $key ] = $value;
return $this;
}
/**
* initialize
*
* Allows easy access to modifying properties without changing constructor.
*
* @date 31/7/18
* @since 5.7.2
*
* @param void
* @return void
*/
function initialize() {
/* do nothing */
}
/**
* add_actions
*
* Adds the ajax actions for this response.
*
* @date 31/7/18
* @since 5.7.2
*
* @param void
* @return void
*/
function add_actions() {
// add action for logged-in users
add_action( "wp_ajax_{$this->action}", array( $this, 'request' ) );
// add action for non logged-in users
if ( $this->public ) {
add_action( "wp_ajax_nopriv_{$this->action}", array( $this, 'request' ) );
}
}
/**
* request
*
* Callback for ajax action. Sets up properties and calls the get_response() function.
*
* @date 1/8/18
* @since 5.7.2
*
* @param void
* @return void
*/
function request() {
// Store data for has() and get() functions.
$this->request = wp_unslash( $_REQUEST );
// Verify request and handle error.
$error = $this->verify_request( $this->request );
if ( is_wp_error( $error ) ) {
$this->send( $error );
}
// Send response.
$this->send( $this->get_response( $this->request ) );
}
/**
* Verifies the request.
*
* @date 9/3/20
* @since 5.8.8
*
* @param array $request The request args.
* @return (bool|WP_Error) True on success, WP_Error on fail.
*/
function verify_request( $request ) {
// Verify nonce.
if ( ! acf_verify_ajax() ) {
return new WP_Error( 'acf_invalid_nonce', __( 'Invalid nonce.', 'acf' ), array( 'status' => 404 ) );
}
return true;
}
/**
* get_response
*
* Returns the response data to sent back.
*
* @date 31/7/18
* @since 5.7.2
*
* @param array $request The request args.
* @return mixed The response data or WP_Error.
*/
function get_response( $request ) {
return true;
}
/**
* send
*
* Sends back JSON based on the $response as either success or failure.
*
* @date 31/7/18
* @since 5.7.2
*
* @param mixed $response The response to send back.
* @return void
*/
function send( $response ) {
// Return error.
if ( is_wp_error( $response ) ) {
$this->send_error( $response );
// Return success.
} else {
wp_send_json( $response );
}
}
/**
* Sends a JSON response for the given WP_Error object.
*
* @date 8/3/20
* @since 5.8.8
*
* @param WP_Error error The error object.
* @return void
*/
function send_error( $error ) {
// Get error status
$error_data = $error->get_error_data();
if ( is_array( $error_data ) && isset( $error_data['status'] ) ) {
$status_code = $error_data['status'];
} else {
$status_code = 500;
}
wp_send_json(
array(
'code' => $error->get_error_code(),
'message' => $error->get_error_message(),
'data' => $error->get_error_data(),
),
$status_code
);
}
}
endif; // class_exists check

View File

@@ -0,0 +1,522 @@
<?php
/*
* acf_get_taxonomies
*
* Returns an array of taxonomy names.
*
* @date 7/10/13
* @since 5.0.0
*
* @param array $args An array of args used in the get_taxonomies() function.
* @return array An array of taxonomy names.
*/
function acf_get_taxonomies( $args = array() ) {
// vars
$taxonomies = array();
// get taxonomy objects
$objects = get_taxonomies( $args, 'objects' );
// loop
foreach ( $objects as $i => $object ) {
// bail early if is builtin (WP) private post type
// - nav_menu_item, revision, customize_changeset, etc
if ( $object->_builtin && ! $object->public ) {
continue;
}
// append
$taxonomies[] = $i;
}
// custom post_type arg which does not yet exist in core
if ( isset( $args['post_type'] ) ) {
$taxonomies = acf_get_taxonomies_for_post_type( $args['post_type'] );
}
// filter
$taxonomies = apply_filters( 'acf/get_taxonomies', $taxonomies, $args );
// return
return $taxonomies;
}
/**
* acf_get_taxonomies_for_post_type
*
* Returns an array of taxonomies for a given post type(s)
*
* @date 7/9/18
* @since 5.7.5
*
* @param string|array $post_types The post types to compare against.
* @return array
*/
function acf_get_taxonomies_for_post_type( $post_types = 'post' ) {
// vars
$taxonomies = array();
// loop
foreach ( (array) $post_types as $post_type ) {
$object_taxonomies = get_object_taxonomies( $post_type );
foreach ( (array) $object_taxonomies as $taxonomy ) {
$taxonomies[] = $taxonomy;
}
}
// remove duplicates
$taxonomies = array_unique( $taxonomies );
// return
return $taxonomies;
}
/*
* acf_get_taxonomy_labels
*
* Returns an array of taxonomies in the format "name => label" for use in a select field.
*
* @date 3/8/18
* @since 5.7.2
*
* @param array $taxonomies Optional. An array of specific taxonomies to return.
* @return array
*/
function acf_get_taxonomy_labels( $taxonomies = array() ) {
// default
if ( empty( $taxonomies ) ) {
$taxonomies = acf_get_taxonomies();
}
// vars
$ref = array();
$data = array();
// loop
foreach ( $taxonomies as $taxonomy ) {
// vars
$object = get_taxonomy( $taxonomy );
$label = $object->labels->singular_name;
// append
$data[ $taxonomy ] = $label;
// increase counter
if ( ! isset( $ref[ $label ] ) ) {
$ref[ $label ] = 0;
}
$ref[ $label ]++;
}
// show taxonomy name next to label for shared labels
foreach ( $data as $taxonomy => $label ) {
if ( $ref[ $label ] > 1 ) {
$data[ $taxonomy ] .= ' (' . $taxonomy . ')';
}
}
// return
return $data;
}
/**
* acf_get_term_title
*
* Returns the title for this term object.
*
* @date 10/9/18
* @since 5.0.0
*
* @param object $term The WP_Term object.
* @return string
*/
function acf_get_term_title( $term ) {
$title = $term->name;
// Allow for empty name.
if ( $title === '' ) {
$title = __( '(no title)', 'acf' );
}
// Prepend ancestors indentation.
if ( is_taxonomy_hierarchical( $term->taxonomy ) ) {
$ancestors = get_ancestors( $term->term_id, $term->taxonomy );
$title = str_repeat( '- ', count( $ancestors ) ) . $title;
}
return $title;
}
/**
* acf_get_grouped_terms
*
* Returns an array of terms for the given query $args and groups by taxonomy name.
*
* @date 2/8/18
* @since 5.7.2
*
* @param array $args An array of args used in the get_terms() function.
* @return array
*/
function acf_get_grouped_terms( $args ) {
// vars
$data = array();
// defaults
$args = wp_parse_args(
$args,
array(
'taxonomy' => null,
'hide_empty' => false,
'update_term_meta_cache' => false,
)
);
// vars
$taxonomies = acf_get_taxonomy_labels( acf_get_array( $args['taxonomy'] ) );
$is_single = ( count( $taxonomies ) == 1 );
// specify exact taxonomies required for _acf_terms_clauses() to work.
$args['taxonomy'] = array_keys( $taxonomies );
// add filter to group results by taxonomy
if ( ! $is_single ) {
add_filter( 'terms_clauses', '_acf_terms_clauses', 10, 3 );
}
// get terms
$terms = get_terms( $args );
// remove this filter (only once)
if ( ! $is_single ) {
remove_filter( 'terms_clauses', '_acf_terms_clauses', 10, 3 );
}
// loop
foreach ( $taxonomies as $taxonomy => $label ) {
// vars
$this_terms = array();
// populate $this_terms
foreach ( $terms as $term ) {
if ( $term->taxonomy == $taxonomy ) {
$this_terms[] = $term;
}
}
// bail early if no $items
if ( empty( $this_terms ) ) {
continue;
}
// sort into hierachial order
// this will fail if a search has taken place because parents wont exist
if ( is_taxonomy_hierarchical( $taxonomy ) && empty( $args['s'] ) ) {
// get all terms from this taxonomy
$all_terms = get_terms(
array_merge(
$args,
array(
'number' => 0,
'offset' => 0,
'taxonomy' => $taxonomy,
)
)
);
// vars
$length = count( $this_terms );
$offset = 0;
// find starting point (offset)
foreach ( $all_terms as $i => $term ) {
if ( $term->term_id == $this_terms[0]->term_id ) {
$offset = $i;
break;
}
}
// order terms
$parent = acf_maybe_get( $args, 'parent', 0 );
$parent = acf_maybe_get( $args, 'child_of', $parent );
$ordered_terms = _get_term_children( $parent, $all_terms, $taxonomy );
// compare aray lengths
// if $ordered_posts is smaller than $all_posts, WP has lost posts during the get_page_children() function
// this is possible when get_post( $args ) filter out parents (via taxonomy, meta and other search parameters)
if ( count( $ordered_terms ) == count( $all_terms ) ) {
$this_terms = array_slice( $ordered_terms, $offset, $length );
}
}
// populate group
$data[ $label ] = array();
foreach ( $this_terms as $term ) {
$data[ $label ][ $term->term_id ] = $term;
}
}
// return
return $data;
}
/**
* _acf_terms_clauses
*
* Used in the 'terms_clauses' filter to order terms by taxonomy name.
*
* @date 2/8/18
* @since 5.7.2
*
* @param array $pieces Terms query SQL clauses.
* @param array $taxonomies An array of taxonomies.
* @param array $args An array of terms query arguments.
* @return array $pieces
*/
function _acf_terms_clauses( $pieces, $taxonomies, $args ) {
// prepend taxonomy to 'orderby' SQL
if ( is_array( $taxonomies ) ) {
$sql = "FIELD(tt.taxonomy,'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "')";
$pieces['orderby'] = str_replace( 'ORDER BY', "ORDER BY $sql,", $pieces['orderby'] );
}
// return
return $pieces;
}
/**
* acf_get_pretty_taxonomies
*
* Deprecated in favor of acf_get_taxonomy_labels() function.
*
* @date 7/10/13
* @since 5.0.0
* @deprecated 5.7.2
*/
function acf_get_pretty_taxonomies( $taxonomies = array() ) {
return acf_get_taxonomy_labels( $taxonomies );
}
/**
* acf_get_term
*
* Similar to get_term() but with some extra functionality.
*
* @date 19/8/18
* @since 5.7.3
*
* @param mixed $term_id The term ID or a string of "taxonomy:slug".
* @param string $taxonomy The taxonomyname.
* @return WP_Term
*/
function acf_get_term( $term_id, $taxonomy = '' ) {
// allow $term_id parameter to be a string of "taxonomy:slug" or "taxonomy:id"
if ( is_string( $term_id ) && strpos( $term_id, ':' ) ) {
list( $taxonomy, $term_id ) = explode( ':', $term_id );
$term = get_term_by( 'slug', $term_id, $taxonomy );
if ( $term ) {
return $term;
}
}
// return
return get_term( $term_id, $taxonomy );
}
/**
* acf_encode_term
*
* Returns a "taxonomy:slug" string for a given WP_Term.
*
* @date 27/8/18
* @since 5.7.4
*
* @param WP_Term $term The term object.
* @return string
*/
function acf_encode_term( $term ) {
return "{$term->taxonomy}:{$term->slug}";
}
/**
* acf_decode_term
*
* Decodes a "taxonomy:slug" string into an array of taxonomy and slug.
*
* @date 27/8/18
* @since 5.7.4
*
* @param WP_Term $term The term object.
* @return string
*/
function acf_decode_term( $string ) {
if ( is_string( $string ) && strpos( $string, ':' ) ) {
list( $taxonomy, $slug ) = explode( ':', $string );
return compact( 'taxonomy', 'slug' );
}
return false;
}
/**
* acf_get_encoded_terms
*
* Returns an array of WP_Term objects from an array of encoded strings
*
* @date 9/9/18
* @since 5.7.5
*
* @param array $values The array of encoded strings.
* @return array
*/
function acf_get_encoded_terms( $values ) {
// vars
$terms = array();
// loop over values
foreach ( (array) $values as $value ) {
// find term from string
$term = acf_get_term( $value );
// append
if ( $term instanceof WP_Term ) {
$terms[] = $term;
}
}
// return
return $terms;
}
/**
* acf_get_choices_from_terms
*
* Returns an array of choices from the terms provided.
*
* @date 8/9/18
* @since 5.7.5
*
* @param array $values and array of WP_Terms objects or encoded strings.
* @param string $format The value format (term_id, slug).
* @return array
*/
function acf_get_choices_from_terms( $terms, $format = 'term_id' ) {
// vars
$groups = array();
// get taxonomy lables
$labels = acf_get_taxonomy_labels();
// convert array of encoded strings to terms
$term = reset( $terms );
if ( ! $term instanceof WP_Term ) {
$terms = acf_get_encoded_terms( $terms );
}
// loop over terms
foreach ( $terms as $term ) {
$group = $labels[ $term->taxonomy ];
$choice = acf_get_choice_from_term( $term, $format );
$groups[ $group ][ $choice['id'] ] = $choice['text'];
}
// return
return $groups;
}
/**
* acf_get_choices_from_grouped_terms
*
* Returns an array of choices from the grouped terms provided.
*
* @date 8/9/18
* @since 5.7.5
*
* @param array $value A grouped array of WP_Terms objects.
* @param string $format The value format (term_id, slug).
* @return array
*/
function acf_get_choices_from_grouped_terms( $value, $format = 'term_id' ) {
// vars
$groups = array();
// loop over values
foreach ( $value as $group => $terms ) {
$groups[ $group ] = array();
foreach ( $terms as $term_id => $term ) {
$choice = acf_get_choice_from_term( $term, $format );
$groups[ $group ][ $choice['id'] ] = $choice['text'];
}
}
// return
return $groups;
}
/**
* acf_get_choice_from_term
*
* Returns an array containing the id and text for this item.
*
* @date 10/9/18
* @since 5.7.6
*
* @param object $item The item object such as WP_Post or WP_Term.
* @param string $format The value format (term_id, slug)
* @return array
*/
function acf_get_choice_from_term( $term, $format = 'term_id' ) {
// vars
$id = $term->term_id;
$text = acf_get_term_title( $term );
// return format
if ( $format == 'slug' ) {
$id = acf_encode_term( $term );
}
// return
return array(
'id' => $id,
'text' => $text,
);
}
/**
* Returns a valid post_id string for a given term and taxonomy.
* No longer needed since WP introduced the termmeta table in WP 4.4.
*
* @date 6/2/17
* @since 5.5.6
* @deprecated 5.9.2
*
* @param $taxonomy (string) The taxonomy type.
* @param $term_id (int) The term ID.
* @return (string)
*/
function acf_get_term_post_id( $taxonomy, $term_id ) {
_deprecated_function( __FUNCTION__, '5.9.2', 'string format term_%d' );
return 'term_' . $term_id;
}

View File

@@ -0,0 +1,614 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Assets' ) ) :
class ACF_Assets {
/**
* Storage for i18n data.
*
* @since 5.6.9
* @var array
*/
public $text = array();
/**
* Storage for l10n data.
*
* @since 5.6.9
* @var array
*/
public $data = array();
/**
* List of enqueue flags.
*
* @since 5.9.0
* @var bool
*/
private $enqueue = array();
/**
* Constructor.
*
* @date 10/4/18
* @since 5.6.9
*
* @param void
* @return void
*/
public function __construct() {
add_action( 'init', array( $this, 'register_scripts' ) );
}
/**
* Magic __call method for backwards compatibility.
*
* @date 10/4/20
* @since 5.9.0
*
* @param string $name The method name.
* @param array $arguments The array of arguments.
* @return mixed
*/
public function __call( $name, $arguments ) {
switch ( $name ) {
case 'admin_enqueue_scripts':
case 'admin_print_scripts':
case 'admin_head':
case 'admin_footer':
case 'admin_print_footer_scripts':
_doing_it_wrong( __FUNCTION__, 'The ACF_Assets class should not be accessed directly.', '5.9.0' );
}
}
/**
* Appends an array of i18n data.
*
* @date 13/4/18
* @since 5.6.9
*
* @param array $text An array of text for i18n.
* @return void
*/
public function add_text( $text ) {
foreach ( (array) $text as $k => $v ) {
$this->text[ $k ] = $v;
}
}
/**
* Appends an array of l10n data.
*
* @date 13/4/18
* @since 5.6.9
*
* @param array $data An array of data for l10n.
* @return void
*/
public function add_data( $data ) {
foreach ( (array) $data as $k => $v ) {
$this->data[ $k ] = $v;
}
}
/**
* Registers the ACF scripts and styles.
*
* @date 10/4/18
* @since 5.6.9
*
* @param void
* @return void
*/
public function register_scripts() {
// Extract vars.
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
$version = acf_get_setting( 'version' );
// Register scripts.
wp_register_script( 'acf', acf_get_url( 'assets/build/js/acf' . $suffix . '.js' ), array( 'jquery' ), $version );
wp_register_script( 'acf-input', acf_get_url( 'assets/build/js/acf-input' . $suffix . '.js' ), array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-resizable', 'acf' ), $version );
wp_register_script( 'acf-field-group', acf_get_url( 'assets/build/js/acf-field-group' . $suffix . '.js' ), array( 'acf-input' ), $version );
// Register styles.
wp_register_style( 'acf-global', acf_get_url( 'assets/build/css/acf-global.css' ), array( 'dashicons' ), $version );
wp_register_style( 'acf-input', acf_get_url( 'assets/build/css/acf-input.css' ), array( 'acf-global' ), $version );
wp_register_style( 'acf-field-group', acf_get_url( 'assets/build/css/acf-field-group.css' ), array( 'acf-input' ), $version );
/**
* Fires after core scripts and styles have been registered.
*
* @since 5.6.9
*
* @param string $version The ACF version.
* @param string $suffix The potential ".min" filename suffix.
*/
do_action( 'acf/register_scripts', $version, $suffix );
}
/**
* Enqueues a script and sets up actions for priting supplemental scripts.
*
* @date 27/4/20
* @since 5.9.0
*
* @param string $name The script name.
* @return void
*/
public function enqueue_script( $name ) {
wp_enqueue_script( $name );
$this->add_actions();
}
/**
* Enqueues a style.
*
* @date 27/4/20
* @since 5.9.0
*
* @param string $name The style name.
* @return void
*/
public function enqueue_style( $name ) {
wp_enqueue_style( $name );
}
/**
* Adds the actions needed to print supporting inline scripts.
*
* @date 27/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
private function add_actions() {
// Only run once.
if ( acf_has_done( 'ACF_Assets::add_actions' ) ) {
return;
}
// Add actions.
$this->add_action( 'admin_enqueue_scripts', 'enqueue_scripts', 20 );
$this->add_action( 'admin_print_scripts', 'print_scripts', 20 );
$this->add_action( 'admin_print_footer_scripts', 'print_footer_scripts', 20 );
}
/**
* Extends the add_action() function with two additional features:
* 1. Renames $action depending on the current page (customizer, login, front-end).
* 2. Alters the priotiry or calls the method directly if the action has already passed.
*
* @date 28/4/20
* @since 5.9.0
*
* @param string $action The action name.
* @param string $method The method name.
* @param int $priority See add_action().
* @param int $accepted_args See add_action().
* @return void
*/
public function add_action( $action, $method, $priority = 10, $accepted_args = 1 ) {
// Generate an array of action replacements.
$replacements = array(
'customizer' => array(
'admin_enqueue_scripts' => 'admin_enqueue_scripts',
'admin_print_scripts' => 'customize_controls_print_scripts',
'admin_head' => 'customize_controls_print_scripts',
'admin_footer' => 'customize_controls_print_footer_scripts',
'admin_print_footer_scripts' => 'customize_controls_print_footer_scripts',
),
'login' => array(
'admin_enqueue_scripts' => 'login_enqueue_scripts',
'admin_print_scripts' => 'login_head',
'admin_head' => 'login_head',
'admin_footer' => 'login_footer',
'admin_print_footer_scripts' => 'login_footer',
),
'wp' => array(
'admin_enqueue_scripts' => 'wp_enqueue_scripts',
'admin_print_scripts' => 'wp_print_scripts',
'admin_head' => 'wp_head',
'admin_footer' => 'wp_footer',
'admin_print_footer_scripts' => 'wp_print_footer_scripts',
),
);
// Determine the current context.
if ( did_action( 'customize_controls_init' ) ) {
$context = 'customizer';
} elseif ( did_action( 'login_form_register' ) ) {
$context = 'login';
} elseif ( is_admin() ) {
$context = 'admin';
} else {
$context = 'wp';
}
// Replace action if possible.
if ( isset( $replacements[ $context ][ $action ] ) ) {
$action = $replacements[ $context ][ $action ];
}
// Check if action is currently being or has already been run.
if ( did_action( $action ) ) {
$doing = acf_doing_action( $action );
if ( $doing && $doing < $priority ) {
// Allow action to be added as per usual.
} else {
// Call method directly.
return call_user_func( array( $this, $method ) );
}
}
// Add action.
add_action( $action, array( $this, $method ), $priority, $accepted_args );
}
/**
* Generic controller for enqueuing scripts and styles.
*
* @date 28/4/20
* @since 5.9.0
*
* @param array $args {
* @type bool $uploader Whether or not to enqueue uploader scripts.
* }
* @return void
*/
public function enqueue( $args = array() ) {
// Apply defaults.
$args = wp_parse_args(
$args,
array(
'input' => true,
'uploader' => false,
)
);
// Set enqueue flags and add actions.
if ( $args['input'] ) {
$this->enqueue[] = 'input';
}
if ( $args['uploader'] ) {
$this->enqueue[] = 'uploader';
}
$this->add_actions();
}
/**
* Enqueues the scripts and styles needed for the WP media uploader.
*
* @date 27/10/2014
* @since 5.0.9
*
* @param void
* @return void
*/
public function enqueue_uploader() {
// Only run once.
if ( acf_has_done( 'ACF_Assets::enqueue_uploader' ) ) {
return;
}
// Enqueue media assets.
if ( current_user_can( 'upload_files' ) ) {
wp_enqueue_media();
}
// Add actions.
$this->add_action( 'admin_footer', 'print_uploader_scripts', 1 );
/**
* Fires when enqueuing the uploader.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/enqueue_uploader' );
}
/**
* Enqueues and localizes scripts.
*
* @date 27/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function enqueue_scripts() {
// Enqueue input scripts.
if ( in_array( 'input', $this->enqueue ) ) {
wp_enqueue_script( 'acf-input' );
wp_enqueue_style( 'acf-input' );
}
// Enqueue media scripts.
if ( in_array( 'uploader', $this->enqueue ) ) {
$this->enqueue_uploader();
}
// Localize text.
acf_localize_text(
array(
// Tooltip
'Are you sure?' => __( 'Are you sure?', 'acf' ),
'Yes' => __( 'Yes', 'acf' ),
'No' => __( 'No', 'acf' ),
'Remove' => __( 'Remove', 'acf' ),
'Cancel' => __( 'Cancel', 'acf' ),
)
);
// Localize "input" text.
if ( wp_script_is( 'acf-input' ) ) {
acf_localize_text(
array(
// Unload
'The changes you made will be lost if you navigate away from this page' => __( 'The changes you made will be lost if you navigate away from this page', 'acf' ),
// Validation
'Validation successful' => __( 'Validation successful', 'acf' ),
'Validation failed' => __( 'Validation failed', 'acf' ),
'1 field requires attention' => __( '1 field requires attention', 'acf' ),
'%d fields require attention' => __( '%d fields require attention', 'acf' ),
// Other
'Edit field group' => __( 'Edit field group', 'acf' ),
)
);
/**
* Fires during "admin_enqueue_scripts" when ACF scripts are enqueued.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/input/admin_enqueue_scripts' );
}
/**
* Fires during "admin_enqueue_scripts" when ACF scripts are enqueued.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/admin_enqueue_scripts' );
do_action( 'acf/enqueue_scripts' );
// Filter i18n translations that differ from English and localize script.
$text = array();
foreach ( $this->text as $k => $v ) {
if ( str_replace( '.verb', '', $k ) !== $v ) {
$text[ $k ] = $v;
}
}
if ( $text ) {
wp_localize_script( 'acf', 'acfL10n', $text );
}
}
/**
* Prints scripts in head.
*
* @date 27/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function print_scripts() {
if ( wp_script_is( 'acf-input' ) ) {
/**
* Fires during "admin_head" when ACF scripts are enqueued.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/input/admin_head' );
do_action( 'acf/input/admin_print_scripts' );
}
/**
* Fires during "admin_head" when ACF scripts are enqueued.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/admin_head' );
do_action( 'acf/admin_print_scripts' );
}
/**
* Prints scripts in footer.
*
* @date 27/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function print_footer_scripts() {
global $wp_version;
// Bail early if 'acf' script was never enqueued (fixes Elementor enqueue reset conflict).
if ( ! wp_script_is( 'acf' ) ) {
return;
}
// Localize data.
acf_localize_data(
array(
'admin_url' => admin_url(),
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'acf_nonce' ),
'acf_version' => acf_get_setting( 'version' ),
'wp_version' => $wp_version,
'browser' => acf_get_browser(),
'locale' => acf_get_locale(),
'rtl' => is_rtl(),
'screen' => acf_get_form_data( 'screen' ),
'post_id' => acf_get_form_data( 'post_id' ),
'validation' => acf_get_form_data( 'validation' ),
'editor' => acf_is_block_editor() ? 'block' : 'classic',
)
);
// Print inline script.
printf( "<script>\n%s\n</script>\n", 'acf.data = ' . wp_json_encode( $this->data ) . ';' );
if ( wp_script_is( 'acf-input' ) ) {
/**
* Filters an empty array for compat l10n data.
*
* @since 5.0.0
*
* @param array $data An array of data to append to.
*/
$compat_l10n = apply_filters( 'acf/input/admin_l10n', array() );
if ( $compat_l10n ) {
printf( "<script>\n%s\n</script>\n", 'acf.l10n = ' . wp_json_encode( $compat_l10n ) . ';' );
}
/**
* Fires during "admin_footer" when ACF scripts are enqueued.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/input/admin_footer' );
do_action( 'acf/input/admin_print_footer_scripts' );
}
/**
* Fires during "admin_footer" when ACF scripts are enqueued.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/admin_footer' );
do_action( 'acf/admin_print_footer_scripts' );
// Once all data is localized, trigger acf.prepare() to execute functionality before DOM ready.
printf( "<script>\n%s\n</script>\n", "acf.doAction( 'prepare' );" );
}
/**
* Prints uploader scripts in footer.
*
* @date 11/06/2020
* @since 5.9.0
*
* @param void
* @return void
*/
public function print_uploader_scripts() {
// Todo: investigate output-buffer to hide HTML.
?>
<div id="acf-hidden-wp-editor" style="display: none;">
<?php wp_editor( '', 'acf_content' ); ?>
</div>
<?php
/**
* Fires when printing uploader scripts.
*
* @since 5.6.9
*
* @param void
*/
do_action( 'acf/admin_print_uploader_scripts' );
}
}
// instantiate
acf_new_instance( 'ACF_Assets' );
endif; // class_exists check
/**
* Appends an array of i18n data for localization.
*
* @date 13/4/18
* @since 5.6.9
*
* @param array $text An array of text for i18n.
* @return void
*/
function acf_localize_text( $text ) {
return acf_get_instance( 'ACF_Assets' )->add_text( $text );
}
/**
* Appends an array of l10n data for localization.
*
* @date 13/4/18
* @since 5.6.9
*
* @param array $data An array of data for l10n.
* @return void
*/
function acf_localize_data( $data ) {
return acf_get_instance( 'ACF_Assets' )->add_data( $data );
}
/**
* Enqueues a script with support for supplemental inline scripts.
*
* @date 27/4/20
* @since 5.9.0
*
* @param string $name The script name.
* @return void
*/
function acf_enqueue_script( $name ) {
return acf_get_instance( 'ACF_Assets' )->enqueue_script( $name );
}
/**
* Enqueues the input scripts required for fields.
*
* @date 13/4/18
* @since 5.6.9
*
* @param array $args See ACF_Assets::enqueue_scripts() for a list of args.
* @return void
*/
function acf_enqueue_scripts( $args = array() ) {
return acf_get_instance( 'ACF_Assets' )->enqueue( $args );
}
/**
* Enqueues the WP media uploader scripts and styles.
*
* @date 27/10/2014
* @since 5.0.9
*
* @param void
* @return void
*/
function acf_enqueue_uploader() {
return acf_get_instance( 'ACF_Assets' )->enqueue_uploader();
}

View File

@@ -0,0 +1,356 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'ACF_Data' ) ) :
class ACF_Data {
/** @var string Unique identifier. */
var $cid = '';
/** @var array Storage for data. */
var $data = array();
/** @var array Storage for data aliases. */
var $aliases = array();
/** @var bool Enables unique data per site. */
var $multisite = false;
/**
* __construct
*
* Sets up the class functionality.
*
* @date 9/1/19
* @since 5.7.10
*
* @param array $data Optional data to set.
* @return void
*/
function __construct( $data = false ) {
// Set cid.
$this->cid = acf_uniqid();
// Set data.
if ( $data ) {
$this->set( $data );
}
// Initialize.
$this->initialize();
}
/**
* initialize
*
* Called during constructor to setup class functionality.
*
* @date 9/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function initialize() {
// Do nothing.
}
/**
* prop
*
* Sets a property for the given name and returns $this for chaining.
*
* @date 9/1/19
* @since 5.7.10
*
* @param (string|array) $name The data name or an array of data.
* @param mixed $value The data value.
* @return ACF_Data
*/
function prop( $name = '', $value = null ) {
// Update property.
$this->{$name} = $value;
// Return this for chaining.
return $this;
}
/**
* _key
*
* Returns a key for the given name allowing aliasses to work.
*
* @date 18/1/19
* @since 5.7.10
*
* @param type $var Description. Default.
* @return type Description.
*/
function _key( $name = '' ) {
return isset( $this->aliases[ $name ] ) ? $this->aliases[ $name ] : $name;
}
/**
* has
*
* Returns true if this has data for the given name.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $name The data name.
* @return boolean
*/
function has( $name = '' ) {
$key = $this->_key( $name );
return isset( $this->data[ $key ] );
}
/**
* is
*
* Similar to has() but does not check aliases.
*
* @date 7/2/19
* @since 5.7.11
*
* @param type $var Description. Default.
* @return type Description.
*/
function is( $key = '' ) {
return isset( $this->data[ $key ] );
}
/**
* get
*
* Returns data for the given name of null if doesn't exist.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $name The data name.
* @return mixed
*/
function get( $name = false ) {
// Get all.
if ( $name === false ) {
return $this->data;
// Get specific.
} else {
$key = $this->_key( $name );
return isset( $this->data[ $key ] ) ? $this->data[ $key ] : null;
}
}
/**
* get_data
*
* Returns an array of all data.
*
* @date 9/1/19
* @since 5.7.10
*
* @param void
* @return array
*/
function get_data() {
return $this->data;
}
/**
* set
*
* Sets data for the given name and returns $this for chaining.
*
* @date 9/1/19
* @since 5.7.10
*
* @param (string|array) $name The data name or an array of data.
* @param mixed $value The data value.
* @return ACF_Data
*/
function set( $name = '', $value = null ) {
// Set multiple.
if ( is_array( $name ) ) {
$this->data = array_merge( $this->data, $name );
// Set single.
} else {
$this->data[ $name ] = $value;
}
// Return this for chaining.
return $this;
}
/**
* append
*
* Appends data for the given name and returns $this for chaining.
*
* @date 9/1/19
* @since 5.7.10
*
* @param mixed $value The data value.
* @return ACF_Data
*/
function append( $value = null ) {
// Append.
$this->data[] = $value;
// Return this for chaining.
return $this;
}
/**
* remove
*
* Removes data for the given name.
*
* @date 9/1/19
* @since 5.7.10
*
* @param string $name The data name.
* @return ACF_Data
*/
function remove( $name = '' ) {
// Remove data.
unset( $this->data[ $name ] );
// Return this for chaining.
return $this;
}
/**
* reset
*
* Resets the data.
*
* @date 22/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function reset() {
$this->data = array();
$this->aliases = array();
}
/**
* count
*
* Returns the data count.
*
* @date 23/1/19
* @since 5.7.10
*
* @param void
* @return int
*/
function count() {
return count( $this->data );
}
/**
* query
*
* Returns a filtered array of data based on the set of key => value arguments.
*
* @date 23/1/19
* @since 5.7.10
*
* @param void
* @return int
*/
function query( $args, $operator = 'AND' ) {
return wp_list_filter( $this->data, $args, $operator );
}
/**
* alias
*
* Sets an alias for the given name allowing data to be found via multiple identifiers.
*
* @date 18/1/19
* @since 5.7.10
*
* @param type $var Description. Default.
* @return type Description.
*/
function alias( $name = '' /*, $alias, $alias2, etc */ ) {
// Get all aliases.
$args = func_get_args();
array_shift( $args );
// Loop over aliases and add to data.
foreach ( $args as $alias ) {
$this->aliases[ $alias ] = $name;
}
// Return this for chaining.
return $this;
}
/**
* switch_site
*
* Triggered when switching between sites on a multisite installation.
*
* @date 13/2/19
* @since 5.7.11
*
* @param int $site_id New blog ID.
* @param int prev_blog_id Prev blog ID.
* @return void
*/
function switch_site( $site_id, $prev_site_id ) {
// Bail early if not multisite compatible.
if ( ! $this->multisite ) {
return;
}
// Bail early if no change in blog ID.
if ( $site_id === $prev_site_id ) {
return;
}
// Create storage.
if ( ! isset( $this->site_data ) ) {
$this->site_data = array();
$this->site_aliases = array();
}
// Save state.
$this->site_data[ $prev_site_id ] = $this->data;
$this->site_aliases[ $prev_site_id ] = $this->aliases;
// Reset state.
$this->data = array();
$this->aliases = array();
// Load state.
if ( isset( $this->site_data[ $site_id ] ) ) {
$this->data = $this->site_data[ $site_id ];
$this->aliases = $this->site_aliases[ $site_id ];
unset( $this->site_data[ $site_id ] );
unset( $this->site_aliases[ $site_id ] );
}
}
}
endif; // class_exists check

View File

@@ -0,0 +1,488 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Compatibility' ) ) :
class ACF_Compatibility {
/**
* __construct
*
* Sets up the class functionality.
*
* @date 30/04/2014
* @since 5.0.0
*
* @param void
* @return void
*/
function __construct() {
// actions
add_filter( 'acf/validate_field', array( $this, 'validate_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=textarea', array( $this, 'validate_textarea_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=relationship', array( $this, 'validate_relationship_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=post_object', array( $this, 'validate_relationship_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=page_link', array( $this, 'validate_relationship_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=image', array( $this, 'validate_image_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=file', array( $this, 'validate_image_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=wysiwyg', array( $this, 'validate_wysiwyg_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=date_picker', array( $this, 'validate_date_picker_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=taxonomy', array( $this, 'validate_taxonomy_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=date_time_picker', array( $this, 'validate_date_time_picker_field' ), 20, 1 );
add_filter( 'acf/validate_field/type=user', array( $this, 'validate_user_field' ), 20, 1 );
add_filter( 'acf/validate_field_group', array( $this, 'validate_field_group' ), 20, 1 );
// Modify field wrapper attributes
add_filter( 'acf/field_wrapper_attributes', array( $this, 'field_wrapper_attributes' ), 20, 2 );
// location
add_filter( 'acf/location/validate_rule/type=post_taxonomy', array( $this, 'validate_post_taxonomy_location_rule' ), 20, 1 );
add_filter( 'acf/location/validate_rule/type=post_category', array( $this, 'validate_post_taxonomy_location_rule' ), 20, 1 );
// Update settings
add_action( 'acf/init', array( $this, 'init' ) );
}
/**
* init
*
* Adds compatibility for deprecated settings.
*
* @date 10/6/19
* @since 5.8.1
*
* @param void
* @return void
*/
function init() {
// Update "show_admin" setting based on defined constant.
if ( defined( 'ACF_LITE' ) && ACF_LITE ) {
acf_update_setting( 'show_admin', false );
}
}
/**
* field_wrapper_attributes
*
* Adds compatibility with deprecated field wrap attributes.
*
* @date 21/1/19
* @since 5.7.10
*
* @param array $wrapper The wrapper attributes array.
* @param array $field The field array.
*/
function field_wrapper_attributes( $wrapper, $field ) {
// Check compatibility setting.
if ( acf_get_compatibility( 'field_wrapper_class' ) ) {
$wrapper['class'] .= " field_type-{$field['type']}";
if ( $field['key'] ) {
$wrapper['class'] .= " field_key-{$field['key']}";
}
}
// Return wrapper.
return $wrapper;
}
/**
* validate_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.0.0
*
* @param array $field The field array.
* @return array $field
*/
function validate_field( $field ) {
// conditional logic data structure changed to groups in version 5.0.0
// convert previous data (status, rules, allorany) into groups
if ( isset( $field['conditional_logic']['status'] ) ) {
// check status
if ( $field['conditional_logic']['status'] ) {
$field['conditional_logic'] = acf_convert_rules_to_groups( $field['conditional_logic']['rules'], $field['conditional_logic']['allorany'] );
} else {
$field['conditional_logic'] = 0;
}
}
// return
return $field;
}
/**
* validate_textarea_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.0.0
*
* @param array $field The field array.
* @return array $field
*/
function validate_textarea_field( $field ) {
// formatting has been removed
$formatting = acf_extract_var( $field, 'formatting' );
if ( $formatting === 'br' ) {
$field['new_lines'] = 'br';
}
// return
return $field;
}
/**
* validate_relationship_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.0.0
*
* @param array $field The field array.
* @return array $field
*/
function validate_relationship_field( $field ) {
// remove 'all' from post_type
if ( acf_in_array( 'all', $field['post_type'] ) ) {
$field['post_type'] = array();
}
// remove 'all' from taxonomy
if ( acf_in_array( 'all', $field['taxonomy'] ) ) {
$field['taxonomy'] = array();
}
// result_elements is now elements
if ( isset( $field['result_elements'] ) ) {
$field['elements'] = acf_extract_var( $field, 'result_elements' );
}
// return
return $field;
}
/**
* validate_image_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.0.0
*
* @param array $field The field array.
* @return array $field
*/
function validate_image_field( $field ) {
// save_format is now return_format
if ( isset( $field['save_format'] ) ) {
$field['return_format'] = acf_extract_var( $field, 'save_format' );
}
// object is now array
if ( $field['return_format'] == 'object' ) {
$field['return_format'] = 'array';
}
// return
return $field;
}
/**
* validate_wysiwyg_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.0.0
*
* @param array $field The field array.
* @return array $field
*/
function validate_wysiwyg_field( $field ) {
// media_upload is now numeric
if ( $field['media_upload'] === 'yes' ) {
$field['media_upload'] = 1;
} elseif ( $field['media_upload'] === 'no' ) {
$field['media_upload'] = 0;
}
// return
return $field;
}
/**
* validate_date_picker_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.0.0
*
* @param array $field The field array.
* @return array $field
*/
function validate_date_picker_field( $field ) {
// date_format has changed to display_format
if ( isset( $field['date_format'] ) ) {
// extract vars
$date_format = $field['date_format'];
$display_format = $field['display_format'];
// convert from js to php
$display_format = acf_convert_date_to_php( $display_format );
// append settings
$field['display_format'] = $display_format;
$field['save_format'] = $date_format;
// clean up
unset( $field['date_format'] );
}
// return
return $field;
}
/**
* validate_taxonomy_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.2.7
*
* @param array $field The field array.
* @return array $field
*/
function validate_taxonomy_field( $field ) {
// load_save_terms deprecated in favour of separate save_terms
if ( isset( $field['load_save_terms'] ) ) {
$field['save_terms'] = acf_extract_var( $field, 'load_save_terms' );
}
// return
return $field;
}
/**
* validate_date_time_picker_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.2.7
*
* @param array $field The field array.
* @return array $field
*/
function validate_date_time_picker_field( $field ) {
// 3rd party date time picker
// https://github.com/soderlind/acf-field-date-time-picker
if ( ! empty( $field['time_format'] ) ) {
// extract vars
$time_format = acf_extract_var( $field, 'time_format' );
$date_format = acf_extract_var( $field, 'date_format' );
$get_as_timestamp = acf_extract_var( $field, 'get_as_timestamp' );
// convert from js to php
$time_format = acf_convert_time_to_php( $time_format );
$date_format = acf_convert_date_to_php( $date_format );
// append settings
$field['return_format'] = $date_format . ' ' . $time_format;
$field['display_format'] = $date_format . ' ' . $time_format;
// timestamp
if ( $get_as_timestamp === 'true' ) {
$field['return_format'] = 'U';
}
}
// return
return $field;
}
/**
* validate_user_field
*
* Adds compatibility with deprecated settings
*
* @date 23/04/2014
* @since 5.2.7
*
* @param array $field The field array.
* @return array $field
*/
function validate_user_field( $field ) {
// remove 'all' from roles
if ( acf_in_array( 'all', $field['role'] ) ) {
$field['role'] = '';
}
// field_type removed in favour of multiple
if ( isset( $field['field_type'] ) ) {
// extract vars
$field_type = acf_extract_var( $field, 'field_type' );
// multiple
if ( $field_type === 'multi_select' ) {
$field['multiple'] = true;
}
}
// return
return $field;
}
/*
* validate_field_group
*
* This function will provide compatibility with ACF4 field groups
*
* @type function
* @date 23/04/2014
* @since 5.0.0
*
* @param $field_group (array)
* @return $field_group
*/
function validate_field_group( $field_group ) {
// vars
$version = 5;
// field group key was added in version 5.0.0
// detect ACF4 data and generate key
if ( ! $field_group['key'] ) {
$version = 4;
$field_group['key'] = isset( $field_group['id'] ) ? "group_{$field_group['id']}" : uniqid( 'group_' );
}
// prior to version 5.0.0, settings were saved in an 'options' array
// extract and merge options into the field group
if ( isset( $field_group['options'] ) ) {
$options = acf_extract_var( $field_group, 'options' );
$field_group = array_merge( $field_group, $options );
}
// location data structure changed to groups in version 4.1.0
// convert previous data (rules, allorany) into groups
if ( isset( $field_group['location']['rules'] ) ) {
$field_group['location'] = acf_convert_rules_to_groups( $field_group['location']['rules'], $field_group['location']['allorany'] );
}
// some location rule names have changed in version 5.0.0
// loop over location data and modify rules
$replace = array(
'taxonomy' => 'post_taxonomy',
'ef_media' => 'attachment',
'ef_taxonomy' => 'taxonomy',
'ef_user' => 'user_role',
'user_type' => 'current_user_role', // 5.2.0
);
// only replace 'taxonomy' rule if is an ACF4 field group
if ( $version > 4 ) {
unset( $replace['taxonomy'] );
}
// loop over location groups
if ( $field_group['location'] ) {
foreach ( $field_group['location'] as $i => $group ) {
// loop over group rules
if ( $group ) {
foreach ( $group as $j => $rule ) {
// migrate param
if ( isset( $replace[ $rule['param'] ] ) ) {
$field_group['location'][ $i ][ $j ]['param'] = $replace[ $rule['param'] ];
}
}
}
}
}
// change layout to style (v5.0.0)
if ( isset( $field_group['layout'] ) ) {
$field_group['style'] = acf_extract_var( $field_group, 'layout' );
}
// change no_box to seamless (v5.0.0)
if ( $field_group['style'] === 'no_box' ) {
$field_group['style'] = 'seamless';
}
// return
return $field_group;
}
/**
* validate_post_taxonomy_location_rule
*
* description
*
* @date 27/8/18
* @since 5.7.4
*
* @param type $var Description. Default.
* @return type Description.
*/
function validate_post_taxonomy_location_rule( $rule ) {
// previous versions of ACF (v4.4.12) saved value as term_id
// convert term_id into "taxonomy:slug" string
if ( is_numeric( $rule['value'] ) ) {
$term = acf_get_term( $rule['value'] );
if ( $term ) {
$rule['value'] = acf_encode_term( $term );
}
}
// return
return $rule;
}
}
acf_new_instance( 'ACF_Compatibility' );
endif; // class_exists check
/*
* acf_get_compatibility
*
* Returns true if compatibility is enabled for the given component.
*
* @date 20/1/15
* @since 5.1.5
*
* @param string $name The name of the component to check.
* @return bool
*/
function acf_get_compatibility( $name ) {
return apply_filters( "acf/compatibility/{$name}", false );
}

View File

@@ -0,0 +1,154 @@
<?php
// Register deprecated filters ( $deprecated, $version, $replacement ).
acf_add_deprecated_filter( 'acf/settings/export_textdomain', '5.3.3', 'acf/settings/l10n_textdomain' );
acf_add_deprecated_filter( 'acf/settings/export_translate', '5.3.3', 'acf/settings/l10n_field' );
acf_add_deprecated_filter( 'acf/settings/export_translate', '5.3.3', 'acf/settings/l10n_field_group' );
acf_add_deprecated_filter( 'acf/settings/dir', '5.6.8', 'acf/settings/url' );
acf_add_deprecated_filter( 'acf/get_valid_field', '5.5.6', 'acf/validate_field' );
acf_add_deprecated_filter( 'acf/get_valid_field_group', '5.5.6', 'acf/validate_field_group' );
acf_add_deprecated_filter( 'acf/get_valid_post_id', '5.5.6', 'acf/validate_post_id' );
acf_add_deprecated_filter( 'acf/get_field_reference', '5.6.5', 'acf/load_reference' );
acf_add_deprecated_filter( 'acf/get_field_group', '5.7.11', 'acf/load_field_group' );
acf_add_deprecated_filter( 'acf/get_field_groups', '5.7.11', 'acf/load_field_groups' );
acf_add_deprecated_filter( 'acf/get_fields', '5.7.11', 'acf/load_fields' );
// Register variations for deprecated filters.
acf_add_filter_variations( 'acf/get_valid_field', array( 'type' ), 0 );
/**
* acf_render_field_wrap_label
*
* Renders the field's label.
*
* @date 19/9/17
* @since 5.6.3
* @deprecated 5.6.5
*
* @param array $field The field array.
* @return void
*/
function acf_render_field_wrap_label( $field ) {
// Warning.
_deprecated_function( __FUNCTION__, '5.7.11', 'acf_render_field_label()' );
// Render.
acf_render_field_label( $field );
}
/**
* acf_render_field_wrap_description
*
* Renders the field's instructions.
*
* @date 19/9/17
* @since 5.6.3
* @deprecated 5.6.5
*
* @param array $field The field array.
* @return void
*/
function acf_render_field_wrap_description( $field ) {
// Warning.
_deprecated_function( __FUNCTION__, '5.7.11', 'acf_render_field_instructions()' );
// Render.
acf_render_field_instructions( $field );
}
/*
* acf_get_fields_by_id
*
* Returns and array of fields for the given $parent_id.
*
* @date 27/02/2014
* @since 5.0.0.
* @deprecated 5.7.11
*
* @param int $parent_id The parent ID.
* @return array
*/
function acf_get_fields_by_id( $parent_id = 0 ) {
// Warning.
_deprecated_function( __FUNCTION__, '5.7.11', 'acf_get_fields()' );
// Return fields.
return acf_get_fields(
array(
'ID' => $parent_id,
'key' => "group_$parent_id",
)
);
}
/**
* acf_update_option
*
* A wrapper for the WP update_option but provides logic for a 'no' autoload
*
* @date 4/01/2014
* @since 5.0.0
* @deprecated 5.7.11
*
* @param string $option The option name.
* @param string $value The option value.
* @param string $autoload An optional autoload value.
* @return bool
*/
function acf_update_option( $option = '', $value = '', $autoload = null ) {
// Warning.
_deprecated_function( __FUNCTION__, '5.7.11', 'update_option()' );
// Update.
if ( $autoload === null ) {
$autoload = (bool) acf_get_setting( 'autoload' );
}
return update_option( $option, $value, $autoload );
}
/**
* acf_get_field_reference
*
* Finds the field key for a given field name and post_id.
*
* @date 26/1/18
* @since 5.6.5
* @deprecated 5.6.8
*
* @param string $field_name The name of the field. eg 'sub_heading'
* @param mixed $post_id The post_id of which the value is saved against
* @return string $reference The field key
*/
function acf_get_field_reference( $field_name, $post_id ) {
// Warning.
_deprecated_function( __FUNCTION__, '5.6.8', 'acf_get_reference()' );
// Return reference.
return acf_get_reference( $field_name, $post_id );
}
/**
* acf_get_dir
*
* Returns the plugin url to a specified file.
*
* @date 28/09/13
* @since 5.0.0
* @deprecated 5.6.8
*
* @param string $filename The specified file.
* @return string
*/
function acf_get_dir( $filename = '' ) {
// Warning.
_deprecated_function( __FUNCTION__, '5.6.8', 'acf_get_url()' );
// Return.
return acf_get_url( $filename );
}

View File

@@ -0,0 +1,380 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'acf_fields' ) ) :
class acf_fields {
/** @var array Contains an array of field type instances */
var $types = array();
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.4.0
*
* @param n/a
* @return n/a
*/
function __construct() {
/* do nothing */
}
/*
* register_field_type
*
* This function will register a field type instance
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $class (string)
* @return n/a
*/
function register_field_type( $class ) {
// allow instance
if ( $class instanceof acf_field ) {
$this->types[ $class->name ] = $class;
// allow class name
} else {
$instance = new $class();
$this->types[ $instance->name ] = $instance;
}
}
/*
* get_field_type
*
* This function will return a field type instance
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $name (string)
* @return (mixed)
*/
function get_field_type( $name ) {
return isset( $this->types[ $name ] ) ? $this->types[ $name ] : null;
}
/*
* is_field_type
*
* This function will return true if a field type exists
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $name (string)
* @return (mixed)
*/
function is_field_type( $name ) {
return isset( $this->types[ $name ] );
}
/*
* register_field_type_info
*
* This function will store a basic array of info about the field type
* to later be overriden by the above register_field_type function
*
* @type function
* @date 29/5/17
* @since 5.6.0
*
* @param $info (array)
* @return n/a
*/
function register_field_type_info( $info ) {
// convert to object
$instance = (object) $info;
$this->types[ $instance->name ] = $instance;
}
/*
* get_field_types
*
* This function will return an array of all field types
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $name (string)
* @return (mixed)
*/
function get_field_types() {
return $this->types;
}
}
// initialize
acf()->fields = new acf_fields();
endif; // class_exists check
/*
* acf_register_field_type
*
* alias of acf()->fields->register_field_type()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_register_field_type( $class ) {
return acf()->fields->register_field_type( $class );
}
/*
* acf_register_field_type_info
*
* alias of acf()->fields->register_field_type_info()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_register_field_type_info( $info ) {
return acf()->fields->register_field_type_info( $info );
}
/*
* acf_get_field_type
*
* alias of acf()->fields->get_field_type()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_field_type( $name ) {
return acf()->fields->get_field_type( $name );
}
/*
* acf_get_field_types
*
* alias of acf()->fields->get_field_types()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_field_types( $args = array() ) {
// default
$args = wp_parse_args(
$args,
array(
'public' => true, // true, false
)
);
// get field types
$field_types = acf()->fields->get_field_types();
// filter
return wp_filter_object_list( $field_types, $args );
}
/**
* acf_get_field_types_info
*
* Returns an array containing information about each field type
*
* @date 18/6/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_get_field_types_info( $args = array() ) {
// vars
$data = array();
$field_types = acf_get_field_types();
// loop
foreach ( $field_types as $type ) {
$data[ $type->name ] = array(
'label' => $type->label,
'name' => $type->name,
'category' => $type->category,
'public' => $type->public,
);
}
// return
return $data;
}
/*
* acf_is_field_type
*
* alias of acf()->fields->is_field_type()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_is_field_type( $name = '' ) {
return acf()->fields->is_field_type( $name );
}
/*
* acf_get_field_type_prop
*
* This function will return a field type's property
*
* @type function
* @date 1/10/13
* @since 5.0.0
*
* @param n/a
* @return (array)
*/
function acf_get_field_type_prop( $name = '', $prop = '' ) {
$type = acf_get_field_type( $name );
return ( $type && isset( $type->$prop ) ) ? $type->$prop : null;
}
/*
* acf_get_field_type_label
*
* This function will return the label of a field type
*
* @type function
* @date 1/10/13
* @since 5.0.0
*
* @param n/a
* @return (array)
*/
function acf_get_field_type_label( $name = '' ) {
$label = acf_get_field_type_prop( $name, 'label' );
return $label ? $label : '<span class="acf-tooltip-js" title="' . __( 'Field type does not exist', 'acf' ) . '">' . __( 'Unknown', 'acf' ) . '</span>';
}
/*
* acf_field_type_exists (deprecated)
*
* deprecated in favour of acf_is_field_type()
*
* @type function
* @date 1/10/13
* @since 5.0.0
*
* @param $type (string)
* @return (boolean)
*/
function acf_field_type_exists( $type = '' ) {
return acf_is_field_type( $type );
}
/*
* acf_get_grouped_field_types
*
* Returns an multi-dimentional array of field types "name => label" grouped by category
*
* @type function
* @date 1/10/13
* @since 5.0.0
*
* @param n/a
* @return (array)
*/
function acf_get_grouped_field_types() {
// vars
$types = acf_get_field_types();
$groups = array();
$l10n = array(
'basic' => __( 'Basic', 'acf' ),
'content' => __( 'Content', 'acf' ),
'choice' => __( 'Choice', 'acf' ),
'relational' => __( 'Relational', 'acf' ),
'jquery' => __( 'jQuery', 'acf' ),
'layout' => __( 'Layout', 'acf' ),
);
// loop
foreach ( $types as $type ) {
// translate
$cat = $type->category;
$cat = isset( $l10n[ $cat ] ) ? $l10n[ $cat ] : $cat;
// append
$groups[ $cat ][ $type->name ] = $type->label;
}
// filter
$groups = apply_filters( 'acf/get_field_types', $groups );
// return
return $groups;
}

View File

@@ -0,0 +1,174 @@
<?php
if ( ! class_exists( 'acf_field__accordion' ) ) :
class acf_field__accordion extends acf_field {
/**
* 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->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 acf_esc_attr_e( $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 ) {
/*
// message
$message = '';
$message .= '<p>' . __( 'Accordions help you organize fields into panels that open and close.', 'acf') . '</p>';
$message .= '<p>' . __( 'All fields following this accordion (or until another accordion is defined) will be grouped together.','acf') . '</p>';
// default_value
acf_render_field_setting( $field, array(
'label' => __('Instructions','acf'),
'instructions' => '',
'name' => 'notes',
'type' => 'message',
'message' => $message,
));
*/
// active
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,
)
);
// multi_expand
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,
)
);
// endpoint
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,299 @@
<?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->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'] );
// choices
acf_render_field_setting(
$field,
array(
'label' => __( 'Choices', 'acf' ),
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br /><br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><br />' . __( 'red : Red', 'acf' ),
'type' => 'textarea',
'name' => 'choices',
)
);
// allow_null
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Null?', 'acf' ),
'instructions' => '',
'name' => 'allow_null',
'type' => 'true_false',
'ui' => 1,
)
);
// 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',
)
);
// layout
acf_render_field_setting(
$field,
array(
'label' => __( 'Layout', 'acf' ),
'instructions' => '',
'type' => 'radio',
'name' => 'layout',
'layout' => 'horizontal',
'choices' => array(
'horizontal' => __( 'Horizontal', 'acf' ),
'vertical' => __( 'Vertical', 'acf' ),
),
)
);
// return_format
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' ),
),
)
);
}
/*
* 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 );
}
}
// initialize
acf_register_field_type( 'acf_field_button_group' );
endif; // class_exists check

View File

@@ -0,0 +1,575 @@
<?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->defaults = array(
'layout' => 'vertical',
'choices' => array(),
'default_value' => '',
'allow_custom' => 0,
'save_custom' => 0,
'toggle' => 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 ) {
// 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 );
}
/*
* 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 ealry 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__( 'Add new choice', 'acf' ) . '</a></li>' . "\n";
// return
return $html;
}
function walk( $choices = array(), $args = array(), $depth = 0 ) {
// bail ealry 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 );
// choices
acf_render_field_setting(
$field,
array(
'label' => __( 'Choices', 'acf' ),
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br /><br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><br />' . __( 'red : Red', 'acf' ),
'type' => 'textarea',
'name' => 'choices',
)
);
// other_choice
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Custom', 'acf' ),
'instructions' => '',
'name' => 'allow_custom',
'type' => 'true_false',
'ui' => 1,
'message' => __( "Allow 'custom' values to be added", 'acf' ),
)
);
// save_other_choice
acf_render_field_setting(
$field,
array(
'label' => __( 'Save Custom', 'acf' ),
'instructions' => '',
'name' => 'save_custom',
'type' => 'true_false',
'ui' => 1,
'message' => __( "Save 'custom' values to the field's choices", 'acf' ),
'conditions' => array(
'field' => 'allow_custom',
'operator' => '==',
'value' => 1,
),
)
);
// default_value
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',
)
);
// layout
acf_render_field_setting(
$field,
array(
'label' => __( 'Layout', 'acf' ),
'instructions' => '',
'type' => 'radio',
'name' => 'layout',
'layout' => 'horizontal',
'choices' => array(
'vertical' => __( 'Vertical', 'acf' ),
'horizontal' => __( 'Horizontal', 'acf' ),
),
)
);
// layout
acf_render_field_setting(
$field,
array(
'label' => __( 'Toggle', 'acf' ),
'instructions' => __( 'Prepend an extra checkbox to toggle all choices', 'acf' ),
'name' => 'toggle',
'type' => 'true_false',
'ui' => 1,
)
);
// return_format
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' ),
),
)
);
}
/*
* 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 );
}
}
// initialize
acf_register_field_type( 'acf_field_checkbox' );
endif; // class_exists check

View File

@@ -0,0 +1,296 @@
<?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 = 'jquery';
$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' ),
'clearAriaLabel' => __( 'Clear color' ),
'defaultString' => __( 'Default' ),
'defaultAriaLabel' => __( 'Select default color' ),
'pick' => __( 'Select Color' ),
'defaultLabel' => __( 'Color value' ),
)
);
}
}
// 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 ) {
// vars
$text_input = acf_get_sub_array( $field, array( 'id', 'class', 'name', 'value' ) );
$hidden_input = acf_get_sub_array( $field, array( 'name', 'value' ) );
// 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 ) {
// Trim Value
$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,286 @@
<?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 = 'jquery';
$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 ealry 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' => '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 acf_esc_attr_e( $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
global $wp_locale;
// vars
$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' );
// display_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Display Format', 'acf' ),
'instructions' => __( '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'] ) ) {
// save_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Save Format', 'acf' ),
'instructions' => __( 'The format used when saving a value', 'acf' ),
'type' => 'text',
'name' => 'save_format',
// 'readonly' => 1 // this setting was not readonly in v4
)
);
} else {
// return_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Return Format', 'acf' ),
'instructions' => __( '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>',
),
)
);
}
// first_day
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'] );
}
}
// initialize
acf_register_field_type( 'acf_field_date_picker' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,261 @@
<?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 = 'jquery';
$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 ealry 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' => '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 acf_esc_attr_e( $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
global $wp_locale;
// vars
$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' );
// display_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Display Format', 'acf' ),
'instructions' => __( '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>',
),
)
);
// return_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Return Format', 'acf' ),
'instructions' => __( '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>',
),
)
);
// first_day
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'] );
}
}
// initialize
acf_register_field_type( 'acf_field_date_and_time_picker' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,189 @@
<?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->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 ) {
// 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',
)
);
// placeholder
acf_render_field_setting(
$field,
array(
'label' => __( 'Placeholder Text', 'acf' ),
'instructions' => __( 'Appears within the input', 'acf' ),
'type' => 'text',
'name' => 'placeholder',
)
);
// prepend
acf_render_field_setting(
$field,
array(
'label' => __( 'Prepend', 'acf' ),
'instructions' => __( 'Appears before the input', 'acf' ),
'type' => 'text',
'name' => 'prepend',
)
);
// append
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;
}
}
// initialize
acf_register_field_type( 'acf_field_email' );
endif; // class_exists check

View File

@@ -0,0 +1,460 @@
<?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->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 acf_esc_attr_e( $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'],
)
);
?>
</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 ) {
// clear numeric settings
$clear = array(
'min_size',
'max_size',
);
foreach ( $clear as $k ) {
if ( empty( $field[ $k ] ) ) {
$field[ $k ] = '';
}
}
// return_format
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' ),
),
)
);
// library
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' ),
),
)
);
// min
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',
)
);
// max
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',
)
);
// allowed type
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',
)
);
}
/*
* 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 ealry if is numeric
if ( is_numeric( $value ) ) {
return $valid;
}
// bail ealry 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;
}
}
// initialize
acf_register_field_type( 'acf_field_file' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,312 @@
<?php
if ( ! class_exists( 'acf_field_google_map' ) ) :
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 = 'jquery';
$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 ealry 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' => '',
'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 acf_esc_attr_e( $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' ),
'instructions' => __( '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' ),
'instructions' => __( '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;
}
}
// initialize
acf_register_field_type( 'acf_field_google_map' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,670 @@
<?php
if ( ! class_exists( 'acf_field__group' ) ) :
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->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;
}
/*
* 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;
}
// 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 );
// 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 ealry 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 ealry 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 acf_esc_attr_e( $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'],
);
?>
<tr class="acf-field acf-field-setting-sub_fields" data-setting="group" data-name="sub_fields">
<td class="acf-label">
<label><?php _e( 'Sub Fields', 'acf' ); ?></label>
</td>
<td class="acf-input">
<?php
acf_get_view( 'field-group-fields', $args );
?>
</td>
</tr>
<?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 ealry 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'] );
}
}
}
}
// initialize
acf_register_field_type( 'acf_field__group' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,452 @@
<?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->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'],
)
);
?>
</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 ) {
// 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 ] = '';
}
}
// return_format
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' ),
),
)
);
// preview_size
acf_render_field_setting(
$field,
array(
'label' => __( 'Preview Size', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'preview_size',
'choices' => acf_get_image_sizes(),
)
);
// library
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' ),
),
)
);
// min
acf_render_field_setting(
$field,
array(
'label' => __( 'Minimum', 'acf' ),
'instructions' => __( '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',
)
);
// max
acf_render_field_setting(
$field,
array(
'label' => __( 'Maximum', 'acf' ),
'instructions' => __( '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',
)
);
// allowed type
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',
)
);
}
/*
* 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 );
}
}
// initialize
acf_register_field_type( 'acf_field_image' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,291 @@
<?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->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 acf_esc_attr_e( $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 ) {
// return_format
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;
}
}
// initialize
acf_register_field_type( 'acf_field_link' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,200 @@
<?php
if ( ! class_exists( 'acf_field_message' ) ) :
class acf_field_message 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 = 'message';
$this->label = __( 'Message', 'acf' );
$this->category = 'layout';
$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 ) {
// default_value
acf_render_field_setting(
$field,
array(
'label' => __( 'Message', 'acf' ),
'instructions' => '',
'type' => 'textarea',
'name' => 'message',
)
);
// formatting
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' ),
),
)
);
// HTML
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,307 @@
<?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->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',
)
);
// placeholder
acf_render_field_setting(
$field,
array(
'label' => __( 'Placeholder Text', 'acf' ),
'instructions' => __( 'Appears within the input', 'acf' ),
'type' => 'text',
'name' => 'placeholder',
)
);
// prepend
acf_render_field_setting(
$field,
array(
'label' => __( 'Prepend', 'acf' ),
'instructions' => __( 'Appears before the input', 'acf' ),
'type' => 'text',
'name' => 'prepend',
)
);
// append
acf_render_field_setting(
$field,
array(
'label' => __( 'Append', 'acf' ),
'instructions' => __( 'Appears after the input', 'acf' ),
'type' => 'text',
'name' => 'append',
)
);
// min
acf_render_field_setting(
$field,
array(
'label' => __( 'Minimum Value', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'min',
)
);
// max
acf_render_field_setting(
$field,
array(
'label' => __( 'Maximum Value', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'max',
)
);
// max
acf_render_field_setting(
$field,
array(
'label' => __( 'Step Size', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'step',
)
);
}
/*
* 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;
}
}
// initialize
acf_register_field_type( 'acf_field_number' );
endif; // class_exists check

View File

@@ -0,0 +1,344 @@
<?php
if ( ! class_exists( 'acf_field_oembed' ) ) :
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->defaults = array(
'width' => '',
'height' => '',
);
$this->width = 640;
$this->height = 390;
// 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;
}
/*
* wp_oembed_get
*
* description
*
* @type function
* @date 24/01/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function wp_oembed_get( $url = '', $width = 0, $height = 0 ) {
// vars
$embed = '';
$res = array(
'width' => $width,
'height' => $height,
);
// get emebed
$embed = @wp_oembed_get( $url, $res );
// try shortcode
if ( ! $embed ) {
// global
global $wp_embed;
// get emebed
$embed = $wp_embed->shortcode( $res, $url );
}
// return
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 acf_esc_attr_e( $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 ) {
// width
acf_render_field_setting(
$field,
array(
'label' => __( 'Embed Size', 'acf' ),
'type' => 'text',
'name' => 'width',
'prepend' => __( 'Width', 'acf' ),
'append' => 'px',
'placeholder' => $this->width,
)
);
// height
acf_render_field_setting(
$field,
array(
'label' => __( 'Embed Size', 'acf' ),
'type' => 'text',
'name' => 'height',
'prepend' => __( 'Height', 'acf' ),
'append' => 'px',
'placeholder' => $this->height,
'_append' => 'width',
)
);
}
/*
* 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;
}
// 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;
}
}
// initialize
acf_register_field_type( 'acf_field_oembed' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,78 @@
<?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,630 @@
<?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->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();
}
// 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 ) {
// post_type
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' ),
)
);
// taxonomy
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' ),
)
);
// allow_null
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Null?', 'acf' ),
'instructions' => '',
'name' => 'allow_null',
'type' => 'true_false',
'ui' => 1,
)
);
// allow_archives
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Archives URLs', 'acf' ),
'instructions' => '',
'name' => 'allow_archives',
'type' => 'true_false',
'ui' => 1,
)
);
// multiple
acf_render_field_setting(
$field,
array(
'label' => __( 'Select multiple values?', 'acf' ),
'instructions' => '',
'name' => 'multiple',
'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;
}
}
// initialize
acf_register_field_type( 'acf_field_page_link' );
endif; // class_exists check

View File

@@ -0,0 +1,111 @@
<?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->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 ) {
// placeholder
acf_render_field_setting(
$field,
array(
'label' => __( 'Placeholder Text', 'acf' ),
'instructions' => __( 'Appears within the input', 'acf' ),
'type' => 'text',
'name' => 'placeholder',
)
);
// prepend
acf_render_field_setting(
$field,
array(
'label' => __( 'Prepend', 'acf' ),
'instructions' => __( 'Appears before the input', 'acf' ),
'type' => 'text',
'name' => 'prepend',
)
);
// append
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,591 @@
<?php
if ( ! class_exists( 'acf_field_post_object' ) ) :
class acf_field_post_object 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 = 'post_object';
$this->label = __( 'Post Object', 'acf' );
$this->category = 'relational';
$this->defaults = array(
'post_type' => array(),
'taxonomy' => array(),
'allow_null' => 0,
'multiple' => 0,
'return_format' => 'object',
'ui' => 1,
);
// 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();
}
// 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 ) {
// default_value
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' ),
)
);
// default_value
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' ),
)
);
// allow_null
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Null?', 'acf' ),
'instructions' => '',
'name' => 'allow_null',
'type' => 'true_false',
'ui' => 1,
)
);
// multiple
acf_render_field_setting(
$field,
array(
'label' => __( 'Select multiple values?', 'acf' ),
'instructions' => '',
'name' => 'multiple',
'type' => 'true_false',
'ui' => 1,
)
);
// return_format
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',
)
);
}
/*
* 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;
}
/*
* 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_idval', $value );
$value = array_map( 'strval', $value );
// Parse single value for id.
} else {
$value = acf_idval( $value );
}
// Return value.
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;
}
}
// initialize
acf_register_field_type( 'acf_field_post_object' );
endif; // class_exists check

View File

@@ -0,0 +1,454 @@
<?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->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'] );
// choices
acf_render_field_setting(
$field,
array(
'label' => __( 'Choices', 'acf' ),
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br /><br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><br />' . __( 'red : Red', 'acf' ),
'type' => 'textarea',
'name' => 'choices',
)
);
// allow_null
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Null?', 'acf' ),
'instructions' => '',
'name' => 'allow_null',
'type' => 'true_false',
'ui' => 1,
)
);
// other_choice
acf_render_field_setting(
$field,
array(
'label' => __( 'Other', 'acf' ),
'instructions' => '',
'name' => 'other_choice',
'type' => 'true_false',
'ui' => 1,
'message' => __( "Add 'other' choice to allow for custom values", 'acf' ),
)
);
// save_other_choice
acf_render_field_setting(
$field,
array(
'label' => __( 'Save Other', 'acf' ),
'instructions' => '',
'name' => 'save_other_choice',
'type' => 'true_false',
'ui' => 1,
'message' => __( "Save 'other' values to the field's choices", 'acf' ),
'conditions' => array(
'field' => 'other_choice',
'operator' => '==',
'value' => 1,
),
)
);
// 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',
)
);
// layout
acf_render_field_setting(
$field,
array(
'label' => __( 'Layout', 'acf' ),
'instructions' => '',
'type' => 'radio',
'name' => 'layout',
'layout' => 'horizontal',
'choices' => array(
'vertical' => __( 'Vertical', 'acf' ),
'horizontal' => __( 'Horizontal', 'acf' ),
),
)
);
// return_format
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' ),
),
)
);
}
/*
* 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, true );
// 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 );
}
}
// initialize
acf_register_field_type( 'acf_field_radio' );
endif; // class_exists check

View File

@@ -0,0 +1,239 @@
<?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->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 ) {
// default_value
acf_render_field_setting(
$field,
array(
'label' => __( 'Default Value', 'acf' ),
'instructions' => __( 'Appears when creating a new post', 'acf' ),
'type' => 'number',
'name' => 'default_value',
)
);
// min
acf_render_field_setting(
$field,
array(
'label' => __( 'Minimum Value', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'min',
'placeholder' => '0',
)
);
// max
acf_render_field_setting(
$field,
array(
'label' => __( 'Maximum Value', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'max',
'placeholder' => '100',
)
);
// step
acf_render_field_setting(
$field,
array(
'label' => __( 'Step Size', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'step',
'placeholder' => '1',
)
);
// prepend
acf_render_field_setting(
$field,
array(
'label' => __( 'Prepend', 'acf' ),
'instructions' => __( 'Appears before the input', 'acf' ),
'type' => 'text',
'name' => 'prepend',
)
);
// append
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_range' );
endif; // class_exists check

View File

@@ -0,0 +1,810 @@
<?php
if ( ! class_exists( 'acf_field_relationship' ) ) :
class acf_field_relationship 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 = 'relationship';
$this->label = __( 'Relationship', 'acf' );
$this->category = 'relational';
$this->defaults = array(
'post_type' => array(),
'taxonomy' => array(),
'min' => 0,
'max' => 0,
'filters' => array( 'search', 'post_type', 'taxonomy' ),
'elements' => array(),
'return_format' => 'object',
);
// 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();
}
// 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 acf_esc_attr_e( $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 data-id="<?php echo esc_attr( $post->ID ); ?>" class="acf-rel-item">
<?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 ) {
// vars
$field['min'] = empty( $field['min'] ) ? '' : $field['min'];
$field['max'] = empty( $field['max'] ) ? '' : $field['max'];
// post_type
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' ),
)
);
// taxonomy
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' ),
)
);
// filters
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' ),
),
)
);
// filters
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' ),
),
)
);
// min
acf_render_field_setting(
$field,
array(
'label' => __( 'Minimum posts', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'min',
)
);
// max
acf_render_field_setting(
$field,
array(
'label' => __( 'Maximum posts', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'max',
)
);
// return_format
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',
)
);
}
/*
* 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;
}
/*
* update_value()
*
* This filter is applied 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_idval', $value );
$value = array_map( 'strval', $value );
// Parse single value for id.
} else {
$value = acf_idval( $value );
}
// Return value.
return $value;
}
}
// initialize
acf_register_field_type( 'acf_field_relationship' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,638 @@
<?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->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 ealry 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';
$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 );
}
/*
* 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;
}
// get choices
$choices = acf_get_array( $field['choices'] );
if ( empty( $field['choices'] ) ) {
return false;
}
// vars
$results = array();
$s = null;
// search
if ( $options['s'] !== '' ) {
// strip slashes (search may be integer)
$s = strval( $options['s'] );
$s = wp_unslash( $s );
}
// loop
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[] = array(
'id' => $k,
'text' => $v,
);
}
// vars
$response = array(
'results' => $results,
);
// 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 ) {
// 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'],
);
// 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'];
}
// 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'],
)
);
}
// 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 /><br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><br />' . __( 'red : Red', 'acf' ),
'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',
)
);
// allow_null
acf_render_field_setting(
$field,
array(
'label' => __( 'Allow Null?', 'acf' ),
'instructions' => '',
'name' => 'allow_null',
'type' => 'true_false',
'ui' => 1,
)
);
// multiple
acf_render_field_setting(
$field,
array(
'label' => __( 'Select multiple values?', 'acf' ),
'instructions' => '',
'name' => 'multiple',
'type' => 'true_false',
'ui' => 1,
)
);
// ui
acf_render_field_setting(
$field,
array(
'label' => __( 'Stylised UI', 'acf' ),
'instructions' => '',
'name' => 'ui',
'type' => 'true_false',
'ui' => 1,
)
);
// ajax
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,
),
)
);
// return_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Return Format', 'acf' ),
'instructions' => __( 'Specify the value returned', 'acf' ),
'type' => 'select',
'name' => 'return_format',
'choices' => array(
'value' => __( 'Value', 'acf' ),
'label' => __( 'Label', 'acf' ),
'array' => __( 'Both (Array)', 'acf' ),
),
)
);
}
/*
* 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 ealry 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;
}
}
// initialize
acf_register_field_type( 'acf_field_select' );
endif; // class_exists check

View File

@@ -0,0 +1,88 @@
<?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->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,167 @@
<?php
if ( ! class_exists( 'acf_field_tab' ) ) :
class acf_field_tab 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 = 'tab';
$this->label = __( 'Tab', 'acf' );
$this->category = 'layout';
$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'],
);
?>
<a <?php acf_esc_attr_e( $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' => __( 'Endpoint', 'acf' ),
'instructions' => __( 'Define an endpoint for the previous tabs to stop. This will start a new group of tabs.', '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,978 @@
<?php
if ( ! class_exists( 'acf_field_taxonomy' ) ) :
class acf_field_taxonomy extends acf_field {
// vars
var $save_post_terms = array();
/*
* __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 = 'taxonomy';
$this->label = __( 'Taxonomy', 'acf' );
$this->category = 'relational';
$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
);
// 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.
extract( acf_decode_post_id( $post_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;
}
/*
* 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 ) {
// vars
if ( is_array( $value ) ) {
$value = array_filter( $value );
}
// save_terms
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
return $value;
}
/*
* save_post
*
* This function will save any terms in the save_post_terms array
*
* @type function
* @date 26/11/2014
* @since 5.0.9
*
* @param $post_id (int)
* @return n/a
*/
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 discoraged, 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.
extract( acf_decode_post_id( $post_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 acf_esc_attr_e( $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 );
}
/*
* render_field_checkbox()
*
* 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_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' ), strtolower( $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 ) {
// default_value
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(),
)
);
// field_type
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' ),
),
),
)
);
// allow_null
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',
),
)
);
// add_term
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,
)
);
// save_terms
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,
)
);
// load_terms
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,
)
);
// return_format
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',
)
);
}
/*
* 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() {
// vars
$args = wp_parse_args(
$_POST,
array(
'nonce' => '',
'field_key' => '',
'term_name' => '',
'term_parent' => '',
)
);
// verify nonce
if ( ! acf_verify_ajax() ) {
die();
}
// load field
$field = acf_get_field( $args['field_key'] );
if ( ! $field ) {
die();
}
// vars
$taxonomy_obj = get_taxonomy( $field['taxonomy'] );
$taxonomy_label = $taxonomy_obj->labels->singular_name;
// validate cap
// note: this situation should never occur due to condition of the add new button
if ( ! current_user_can( $taxonomy_obj->cap->manage_terms ) ) {
wp_send_json_error(
array(
'error' => sprintf( __( 'User unable to add new %s', 'acf' ), $taxonomy_label ),
)
);
}
// save?
if ( $args['term_name'] ) {
// exists
if ( term_exists( $args['term_name'], $field['taxonomy'], $args['term_parent'] ) ) {
wp_send_json_error(
array(
'error' => sprintf( __( '%s already exists', 'acf' ), $taxonomy_label ),
)
);
}
// vars
$extra = array();
if ( $args['term_parent'] ) {
$extra['parent'] = (int) $args['term_parent'];
}
// insert
$data = wp_insert_term( $args['term_name'], $field['taxonomy'], $extra );
// error
if ( is_wp_error( $data ) ) {
wp_send_json_error(
array(
'error' => $data->get_error_message(),
)
);
}
// load term
$term = get_term( $data['term_id'] );
// prepend ancenstors count to term name
$prefix = '';
$ancestors = get_ancestors( $term->term_id, $term->taxonomy );
if ( ! empty( $ancestors ) ) {
$prefix = str_repeat( '- ', count( $ancestors ) );
}
// success
wp_send_json_success(
array(
'message' => sprintf( __( '%s added', 'acf' ), $taxonomy_label ),
'term_id' => $term->term_id,
'term_name' => $term->name,
'term_label' => $prefix . $term->name,
'term_parent' => $term->parent,
)
);
}
?>
<form method="post">
<?php
acf_render_field_wrap(
array(
'label' => __( 'Name', 'acf' ),
'name' => 'term_name',
'type' => 'text',
)
);
if ( is_taxonomy_hierarchical( $field['taxonomy'] ) ) {
$choices = array();
$response = $this->get_ajax_query( $args );
if ( $response ) {
foreach ( $response['results'] as $v ) {
$choices[ $v['id'] ] = $v['text'];
}
}
acf_render_field_wrap(
array(
'label' => __( 'Parent', 'acf' ),
'name' => 'term_parent',
'type' => 'select',
'allow_null' => 1,
'ui' => 0,
'choices' => $choices,
)
);
}
?>
<p class="acf-submit">
<button class="acf-submit-button button button-primary" type="submit"><?php _e( 'Add', 'acf' ); ?></button>
</p>
</form><?php
// die
die;
}
}
// initialize
acf_register_field_type( 'acf_field_taxonomy' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,182 @@
<?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->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 ];
}
}
$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 ) {
// 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',
)
);
// placeholder
acf_render_field_setting(
$field,
array(
'label' => __( 'Placeholder Text', 'acf' ),
'instructions' => __( 'Appears within the input', 'acf' ),
'type' => 'text',
'name' => 'placeholder',
)
);
// prepend
acf_render_field_setting(
$field,
array(
'label' => __( 'Prepend', 'acf' ),
'instructions' => __( 'Appears before the input', 'acf' ),
'type' => 'text',
'name' => 'prepend',
)
);
// append
acf_render_field_setting(
$field,
array(
'label' => __( 'Append', 'acf' ),
'instructions' => __( 'Appears after the input', 'acf' ),
'type' => 'text',
'name' => 'append',
)
);
// maxlength
acf_render_field_setting(
$field,
array(
'label' => __( 'Character Limit', 'acf' ),
'instructions' => __( 'Leave blank for no limit', 'acf' ),
'type' => 'number',
'name' => 'maxlength',
)
);
}
/**
* 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;
}
}
// initialize
acf_register_field_type( 'acf_field_text' );
endif; // class_exists check

View File

@@ -0,0 +1,235 @@
<?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->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 ) {
// default_value
acf_render_field_setting(
$field,
array(
'label' => __( 'Default Value', 'acf' ),
'instructions' => __( 'Appears when creating a new post', 'acf' ),
'type' => 'textarea',
'name' => 'default_value',
)
);
// placeholder
acf_render_field_setting(
$field,
array(
'label' => __( 'Placeholder Text', 'acf' ),
'instructions' => __( 'Appears within the input', 'acf' ),
'type' => 'text',
'name' => 'placeholder',
)
);
// maxlength
acf_render_field_setting(
$field,
array(
'label' => __( 'Character Limit', 'acf' ),
'instructions' => __( 'Leave blank for no limit', 'acf' ),
'type' => 'number',
'name' => 'maxlength',
)
);
// rows
acf_render_field_setting(
$field,
array(
'label' => __( 'Rows', 'acf' ),
'instructions' => __( 'Sets the textarea height', 'acf' ),
'type' => 'number',
'name' => 'rows',
'placeholder' => 8,
)
);
// formatting
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;
}
}
// initialize
acf_register_field_type( 'acf_field_textarea' );
endif; // class_exists check

View File

@@ -0,0 +1,177 @@
<?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 = 'jquery';
$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' => '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 acf_esc_attr_e( $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 ) {
// vars
$g_i_a = date_i18n( 'g:i a' );
$H_i_s = date_i18n( 'H:i:s' );
// display_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Display Format', 'acf' ),
'instructions' => __( '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>',
),
)
);
// return_format
acf_render_field_setting(
$field,
array(
'label' => __( 'Return Format', 'acf' ),
'instructions' => __( '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>',
),
)
);
}
/*
* 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'] );
}
}
// initialize
acf_register_field_type( 'acf_field_time_picker' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,296 @@
<?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->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 ) {
// message
acf_render_field_setting(
$field,
array(
'label' => __( 'Message', 'acf' ),
'instructions' => __( 'Displays text alongside the checkbox', 'acf' ),
'type' => 'text',
'name' => 'message',
)
);
// default_value
acf_render_field_setting(
$field,
array(
'label' => __( 'Default Value', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'default_value',
)
);
// ui
acf_render_field_setting(
$field,
array(
'label' => __( 'Stylised UI', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'ui',
'ui' => 1,
'class' => 'acf-field-object-true-false-ui',
)
);
// on_text
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,
),
)
);
// on_text
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,
),
)
);
}
/*
* 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;
}
}
// initialize
acf_register_field_type( 'acf_field_true_false' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,171 @@
<?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->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 ) {
// 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',
)
);
// placeholder
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;
}
}
// initialize
acf_register_field_type( 'acf_field_url' );
endif; // class_exists check

View File

@@ -0,0 +1,477 @@
<?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
*
* @param void
* @return void
*/
function initialize() {
// Props.
$this->name = 'user';
$this->label = __( 'User', 'acf' );
$this->category = 'relational';
$this->defaults = array(
'role' => '',
'multiple' => 0,
'allow_null' => 0,
'return_format' => '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' => __( 'Allow Null?', 'acf' ),
'instructions' => '',
'name' => 'allow_null',
'type' => 'true_false',
'ui' => 1,
)
);
acf_render_field_setting(
$field,
array(
'label' => __( 'Select multiple values?', 'acf' ),
'instructions' => '',
'name' => 'multiple',
'type' => 'true_false',
'ui' => 1,
)
);
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',
)
);
}
/**
* 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();
// 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.
*
* @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 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_idval', $value );
$value = array_map( 'strval', $value );
// Parse single value for id.
} else {
$value = acf_idval( $value );
}
// 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() {
// Modify Request args.
if ( isset( $_REQUEST['s'] ) ) {
$_REQUEST['search'] = $_REQUEST['s'];
}
if ( isset( $_REQUEST['paged'] ) ) {
$_REQUEST['page'] = $_REQUEST['paged'];
}
// 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.
if ( ! $query->field ) {
$query->send( new WP_Error( 'acf_missing_field', __( 'Error loading field.', '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;
}
}
// initialize
acf_register_field_type( 'ACF_Field_User' );
endif; // class_exists check

View File

@@ -0,0 +1,449 @@
<?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->defaults = array(
'tabs' => 'all',
'toolbar' => 'full',
'media_upload' => 1,
'default_value' => '',
'delay' => 0,
);
// 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' );
// WP < 4.7
if ( acf_version_compare( 'wp', '<', '4.7' ) ) {
$mce_buttons = array( 'bold', 'italic', 'strikethrough', 'bullist', 'numlist', 'blockquote', 'hr', 'alignleft', 'aligncenter', 'alignright', 'link', 'unlink', 'wp_more', 'spellchecker', 'fullscreen', 'wp_adv' );
$mce_buttons_2 = array( 'formatselect', 'underline', 'alignjustify', 'forecolor', 'pastetext', 'removeformat', 'charmap', 'outdent', 'indent', 'undo', 'redo', 'wp_help' );
}
// 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,
)
);
}
/*
* 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 ) {
// 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'] = 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 acf_esc_attr_e( $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 ) {
// vars
$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;
}
}
// default_value
acf_render_field_setting(
$field,
array(
'label' => __( 'Default Value', 'acf' ),
'instructions' => __( 'Appears when creating a new post', 'acf' ),
'type' => 'textarea',
'name' => 'default_value',
)
);
// tabs
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' ),
),
)
);
// toolbar
acf_render_field_setting(
$field,
array(
'label' => __( 'Toolbar', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'toolbar',
'choices' => $choices,
'conditions' => array(
'field' => 'tabs',
'operator' => '!=',
'value' => 'text',
),
)
);
// media_upload
acf_render_field_setting(
$field,
array(
'label' => __( 'Show Media Upload Buttons?', 'acf' ),
'instructions' => '',
'name' => 'media_upload',
'type' => 'true_false',
'ui' => 1,
)
);
// delay
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',
),
)
);
}
/*
* 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;
}
// apply filters
$value = apply_filters( 'acf_the_content', $value );
// follow the_content function in /wp-includes/post-template.php
$value = str_replace( ']]>', ']]&gt;', $value );
return $value;
}
}
// initialize
acf_register_field_type( 'acf_field_wysiwyg' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,275 @@
<?php
if ( ! class_exists( 'acf_field' ) ) :
class acf_field {
// vars
var $name = '',
$label = '',
$category = 'basic',
$defaults = array(),
$l10n = array(),
$public = true;
/*
* __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,
'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, 3 );
$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_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 );
}
/*
* 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;
}
}
endif; // class_exists check

View File

@@ -0,0 +1,236 @@
<?php
/*
* ACF Attachment Form Class
*
* All the logic for adding fields to attachments
*
* @class acf_form_attachment
* @package ACF
* @subpackage Forms
*/
if ( ! class_exists( 'acf_form_attachment' ) ) :
class acf_form_attachment {
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
// render
add_filter( 'attachment_fields_to_edit', array( $this, 'edit_attachment' ), 10, 2 );
// save
add_filter( 'attachment_fields_to_save', array( $this, 'save_attachment' ), 10, 2 );
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 26/01/13
* @since 3.6.0
*
* @param N/A
* @return N/A
*/
function admin_enqueue_scripts() {
// bail early if not valid screen
if ( ! acf_is_screen( array( 'attachment', 'upload' ) ) ) {
return;
}
// load acf scripts
acf_enqueue_scripts(
array(
'uploader' => true,
)
);
// actions
if ( acf_is_screen( 'upload' ) ) {
add_action( 'admin_footer', array( $this, 'admin_footer' ), 0 );
}
}
/*
* admin_footer
*
* This function will add acf_form_data to the WP 4.0 attachment grid
*
* @type action (admin_footer)
* @date 11/09/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_footer() {
// render post data
acf_form_data(
array(
'screen' => 'attachment',
'post_id' => 0,
)
);
?>
<script type="text/javascript">
// WP saves attachment on any input change, so unload is not needed
acf.unload.active = 0;
</script>
<?php
}
/*
* edit_attachment
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function edit_attachment( $form_fields, $post ) {
// vars
$is_page = acf_is_screen( 'attachment' );
$post_id = $post->ID;
$el = 'tr';
// get field groups
$field_groups = acf_get_field_groups(
array(
'attachment_id' => $post_id,
'attachment' => $post_id, // Leave for backwards compatibility
)
);
// render
if ( ! empty( $field_groups ) ) {
// get acf_form_data
ob_start();
acf_form_data(
array(
'screen' => 'attachment',
'post_id' => $post_id,
)
);
// open
echo '</td></tr>';
// loop
foreach ( $field_groups as $field_group ) {
// load fields
$fields = acf_get_fields( $field_group );
// override instruction placement for modal
if ( ! $is_page ) {
$field_group['instruction_placement'] = 'field';
}
// render
acf_render_fields( $fields, $post_id, $el, $field_group['instruction_placement'] );
}
// close
echo '<tr class="compat-field-acf-blank"><td>';
$html = ob_get_contents();
ob_end_clean();
$form_fields['acf-form-data'] = array(
'label' => '',
'input' => 'html',
'html' => $html,
);
}
// return
return $form_fields;
}
/*
* save_attachment
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function save_attachment( $post, $attachment ) {
// bail early if not valid nonce
if ( ! acf_verify_nonce( 'attachment' ) ) {
return $post;
}
// bypass validation for ajax
if ( acf_is_ajax( 'save-attachment-compat' ) ) {
acf_save_post( $post['ID'] );
// validate and save
} elseif ( acf_validate_save_post( true ) ) {
acf_save_post( $post['ID'] );
}
// return
return $post;
}
}
new acf_form_attachment();
endif;
?>

View File

@@ -0,0 +1,342 @@
<?php
/*
* ACF Comment Form Class
*
* All the logic for adding fields to comments
*
* @class acf_form_comment
* @package ACF
* @subpackage Forms
*/
if ( ! class_exists( 'acf_form_comment' ) ) :
class acf_form_comment {
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
// render
add_filter( 'comment_form_field_comment', array( $this, 'comment_form_field_comment' ), 999, 1 );
// add_action( 'comment_form_logged_in_after', array( $this, 'add_comment') );
// add_action( 'comment_form', array( $this, 'add_comment') );
// save
add_action( 'edit_comment', array( $this, 'save_comment' ), 10, 1 );
add_action( 'comment_post', array( $this, 'save_comment' ), 10, 1 );
}
/*
* validate_page
*
* This function will check if the current page is for a post/page edit form
*
* @type function
* @date 23/06/12
* @since 3.1.8
*
* @param n/a
* @return (boolean)
*/
function validate_page() {
// global
global $pagenow;
// validate page
if ( $pagenow == 'comment.php' ) {
return true;
}
// return
return false;
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 26/01/13
* @since 3.6.0
*
* @param n/a
* @return n/a
*/
function admin_enqueue_scripts() {
// validate page
if ( ! $this->validate_page() ) {
return;
}
// load acf scripts
acf_enqueue_scripts();
// actions
add_action( 'admin_footer', array( $this, 'admin_footer' ), 10, 1 );
add_action( 'add_meta_boxes_comment', array( $this, 'edit_comment' ), 10, 1 );
}
/*
* edit_comment
*
* This function is run on the admin comment.php page and will render the ACF fields within custom metaboxes to look native
*
* @type function
* @date 19/10/13
* @since 5.0.0
*
* @param $comment (object)
* @return n/a
*/
function edit_comment( $comment ) {
// vars
$post_id = "comment_{$comment->comment_ID}";
// get field groups
$field_groups = acf_get_field_groups(
array(
'comment' => get_post_type( $comment->comment_post_ID ),
)
);
// render
if ( ! empty( $field_groups ) ) {
// render post data
acf_form_data(
array(
'screen' => 'comment',
'post_id' => $post_id,
)
);
foreach ( $field_groups as $field_group ) {
// load fields
$fields = acf_get_fields( $field_group );
// vars
$o = array(
'id' => 'acf-' . $field_group['ID'],
'key' => $field_group['key'],
// 'style' => $field_group['style'],
'label' => $field_group['label_placement'],
'edit_url' => '',
'edit_title' => __( 'Edit field group', 'acf' ),
// 'visibility' => $visibility
);
// edit_url
if ( $field_group['ID'] && acf_current_user_can_admin() ) {
$o['edit_url'] = admin_url( 'post.php?post=' . $field_group['ID'] . '&action=edit' );
}
?>
<div id="acf-<?php echo $field_group['ID']; ?>" class="stuffbox">
<h3 class="hndle"><?php echo $field_group['title']; ?></h3>
<div class="inside">
<?php acf_render_fields( $fields, $post_id, 'div', $field_group['instruction_placement'] ); ?>
<script type="text/javascript">
if( typeof acf !== 'undefined' ) {
acf.newPostbox(<?php echo json_encode( $o ); ?>);
}
</script>
</div>
</div>
<?php
}
}
}
/*
* comment_form_field_comment
*
* description
*
* @type function
* @date 18/04/2016
* @since 5.3.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function comment_form_field_comment( $html ) {
// global
global $post;
// vars
$post_id = false;
// get field groups
$field_groups = acf_get_field_groups(
array(
'comment' => $post->post_type,
)
);
// bail early if no field groups
if ( ! $field_groups ) {
return $html;
}
// enqueue scripts
acf_enqueue_scripts();
// ob
ob_start();
// render post data
acf_form_data(
array(
'screen' => 'comment',
'post_id' => $post_id,
)
);
echo '<div class="acf-comment-fields acf-fields -clear">';
foreach ( $field_groups as $field_group ) {
$fields = acf_get_fields( $field_group );
acf_render_fields( $fields, $post_id, 'p', $field_group['instruction_placement'] );
}
echo '</div>';
// append
$html .= ob_get_contents();
ob_end_clean();
// return
return $html;
}
/*
* save_comment
*
* This function will save the comment data
*
* @type function
* @date 19/10/13
* @since 5.0.0
*
* @param comment_id (int)
* @return n/a
*/
function save_comment( $comment_id ) {
// bail early if not valid nonce
if ( ! acf_verify_nonce( 'comment' ) ) {
return $comment_id;
}
// kses
if ( isset( $_POST['acf'] ) ) {
$_POST['acf'] = wp_kses_post_deep( $_POST['acf'] );
}
// validate and save
if ( acf_validate_save_post( true ) ) {
acf_save_post( "comment_{$comment_id}" );
}
}
/*
* admin_footer
*
* description
*
* @type function
* @date 27/03/2015
* @since 5.1.5
*
* @param $post_id (int)
* @return $post_id (int)
*/
function admin_footer() {
?>
<script type="text/javascript">
(function($) {
// vars
var $spinner = $('#publishing-action .spinner');
// create spinner if not exists (may exist in future WP versions)
if( !$spinner.exists() ) {
// create spinner
$spinner = $('<span class="spinner"></span>');
// append
$('#publishing-action').prepend( $spinner );
}
})(jQuery);
</script>
<?php
}
}
new acf_form_comment();
endif;
?>

View File

@@ -0,0 +1,470 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'acf_form_customizer' ) ) :
class acf_form_customizer {
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// vars
$this->preview_values = array();
$this->preview_fields = array();
$this->preview_errors = array();
// actions
add_action( 'customize_controls_init', array( $this, 'customize_controls_init' ) );
add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ), 1, 1 );
add_action( 'customize_save', array( $this, 'customize_save' ), 1, 1 );
// save
add_filter( 'widget_update_callback', array( $this, 'save_widget' ), 10, 4 );
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 26/01/13
* @since 3.6.0
*
* @param N/A
* @return N/A
*/
function customize_controls_init() {
// load acf scripts
acf_enqueue_scripts(
array(
'context' => 'customize_controls',
)
);
// actions
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ), 1 );
}
/*
* save_widget
*
* This function will hook into the widget update filter and save ACF data
*
* @type function
* @date 27/05/2015
* @since 5.2.3
*
* @param $instance (array) widget settings
* @param $new_instance (array) widget settings
* @param $old_instance (array) widget settings
* @param $widget (object) widget info
* @return $instance
*/
function save_widget( $instance, $new_instance, $old_instance, $widget ) {
// bail ealry if not valid (customize + acf values + nonce)
if ( ! isset( $_POST['wp_customize'] ) || ! isset( $new_instance['acf'] ) || ! acf_verify_nonce( 'widget' ) ) {
return $instance;
}
// vars
$data = array(
'post_id' => "widget_{$widget->id}",
'values' => array(),
'fields' => array(),
);
// append values
$data['values'] = $new_instance['acf'];
// append fields (name => key relationship) - used later in 'acf/get_field_reference' for customizer previews
foreach ( $data['values'] as $k => $v ) {
// get field
$field = acf_get_field( $k );
// continue if no field
if ( ! $field ) {
continue;
}
// update
$data['fields'][ $field['name'] ] = $field['key'];
}
// append data to instance
$instance['acf'] = $data;
// return
return $instance;
}
/*
* settings
*
* This function will return an array of cutomizer settings that include ACF data
* similar to `$customizer->settings();`
*
* @type function
* @date 22/03/2016
* @since 5.3.2
*
* @param $customizer (object)
* @return $value (mixed)
*/
function settings( $customizer ) {
// vars
$data = array();
$settings = $customizer->settings();
// bail ealry if no settings
if ( empty( $settings ) ) {
return false;
}
// loop over settings
foreach ( $settings as $setting ) {
// vars
$id = $setting->id;
// verify settings type
if ( substr( $id, 0, 6 ) == 'widget' || substr( $id, 0, 7 ) == 'nav_menu' ) {
// allow
} else {
continue;
}
// get value
$value = $setting->post_value();
// bail early if no acf
if ( ! is_array( $value ) || ! isset( $value['acf'] ) ) {
continue;
}
// set data
$setting->acf = $value['acf'];
// append
$data[] = $setting;
}
// bail ealry if no settings
if ( empty( $data ) ) {
return false;
}
// return
return $data;
}
/*
* customize_preview_init
*
* This function is called when customizer preview is initialized
*
* @type function
* @date 22/03/2016
* @since 5.3.2
*
* @param $customizer (object)
* @return n/a
*/
function customize_preview_init( $customizer ) {
// get customizer settings (widgets)
$settings = $this->settings( $customizer );
// bail ealry if no settings
if ( empty( $settings ) ) {
return;
}
// append values
foreach ( $settings as $setting ) {
// get acf data
$data = $setting->acf;
// append acf_value to preview_values
$this->preview_values[ $data['post_id'] ] = $data['values'];
$this->preview_fields[ $data['post_id'] ] = $data['fields'];
}
// bail ealry if no preview_values
if ( empty( $this->preview_values ) ) {
return;
}
// add filters
add_filter( 'acf/pre_load_value', array( $this, 'pre_load_value' ), 10, 3 );
add_filter( 'acf/pre_load_reference', array( $this, 'pre_load_reference' ), 10, 3 );
}
/**
* pre_load_value
*
* Used to inject preview value
*
* @date 2/2/18
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
function pre_load_value( $value, $post_id, $field ) {
// check
if ( isset( $this->preview_values[ $post_id ][ $field['key'] ] ) ) {
return $this->preview_values[ $post_id ][ $field['key'] ];
}
// return
return $value;
}
/**
* pre_load_reference
*
* Used to inject preview value
*
* @date 2/2/18
* @since 5.6.5
*
* @param type $var Description. Default.
* @return type Description.
*/
function pre_load_reference( $field_key, $field_name, $post_id ) {
// check
if ( isset( $this->preview_fields[ $post_id ][ $field_name ] ) ) {
return $this->preview_fields[ $post_id ][ $field_name ];
}
// return
return $field_key;
}
/*
* customize_save
*
* This function is called when customizer saves a widget.
* Normally, the widget_update_callback filter would be used, but the customizer disables this and runs a custom action
* class-customizer-settings.php will save the widget data via the function set_root_value which uses update_option
*
* @type function
* @date 22/03/2016
* @since 5.3.2
*
* @param $customizer (object)
* @return n/a
*/
function customize_save( $customizer ) {
// get customizer settings (widgets)
$settings = $this->settings( $customizer );
// bail ealry if no settings
if ( empty( $settings ) ) {
return;
}
// append values
foreach ( $settings as $setting ) {
// get acf data
$data = $setting->acf;
// save acf data
acf_save_post( $data['post_id'], $data['values'] );
// remove [acf] data from saved widget array
$id_data = $setting->id_data();
add_filter( 'pre_update_option_' . $id_data['base'], array( $this, 'pre_update_option' ), 10, 3 );
}
}
/*
* pre_update_option
*
* this function will remove the [acf] data from widget insance
*
* @type function
* @date 22/03/2016
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
function pre_update_option( $value, $option, $old_value ) {
// bail ealry if no value
if ( empty( $value ) ) {
return $value;
}
// loop over widgets
// WP saves all widgets (of the same type) as an array of widgets
foreach ( $value as $i => $widget ) {
// bail ealry if no acf
if ( ! isset( $widget['acf'] ) ) {
continue;
}
// remove widget
unset( $value[ $i ]['acf'] );
}
// return
return $value;
}
/*
* admin_footer
*
* This function will add some custom HTML to the footer of the edit page
*
* @type function
* @date 11/06/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_footer() {
?>
<script type="text/javascript">
(function($) {
// customizer saves widget on any input change, so unload is not needed
acf.unload.active = 0;
// hack customizer function to remove bug caused by WYSIWYG field using aunique ID
// customizer compares returned AJAX HTML with the HTML of the widget form.
// the _getInputsSignature() function is used to generate a string based of input name + id.
// because ACF generates a unique ID on the WYSIWYG field, this string will not match causing the preview function to bail.
// an attempt was made to remove the WYSIWYG unique ID, but this caused multiple issues in the wp-admin and altimately doesn't make sense with the tinymce rule that all editors must have a unique ID.
// source: wp-admin/js/customize-widgets.js
// vars
var WidgetControl = wp.customize.Widgets.WidgetControl.prototype;
// backup functions
WidgetControl.__getInputsSignature = WidgetControl._getInputsSignature;
WidgetControl.__setInputState = WidgetControl._setInputState;
// modify __getInputsSignature
WidgetControl._getInputsSignature = function( inputs ) {
// vars
var signature = this.__getInputsSignature( inputs );
safe = [];
// split
signature = signature.split(';');
// loop
for( var i in signature ) {
// vars
var bit = signature[i];
// bail ealry if acf is found
if( bit.indexOf('acf') !== -1 ) continue;
// append
safe.push( bit );
}
// update
signature = safe.join(';');
// return
return signature;
};
// modify _setInputState
// this function deosn't seem to run on widget title/content, only custom fields
// either way, this function is not needed and will break ACF fields
WidgetControl._setInputState = function( input, state ) {
return true;
};
})(jQuery);
</script>
<?php
}
}
new acf_form_customizer();
endif;
?>

View File

@@ -0,0 +1,641 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'acf_form_front' ) ) :
class acf_form_front {
/** @var array An array of registered form settings */
private $forms = array();
/** @var array An array of default fields */
public $fields = array();
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// vars
$this->fields = array(
'_post_title' => array(
'prefix' => 'acf',
'name' => '_post_title',
'key' => '_post_title',
'label' => __( 'Title', 'acf' ),
'type' => 'text',
'required' => true,
),
'_post_content' => array(
'prefix' => 'acf',
'name' => '_post_content',
'key' => '_post_content',
'label' => __( 'Content', 'acf' ),
'type' => 'wysiwyg',
),
'_validate_email' => array(
'prefix' => 'acf',
'name' => '_validate_email',
'key' => '_validate_email',
'label' => __( 'Validate Email', 'acf' ),
'type' => 'text',
'value' => '',
'wrapper' => array( 'style' => 'display:none !important;' ),
),
);
// actions
add_action( 'acf/validate_save_post', array( $this, 'validate_save_post' ), 1 );
// filters
add_filter( 'acf/pre_save_post', array( $this, 'pre_save_post' ), 5, 2 );
}
/*
* validate_form
*
* description
*
* @type function
* @date 28/2/17
* @since 5.5.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function validate_form( $args ) {
// defaults
// Todo: Allow message and button text to be generated by CPT settings.
$args = wp_parse_args(
$args,
array(
'id' => 'acf-form',
'post_id' => false,
'new_post' => false,
'field_groups' => false,
'fields' => false,
'post_title' => false,
'post_content' => false,
'form' => true,
'form_attributes' => array(),
'return' => add_query_arg( 'updated', 'true', acf_get_current_url() ),
'html_before_fields' => '',
'html_after_fields' => '',
'submit_value' => __( 'Update', 'acf' ),
'updated_message' => __( 'Post updated', 'acf' ),
'label_placement' => 'top',
'instruction_placement' => 'label',
'field_el' => 'div',
'uploader' => 'wp',
'honeypot' => true,
'html_updated_message' => '<div id="message" class="updated"><p>%s</p></div>', // 5.5.10
'html_submit_button' => '<input type="submit" class="acf-button button button-primary button-large" value="%s" />', // 5.5.10
'html_submit_spinner' => '<span class="acf-spinner"></span>', // 5.5.10
'kses' => true, // 5.6.5
)
);
$args['form_attributes'] = wp_parse_args(
$args['form_attributes'],
array(
'id' => $args['id'],
'class' => 'acf-form',
'action' => '',
'method' => 'post',
)
);
// filter post_id
$args['post_id'] = acf_get_valid_post_id( $args['post_id'] );
// new post?
if ( $args['post_id'] === 'new_post' ) {
$args['new_post'] = wp_parse_args(
$args['new_post'],
array(
'post_type' => 'post',
'post_status' => 'draft',
)
);
}
// filter
$args = apply_filters( 'acf/validate_form', $args );
// return
return $args;
}
/*
* add_form
*
* description
*
* @type function
* @date 28/2/17
* @since 5.5.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function add_form( $args = array() ) {
// validate
$args = $this->validate_form( $args );
// append
$this->forms[ $args['id'] ] = $args;
}
/*
* get_form
*
* description
*
* @type function
* @date 28/2/17
* @since 5.5.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function get_form( $id = '' ) {
// bail early if not set
if ( ! isset( $this->forms[ $id ] ) ) {
return false;
}
// return
return $this->forms[ $id ];
}
/*
* validate_save_post
*
* This function will validate fields from the above array
*
* @type function
* @date 7/09/2016
* @since 5.4.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function validate_save_post() {
// register field if isset in $_POST
foreach ( $this->fields as $k => $field ) {
// bail early if no in $_POST
if ( ! isset( $_POST['acf'][ $k ] ) ) {
continue;
}
// register
acf_add_local_field( $field );
}
// honeypot
if ( ! empty( $_POST['acf']['_validate_email'] ) ) {
acf_add_validation_error( '', __( 'Spam Detected', 'acf' ) );
}
}
/*
* pre_save_post
*
* description
*
* @type function
* @date 7/09/2016
* @since 5.4.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function pre_save_post( $post_id, $form ) {
// vars
$save = array(
'ID' => 0,
);
// determine save data
if ( is_numeric( $post_id ) ) {
// update post
$save['ID'] = $post_id;
} elseif ( $post_id == 'new_post' ) {
// merge in new post data
$save = array_merge( $save, $form['new_post'] );
} else {
// not post
return $post_id;
}
// save post_title
if ( isset( $_POST['acf']['_post_title'] ) ) {
$save['post_title'] = acf_extract_var( $_POST['acf'], '_post_title' );
}
// save post_content
if ( isset( $_POST['acf']['_post_content'] ) ) {
$save['post_content'] = acf_extract_var( $_POST['acf'], '_post_content' );
}
// honeypot
if ( ! empty( $_POST['acf']['_validate_email'] ) ) {
return false;
}
// validate
if ( count( $save ) == 1 ) {
return $post_id;
}
// save
if ( $save['ID'] ) {
wp_update_post( $save );
} else {
$post_id = wp_insert_post( $save );
}
// return
return $post_id;
}
/*
* enqueue
*
* This function will enqueue a form
*
* @type function
* @date 7/09/2016
* @since 5.4.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function enqueue_form() {
// check
$this->check_submit_form();
// load acf scripts
acf_enqueue_scripts();
}
/*
* check_submit_form
*
* This function will maybe submit form data
*
* @type function
* @date 3/3/17
* @since 5.5.10
*
* @param n/a
* @return n/a
*/
function check_submit_form() {
// Verify nonce.
if ( ! acf_verify_nonce( 'acf_form' ) ) {
return false;
}
// Confirm form was submit.
if ( ! isset( $_POST['_acf_form'] ) ) {
return false;
}
// Load registered form using id.
$form = $this->get_form( $_POST['_acf_form'] );
// Fallback to encrypted JSON.
if ( ! $form ) {
$form = json_decode( acf_decrypt( $_POST['_acf_form'] ), true );
if ( ! $form ) {
return false;
}
}
// Run kses on all $_POST data.
if ( $form['kses'] && isset( $_POST['acf'] ) ) {
$_POST['acf'] = wp_kses_post_deep( $_POST['acf'] );
}
// Validate data and show errors.
// Todo: Return WP_Error and show above form, keeping input values.
acf_validate_save_post( true );
// Submit form.
$this->submit_form( $form );
}
/*
* submit_form
*
* This function will submit form data
*
* @type function
* @date 3/3/17
* @since 5.5.10
*
* @param n/a
* @return n/a
*/
function submit_form( $form ) {
// filter
$form = apply_filters( 'acf/pre_submit_form', $form );
// vars
$post_id = acf_maybe_get( $form, 'post_id', 0 );
// add global for backwards compatibility
$GLOBALS['acf_form'] = $form;
// allow for custom save
$post_id = apply_filters( 'acf/pre_save_post', $post_id, $form );
// save
acf_save_post( $post_id );
// restore form (potentially modified)
$form = $GLOBALS['acf_form'];
// action
do_action( 'acf/submit_form', $form, $post_id );
// vars
$return = acf_maybe_get( $form, 'return', '' );
// redirect
if ( $return ) {
// update %placeholders%
$return = str_replace( '%post_id%', $post_id, $return );
$return = str_replace( '%post_url%', get_permalink( $post_id ), $return );
// redirect
wp_redirect( $return );
exit;
}
}
/*
* render
*
* description
*
* @type function
* @date 7/09/2016
* @since 5.4.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function render_form( $args = array() ) {
// Vars.
$is_registered = false;
$field_groups = array();
$fields = array();
// Allow form settings to be directly provided.
if ( is_array( $args ) ) {
$args = $this->validate_form( $args );
// Otherwise, lookup registered form.
} else {
$is_registered = true;
$args = $this->get_form( $args );
if ( ! $args ) {
return false;
}
}
// Extract vars.
$post_id = $args['post_id'];
// Prevent ACF from loading values for "new_post".
if ( $post_id === 'new_post' ) {
$post_id = false;
}
// Set uploader type.
acf_update_setting( 'uploader', $args['uploader'] );
// Register local fields.
foreach ( $this->fields as $k => $field ) {
acf_add_local_field( $field );
}
// Append post_title field.
if ( $args['post_title'] ) {
$_post_title = acf_get_field( '_post_title' );
$_post_title['value'] = $post_id ? get_post_field( 'post_title', $post_id ) : '';
$fields[] = $_post_title;
}
// Append post_content field.
if ( $args['post_content'] ) {
$_post_content = acf_get_field( '_post_content' );
$_post_content['value'] = $post_id ? get_post_field( 'post_content', $post_id ) : '';
$fields[] = $_post_content;
}
// Load specific fields.
if ( $args['fields'] ) {
// Lookup fields using $strict = false for better compatibility with field names.
foreach ( $args['fields'] as $selector ) {
$fields[] = acf_maybe_get_field( $selector, $post_id, false );
}
// Load specific field groups.
} elseif ( $args['field_groups'] ) {
foreach ( $args['field_groups'] as $selector ) {
$field_groups[] = acf_get_field_group( $selector );
}
// Load fields for the given "new_post" args.
} elseif ( $args['post_id'] == 'new_post' ) {
$field_groups = acf_get_field_groups( $args['new_post'] );
// Load fields for the given "post_id" arg.
} else {
$field_groups = acf_get_field_groups(
array(
'post_id' => $args['post_id'],
)
);
}
// load fields from the found field groups.
if ( $field_groups ) {
foreach ( $field_groups as $field_group ) {
$_fields = acf_get_fields( $field_group );
if ( $_fields ) {
foreach ( $_fields as $_field ) {
$fields[] = $_field;
}
}
}
}
// Add honeypot field.
if ( $args['honeypot'] ) {
$fields[] = acf_get_field( '_validate_email' );
}
// Display updated_message
if ( ! empty( $_GET['updated'] ) && $args['updated_message'] ) {
printf( $args['html_updated_message'], $args['updated_message'] );
}
// display form
if ( $args['form'] ) : ?>
<form <?php echo acf_esc_attrs( $args['form_attributes'] ); ?>>
<?php
endif;
// Render hidde form data.
acf_form_data(
array(
'screen' => 'acf_form',
'post_id' => $args['post_id'],
'form' => $is_registered ? $args['id'] : acf_encrypt( json_encode( $args ) ),
)
);
?>
<div class="acf-fields acf-form-fields -<?php echo esc_attr( $args['label_placement'] ); ?>">
<?php echo $args['html_before_fields']; ?>
<?php acf_render_fields( $fields, $post_id, $args['field_el'], $args['instruction_placement'] ); ?>
<?php echo $args['html_after_fields']; ?>
</div>
<?php if ( $args['form'] ) : ?>
<div class="acf-form-submit">
<?php printf( $args['html_submit_button'], $args['submit_value'] ); ?>
<?php echo $args['html_submit_spinner']; ?>
</div>
</form>
<?php endif;
}
}
// initialize
acf()->form_front = new acf_form_front();
endif; // class_exists check
/*
* Functions
*
* alias of acf()->form->functions
*
* @type function
* @date 11/06/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function acf_form_head() {
acf()->form_front->enqueue_form();
}
function acf_form( $args = array() ) {
acf()->form_front->render_form( $args );
}
function acf_get_form( $id = '' ) {
return acf()->form_front->get_form( $id );
}
function acf_register_form( $args ) {
acf()->form_front->add_form( $args );
}
?>

View File

@@ -0,0 +1,183 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'ACF_Form_Gutenberg' ) ) :
class ACF_Form_Gutenberg {
/**
* __construct
*
* Setup for class functionality.
*
* @date 13/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function __construct() {
// Add actions.
add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_block_editor_assets' ) );
// Ignore validation during meta-box-loader AJAX request.
add_action( 'acf/validate_save_post', array( $this, 'acf_validate_save_post' ), 999 );
}
/**
* enqueue_block_editor_assets
*
* Allows a safe way to customize Guten-only functionality.
*
* @date 14/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function enqueue_block_editor_assets() {
// Remove edit_form_after_title.
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 20, 0 );
// Call edit_form_after_title manually.
add_action( 'block_editor_meta_box_hidden_fields', array( $this, 'block_editor_meta_box_hidden_fields' ) );
// Cusotmize editor metaboxes.
add_filter( 'filter_block_editor_meta_boxes', array( $this, 'filter_block_editor_meta_boxes' ) );
}
/**
* add_meta_boxes
*
* Modify screen for Gutenberg.
*
* @date 13/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function add_meta_boxes() {
// Remove 'edit_form_after_title' action.
remove_action( 'edit_form_after_title', array( acf_get_instance( 'ACF_Form_Post' ), 'edit_form_after_title' ) );
}
/**
* block_editor_meta_box_hidden_fields
*
* Modify screen for Gutenberg.
*
* @date 13/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function block_editor_meta_box_hidden_fields() {
// Manually call 'edit_form_after_title' function.
acf_get_instance( 'ACF_Form_Post' )->edit_form_after_title();
}
/**
* filter_block_editor_meta_boxes
*
* description
*
* @date 5/4/19
* @since 5.7.14
*
* @param type $var Description. Default.
* @return type Description.
*/
function filter_block_editor_meta_boxes( $wp_meta_boxes ) {
// Globals
global $current_screen;
// Move 'acf_after_title' metaboxes into 'normal' location.
if ( isset( $wp_meta_boxes[ $current_screen->id ]['acf_after_title'] ) ) {
// Extract locations.
$locations = $wp_meta_boxes[ $current_screen->id ];
// Ensure normal location exists.
if ( ! isset( $locations['normal'] ) ) {
$locations['normal'] = array();
}
if ( ! isset( $locations['normal']['high'] ) ) {
$locations['normal']['high'] = array();
}
// Append metaboxes.
foreach ( $locations['acf_after_title'] as $priority => $meta_boxes ) {
$locations['normal']['high'] = array_merge( $meta_boxes, $locations['normal']['high'] );
}
// Update original data.
$wp_meta_boxes[ $current_screen->id ] = $locations;
unset( $wp_meta_boxes[ $current_screen->id ]['acf_after_title'] );
// Avoid conflicts with saved metabox order.
add_filter( 'get_user_option_meta-box-order_' . $current_screen->id, array( $this, 'modify_user_option_meta_box_order' ) );
}
// Return
return $wp_meta_boxes;
}
/**
* modify_user_option_meta_box_order
*
* Filters the `meta-box-order_{$post_type}` value by prepending "acf_after_title" data to "normal".
* Fixes a bug where metaboxes with position "acf_after_title" do not appear in the block editor.
*
* @date 11/7/19
* @since 5.8.2
*
* @param array $stored_meta_box_order User's existing meta box order.
* @return array Modified array with meta boxes moved around.
*/
function modify_user_option_meta_box_order( $locations ) {
if ( ! empty( $locations['acf_after_title'] ) ) {
if ( ! empty( $locations['normal'] ) ) {
$locations['normal'] = $locations['acf_after_title'] . ',' . $locations['normal'];
} else {
$locations['normal'] = $locations['acf_after_title'];
}
unset( $locations['acf_after_title'] );
}
return $locations;
}
/**
* acf_validate_save_post
*
* Ignore errors during the Gutenberg "save metaboxes" AJAX request.
* Allows data to save and prevent UX issues.
*
* @date 16/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function acf_validate_save_post() {
// Check if current request came from Gutenberg.
if ( isset( $_GET['meta-box-loader'] ) ) {
acf_reset_validation_errors();
}
}
}
acf_new_instance( 'ACF_Form_Gutenberg' );
endif;

View File

@@ -0,0 +1,400 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'acf_form_nav_menu' ) ) :
class acf_form_nav_menu {
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'wp_update_nav_menu', array( $this, 'update_nav_menu' ) );
add_action( 'acf/validate_save_post', array( $this, 'acf_validate_save_post' ), 5 );
add_action( 'wp_nav_menu_item_custom_fields', array( $this, 'wp_nav_menu_item_custom_fields' ), 10, 5 );
// filters
add_filter( 'wp_get_nav_menu_items', array( $this, 'wp_get_nav_menu_items' ), 10, 3 );
add_filter( 'wp_edit_nav_menu_walker', array( $this, 'wp_edit_nav_menu_walker' ), 10, 2 );
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 26/01/13
* @since 3.6.0
*
* @param N/A
* @return N/A
*/
function admin_enqueue_scripts() {
// validate screen
if ( ! acf_is_screen( 'nav-menus' ) ) {
return;
}
// load acf scripts
acf_enqueue_scripts();
// actions
add_action( 'admin_footer', array( $this, 'admin_footer' ), 1 );
}
/**
* wp_nav_menu_item_custom_fields
*
* description
*
* @date 30/7/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function wp_nav_menu_item_custom_fields( $item_id, $item, $depth, $args, $id = '' ) {
// vars
$prefix = "menu-item-acf[$item_id]";
// get field groups
$field_groups = acf_get_field_groups(
array(
'nav_menu_item' => $item->type,
'nav_menu_item_id' => $item_id,
'nav_menu_item_depth' => $depth,
)
);
// render
if ( ! empty( $field_groups ) ) {
// open
echo '<div class="acf-menu-item-fields acf-fields -clear">';
// loop
foreach ( $field_groups as $field_group ) {
// load fields
$fields = acf_get_fields( $field_group );
// bail if not fields
if ( empty( $fields ) ) {
continue;
}
// change prefix
acf_prefix_fields( $fields, $prefix );
// render
acf_render_fields( $fields, $item_id, 'div', $field_group['instruction_placement'] );
}
// close
echo '</div>';
// Trigger append for newly created menu item (via AJAX)
if ( acf_is_ajax( 'add-menu-item' ) ) : ?>
<script type="text/javascript">
(function($) {
acf.doAction('append', $('#menu-item-settings-<?php echo $item_id; ?>') );
})(jQuery);
</script>
<?php
endif;
}
}
/*
* update_nav_menu
*
* description
*
* @type function
* @date 26/5/17
* @since 5.6.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function update_nav_menu( $menu_id ) {
// vars
$post_id = 'term_' . $menu_id;
// verify and remove nonce
if ( ! acf_verify_nonce( 'nav_menu' ) ) {
return $menu_id;
}
// validate and show errors
acf_validate_save_post( true );
// save
acf_save_post( $post_id );
// save nav menu items
$this->update_nav_menu_items( $menu_id );
}
/*
* update_nav_menu_items
*
* description
*
* @type function
* @date 26/5/17
* @since 5.6.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function update_nav_menu_items( $menu_id ) {
// bail ealry if not set
if ( empty( $_POST['menu-item-acf'] ) ) {
return;
}
// loop
foreach ( $_POST['menu-item-acf'] as $post_id => $values ) {
acf_save_post( $post_id, $values );
}
}
/**
* wp_get_nav_menu_items
*
* WordPress does not provide an easy way to find the current menu being edited.
* This function listens to when a menu's items are loaded and stores the menu.
* Needed on nav-menus.php page for new menu with no items
*
* @date 23/2/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function wp_get_nav_menu_items( $items, $menu, $args ) {
acf_set_data( 'nav_menu_id', $menu->term_id );
return $items;
}
/**
* Called when WP renders a menu edit form.
* Used to set global data and customize the Walker class.
*
* @date 26/5/17
* @since 5.6.0
*
* @param string $class The walker class to use. Default 'Walker_Nav_Menu_Edit'.
* @param int $menu_id ID of the menu being rendered.
* @return string
*/
function wp_edit_nav_menu_walker( $class, $menu_id = 0 ) {
// update data (needed for ajax location rules to work)
acf_set_data( 'nav_menu_id', $menu_id );
// Use custom walker class to inject "wp_nav_menu_item_custom_fields" action prioir to WP 5.4.
if ( acf_version_compare( 'wp', '<', '5.3.99' ) ) {
acf_include( 'includes/walkers/class-acf-walker-nav-menu-edit.php' );
return 'ACF_Walker_Nav_Menu_Edit';
}
// Return class.
return $class;
}
/*
* acf_validate_save_post
*
* This function will loop over $_POST data and validate
*
* @type action 'acf/validate_save_post' 5
* @date 7/09/2016
* @since 5.4.0
*
* @param n/a
* @return n/a
*/
function acf_validate_save_post() {
// bail ealry if not set
if ( empty( $_POST['menu-item-acf'] ) ) {
return;
}
// loop
foreach ( $_POST['menu-item-acf'] as $post_id => $values ) {
// vars
$prefix = 'menu-item-acf[' . $post_id . ']';
// validate
acf_validate_values( $values, $prefix );
}
}
/*
* admin_footer
*
* This function will add some custom HTML to the footer of the edit page
*
* @type function
* @date 11/06/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_footer() {
// vars
$nav_menu_id = acf_get_data( 'nav_menu_id' );
$post_id = 'term_' . $nav_menu_id;
// get field groups
$field_groups = acf_get_field_groups(
array(
'nav_menu' => $nav_menu_id,
)
);
?>
<div id="tmpl-acf-menu-settings" style="display: none;">
<?php
// data (always needed to save nav menu items)
acf_form_data(
array(
'screen' => 'nav_menu',
'post_id' => $post_id,
'ajax' => 1,
)
);
// render
if ( ! empty( $field_groups ) ) {
// loop
foreach ( $field_groups as $field_group ) {
$fields = acf_get_fields( $field_group );
echo '<div class="acf-menu-settings -' . $field_group['style'] . '">';
echo '<h2>' . $field_group['title'] . '</h2>';
echo '<div class="acf-fields -left -clear">';
acf_render_fields( $fields, $post_id, 'div', $field_group['instruction_placement'] );
echo '</div>';
echo '</div>';
}
}
?>
</div>
<script type="text/javascript">
(function($) {
// append html
$('#post-body-content').append( $('#tmpl-acf-menu-settings').html() );
// avoid WP over-writing $_POST data
// - https://core.trac.wordpress.org/ticket/41502#ticket
$(document).on('submit', '#update-nav-menu', function() {
// vars
var $form = $(this);
var $input = $('input[name="nav-menu-data"]');
// decode json
var json = $form.serializeArray();
var json2 = [];
// loop
$.each( json, function( i, pair ) {
// avoid nesting (unlike WP)
if( pair.name === 'nav-menu-data' ) return;
// bail early if is 'acf[' input
if( pair.name.indexOf('acf[') > -1 ) return;
// append
json2.push( pair );
});
// update
$input.val( JSON.stringify(json2) );
});
})(jQuery);
</script>
<?php
}
}
acf_new_instance( 'acf_form_nav_menu' );
endif;
?>

View File

@@ -0,0 +1,339 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Form_Post' ) ) :
class ACF_Form_Post {
/** @var string The first field groups style CSS. */
var $style = '';
/**
* __construct
*
* Sets up the class functionality.
*
* @date 5/03/2014
* @since 5.0.0
*
* @param void
* @return void
*/
function __construct() {
// initialize on post edit screens
add_action( 'load-post.php', array( $this, 'initialize' ) );
add_action( 'load-post-new.php', array( $this, 'initialize' ) );
// save
add_filter( 'wp_insert_post_empty_content', array( $this, 'wp_insert_post_empty_content' ), 10, 2 );
add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
}
/**
* initialize
*
* Sets up Form functionality.
*
* @date 19/9/18
* @since 5.7.6
*
* @param void
* @return void
*/
function initialize() {
// globals
global $typenow;
// restrict specific post types
$restricted = array( 'acf-field-group', 'attachment' );
if ( in_array( $typenow, $restricted ) ) {
return;
}
// enqueue scripts
acf_enqueue_scripts(
array(
'uploader' => true,
)
);
// actions
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
}
/**
* add_meta_boxes
*
* Adds ACF metaboxes for the given $post_type and $post.
*
* @date 19/9/18
* @since 5.7.6
*
* @param string $post_type The post type.
* @param WP_Post $post The post being edited.
* @return void
*/
function add_meta_boxes( $post_type, $post ) {
// Storage for localized postboxes.
$postboxes = array();
// Get field groups for this screen.
$field_groups = acf_get_field_groups(
array(
'post_id' => $post->ID,
'post_type' => $post_type,
)
);
// Loop over field groups.
if ( $field_groups ) {
foreach ( $field_groups as $field_group ) {
// vars
$id = "acf-{$field_group['key']}"; // acf-group_123
$title = $field_group['title']; // Group 1
$context = $field_group['position']; // normal, side, acf_after_title
$priority = 'high'; // high, core, default, low
// Reduce priority for sidebar metaboxes for best position.
if ( $context == 'side' ) {
$priority = 'core';
}
/**
* Filters the metabox priority.
*
* @date 23/06/12
* @since 3.1.8
*
* @param string $priority The metabox priority (high, core, default, low).
* @param array $field_group The field group array.
*/
$priority = apply_filters( 'acf/input/meta_box_priority', $priority, $field_group );
// Localize data
$postboxes[] = array(
'id' => $id,
'key' => $field_group['key'],
'style' => $field_group['style'],
'label' => $field_group['label_placement'],
'edit' => acf_get_field_group_edit_link( $field_group['ID'] ),
);
// Add the meta box.
add_meta_box( $id, acf_esc_html( $title ), array( $this, 'render_meta_box' ), $post_type, $context, $priority, array( 'field_group' => $field_group ) );
}
// Set style from first field group.
$this->style = acf_get_field_group_style( $field_groups[0] );
// Localize postboxes.
acf_localize_data(
array(
'postboxes' => $postboxes,
)
);
}
// remove postcustom metabox (removes expensive SQL query)
if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
remove_meta_box( 'postcustom', false, 'normal' );
}
// Add hidden input fields.
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ) );
/**
* Fires after metaboxes have been added.
*
* @date 13/12/18
* @since 5.8.0
*
* @param string $post_type The post type.
* @param WP_Post $post The post being edited.
* @param array $field_groups The field groups added.
*/
do_action( 'acf/add_meta_boxes', $post_type, $post, $field_groups );
}
/**
* edit_form_after_title
*
* Called after the title adn before the content editor.
*
* @date 19/9/18
* @since 5.7.6
*
* @param void
* @return void
*/
function edit_form_after_title() {
// globals
global $post, $wp_meta_boxes;
// render post data
acf_form_data(
array(
'screen' => 'post',
'post_id' => $post->ID,
)
);
// render 'acf_after_title' metaboxes
do_meta_boxes( get_current_screen(), 'acf_after_title', $post );
// render dynamic field group style
echo '<style type="text/css" id="acf-style">' . $this->style . '</style>';
}
/**
* render_meta_box
*
* Renders the ACF metabox HTML.
*
* @date 19/9/18
* @since 5.7.6
*
* @param WP_Post $post The post being edited.
* @param array metabox The add_meta_box() args.
* @return void
*/
function render_meta_box( $post, $metabox ) {
// vars
$id = $metabox['id'];
$field_group = $metabox['args']['field_group'];
// Render fields.
$fields = acf_get_fields( $field_group );
acf_render_fields( $fields, $post->ID, 'div', $field_group['instruction_placement'] );
}
/**
* wp_insert_post_empty_content
*
* Allows WP to insert a new post without title or post_content if ACF data exists.
*
* @date 16/07/2014
* @since 5.0.1
*
* @param bool $maybe_empty Whether the post should be considered "empty".
* @param array $postarr Array of post data.
* @return bool
*/
function wp_insert_post_empty_content( $maybe_empty, $postarr ) {
// return false and allow insert if '_acf_changed' exists
if ( $maybe_empty && acf_maybe_get_POST( '_acf_changed' ) ) {
return false;
}
// return
return $maybe_empty;
}
/*
* allow_save_post
*
* Checks if the $post is allowed to be saved.
* Used to avoid triggering "acf/save_post" on dynamically created posts during save.
*
* @type function
* @date 26/06/2016
* @since 5.3.8
*
* @param WP_Post $post The post to check.
* @return bool
*/
function allow_save_post( $post ) {
// vars
$allow = true;
// restrict post types
$restrict = array( 'auto-draft', 'revision', 'acf-field', 'acf-field-group' );
if ( in_array( $post->post_type, $restrict ) ) {
$allow = false;
}
// disallow if the $_POST ID value does not match the $post->ID
$form_post_id = (int) acf_maybe_get_POST( 'post_ID' );
if ( $form_post_id && $form_post_id !== $post->ID ) {
$allow = false;
}
// revision (preview)
if ( $post->post_type == 'revision' ) {
// allow if doing preview and this $post is a child of the $_POST ID
if ( acf_maybe_get_POST( 'wp-preview' ) == 'dopreview' && $form_post_id === $post->post_parent ) {
$allow = true;
}
}
// return
return $allow;
}
/*
* save_post
*
* Triggers during the 'save_post' action to save the $_POST data.
*
* @type function
* @date 23/06/12
* @since 1.0.0
*
* @param int $post_id The post ID
* @param WP_POST $post the post object.
* @return int
*/
function save_post( $post_id, $post ) {
// bail ealry if no allowed to save this post type
if ( ! $this->allow_save_post( $post ) ) {
return $post_id;
}
// verify nonce
if ( ! acf_verify_nonce( 'post' ) ) {
return $post_id;
}
// validate for published post (allow draft to save without validation)
if ( $post->post_status == 'publish' ) {
// bail early if validation fails
if ( ! acf_validate_save_post() ) {
return;
}
}
// save
acf_save_post( $post_id );
// save revision
if ( post_type_supports( $post->post_type, 'revisions' ) ) {
acf_save_post_revision( $post_id );
}
// return
return $post_id;
}
}
acf_new_instance( 'ACF_Form_Post' );
endif;

View File

@@ -0,0 +1,409 @@
<?php
/*
* ACF Taxonomy Form Class
*
* All the logic for adding fields to taxonomy terms
*
* @class acf_form_taxonomy
* @package ACF
* @subpackage Forms
*/
if ( ! class_exists( 'acf_form_taxonomy' ) ) :
class acf_form_taxonomy {
var $view = 'add';
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
// save
add_action( 'create_term', array( $this, 'save_term' ), 10, 3 );
add_action( 'edit_term', array( $this, 'save_term' ), 10, 3 );
// delete
add_action( 'delete_term', array( $this, 'delete_term' ), 10, 4 );
}
/*
* validate_page
*
* This function will check if the current page is for a post/page edit form
*
* @type function
* @date 23/06/12
* @since 3.1.8
*
* @param n/a
* @return (boolean)
*/
function validate_page() {
// global
global $pagenow;
// validate page
if ( $pagenow === 'edit-tags.php' || $pagenow === 'term.php' ) {
return true;
}
// return
return false;
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 26/01/13
* @since 3.6.0
*
* @param N/A
* @return N/A
*/
function admin_enqueue_scripts() {
// validate page
if ( ! $this->validate_page() ) {
return;
}
// vars
$screen = get_current_screen();
$taxonomy = $screen->taxonomy;
// load acf scripts
acf_enqueue_scripts();
// actions
add_action( 'admin_footer', array( $this, 'admin_footer' ), 10, 1 );
add_action( "{$taxonomy}_add_form_fields", array( $this, 'add_term' ), 10, 1 );
add_action( "{$taxonomy}_edit_form", array( $this, 'edit_term' ), 10, 2 );
}
/*
* add_term
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function add_term( $taxonomy ) {
// vars
$post_id = 'term_0';
// update vars
$this->view = 'add';
// get field groups
$field_groups = acf_get_field_groups(
array(
'taxonomy' => $taxonomy,
)
);
// render
if ( ! empty( $field_groups ) ) {
// data
acf_form_data(
array(
'screen' => 'taxonomy',
'post_id' => $post_id,
)
);
// wrap
echo '<div id="acf-term-fields" class="acf-fields -clear">';
// loop
foreach ( $field_groups as $field_group ) {
$fields = acf_get_fields( $field_group );
acf_render_fields( $fields, $post_id, 'div', 'field' );
}
// wrap
echo '</div>';
}
}
/*
* edit_term
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function edit_term( $term, $taxonomy ) {
// vars
$post_id = 'term_' . $term->term_id;
// update vars
$this->view = 'edit';
// get field groups
$field_groups = acf_get_field_groups(
array(
'taxonomy' => $taxonomy,
)
);
// render
if ( ! empty( $field_groups ) ) {
acf_form_data(
array(
'screen' => 'taxonomy',
'post_id' => $post_id,
)
);
foreach ( $field_groups as $field_group ) {
// title
if ( $field_group['style'] == 'default' ) {
echo '<h2>' . $field_group['title'] . '</h2>';
}
// fields
echo '<table class="form-table">';
$fields = acf_get_fields( $field_group );
acf_render_fields( $fields, $post_id, 'tr', 'field' );
echo '</table>';
}
}
}
/*
* admin_footer
*
* description
*
* @type function
* @date 27/03/2015
* @since 5.1.5
*
* @param $post_id (int)
* @return $post_id (int)
*/
function admin_footer() {
?>
<script type="text/javascript">
(function($) {
// Define vars.
var view = '<?php echo $this->view; ?>';
var $form = $('#' + view + 'tag');
var $submit = $('#' + view + 'tag input[type="submit"]:last');
// Add missing spinner.
if( !$submit.next('.spinner').length ) {
$submit.after('<span class="spinner"></span>');
}
<?php
// View: Add.
if ( $this->view == 'add' ) :
?>
// vars
var $fields = $('#acf-term-fields');
var html = '';
// Store a copy of the $fields html used later to replace after AJAX request.
// Hook into 'prepare' action to allow ACF core helpers to first modify DOM.
// Fixes issue where hidden #acf-hidden-wp-editor is initialized again.
acf.addAction('prepare', function(){
html = $fields.html();
}, 6);
// WP triggers click as primary action
$submit.on('click', function( e ){
// validate
var valid = acf.validateForm({
form: $form,
event: e,
reset: true
});
// if not valid, stop event and allow validation to continue
if( !valid ) {
e.preventDefault();
e.stopImmediatePropagation();
}
});
// listen to AJAX add-tag complete
$(document).ajaxComplete(function(event, xhr, settings) {
// bail early if is other ajax call
if( settings.data.indexOf('action=add-tag') == -1 ) {
return;
}
// bail early if response contains error
if( xhr.responseText.indexOf('wp_error') !== -1 ) {
return;
}
// action for 3rd party customization
acf.doAction('remove', $fields);
// reset HTML
$fields.html( html );
// action for 3rd party customization
acf.doAction('append', $fields);
// reset unload
acf.unload.reset();
});
<?php endif; ?>
})(jQuery);
</script>
<?php
}
/*
* save_term
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function save_term( $term_id, $tt_id, $taxonomy ) {
// vars
$post_id = 'term_' . $term_id;
// verify and remove nonce
if ( ! acf_verify_nonce( 'taxonomy' ) ) {
return $term_id;
}
// valied and show errors
acf_validate_save_post( true );
// save
acf_save_post( $post_id );
}
/*
* delete_term
*
* description
*
* @type function
* @date 15/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function delete_term( $term, $tt_id, $taxonomy, $deleted_term ) {
// bail early if termmeta table exists
if ( acf_isset_termmeta() ) {
return $term;
}
// globals
global $wpdb;
// vars
$search = $taxonomy . '_' . $term . '_%';
$_search = '_' . $search;
// escape '_'
// http://stackoverflow.com/questions/2300285/how-do-i-escape-in-sql-server
$search = str_replace( '_', '\_', $search );
$_search = str_replace( '_', '\_', $_search );
// delete
$result = $wpdb->query(
$wpdb->prepare(
"DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s",
$search,
$_search
)
);
}
}
new acf_form_taxonomy();
endif;
?>

View File

@@ -0,0 +1,387 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Form_User' ) ) :
class ACF_Form_User {
/** @var string The current view (new, edit, register) */
var $view = '';
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// enqueue
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'login_form_register', array( $this, 'login_form_register' ) );
// render
add_action( 'show_user_profile', array( $this, 'render_edit' ) );
add_action( 'edit_user_profile', array( $this, 'render_edit' ) );
add_action( 'user_new_form', array( $this, 'render_new' ) );
add_action( 'register_form', array( $this, 'render_register' ) );
// save
add_action( 'user_register', array( $this, 'save_user' ) );
add_action( 'profile_update', array( $this, 'save_user' ) );
// Perform validation before new user is registered.
add_filter( 'registration_errors', array( $this, 'filter_registration_errors' ), 10, 3 );
}
/**
* admin_enqueue_scripts
*
* Checks current screen and enqueues scripts
*
* @date 17/4/18
* @since 5.6.9
*
* @param void
* @return void
*/
function admin_enqueue_scripts() {
// bail early if not valid screen
if ( ! acf_is_screen( array( 'profile', 'user', 'user-edit' ) ) ) {
return;
}
// enqueue
acf_enqueue_scripts();
}
/**
* login_form_register
*
* Customizes and enqueues scripts
*
* @date 17/4/18
* @since 5.6.9
*
* @param void
* @return void
*/
function login_form_register() {
// customize action prefix so that "admin_head" = "login_head"
acf_enqueue_scripts(
array(
'context' => 'login',
)
);
}
/*
* register_user
*
* Called during the user register form
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param void
* @return void
*/
function render_register() {
// render
$this->render(
array(
'user_id' => 0,
'view' => 'register',
'el' => 'div',
)
);
}
/*
* render_edit
*
* Called during the user edit form
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param void
* @return void
*/
function render_edit( $user ) {
// add compatibility with front-end user profile edit forms such as bbPress
if ( ! is_admin() ) {
acf_enqueue_scripts();
}
// render
$this->render(
array(
'user_id' => $user->ID,
'view' => 'edit',
'el' => 'tr',
)
);
}
/*
* user_new_form
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function render_new() {
// Multisite uses a different 'user-new.php' form. Don't render fields here
if ( is_multisite() ) {
return;
}
// render
$this->render(
array(
'user_id' => 0,
'view' => 'add',
'el' => 'tr',
)
);
}
/*
* render
*
* This function will render ACF fields for a given $post_id parameter
*
* @type function
* @date 7/10/13
* @since 5.0.0
*
* @param $user_id (int) this can be set to 0 for a new user
* @param $user_form (string) used for location rule matching. edit | add | register
* @param $el (string)
* @return n/a
*/
function render( $args = array() ) {
// Allow $_POST data to persist across form submission attempts.
if ( isset( $_POST['acf'] ) ) {
add_filter( 'acf/pre_load_value', array( $this, 'filter_pre_load_value' ), 10, 3 );
}
// defaults
$args = wp_parse_args(
$args,
array(
'user_id' => 0,
'view' => 'edit',
'el' => 'tr',
)
);
// vars
$post_id = 'user_' . $args['user_id'];
// get field groups
$field_groups = acf_get_field_groups(
array(
'user_id' => $args['user_id'] ? $args['user_id'] : 'new',
'user_form' => $args['view'],
)
);
// bail early if no field groups
if ( empty( $field_groups ) ) {
return;
}
// form data
acf_form_data(
array(
'screen' => 'user',
'post_id' => $post_id,
'validation' => ( $args['view'] == 'register' ) ? 0 : 1,
)
);
// elements
$before = '<table class="form-table"><tbody>';
$after = '</tbody></table>';
if ( $args['el'] == 'div' ) {
$before = '<div class="acf-user-' . $args['view'] . '-fields acf-fields -clear">';
$after = '</div>';
}
// loop
foreach ( $field_groups as $field_group ) {
// vars
$fields = acf_get_fields( $field_group );
// title
if ( $field_group['style'] === 'default' ) {
echo '<h2>' . $field_group['title'] . '</h2>';
}
// render
echo $before;
acf_render_fields( $fields, $post_id, $args['el'], $field_group['instruction_placement'] );
echo $after;
}
// actions
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ), 10, 1 );
}
/*
* admin_footer
*
* description
*
* @type function
* @date 27/03/2015
* @since 5.1.5
*
* @param $post_id (int)
* @return $post_id (int)
*/
function admin_footer() {
// script
?>
<script type="text/javascript">
(function($) {
// vars
var view = '<?php echo $this->view; ?>';
// add missing spinners
var $submit = $('input.button-primary');
if( !$submit.next('.spinner').length ) {
$submit.after('<span class="spinner"></span>');
}
})(jQuery);
</script>
<?php
}
/*
* save_user
*
* description
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function save_user( $user_id ) {
// verify nonce
if ( ! acf_verify_nonce( 'user' ) ) {
return $user_id;
}
// save
if ( acf_validate_save_post( true ) ) {
acf_save_post( "user_$user_id" );
}
}
/**
* filter_registration_errors
*
* Validates $_POST data and appends any errors to prevent new user registration.
*
* @date 12/7/19
* @since 5.8.1
*
* @param WP_Error $errors A WP_Error object containing any errors encountered during registration.
* @param string $sanitized_user_login User's username after it has been sanitized.
* @param string $user_email User's email.
* @return WP_Error
*/
function filter_registration_errors( $errors, $sanitized_user_login, $user_email ) {
if ( ! acf_validate_save_post() ) {
$acf_errors = acf_get_validation_errors();
foreach ( $acf_errors as $acf_error ) {
$errors->add(
acf_idify( $acf_error['input'] ),
acf_esc_html( acf_punctify( sprintf( __( '<strong>Error</strong>: %s', 'acf' ), $acf_error['message'] ) ) )
);
}
}
return $errors;
}
/**
* filter_pre_load_value
*
* Checks if a $_POST value exists for this field to allow persistent values.
*
* @date 12/7/19
* @since 5.8.2
*
* @param null $null A null placeholder.
* @param (int|string) $post_id The post id.
* @param array $field The field array.
* @return mixed
*/
function filter_pre_load_value( $null, $post_id, $field ) {
$field_key = $field['key'];
if ( isset( $_POST['acf'][ $field_key ] ) ) {
return $_POST['acf'][ $field_key ];
}
return $null;
}
}
// instantiate
acf_new_instance( 'ACF_Form_User' );
endif; // class_exists check
?>

View File

@@ -0,0 +1,332 @@
<?php
/*
* ACF Widget Form Class
*
* All the logic for adding fields to widgets
*
* @class acf_form_widget
* @package ACF
* @subpackage Forms
*/
if ( ! class_exists( 'acf_form_widget' ) ) :
class acf_form_widget {
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// vars
$this->preview_values = array();
$this->preview_reference = array();
$this->preview_errors = array();
// actions
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'in_widget_form', array( $this, 'edit_widget' ), 10, 3 );
add_action( 'acf/validate_save_post', array( $this, 'acf_validate_save_post' ), 5 );
// filters
add_filter( 'widget_update_callback', array( $this, 'save_widget' ), 10, 4 );
}
/*
* admin_enqueue_scripts
*
* This action is run after post query but before any admin script / head actions.
* It is a good place to register all actions.
*
* @type action (admin_enqueue_scripts)
* @date 26/01/13
* @since 3.6.0
*
* @param N/A
* @return N/A
*/
function admin_enqueue_scripts() {
// validate screen
if ( acf_is_screen( 'widgets' ) || acf_is_screen( 'customize' ) ) {
// valid
} else {
return;
}
// load acf scripts
acf_enqueue_scripts();
// actions
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ), 1 );
}
/*
* acf_validate_save_post
*
* This function will loop over $_POST data and validate
*
* @type action 'acf/validate_save_post' 5
* @date 7/09/2016
* @since 5.4.0
*
* @param n/a
* @return n/a
*/
function acf_validate_save_post() {
// bail ealry if not widget
if ( ! isset( $_POST['_acf_widget_id'] ) ) {
return;
}
// vars
$id = $_POST['_acf_widget_id'];
$number = $_POST['_acf_widget_number'];
$prefix = $_POST['_acf_widget_prefix'];
// validate
acf_validate_values( $_POST[ $id ][ $number ]['acf'], $prefix );
}
/*
* edit_widget
*
* This function will render the fields for a widget form
*
* @type function
* @date 11/06/2014
* @since 5.0.0
*
* @param $widget (object)
* @param $return (null)
* @param $instance (object)
* @return $post_id (int)
*/
function edit_widget( $widget, $return, $instance ) {
// vars
$post_id = 0;
$prefix = 'widget-' . $widget->id_base . '[' . $widget->number . '][acf]';
// get id
if ( $widget->number !== '__i__' ) {
$post_id = "widget_{$widget->id}";
}
// get field groups
$field_groups = acf_get_field_groups(
array(
'widget' => $widget->id_base,
)
);
// render
if ( ! empty( $field_groups ) ) {
// render post data
acf_form_data(
array(
'screen' => 'widget',
'post_id' => $post_id,
'widget_id' => 'widget-' . $widget->id_base,
'widget_number' => $widget->number,
'widget_prefix' => $prefix,
)
);
// wrap
echo '<div class="acf-widget-fields acf-fields -clear">';
// loop
foreach ( $field_groups as $field_group ) {
// load fields
$fields = acf_get_fields( $field_group );
// bail if not fields
if ( empty( $fields ) ) {
continue;
}
// change prefix
acf_prefix_fields( $fields, $prefix );
// render
acf_render_fields( $fields, $post_id, 'div', $field_group['instruction_placement'] );
}
// wrap
echo '</div>';
// jQuery selector looks odd, but is necessary due to WP adding an incremental number into the ID
// - not possible to find number via PHP parameters
if ( $widget->updated ) : ?>
<script type="text/javascript">
(function($) {
acf.doAction('append', $('[id^="widget"][id$="<?php echo $widget->id; ?>"]') );
})(jQuery);
</script>
<?php
endif;
}
}
/*
* save_widget
*
* This function will hook into the widget update filter and save ACF data
*
* @type function
* @date 27/05/2015
* @since 5.2.3
*
* @param $instance (array) widget settings
* @param $new_instance (array) widget settings
* @param $old_instance (array) widget settings
* @param $widget (object) widget info
* @return $instance
*/
function save_widget( $instance, $new_instance, $old_instance, $widget ) {
// validate nonce if we're not a REST API request.
// the $_POST object is not available to us to validate if we're in a REST API call.
if ( ! ( function_exists( 'wp_is_json_request' ) && wp_is_json_request() ) ) {
if ( ! acf_verify_nonce( 'widget' ) ) {
return $instance;
}
}
// bail early if not valid (!customize + acf values + nonce).
if ( isset( $_POST['wp_customize'] ) || ! isset( $new_instance['acf'] ) ) {
return $instance;
}
// save
acf_save_post( "widget_{$widget->id}", $new_instance['acf'] );
// return
return $instance;
}
/*
* admin_footer
*
* This function will add some custom HTML to the footer of the edit page
*
* @type function
* @date 11/06/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_footer() {
?>
<script type="text/javascript">
(function($) {
// vars
acf.set('post_id', 'widgets');
// Only initialize visible fields.
acf.addFilter('find_fields', function( $fields ){
// not templates
$fields = $fields.not('#available-widgets .acf-field');
// not widget dragging in
$fields = $fields.not('.widget.ui-draggable-dragging .acf-field');
// return
return $fields;
});
// on publish
$('#widgets-right').on('click', '.widget-control-save', function( e ){
// vars
var $button = $(this);
var $form = $button.closest('form');
// validate
var valid = acf.validateForm({
form: $form,
event: e,
reset: true
});
// if not valid, stop event and allow validation to continue
if( !valid ) {
e.preventDefault();
e.stopImmediatePropagation();
}
});
// show
$('#widgets-right').on('click', '.widget-top', function(){
var $widget = $(this).parent();
if( $widget.hasClass('open') ) {
acf.doAction('hide', $widget);
} else {
acf.doAction('show', $widget);
}
});
$(document).on('widget-added', function( e, $widget ){
// - use delay to avoid rendering issues with customizer (ensures div is visible)
setTimeout(function(){
acf.doAction('append', $widget );
}, 100);
});
})(jQuery);
</script>
<?php
}
}
new acf_form_widget();
endif;
?>

View File

@@ -0,0 +1,153 @@
<?php
/**
* Determine the current locale desired for the request.
*
* @since 5.0.0
*
* @global string $pagenow
*
* @return string The determined locale.
*/
if ( ! function_exists( 'determine_locale' ) ) :
function determine_locale() {
/**
* Filters the locale for the current request prior to the default determination process.
*
* Using this filter allows to override the default logic, effectively short-circuiting the function.
*
* @since 5.0.0
*
* @param string|null The locale to return and short-circuit, or null as default.
*/
$determined_locale = apply_filters( 'pre_determine_locale', null );
if ( ! empty( $determined_locale ) && is_string( $determined_locale ) ) {
return $determined_locale;
}
$determined_locale = get_locale();
if ( function_exists( 'get_user_locale' ) && is_admin() ) {
$determined_locale = get_user_locale();
}
if ( function_exists( 'get_user_locale' ) && isset( $_GET['_locale'] ) && 'user' === $_GET['_locale'] ) {
$determined_locale = get_user_locale();
}
if ( ! empty( $_GET['wp_lang'] ) && ! empty( $GLOBALS['pagenow'] ) && 'wp-login.php' === $GLOBALS['pagenow'] ) {
$determined_locale = sanitize_text_field( $_GET['wp_lang'] );
}
/**
* Filters the locale for the current request.
*
* @since 5.0.0
*
* @param string $locale The locale.
*/
return apply_filters( 'determine_locale', $determined_locale );
}
endif;
/*
* acf_get_locale
*
* Returns the current locale.
*
* @date 16/12/16
* @since 5.5.0
*
* @param void
* @return string
*/
function acf_get_locale() {
// Determine local.
$locale = determine_locale();
// Fallback to parent language for regions without translation.
// https://wpastra.com/docs/complete-list-wordpress-locale-codes/
$langs = array(
'az_TR' => 'az', // Azerbaijani (Turkey)
'zh_HK' => 'zh_TW', // Chinese (Hong Kong)
'nl_BE' => 'nl_NL', // Dutch (Belgium)
'fr_BE' => 'fr_FR', // French (Belgium)
'nn_NO' => 'nb_NO', // Norwegian (Nynorsk)
'fa_AF' => 'fa_IR', // Persian (Afghanistan)
'ru_UA' => 'ru_RU', // Russian (Ukraine)
);
if ( isset( $langs[ $locale ] ) ) {
$locale = $langs[ $locale ];
}
/**
* Filters the determined local.
*
* @date 8/1/19
* @since 5.7.10
*
* @param string $locale The local.
*/
return apply_filters( 'acf/get_locale', $locale );
}
/**
* acf_load_textdomain
*
* Loads the plugin's translated strings similar to load_plugin_textdomain().
*
* @date 8/1/19
* @since 5.7.10
*
* @param string $locale The plugin's current locale.
* @return void
*/
function acf_load_textdomain( $domain = 'acf' ) {
/**
* Filters a plugin's locale.
*
* @date 8/1/19
* @since 5.7.10
*
* @param string $locale The plugin's current locale.
* @param string $domain Text domain. Unique identifier for retrieving translated strings.
*/
$locale = apply_filters( 'plugin_locale', acf_get_locale(), $domain );
$mofile = $domain . '-' . $locale . '.mo';
// Try to load from the languages directory first.
if ( load_textdomain( $domain, WP_LANG_DIR . '/plugins/' . $mofile ) ) {
return true;
}
// Load from plugin lang folder.
return load_textdomain( $domain, acf_get_path( 'lang/' . $mofile ) );
}
/**
* _acf_apply_language_cache_key
*
* Applies the current language to the cache key.
*
* @date 23/1/19
* @since 5.7.11
*
* @param string $key The cache key.
* @return string
*/
function _acf_apply_language_cache_key( $key ) {
// Get current language.
$current_language = acf_get_setting( 'current_language' );
if ( $current_language ) {
$key = "{$key}:{$current_language}";
}
// Return key.
return $key;
}
// Hook into filter.
add_filter( 'acf/get_cache_key', '_acf_apply_language_cache_key' );

View File

@@ -0,0 +1,72 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Legacy_Locations' ) ) :
class ACF_Legacy_Locations {
/**
* Magic __isset method for backwards compatibility.
*
* @date 10/4/20
* @since 5.9.0
*
* @param string $key Key name.
* @return bool
*/
public function __isset( $key ) {
// _doing_it_wrong( __FUNCTION__, __( 'The ACF_Locations class should not be accessed directly.', 'acf' ), '5.9.0' );
return (
$key === 'locations'
);
}
/**
* Magic __get method for backwards compatibility.
*
* @date 10/4/20
* @since 5.9.0
*
* @param string $key Key name.
* @return mixed
*/
public function __get( $key ) {
// _doing_it_wrong( __FUNCTION__, __( 'The ACF_Locations class should not be accessed directly.', 'acf' ), '5.9.0' );
switch ( $key ) {
case 'locations':
return call_user_func( 'acf_get_location_types' );
}
return null;
}
/**
* Magic __call method for backwards compatibility.
*
* @date 10/4/20
* @since 5.9.0
*
* @param string $name The method name.
* @param array $arguments The array of arguments.
* @return mixed
*/
public function __call( $name, $arguments ) {
// _doing_it_wrong( __FUNCTION__, __( 'The ACF_Locations class should not be accessed directly.', 'acf' ), '5.9.0' );
switch ( $name ) {
case 'register_location':
return call_user_func_array( 'acf_register_location_type', $arguments );
case 'get_location':
return call_user_func_array( 'acf_get_location_type', $arguments );
case 'get_locations':
return call_user_func_array( 'acf_get_location_rule_types', $arguments );
}
}
}
endif; // class_exists check

View File

@@ -0,0 +1,592 @@
<?php
// Register notices stores.
acf_register_store( 'local-fields' );
acf_register_store( 'local-groups' );
acf_register_store( 'local-empty' );
// Register filter.
acf_enable_filter( 'local' );
/**
* acf_enable_local
*
* Enables the local filter.
*
* @date 22/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function acf_enable_local() {
acf_enable_filter( 'local' );
}
/**
* acf_disable_local
*
* Disables the local filter.
*
* @date 22/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function acf_disable_local() {
acf_disable_filter( 'local' );
}
/**
* acf_is_local_enabled
*
* Returns true if local fields are enabled.
*
* @date 23/1/19
* @since 5.7.10
*
* @param void
* @return bool
*/
function acf_is_local_enabled() {
return ( acf_is_filter_enabled( 'local' ) && acf_get_setting( 'local' ) );
}
/**
* acf_get_local_store
*
* Returns either local store or a dummy store for the given name.
*
* @date 23/1/19
* @since 5.7.10
*
* @param string $name The store name (fields|groups).
* @return ACF_Data
*/
function acf_get_local_store( $name = '' ) {
// Check if enabled.
if ( acf_is_local_enabled() ) {
return acf_get_store( "local-$name" );
// Return dummy store if not enabled.
} else {
return acf_get_store( 'local-empty' );
}
}
/**
* acf_reset_local
*
* Resets the local data.
*
* @date 22/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function acf_reset_local() {
acf_get_local_store( 'fields' )->reset();
acf_get_local_store( 'groups' )->reset();
}
/**
* acf_get_local_field_groups
*
* Returns all local field groups.
*
* @date 22/1/19
* @since 5.7.10
*
* @param void
* @return array
*/
function acf_get_local_field_groups() {
return acf_get_local_store( 'groups' )->get();
}
/**
* acf_have_local_field_groups
*
* description
*
* @date 22/1/19
* @since 5.7.10
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_have_local_field_groups() {
return acf_get_local_store( 'groups' )->count() ? true : false;
}
/**
* acf_count_local_field_groups
*
* description
*
* @date 22/1/19
* @since 5.7.10
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_count_local_field_groups() {
return acf_get_local_store( 'groups' )->count();
}
/**
* acf_add_local_field_group
*
* Adds a local field group.
*
* @date 22/1/19
* @since 5.7.10
*
* @param array $field_group The field group array.
* @return bool
*/
function acf_add_local_field_group( $field_group ) {
// Apply default properties needed for import.
$field_group = wp_parse_args(
$field_group,
array(
'key' => '',
'title' => '',
'fields' => array(),
'local' => 'php',
)
);
// Generate key if only name is provided.
if ( ! $field_group['key'] ) {
$field_group['key'] = 'group_' . acf_slugify( $field_group['title'], '_' );
}
// Bail early if field group already exists.
if ( acf_is_local_field_group( $field_group['key'] ) ) {
return false;
}
// Prepare field group for import (adds menu_order and parent properties to fields).
$field_group = acf_prepare_field_group_for_import( $field_group );
// Extract fields from group.
$fields = acf_extract_var( $field_group, 'fields' );
// Add to store
acf_get_local_store( 'groups' )->set( $field_group['key'], $field_group );
// Add fields
if ( $fields ) {
acf_add_local_fields( $fields );
}
// Return true on success.
return true;
}
/**
* register_field_group
*
* See acf_add_local_field_group().
*
* @date 22/1/19
* @since 5.7.10
*
* @param array $field_group The field group array.
* @return void
*/
function register_field_group( $field_group ) {
acf_add_local_field_group( $field_group );
}
/**
* acf_remove_local_field_group
*
* Removes a field group for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group key.
* @return bool
*/
function acf_remove_local_field_group( $key = '' ) {
return acf_get_local_store( 'groups' )->remove( $key );
}
/**
* acf_is_local_field_group
*
* Returns true if a field group exists for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group key.
* @return bool
*/
function acf_is_local_field_group( $key = '' ) {
return acf_get_local_store( 'groups' )->has( $key );
}
/**
* acf_is_local_field_group_key
*
* Returns true if a field group exists for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group group key.
* @return bool
*/
function acf_is_local_field_group_key( $key = '' ) {
return acf_get_local_store( 'groups' )->is( $key );
}
/**
* acf_get_local_field_group
*
* Returns a field group for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group key.
* @return (array|null)
*/
function acf_get_local_field_group( $key = '' ) {
return acf_get_local_store( 'groups' )->get( $key );
}
/**
* acf_add_local_fields
*
* Adds an array of local fields.
*
* @date 22/1/19
* @since 5.7.10
*
* @param array $fields An array of un prepared fields.
* @return array
*/
function acf_add_local_fields( $fields = array() ) {
// Prepare for import (allows parent fields to offer up children).
$fields = acf_prepare_fields_for_import( $fields );
// Add each field.
foreach ( $fields as $field ) {
acf_add_local_field( $field, true );
}
}
/**
* acf_get_local_fields
*
* Returns all local fields for the given parent.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $parent The parent key.
* @return array
*/
function acf_get_local_fields( $parent = '' ) {
// Return children
if ( $parent ) {
return acf_get_local_store( 'fields' )->query(
array(
'parent' => $parent,
)
);
// Return all.
} else {
return acf_get_local_store( 'fields' )->get();
}
}
/**
* acf_have_local_fields
*
* Returns true if local fields exist.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $parent The parent key.
* @return bool
*/
function acf_have_local_fields( $parent = '' ) {
return acf_get_local_fields( $parent ) ? true : false;
}
/**
* acf_count_local_fields
*
* Returns the number of local fields for the given parent.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $parent The parent key.
* @return int
*/
function acf_count_local_fields( $parent = '' ) {
return count( acf_get_local_fields( $parent ) );
}
/**
* acf_add_local_field
*
* Adds a local field.
*
* @date 22/1/19
* @since 5.7.10
*
* @param array $field The field array.
* @param bool $prepared Whether or not the field has already been prepared for import.
* @return void
*/
function acf_add_local_field( $field, $prepared = false ) {
// Apply default properties needed for import.
$field = wp_parse_args(
$field,
array(
'key' => '',
'name' => '',
'type' => '',
'parent' => '',
)
);
// Generate key if only name is provided.
if ( ! $field['key'] ) {
$field['key'] = 'field_' . $field['name'];
}
// If called directly, allow sub fields to be correctly prepared.
if ( ! $prepared ) {
return acf_add_local_fields( array( $field ) );
}
// Extract attributes.
$key = $field['key'];
$name = $field['name'];
// Allow sub field to be added multipel times to different parents.
$store = acf_get_local_store( 'fields' );
if ( $store->is( $key ) ) {
$old_key = _acf_generate_local_key( $store->get( $key ) );
$new_key = _acf_generate_local_key( $field );
if ( $old_key !== $new_key ) {
$key = $new_key;
}
}
// Add field.
$store->set( $key, $field )->alias( $key, $name );
}
/**
* _acf_generate_local_key
*
* Generates a unique key based on the field's parent.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field key.
* @return bool
*/
function _acf_generate_local_key( $field ) {
return "{$field['key']}:{$field['parent']}";
}
/**
* acf_remove_local_field
*
* Removes a field for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field key.
* @return bool
*/
function acf_remove_local_field( $key = '' ) {
return acf_get_local_store( 'fields' )->remove( $key );
}
/**
* acf_is_local_field
*
* Returns true if a field exists for the given key or name.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group key.
* @return bool
*/
function acf_is_local_field( $key = '' ) {
return acf_get_local_store( 'fields' )->has( $key );
}
/**
* acf_is_local_field_key
*
* Returns true if a field exists for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group key.
* @return bool
*/
function acf_is_local_field_key( $key = '' ) {
return acf_get_local_store( 'fields' )->is( $key );
}
/**
* acf_get_local_field
*
* Returns a field for the given key.
*
* @date 22/1/19
* @since 5.7.10
*
* @param string $key The field group key.
* @return (array|null)
*/
function acf_get_local_field( $key = '' ) {
return acf_get_local_store( 'fields' )->get( $key );
}
/**
* _acf_apply_get_local_field_groups
*
* Appends local field groups to the provided array.
*
* @date 23/1/19
* @since 5.7.10
*
* @param array $field_groups An array of field groups.
* @return array
*/
function _acf_apply_get_local_field_groups( $groups = array() ) {
// Get local groups
$local = acf_get_local_field_groups();
if ( $local ) {
// Generate map of "index" => "key" data.
$map = wp_list_pluck( $groups, 'key' );
// Loop over groups and update/append local.
foreach ( $local as $group ) {
// Get group allowing cache and filters to run.
// $group = acf_get_field_group( $group['key'] );
// Update.
$i = array_search( $group['key'], $map );
if ( $i !== false ) {
unset( $group['ID'] );
$groups[ $i ] = array_merge( $groups[ $i ], $group );
// Append
} else {
$groups[] = acf_get_field_group( $group['key'] );
}
}
// Sort list via menu_order and title.
$groups = wp_list_sort(
$groups,
array(
'menu_order' => 'ASC',
'title' => 'ASC',
)
);
}
// Return groups.
return $groups;
}
// Hook into filter.
add_filter( 'acf/load_field_groups', '_acf_apply_get_local_field_groups', 20, 1 );
/**
* _acf_apply_is_local_field_key
*
* Returns true if is a local key.
*
* @date 23/1/19
* @since 5.7.10
*
* @param bool $bool The result.
* @param string $id The identifier.
* @return bool
*/
function _acf_apply_is_local_field_key( $bool, $id ) {
return acf_is_local_field_key( $id );
}
// Hook into filter.
add_filter( 'acf/is_field_key', '_acf_apply_is_local_field_key', 20, 2 );
/**
* _acf_apply_is_local_field_group_key
*
* Returns true if is a local key.
*
* @date 23/1/19
* @since 5.7.10
*
* @param bool $bool The result.
* @param string $id The identifier.
* @return bool
*/
function _acf_apply_is_local_field_group_key( $bool, $id ) {
return acf_is_local_field_group_key( $id );
}
// Hook into filter.
add_filter( 'acf/is_field_group_key', '_acf_apply_is_local_field_group_key', 20, 2 );
/**
* _acf_do_prepare_local_fields
*
* Local fields that are added too early will not be correctly prepared by the field type class.
*
* @date 23/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function _acf_do_prepare_local_fields() {
// Get fields.
$fields = acf_get_local_fields();
// If fields have been registered early, re-add to correctly prepare them.
if ( $fields ) {
acf_add_local_fields( $fields );
}
}
// Hook into action.
add_action( 'acf/include_fields', '_acf_do_prepare_local_fields', 0, 1 );

View File

@@ -0,0 +1,321 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Local_JSON' ) ) :
class ACF_Local_JSON {
/**
* The found JSON field group files.
*
* @since 5.9.0
* @var array
*/
private $files = array();
/**
* Constructor.
*
* @date 14/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function __construct() {
// Update settings.
acf_update_setting( 'save_json', get_stylesheet_directory() . '/acf-json' );
acf_append_setting( 'load_json', get_stylesheet_directory() . '/acf-json' );
// Add listeners.
add_action( 'acf/update_field_group', array( $this, 'update_field_group' ) );
add_action( 'acf/untrash_field_group', array( $this, 'update_field_group' ) );
add_action( 'acf/trash_field_group', array( $this, 'delete_field_group' ) );
add_action( 'acf/delete_field_group', array( $this, 'delete_field_group' ) );
// Include fields.
add_action( 'acf/include_fields', array( $this, 'include_fields' ) );
}
/**
* Returns true if this component is enabled.
*
* @date 14/4/20
* @since 5.9.0
*
* @param void
* @return bool.
*/
public function is_enabled() {
return (bool) acf_get_setting( 'json' );
}
/**
* Writes field group data to JSON file.
*
* @date 14/4/20
* @since 5.9.0
*
* @param array $field_group The field group.
* @return void
*/
public function update_field_group( $field_group ) {
// Bail early if disabled.
if ( ! $this->is_enabled() ) {
return false;
}
// Append fields.
$field_group['fields'] = acf_get_fields( $field_group );
// Save to file.
$this->save_file( $field_group['key'], $field_group );
}
/**
* Deletes a field group JSON file.
*
* @date 14/4/20
* @since 5.9.0
*
* @param array $field_group The field group.
* @return void
*/
public function delete_field_group( $field_group ) {
// Bail early if disabled.
if ( ! $this->is_enabled() ) {
return false;
}
// WP appends '__trashed' to end of 'key' (post_name).
$key = str_replace( '__trashed', '', $field_group['key'] );
// Delete file.
$this->delete_file( $key );
}
/**
* Includes all local JSON fields.
*
* @date 14/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function include_fields() {
// Bail early if disabled.
if ( ! $this->is_enabled() ) {
return false;
}
// Get load paths.
$files = $this->scan_field_groups();
foreach ( $files as $key => $file ) {
$json = json_decode( file_get_contents( $file ), true );
$json['local'] = 'json';
$json['local_file'] = $file;
acf_add_local_field_group( $json );
}
}
/**
* Scans for JSON field groups.
*
* @date 14/4/20
* @since 5.9.0
*
* @param void
* @return array
*/
function scan_field_groups() {
$json_files = array();
// Loop over "local_json" paths and parse JSON files.
$paths = (array) acf_get_setting( 'load_json' );
foreach ( $paths as $path ) {
if ( is_dir( $path ) ) {
$files = scandir( $path );
if ( $files ) {
foreach ( $files as $filename ) {
// Ignore hidden files.
if ( $filename[0] === '.' ) {
continue;
}
// Ignore sub directories.
$file = untrailingslashit( $path ) . '/' . $filename;
if ( is_dir( $file ) ) {
continue;
}
// Ignore non JSON files.
$ext = pathinfo( $filename, PATHINFO_EXTENSION );
if ( $ext !== 'json' ) {
continue;
}
// Read JSON data.
$json = json_decode( file_get_contents( $file ), true );
if ( ! is_array( $json ) || ! isset( $json['key'] ) ) {
continue;
}
// Append data.
$json_files[ $json['key'] ] = $file;
}
}
}
}
// Store data and return.
$this->files = $json_files;
return $json_files;
}
/**
* Returns an array of found JSON field group files.
*
* @date 14/4/20
* @since 5.9.0
*
* @param void
* @return array
*/
public function get_files() {
return $this->files;
}
/**
* Saves a field group JSON file.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $key The field group key.
* @param array $field_group The field group.
* @return bool
*/
public function save_file( $key, $field_group ) {
$path = acf_get_setting( 'save_json' );
$file = untrailingslashit( $path ) . '/' . $key . '.json';
if ( ! is_writable( $path ) ) {
return false;
}
// Append modified time.
if ( $field_group['ID'] ) {
$field_group['modified'] = get_post_modified_time( 'U', true, $field_group['ID'] );
} else {
$field_group['modified'] = strtotime( 'now' );
}
// Prepare for export.
$field_group = acf_prepare_field_group_for_export( $field_group );
// Save and return true if bytes were written.
$result = file_put_contents( $file, acf_json_encode( $field_group ) );
return is_int( $result );
}
/**
* Deletes a field group JSON file.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $key The field group key.
* @return bool True on success.
*/
public function delete_file( $key ) {
$path = acf_get_setting( 'save_json' );
$file = untrailingslashit( $path ) . '/' . $key . '.json';
if ( is_readable( $file ) ) {
unlink( $file );
return true;
}
return false;
}
/**
* Includes all local JSON files.
*
* @date 10/03/2014
* @since 5.0.0
* @deprecated 5.9.0
*
* @param void
* @return void
*/
public function include_json_folders() {
_deprecated_function( __METHOD__, '5.9.0', 'ACF_Local_JSON::include_fields()' );
$this->include_fields();
}
/**
* Includes local JSON files within a specific folder.
*
* @date 01/05/2017
* @since 5.5.13
* @deprecated 5.9.0
*
* @param string $path The path to a specific JSON folder.
* @return void
*/
public function include_json_folder( $path = '' ) {
_deprecated_function( __METHOD__, '5.9.0' );
// Do nothing.
}
}
// Initialize.
acf_new_instance( 'ACF_Local_JSON' );
endif; // class_exists check
/**
* Returns an array of found JSON field group files.
*
* @date 14/4/20
* @since 5.9.0
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_get_local_json_files() {
return acf_get_instance( 'ACF_Local_JSON' )->get_files();
}
/**
* Saves a field group JSON file.
*
* @date 5/12/2014
* @since 5.1.5
*
* @param array $field_group The field group.
* @return bool
*/
function acf_write_json_field_group( $field_group ) {
return acf_get_instance( 'ACF_Local_JSON' )->save_file( $field_group['key'], $field_group );
}
/**
* Deletes a field group JSON file.
*
* @date 5/12/2014
* @since 5.1.5
*
* @param string $key The field group key.
* @return bool True on success.
*/
function acf_delete_json_field_group( $key ) {
return acf_get_instance( 'ACF_Local_JSON' )->delete_file( $key );
}

View File

@@ -0,0 +1,256 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Local_Meta' ) ) :
class ACF_Local_Meta {
/** @var array Storage for meta data. */
var $meta = array();
/** @var mixed Storage for the current post_id. */
var $post_id = 0;
/**
* __construct
*
* Sets up the class functionality.
*
* @date 8/10/18
* @since 5.8.0
*
* @param void
* @return void
*/
function __construct() {
// add filters
add_filter( 'acf/pre_load_post_id', array( $this, 'pre_load_post_id' ), 1, 2 );
add_filter( 'acf/pre_load_meta', array( $this, 'pre_load_meta' ), 1, 2 );
add_filter( 'acf/pre_load_metadata', array( $this, 'pre_load_metadata' ), 1, 4 );
}
/**
* add
*
* Adds postmeta to storage.
* Accepts data in either raw or request format.
*
* @date 8/10/18
* @since 5.8.0
*
* @param array $meta An array of metdata to store.
* @param mixed $post_id The post_id for this data.
* @param bool $is_main Makes this postmeta visible to get_field() without a $post_id value.
* @return array
*/
function add( $meta = array(), $post_id = 0, $is_main = false ) {
// Capture meta if supplied meta is from a REQUEST.
if ( $this->is_request( $meta ) ) {
$meta = $this->capture( $meta, $post_id );
}
// Add to storage.
$this->meta[ $post_id ] = $meta;
// Set $post_id reference when is the "main" postmeta.
if ( $is_main ) {
$this->post_id = $post_id;
}
// Return meta.
return $meta;
}
/**
* is_request
*
* Returns true if the supplied $meta is from a REQUEST (serialized <form> data).
*
* @date 11/3/19
* @since 5.7.14
*
* @param array $meta An array of metdata to check.
* @return bool
*/
function is_request( $meta = array() ) {
return acf_is_field_key( key( $meta ) );
}
/**
* capture
*
* Returns a flattened array of meta for the given postdata.
* This is achieved by simulating a save whilst capturing all meta changes.
*
* @date 26/2/19
* @since 5.7.13
*
* @param array $values An array of raw values.
* @param mixed $post_id The post_id for this data.
* @return array
*/
function capture( $values = array(), $post_id = 0 ) {
// Reset meta.
$this->meta[ $post_id ] = array();
// Listen for any added meta.
add_filter( 'acf/pre_update_metadata', array( $this, 'capture_update_metadata' ), 1, 5 );
// Simulate update.
if ( $values ) {
acf_update_values( $values, $post_id );
}
// Remove listener filter.
remove_filter( 'acf/pre_update_metadata', array( $this, 'capture_update_metadata' ), 1, 5 );
// Return meta.
return $this->meta[ $post_id ];
}
/**
* capture_update_metadata
*
* Records all meta activity and returns a non null value to bypass DB updates.
*
* @date 26/2/19
* @since 5.7.13
*
* @param null $null .
* @param (int|string) $post_id The post id.
* @param string $name The meta name.
* @param mixed $value The meta value.
* @param bool $hidden If the meta is hidden (starts with an underscore).
* @return false.
*/
function capture_update_metadata( $null, $post_id, $name, $value, $hidden ) {
$name = ( $hidden ? '_' : '' ) . $name;
$this->meta[ $post_id ][ $name ] = $value;
// Return non null value to escape update process.
return true;
}
/**
* remove
*
* Removes postmeta from storage.
*
* @date 8/10/18
* @since 5.8.0
*
* @param mixed $post_id The post_id for this data.
* @return void
*/
function remove( $post_id = 0 ) {
// unset meta
unset( $this->meta[ $post_id ] );
// reset post_id
if ( $post_id === $this->post_id ) {
$this->post_id = 0;
}
}
/**
* pre_load_meta
*
* Injects the local meta.
*
* @date 8/10/18
* @since 5.8.0
*
* @param null $null An empty parameter. Return a non null value to short-circuit the function.
* @param mixed $post_id The post_id for this data.
* @return mixed
*/
function pre_load_meta( $null, $post_id ) {
if ( isset( $this->meta[ $post_id ] ) ) {
return $this->meta[ $post_id ];
}
return $null;
}
/**
* pre_load_metadata
*
* Injects the local meta.
*
* @date 8/10/18
* @since 5.8.0
*
* @param null $null An empty parameter. Return a non null value to short-circuit the function.
* @param (int|string) $post_id The post id.
* @param string $name The meta name.
* @param bool $hidden If the meta is hidden (starts with an underscore).
* @return mixed
*/
function pre_load_metadata( $null, $post_id, $name, $hidden ) {
$name = ( $hidden ? '_' : '' ) . $name;
if ( isset( $this->meta[ $post_id ] ) ) {
if ( isset( $this->meta[ $post_id ][ $name ] ) ) {
return $this->meta[ $post_id ][ $name ];
}
return '__return_null';
}
return $null;
}
/**
* pre_load_post_id
*
* Injects the local post_id.
*
* @date 8/10/18
* @since 5.8.0
*
* @param null $null An empty parameter. Return a non null value to short-circuit the function.
* @param mixed $post_id The post_id for this data.
* @return mixed
*/
function pre_load_post_id( $null, $post_id ) {
if ( ! $post_id && $this->post_id ) {
return $this->post_id;
}
return $null;
}
}
endif; // class_exists check
/**
* acf_setup_meta
*
* Adds postmeta to storage.
*
* @date 8/10/18
* @since 5.8.0
* @see ACF_Local_Meta::add() for list of parameters.
*
* @return array
*/
function acf_setup_meta( $meta = array(), $post_id = 0, $is_main = false ) {
return acf_get_instance( 'ACF_Local_Meta' )->add( $meta, $post_id, $is_main );
}
/**
* acf_reset_meta
*
* Removes postmeta to storage.
*
* @date 8/10/18
* @since 5.8.0
* @see ACF_Local_Meta::remove() for list of parameters.
*
* @return void
*/
function acf_reset_meta( $post_id = 0 ) {
return acf_get_instance( 'ACF_Local_Meta' )->remove( $post_id );
}

View File

@@ -0,0 +1,343 @@
<?php
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Register store.
acf_register_store( 'location-types' );
/**
* Registers a location type.
*
* @date 8/4/20
* @since 5.9.0
*
* @param string $class_name The location class name.
* @return (ACF_Location|false)
*/
function acf_register_location_type( $class_name ) {
$store = acf_get_store( 'location-types' );
// Check class exists.
if ( ! class_exists( $class_name ) ) {
$message = sprintf( __( 'Class "%s" does not exist.', 'acf' ), $class_name );
_doing_it_wrong( __FUNCTION__, $message, '5.9.0' );
return false;
}
// Create instance.
$location_type = new $class_name();
$name = $location_type->name;
// Check location type is unique.
if ( $store->has( $name ) ) {
$message = sprintf( __( 'Location type "%s" is already registered.' ), $name );
_doing_it_wrong( __FUNCTION__, $message, '5.9.0' );
return false;
}
// Add to store.
$store->set( $name, $location_type );
/**
* Fires after a location type is registered.
*
* @date 8/4/20
* @since 5.9.0
*
* @param string $name The location type name.
* @param ACF_Location $location_type The location type instance.
*/
do_action( 'acf/registered_location_type', $name, $location_type );
// Return location type instance.
return $location_type;
}
/**
* Returns an array of all registered location types.
*
* @date 8/4/20
* @since 5.9.0
*
* @param void
* @return array
*/
function acf_get_location_types() {
return acf_get_store( 'location-types' )->get();
}
/**
* Returns a location type for the given name.
*
* @date 18/2/19
* @since 5.7.12
*
* @param string $name The location type name.
* @return (ACF_Location|null)
*/
function acf_get_location_type( $name ) {
return acf_get_store( 'location-types' )->get( $name );
}
/**
* Returns a grouped array of all location rule types.
*
* @date 8/4/20
* @since 5.9.0
*
* @param void
* @return array
*/
function acf_get_location_rule_types() {
$types = array();
// Default categories.
$categories = array(
'post' => __( 'Post', 'acf' ),
'page' => __( 'Page', 'acf' ),
'user' => __( 'User', 'acf' ),
'forms' => __( 'Forms', 'acf' ),
);
// Loop over all location types and append to $type.
$location_types = acf_get_location_types();
foreach ( $location_types as $location_type ) {
// Ignore if not public.
if ( ! $location_type->public ) {
continue;
}
// Find category label from category name.
$category = $location_type->category;
if ( isset( $categories[ $category ] ) ) {
$category = $categories[ $category ];
}
// Append
$types[ $category ][ $location_type->name ] = esc_html( $location_type->label );
}
/**
* Filters the location rule types.
*
* @date 8/4/20
* @since 5.9.0
*
* @param array $types The location rule types.
*/
return apply_filters( 'acf/location/rule_types', $types );
}
/**
* Returns a validated location rule with all props.
*
* @date 8/4/20
* @since 5.9.0
*
* @param array $rule The location rule.
* @return array
*/
function acf_validate_location_rule( $rule = array() ) {
// Apply defaults.
$rule = wp_parse_args(
$rule,
array(
'id' => '',
'group' => '',
'param' => '',
'operator' => '==',
'value' => '',
)
);
/**
* Filters the location rule to ensure is valid.
*
* @date 8/4/20
* @since 5.9.0
*
* @param array $rule The location rule.
*/
$rule = apply_filters( "acf/location/validate_rule/type={$rule['param']}", $rule );
$rule = apply_filters( 'acf/location/validate_rule', $rule );
return $rule;
}
/**
* Returns an array of operators for a given rule.
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $rule The location rule.
* @return array
*/
function acf_get_location_rule_operators( $rule ) {
$operators = ACF_Location::get_operators( $rule );
// Get operators from location type since 5.9.
$location_type = acf_get_location_type( $rule['param'] );
if ( $location_type ) {
$operators = $location_type->get_operators( $rule );
}
/**
* Filters the location rule operators.
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $types The location rule operators.
*/
$operators = apply_filters( "acf/location/rule_operators/type={$rule['param']}", $operators, $rule );
$operators = apply_filters( "acf/location/rule_operators/{$rule['param']}", $operators, $rule );
$operators = apply_filters( 'acf/location/rule_operators', $operators, $rule );
return $operators;
}
/**
* Returns an array of values for a given rule.
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $rule The location rule.
* @return array
*/
function acf_get_location_rule_values( $rule ) {
$values = array();
// Get values from location type since 5.9.
$location_type = acf_get_location_type( $rule['param'] );
if ( $location_type ) {
$values = $location_type->get_values( $rule );
}
/**
* Filters the location rule values.
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $types The location rule values.
*/
$values = apply_filters( "acf/location/rule_values/type={$rule['param']}", $values, $rule );
$values = apply_filters( "acf/location/rule_values/{$rule['param']}", $values, $rule );
$values = apply_filters( 'acf/location/rule_values', $values, $rule );
return $values;
}
/**
* Returns true if the provided rule matches the screen args.
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $rule The location rule.
* @param array $screen The screen args.
* @param array $field The field group array.
* @return bool
*/
function acf_match_location_rule( $rule, $screen, $field_group ) {
$result = false;
// Get result from location type since 5.9.
$location_type = acf_get_location_type( $rule['param'] );
if ( $location_type ) {
$result = $location_type->match( $rule, $screen, $field_group );
}
/**
* Filters the result.
*
* @date 30/5/17
* @since 5.6.0
*
* @param bool $result The match result.
* @param array $rule The location rule.
* @param array $screen The screen args.
* @param array $field_group The field group array.
*/
$result = apply_filters( "acf/location/match_rule/type={$rule['param']}", $result, $rule, $screen, $field_group );
$result = apply_filters( 'acf/location/match_rule', $result, $rule, $screen, $field_group );
$result = apply_filters( "acf/location/rule_match/{$rule['param']}", $result, $rule, $screen, $field_group );
$result = apply_filters( 'acf/location/rule_match', $result, $rule, $screen, $field_group );
return $result;
}
/**
* Returns ann array of screen args to be used against matching rules.
*
* @date 8/4/20
* @since 5.9.0
*
* @param array $screen The screen args.
* @param array $deprecated The field group array.
* @return array
*/
function acf_get_location_screen( $screen = array(), $deprecated = false ) {
// Apply defaults.
$screen = wp_parse_args(
$screen,
array(
'lang' => acf_get_setting( 'current_language' ),
'ajax' => false,
)
);
/**
* Filters the result.
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $screen The screen args.
* @param array $deprecated The field group array.
*/
return apply_filters( 'acf/location/screen', $screen, $deprecated );
}
/**
* Alias of acf_register_location_type().
*
* @date 31/5/17
* @since 5.6.0
*
* @param string $class_name The location class name.
* @return (ACF_Location|false)
*/
function acf_register_location_rule( $class_name ) {
return acf_register_location_type( $class_name );
}
/**
* Alias of acf_get_location_type().
*
* @date 31/5/17
* @since 5.6.0
*
* @param string $class_name The location class name.
* @return (ACF_Location|false)
*/
function acf_get_location_rule( $name ) {
return acf_get_location_type( $name );
}
/**
* Alias of acf_validate_location_rule().
*
* @date 30/5/17
* @since 5.6.0
*
* @param array $rule The location rule.
* @return array
*/
function acf_get_valid_location_rule( $rule ) {
return acf_validate_location_rule( $rule );
}

View File

@@ -0,0 +1,64 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Legacy_Location' ) ) :
abstract class ACF_Legacy_Location {
/**
* Constructor.
*
* @date 5/03/2014
* @since 5.0.0
*
* @param void
* @return void
*/
public function __construct() {
// Add legacy method filters.
if ( method_exists( $this, 'rule_match' ) ) {
add_filter( "acf/location/rule_match/{$this->name}", array( $this, 'rule_match' ), 5, 3 );
}
if ( method_exists( $this, 'rule_operators' ) ) {
add_filter( "acf/location/rule_operators/{$this->name}", array( $this, 'rule_operators' ), 5, 2 );
}
if ( method_exists( $this, 'rule_values' ) ) {
add_filter( "acf/location/rule_values/{$this->name}", array( $this, 'rule_values' ), 5, 2 );
}
}
/**
* Magic __call method for backwards compatibility.
*
* @date 10/4/20
* @since 5.9.0
*
* @param string $name The method name.
* @param array $arguments The array of arguments.
* @return mixed
*/
public function __call( $name, $arguments ) {
// Add backwards compatibility for legacy methods.
// - Combine 3x legacy filters cases together (remove first args).
switch ( $name ) {
case 'rule_match':
$method = isset( $method ) ? $method : 'match';
$arguments[3] = isset( $arguments[3] ) ? $arguments[3] : false; // Add $field_group param.
case 'rule_operators':
$method = isset( $method ) ? $method : 'get_operators';
case 'rule_values':
$method = isset( $method ) ? $method : 'get_values';
array_shift( $arguments );
return call_user_func_array( array( $this, $method ), $arguments );
case 'compare':
return call_user_func_array( array( $this, 'compare_to_rule' ), $arguments );
}
}
}
endif; // class_exists check

View File

@@ -0,0 +1,190 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Location' ) ) :
abstract class ACF_Location extends ACF_Legacy_Location {
/**
* The location rule name.
*
* @since 5.9.0
* @var string
*/
public $name = '';
/**
* The location rule label.
*
* @since 5.9.0
* @var string
*/
public $label = '';
/**
* The location rule category.
*
* Accepts "post", "page", "user", "forms" or a custom label.
*
* @since 5.9.0
* @var string
*/
public $category = 'post';
/**
* Whether or not the location rule is publicly accessible.
*
* @since 5.0.0
* @var bool
*/
public $public = true;
/**
* The object type related to this location rule.
*
* Accepts an object type discoverable by `acf_get_object_type()`.
*
* @since 5.9.0
* @var string
*/
public $object_type = '';
/**
* The object subtype related to this location rule.
*
* Accepts a custom post type or custom taxonomy.
*
* @since 5.9.0
* @var string
*/
public $object_subtype = '';
/**
* Constructor.
*
* @date 8/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function __construct() {
$this->initialize();
// Call legacy constructor.
parent::__construct();
}
/**
* Initializes props.
*
* @date 5/03/2014
* @since 5.0.0
*
* @param void
* @return void
*/
public function initialize() {
// Set props here.
}
/**
* Returns an array of operators for this location.
*
* @date 9/4/20
* @since 5.9.0
*
* @param array $rule A location rule.
* @return array
*/
public static function get_operators( $rule ) {
return array(
'==' => __( 'is equal to', 'acf' ),
'!=' => __( 'is not equal to', 'acf' ),
);
}
/**
* Returns an array of possible values for this location.
*
* @date 9/4/20
* @since 5.9.0
*
* @param array $rule A location rule.
* @return array
*/
public function get_values( $rule ) {
return array();
}
/**
* Returns the object_type connected to this location.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $rule A location rule.
* @return string
*/
public function get_object_type( $rule ) {
return $this->object_type;
}
/**
* Returns the object_subtype connected to this location.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $rule A location rule.
* @return string|array
*/
public function get_object_subtype( $rule ) {
return $this->object_subtype;
}
/**
* Matches the provided rule against the screen args returning a bool result.
*
* @date 9/4/20
* @since 5.9.0
*
* @param array $rule The location rule.
* @param array $screen The screen args.
* @param array $field_group The field group settings.
* @return bool
*/
public function match( $rule, $screen, $field_group ) {
return false;
}
/**
* Compares the given value and rule params returning true when they match.
*
* @date 17/9/19
* @since 5.8.1
*
* @param array $rule The location rule data.
* @param mixed $value The value to compare against.
* @return bool
*/
public function compare_to_rule( $value, $rule ) {
$result = ( $value == $rule['value'] );
// Allow "all" to match any value.
if ( $rule['value'] === 'all' ) {
$result = true;
}
// Reverse result for "!=" operator.
if ( $rule['operator'] === '!=' ) {
return ! $result;
}
return $result;
}
}
endif; // class_exists check

Some files were not shown because too many files have changed in this diff Show More