first commit

This commit is contained in:
DESKTOP-GBA0BK8\Admin
2023-04-08 12:19:53 -04:00
commit 7c8c8b1c76
4586 changed files with 2050693 additions and 0 deletions
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,163 @@
<?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' );
@@ -0,0 +1,387 @@
<?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;
}
// 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_numericval
*
* 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.
* @return string
*/
function acf_slugify( $str = '' ) {
return str_replace(array('_', '/', ' '), '-', strtolower($str));
}
/**
* acf_punctify
*
* Returns a string with correct full stop puctuation.
*
* @date 12/7/19
* @since 5.8.2
*
* @param string $str The string to format.
* @return string
*/
function acf_punctify( $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;
}
}
@@ -0,0 +1,220 @@
<?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];
}
@@ -0,0 +1,472 @@
<?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 );
}
/**
* acf_esc_html
*
* Encodes <script> tags for safe HTML output.
*
* @date 12/6/19
* @since 5.8.1
*
* @param string $string
* @return string
*/
function acf_esc_html( $string = '' ) {
$string = strval($string);
// Encode "<script" tags to invalidate DOM elements.
if( strpos($string, '<script') !== false ) {
$string = str_replace('<script', htmlspecialchars('<script'), $string);
$string = str_replace('</script', htmlspecialchars('</script'), $string);
}
return $string;
}
/**
* 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'
));
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 );
}
@@ -0,0 +1,441 @@
<?php
/**
* acf_decode_post_id
*
* Returns an array containing the object type and id for the given post_id string.
*
* @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 ) {
// Default data
$data = array(
'type' => 'post',
'id' => 0
);
// Check if is numeric.
if( is_numeric($post_id) ) {
$data['id'] = (int) $post_id;
// Check if is string.
} elseif( is_string($post_id) ) {
// Determine "{$type}_{$id}" from string.
$bits = explode( '_', $post_id );
$id = array_pop( $bits );
$type = implode( '_', $bits );
// Check if is meta type.
if( function_exists("get_{$type}_meta") && is_numeric($id) ) {
$data['type'] = $type;
$data['id'] = (int) $id;
// Check if is taxonomy name.
} elseif( taxonomy_exists($type) && is_numeric($id) ) {
$data['type'] = 'term';
$data['id'] = (int) $id;
// Otherwise, default to option.
} else {
$data['type'] = 'option';
$data['id'] = $post_id;
}
}
/**
* Filters the $data array after it has been decoded.
*
* @date 12/02/2014
* @since 5.0.0
*
* @param array $data The type and id array.
*/
return apply_filters( "acf/decode_post_id", $data, $post_id );
}
/**
* 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) );
// Use get_$type_meta() function when possible.
if( function_exists("get_{$type}_meta") ) {
$allmeta = call_user_func("get_{$type}_meta", $id, '');
// Default to wp_options.
} else {
$allmeta = acf_get_option_meta( $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;
}
// Check option.
if( $type === 'option' ) {
return get_option( "{$prefix}{$id}_{$name}", null );
// Check meta.
} 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;
}
// Update option.
if( $type === 'option' ) {
// Unslash value to match update_metadata() functionality.
$value = wp_unslash( $value );
$autoload = (bool) acf_get_setting('autoload');
return update_option( "{$prefix}{$id}_{$name}", $value, $autoload );
// Update meta.
} 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;
}
// Update option.
if( $type === 'option' ) {
$autoload = (bool) acf_get_setting('autoload');
return delete_option( "{$prefix}{$id}_{$name}" );
// Update meta.
} 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 );
}
@@ -0,0 +1,34 @@
<?php
/**
* acf_get_post_templates
*
* Returns an array of post_type => templates data.
*
* @date 29/8/17
* @since 5.6.2
*
* @param void
* @return array
*/
function acf_get_post_templates() {
// Defaults.
$post_templates = array(
'page' => array()
);
// Loop over post types and append their templates.
if( method_exists('WP_Theme', 'get_page_templates') ) {
$post_types = acf_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;
}
}
}
// Return.
return $post_templates;
}
@@ -0,0 +1,116 @@
<?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->last_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() ) {
// Load all roles if none provided.
if( !$roles ) {
$roles = get_editable_roles();
}
// Loop over roles and populare labels.
$lables = array();
foreach( $roles as $role ) {
$lables[ $role ] = translate_user_role( $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 );
}
@@ -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);
}
}
@@ -0,0 +1,326 @@
<?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 );
}
/**
* acf_get_value
*
* 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 = 0, $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 = null, $post_id = 0, $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 = array(), $post_id = 0 ) {
// 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 );
@@ -0,0 +1,834 @@
<?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'));
add_action('acf/input/admin_footer_js', array($this, 'admin_footer_js'));
// 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'),
'Null' => __('Null', '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');
}
/*
* admin_footer_js
*
* description
*
* @type function
* @date 31/05/2016
* @since 5.3.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function admin_footer_js() {
// 3rd party hook
do_action('acf/field_group/admin_footer_js');
}
/*
* 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
global $field_group;
// vars
$status = $field_group['active'] ? __("Active",'acf') : __("Inactive",'acf');
?>
<script type="text/javascript">
(function($) {
// modify status
$('#post-status-display').html('<?php echo $status; ?>');
// remove edit links
$('#misc-publishing-actions a').remove();
})(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();
// 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();
// 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();
// 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);
// message
$a = '<a href="' . admin_url("post.php?post={$field_group['ID']}&action=edit") . '" target="_blank">' . $field_group['title'] . '</a>';
echo '<p><strong>' . __('Move Complete.', 'acf') . '</strong></p>';
echo '<p>' . sprintf( __('The %s field can now be found in the %s field group', 'acf'), $field['label'], $a ). '</p>';
echo '<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;
?>
@@ -0,0 +1,830 @@
<?php
/*
* ACF Admin Field Groups Class
*
* All the logic for editing a list of field groups
*
* @class acf_admin_field_groups
* @package ACF
* @subpackage Admin
*/
if( ! class_exists('acf_admin_field_groups') ) :
class acf_admin_field_groups {
// vars
var $url = 'edit.php?post_type=acf-field-group',
$sync = 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() {
// actions
add_action('current_screen', array($this, 'current_screen'));
add_action('trashed_post', array($this, 'trashed_post'));
add_action('untrashed_post', array($this, 'untrashed_post'));
add_action('deleted_post', array($this, 'deleted_post'));
add_action('load-edit.php', array($this, 'maybe_redirect_edit'));
}
/**
* maybe_redirect_edit
*
* Redirects the user from the old ACF4 edit page to the new ACF5 edit page
*
* @date 17/9/18
* @since 5.7.6
*
* @param void
* @return void
*/
function maybe_redirect_edit() {
if( acf_maybe_get_GET('post_type') == 'acf' ) {
wp_redirect( admin_url($this->url) );
exit;
}
}
/*
* 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('edit-acf-field-group') ) {
return;
}
// customize post_status
global $wp_post_statuses;
// modify publish post status
$wp_post_statuses['publish']->label_count = _n_noop( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', 'acf' );
// reorder trash to end
$wp_post_statuses['trash'] = acf_extract_var( $wp_post_statuses, 'trash' );
// check stuff
$this->check_duplicate();
$this->check_sync();
// actions
add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'));
add_action('admin_footer', array($this, 'admin_footer'));
// columns
add_filter('manage_edit-acf-field-group_columns', array($this, 'field_group_columns'), 10, 1);
add_action('manage_acf-field-group_posts_custom_column', array($this, 'field_group_columns_html'), 10, 2);
}
/*
* admin_enqueue_scripts
*
* This function will add the already registered css
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_enqueue_scripts() {
wp_enqueue_script('acf-input');
}
/*
* check_duplicate
*
* This function will check for any $_GET data to duplicate
*
* @type function
* @date 17/10/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function check_duplicate() {
// Display notice
if( $ids = acf_maybe_get_GET('acfduplicatecomplete') ) {
// explode
$ids = explode(',', $ids);
$total = count($ids);
// Generate text.
$text = sprintf( _n( 'Field group duplicated.', '%s field groups duplicated.', $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' );
}
// vars
$ids = array();
// check single
if( $id = acf_maybe_get_GET('acfduplicate') ) {
$ids[] = $id;
// check multiple
} elseif( acf_maybe_get_GET('action2') === 'acfduplicate' ) {
$ids = acf_maybe_get_GET('post');
}
// sync
if( !empty($ids) ) {
// validate
check_admin_referer('bulk-posts');
// vars
$new_ids = array();
// loop
foreach( $ids as $id ) {
// duplicate
$field_group = acf_duplicate_field_group( $id );
// increase counter
$new_ids[] = $field_group['ID'];
}
// redirect
wp_redirect( admin_url( $this->url . '&acfduplicatecomplete=' . implode(',', $new_ids)) );
exit;
}
}
/*
* check_sync
*
* This function will check for any $_GET data to sync
*
* @type function
* @date 9/12/2014
* @since 5.1.5
*
* @param n/a
* @return n/a
*/
function check_sync() {
// Display notice
if( $ids = acf_maybe_get_GET('acfsynccomplete') ) {
// explode
$ids = explode(',', $ids);
$total = count($ids);
// Generate text.
$text = sprintf( _n( 'Field group synchronised.', '%s field groups synchronised.', $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' );
}
// vars
$groups = acf_get_field_groups();
// bail early if no field groups
if( empty($groups) ) return;
// find JSON field groups which have not yet been imported
foreach( $groups as $group ) {
// vars
$local = acf_maybe_get($group, 'local', false);
$modified = acf_maybe_get($group, 'modified', 0);
$private = acf_maybe_get($group, 'private', false);
// Ignore if is private.
if( $private ) {
continue;
// Ignore not local "json".
} elseif( $local !== 'json' ) {
continue;
// Append to sync if not yet in database.
} elseif( !$group['ID'] ) {
$this->sync[ $group['key'] ] = $group;
// Append to sync if "json" modified time is newer than database.
} elseif( $modified && $modified > get_post_modified_time('U', true, $group['ID'], true) ) {
$this->sync[ $group['key'] ] = $group;
}
}
// bail if no sync needed
if( empty($this->sync) ) return;
// maybe sync
$sync_keys = array();
// check single
if( $key = acf_maybe_get_GET('acfsync') ) {
$sync_keys[] = $key;
// check multiple
} elseif( acf_maybe_get_GET('action2') === 'acfsync' ) {
$sync_keys = acf_maybe_get_GET('post');
}
// sync
if( !empty($sync_keys) ) {
// validate
check_admin_referer('bulk-posts');
// disable filters to ensure ACF loads raw data from DB
acf_disable_filters();
acf_enable_filter('local');
// disable JSON
// - this prevents a new JSON file being created and causing a 'change' to theme files - solves git anoyance
acf_update_setting('json', false);
// vars
$new_ids = array();
// loop
foreach( $sync_keys as $key ) {
// Bail early if not found.
if( !isset($this->sync[ $key ]) ) {
continue;
}
// Get field group.
$field_group = $this->sync[ $key ];
// Append fields.
$field_group['fields'] = acf_get_fields( $field_group );
// Import field group.
$field_group = acf_import_field_group( $field_group );
// Append imported ID.
$new_ids[] = $field_group['ID'];
}
// redirect
wp_redirect( admin_url( $this->url . '&acfsynccomplete=' . implode(',', $new_ids)) );
exit;
}
// filters
add_filter('views_edit-acf-field-group', array($this, 'list_table_views'));
}
/*
* list_table_views
*
* This function will add an extra link for JSON in the field group list table
*
* @type function
* @date 3/12/2014
* @since 5.1.5
*
* @param $views (array)
* @return $views
*/
function list_table_views( $views ) {
// vars
$class = '';
$total = count($this->sync);
// active
if( acf_maybe_get_GET('post_status') === 'sync' ) {
// actions
add_action('admin_footer', array($this, 'sync_admin_footer'), 5);
// set active class
$class = ' class="current"';
// global
global $wp_list_table;
// update pagination
$wp_list_table->set_pagination_args( array(
'total_items' => $total,
'total_pages' => 1,
'per_page' => $total
));
}
// add view
$views['json'] = '<a' . $class . ' href="' . admin_url($this->url . '&post_status=sync') . '">' . __('Sync available', 'acf') . ' <span class="count">(' . $total . ')</span></a>';
// return
return $views;
}
/*
* trashed_post
*
* This function is run when a post object is sent to the trash
*
* @type action (trashed_post)
* @date 8/01/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return n/a
*/
function trashed_post( $post_id ) {
// validate post type
if( get_post_type($post_id) != 'acf-field-group' ) {
return;
}
// trash field group
acf_trash_field_group( $post_id );
}
/*
* untrashed_post
*
* This function is run when a post object is restored from the trash
*
* @type action (untrashed_post)
* @date 8/01/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return n/a
*/
function untrashed_post( $post_id ) {
// validate post type
if( get_post_type($post_id) != 'acf-field-group' ) {
return;
}
// trash field group
acf_untrash_field_group( $post_id );
}
/*
* deleted_post
*
* This function is run when a post object is deleted from the trash
*
* @type action (deleted_post)
* @date 8/01/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return n/a
*/
function deleted_post( $post_id ) {
// validate post type
if( get_post_type($post_id) != 'acf-field-group' ) {
return;
}
// trash field group
acf_delete_field_group( $post_id );
}
/*
* field_group_columns
*
* This function will customize the columns for the field group table
*
* @type filter (manage_edit-acf-field-group_columns)
* @date 28/09/13
* @since 5.0.0
*
* @param $columns (array)
* @return $columns (array)
*/
function field_group_columns( $columns ) {
return array(
'cb' => '<input type="checkbox" />',
'title' => __('Title', 'acf'),
'acf-fg-description' => __('Description', 'acf'),
'acf-fg-status' => '<i class="acf-icon -dot-3 small acf-js-tooltip" title="' . esc_attr__('Status', 'acf') . '"></i>',
'acf-fg-count' => __('Fields', 'acf'),
);
}
/*
* field_group_columns_html
*
* This function will render the HTML for each table cell
*
* @type action (manage_acf-field-group_posts_custom_column)
* @date 28/09/13
* @since 5.0.0
*
* @param $column (string)
* @param $post_id (int)
* @return n/a
*/
function field_group_columns_html( $column, $post_id ) {
// vars
$field_group = acf_get_field_group( $post_id );
// render
$this->render_column( $column, $field_group );
}
function render_column( $column, $field_group ) {
// description
if( $column == 'acf-fg-description' ) {
if( $field_group['description'] ) {
echo '<span class="acf-description">' . acf_esc_html($field_group['description']) . '</span>';
}
// status
} elseif( $column == 'acf-fg-status' ) {
if( isset($this->sync[ $field_group['key'] ]) ) {
echo '<i class="acf-icon -sync grey small acf-js-tooltip" title="' . esc_attr__('Sync available', 'acf') .'"></i> ';
}
if( $field_group['active'] ) {
//echo '<i class="acf-icon -check small acf-js-tooltip" title="' . esc_attr__('Active', 'acf') .'"></i> ';
} else {
echo '<i class="acf-icon -minus yellow small acf-js-tooltip" title="' . esc_attr__('Inactive', 'acf') . '"></i> ';
}
// fields
} elseif( $column == 'acf-fg-count' ) {
echo esc_html( acf_get_field_count( $field_group ) );
}
}
/*
* admin_footer
*
* This function will render extra HTML onto the page
*
* @type action (admin_footer)
* @date 23/06/12
* @since 3.1.8
*
* @param n/a
* @return n/a
*/
function admin_footer() {
// vars
$url_home = 'https://www.advancedcustomfields.com';
$icon = '<i aria-hidden="true" class="dashicons dashicons-external"></i>';
?>
<script type="text/html" id="tmpl-acf-column-2">
<div class="acf-column-2">
<div class="acf-box">
<div class="inner">
<h2><?php echo acf_get_setting('name'); ?></h2>
<p><?php _e('Customize WordPress with powerful, professional and intuitive fields.','acf'); ?></p>
<h3><?php _e("Changelog",'acf'); ?></h3>
<p><?php
$acf_changelog = admin_url('edit.php?post_type=acf-field-group&page=acf-settings-info&tab=changelog');
$acf_version = acf_get_setting('version');
printf( __('See what\'s new in <a href="%s">version %s</a>.','acf'), esc_url($acf_changelog), $acf_version );
?></p>
<h3><?php _e("Resources",'acf'); ?></h3>
<ul>
<li><a href="<?php echo esc_url( $url_home ); ?>" target="_blank"><?php echo $icon; ?> <?php _e("Website",'acf'); ?></a></li>
<li><a href="<?php echo esc_url( $url_home . '/resources/' ); ?>" target="_blank"><?php echo $icon; ?> <?php _e("Documentation",'acf'); ?></a></li>
<li><a href="<?php echo esc_url( $url_home . '/support/' ); ?>" target="_blank"><?php echo $icon; ?> <?php _e("Support",'acf'); ?></a></li>
<?php if( !acf_get_setting('pro') ): ?>
<li><a href="<?php echo esc_url( $url_home . '/pro/' ); ?>" target="_blank"><?php echo $icon; ?> <?php _e("Pro",'acf'); ?></a></li>
<?php endif; ?>
</ul>
</div>
<div class="footer">
<p><?php printf( __('Thank you for creating with <a href="%s">ACF</a>.','acf'), esc_url($url_home) ); ?></p>
</div>
</div>
</div>
</script>
<script type="text/javascript">
(function($){
// wrap
$('#wpbody .wrap').attr('id', 'acf-field-group-wrap');
// wrap form
$('#posts-filter').wrap('<div class="acf-columns-2" />');
// add column main
$('#posts-filter').addClass('acf-column-1');
// add column side
$('#posts-filter').after( $('#tmpl-acf-column-2').html() );
// modify row actions
$('#the-list tr').each(function(){
// vars
var $tr = $(this),
id = $tr.attr('id'),
description = $tr.find('.column-acf-fg-description').html();
// replace Quick Edit with Duplicate (sync page has no id attribute)
if( id ) {
// vars
var post_id = id.replace('post-', '');
var url = '<?php echo esc_url( admin_url( $this->url . '&acfduplicate=__post_id__&_wpnonce=' . wp_create_nonce('bulk-posts') ) ); ?>';
var $span = $('<span class="acf-duplicate-field-group"><a title="<?php _e('Duplicate this item', 'acf'); ?>" href="' + url.replace('__post_id__', post_id) + '"><?php _e('Duplicate', 'acf'); ?></a> | </span>');
// replace
$tr.find('.column-title .row-actions .inline').replaceWith( $span );
}
// add description to title
$tr.find('.column-title .row-title').after( description );
});
// modify bulk actions
$('#bulk-action-selector-bottom option[value="edit"]').attr('value','acfduplicate').text('<?php _e( 'Duplicate', 'acf' ); ?>');
// clean up table
$('#adv-settings label[for="acf-fg-description-hide"]').remove();
// mobile compatibility
var status = $('.acf-icon.-dot-3').first().attr('title');
$('td.column-acf-fg-status').attr('data-colname', status);
// no field groups found
$('#the-list tr.no-items td').attr('colspan', 4);
// search
$('.subsubsub').append(' | <li><a href="#" class="acf-toggle-search"><?php _e('Search', 'acf'); ?></a></li>');
// events
$(document).on('click', '.acf-toggle-search', function( e ){
// prevent default
e.preventDefault();
// toggle
$('.search-box').slideToggle();
});
})(jQuery);
</script>
<?php
}
/*
* sync_admin_footer
*
* This function will render extra HTML onto the page
*
* @type action (admin_footer)
* @date 23/06/12
* @since 3.1.8
*
* @param n/a
* @return n/a
*/
function sync_admin_footer() {
// vars
$i = -1;
$columns = array(
'acf-fg-description',
'acf-fg-status',
'acf-fg-count'
);
$nonce = wp_create_nonce('bulk-posts');
?>
<script type="text/html" id="tmpl-acf-json-tbody">
<?php foreach( $this->sync as $field_group ):
// vars
$i++;
$key = $field_group['key'];
$title = $field_group['title'];
$url = admin_url( $this->url . '&post_status=sync&acfsync=' . $key . '&_wpnonce=' . $nonce );
?>
<tr <?php if($i%2 == 0): ?>class="alternate"<?php endif; ?>>
<th class="check-column" scope="row">
<label for="cb-select-<?php echo esc_attr($key); ?>" class="screen-reader-text"><?php echo esc_html(sprintf(__('Select %s', 'acf'), $title)); ?></label>
<input type="checkbox" value="<?php echo esc_attr($key); ?>" name="post[]" id="cb-select-<?php echo esc_attr($key); ?>">
</th>
<td class="post-title page-title column-title">
<strong>
<span class="row-title"><?php echo esc_html($title); ?></span><span class="acf-description"><?php echo esc_html($key); ?>.json</span>
</strong>
<div class="row-actions">
<span class="import"><a title="<?php echo esc_attr( __('Synchronise field group', 'acf') ); ?>" href="<?php echo esc_url($url); ?>"><?php _e( 'Sync', 'acf' ); ?></a></span>
</div>
</td>
<?php foreach( $columns as $column ): ?>
<td class="column-<?php echo esc_attr($column); ?>"><?php $this->render_column( $column, $field_group ); ?></td>
<?php endforeach; ?>
</tr>
<?php endforeach; ?>
</script>
<script type="text/html" id="tmpl-acf-bulk-actions">
<?php // source: bulk_actions() wp-admin/includes/class-wp-list-table.php ?>
<select name="action2" id="bulk-action-selector-bottom"></select>
<?php submit_button( __( 'Apply' ), 'action', '', false, array( 'id' => "doaction2" ) ); ?>
</script>
<script type="text/javascript">
(function($){
// update table HTML
$('#the-list').html( $('#tmpl-acf-json-tbody').html() );
// bulk may not exist if no field groups in DB
if( !$('#bulk-action-selector-bottom').exists() ) {
$('.tablenav.bottom .actions.alignleft').html( $('#tmpl-acf-bulk-actions').html() );
}
// set only options
$('#bulk-action-selector-bottom').html('<option value="-1"><?php _e('Bulk Actions'); ?></option><option value="acfsync"><?php _e('Sync', 'acf'); ?></option>');
})(jQuery);
</script>
<?php
}
}
new acf_admin_field_groups();
endif;
?>
@@ -0,0 +1,146 @@
<?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 Optional HTML alternative to text.
'html' => '', */
/** @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() {
// Ensure text contains punctuation.
// todo: Remove this after updating translations.
$text = $this->get('text');
if( substr($text, -1) !== '.' && substr($text, -1) !== '>' ) {
$text .= '.';
}
// Print HTML.
printf('<div class="acf-admin-notice notice notice-%s %s">%s</div>',
// Type class.
$this->get('type'),
// Dismissible class.
$this->get('dismissible') ? 'is-dismissible' : '',
// InnerHTML
$this->has('html') ? $this->get('html') : wpautop($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 ) );
}
@@ -0,0 +1,354 @@
<?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, $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;
}
?>
@@ -0,0 +1,225 @@
<?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 );
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
*
* Setus up logic if DB Upgrade is needed on a multi site.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function network_admin_menu() {
// vars
$has_upgrade = false;
// loop over sites
$sites = acf_get_sites();
if( $sites ) {
foreach( $sites as $site ) {
// switch blog
switch_to_blog( $site['blog_id'] );
// check for upgrade
if( acf_has_upgrade() ) {
$has_upgrade = true;
}
// restore blog
restore_current_blog();
}}
// check if upgrade is avaialble
if( $has_upgrade ) {
// 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'));
// actions
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'));
// load acf scripts
acf_enqueue_scripts();
}
/**
* 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'));
// load acf scripts
acf_enqueue_scripts();
}
/**
* 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
?>
@@ -0,0 +1,89 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_admin') ) :
class acf_admin {
/*
* __construct
*
* Initialize filters, action, variables and includes
*
* @type function
* @date 23/06/12
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action('admin_menu', array($this, 'admin_menu'));
add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts'), 0);
}
/*
* 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;
// vars
$slug = 'edit.php?post_type=acf-field-group';
$cap = acf_get_setting('capability');
// add parent
add_menu_page(__("Custom Fields",'acf'), __("Custom Fields",'acf'), $cap, $slug, false, 'dashicons-welcome-widgets-menus', '80.025');
// add children
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' );
}
/*
* admin_enqueue_scripts
*
* This function will add the already registered css
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_enqueue_scripts() {
wp_enqueue_style( 'acf-global' );
}
}
// initialize
acf()->admin = new acf_admin();
endif; // class_exists check
?>
@@ -0,0 +1,102 @@
<?php
class acf_settings_info {
/*
* __construct
*
* Initialize filters, action, variables and includes
*
* @type function
* @date 23/06/12
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action('admin_menu', array($this, 'admin_menu'));
}
/*
* 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
add_submenu_page('edit.php?post_type=acf-field-group', __('Info','acf'), __('Info','acf'), acf_get_setting('capability'),'acf-settings-info', array($this,'html'));
}
/*
* html
*
* description
*
* @type function
* @date 7/01/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function html() {
// vars
$view = array(
'version' => acf_get_setting('version'),
'have_pro' => acf_get_setting('pro'),
'tabs' => array(
'new' => __("What's New", 'acf'),
'changelog' => __("Changelog", 'acf')
),
'active' => 'new'
);
// set active tab
$tab = acf_maybe_get_GET('tab');
if( $tab && isset($view['tabs'][ $tab ]) ) {
$view['active'] = $tab;
}
// load view
acf_get_view('settings-info', $view);
}
}
// initialize
new acf_settings_info();
?>
@@ -0,0 +1,596 @@
<?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
?>
@@ -0,0 +1,157 @@
<?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
?>
@@ -0,0 +1,195 @@
<?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
?>
@@ -0,0 +1,158 @@
<?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>
@@ -0,0 +1,184 @@
<?php
// vars
$prefix = 'acf_fields[' . $field['ID'] . ']';
$id = acf_idify( $prefix );
// add prefix
$field['prefix'] = $prefix;
// div
$div = array(
'class' => 'acf-field-object acf-field-object-' . acf_slugify($field['type']),
'data-id' => $field['ID'],
'data-key' => $field['key'],
'data-type' => $field['type'],
);
$meta = array(
'ID' => $field['ID'],
'key' => $field['key'],
'parent' => $field['parent'],
'menu_order' => $i,
'save' => ''
);
?>
<div <?php echo acf_esc_attr( $div ); ?>>
<div class="meta">
<?php foreach( $meta as $k => $v ):
acf_hidden_input(array( 'name' => $prefix . '[' . $k . ']', 'value' => $v, 'id' => $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_get_field_label($field, 'admin'); ?></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 $field['name']; ?></li>
<li class="li-field-key"> <?php echo $field['key']; ?></li>
<li class="li-field-type"> <?php echo acf_get_field_type_label($field['type']); ?></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>
@@ -0,0 +1,52 @@
<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>
@@ -0,0 +1,45 @@
<?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>
@@ -0,0 +1,155 @@
<?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>
@@ -0,0 +1,216 @@
<?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 %s to %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
if( acf.isAjaxSuccess(json) ) {
// update
success = true;
// remove input
$input.remove();
// set response text
text = '<?php _e('Upgrade complete.', 'acf'); ?>';
if( jsonText = acf.getAjaxMessage(json) ) {
text = jsonText;
}
// error
} else {
// set response text
text = '<?php _e('Upgrade failed.', 'acf'); ?>';
if( jsonText = acf.getAjaxError(json) ) {
text += ' <pre>' + jsonText + '</pre>';
}
}
},
error: function( jqXHR, textStatus, errorThrown ){
// set response text
text = '<?php _e('Upgrade failed.', 'acf'); ?>';
if( errorThrown) {
text += ' <pre>' + errorThrown + '</pre>';
}
},
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>
@@ -0,0 +1,119 @@
<?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&page=acf-settings-info') ); ?></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
if( acf.isAjaxSuccess(json) ) {
// update
success = true;
// set response text
if( jsonText = acf.getAjaxMessage(json) ) {
response = jsonText;
}
// error
} else {
// set response text
response = '<?php _e('Upgrade failed.', 'acf'); ?>';
if( jsonText = acf.getAjaxError(json) ) {
response += ' <pre>' + jsonText + '</pre>';
}
}
},
error: function( jqXHR, textStatus, errorThrown ){
// set response text
response = '<?php _e('Upgrade failed.', 'acf'); ?>';
if( errorThrown) {
response += ' <pre>' + errorThrown + '</pre>';
}
},
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>
@@ -0,0 +1,27 @@
<?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>
@@ -0,0 +1,25 @@
<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>
@@ -0,0 +1,91 @@
<?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>
@@ -0,0 +1,43 @@
<?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 %s v%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; ?>
@@ -0,0 +1,54 @@
<div class="wrap acf-settings-wrap">
<h1><?php _e("Add-ons",'acf'); ?></h1>
<div class="add-ons-list">
<?php if( !empty($json) ): ?>
<?php foreach( $json as $addon ):
$addon = wp_parse_args($addon, array(
"title" => "",
"slug" => "",
"description" => "",
"thumbnail" => "",
"url" => "",
"btn" => __("Download & Install",'acf'),
"btn_color" => ""
));
?>
<div class="acf-box add-on add-on-<?php echo $addon['slug']; ?>">
<div class="thumbnail">
<a target="_blank" href="<?php echo $addon['url']; ?>">
<img src="<?php echo $addon['thumbnail']; ?>" />
</a>
</div>
<div class="inner">
<h3><a target="_blank" href="<?php echo $addon['url']; ?>"><?php echo $addon['title']; ?></a></h3>
<p><?php echo $addon['description']; ?></p>
</div>
<div class="footer">
<?php if( apply_filters("acf/is_add_on_active/slug={$addon['slug']}", false ) ): ?>
<a class="button" disabled="disabled"><?php _e("Installed",'acf'); ?></a>
<?php else: ?>
<a class="button <?php echo $addon['btn_color']; ?>" target="_blank" href="<?php echo $addon['url']; ?>" ><?php _e($addon['btn']); ?></a>
<?php endif; ?>
<?php if( !empty($addon['footer']) ): ?>
<p><?php echo $addon['footer']; ?></p>
<?php endif; ?>
</div>
</div>
<?php endforeach; ?>
<?php endif; ?>
</div>
</div>
@@ -0,0 +1,157 @@
<div class="wrap about-wrap acf-wrap">
<h1><?php _e("Welcome to Advanced Custom Fields",'acf'); ?> <?php echo $version; ?></h1>
<div class="about-text"><?php printf(__("Thank you for updating! ACF %s is bigger and better than ever before. We hope you like it.", 'acf'), $version); ?></div>
<h2 class="nav-tab-wrapper">
<?php foreach( $tabs as $tab_slug => $tab_title ): ?>
<a class="nav-tab<?php if( $active == $tab_slug ): ?> nav-tab-active<?php endif; ?>" href="<?php echo admin_url("edit.php?post_type=acf-field-group&page=acf-settings-info&tab={$tab_slug}"); ?>"><?php echo $tab_title; ?></a>
<?php endforeach; ?>
</h2>
<?php if( $active == 'new' ): ?>
<div class="feature-section">
<h2><?php _e("A Smoother Experience", 'acf'); ?> </h2>
<div class="acf-three-col">
<div>
<h3><?php _e("Improved Usability", 'acf'); ?></h3>
<p><?php _e("Including the popular Select2 library has improved both usability and speed across a number of field types including post object, page link, taxonomy and select.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Improved Design", 'acf'); ?></h3>
<p><?php _e("Many fields have undergone a visual refresh to make ACF look better than ever! Noticeable changes are seen on the gallery, relationship and oEmbed (new) fields!", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Improved Data", 'acf'); ?></h3>
<p><?php _e("Redesigning the data architecture has allowed sub fields to live independently from their parents. This allows you to drag and drop fields in and out of parent fields!", 'acf'); ?></p>
</div>
</div>
</div>
<hr />
<div class="feature-section">
<h2><?php _e("Goodbye Add-ons. Hello PRO", 'acf'); ?> 👋</h2>
<div class="acf-three-col">
<div>
<h3><?php _e("Introducing ACF PRO", 'acf'); ?></h3>
<p><?php _e("We're changing the way premium functionality is delivered in an exciting way!", 'acf'); ?></p>
<p><?php printf(__('All 4 premium add-ons have been combined into a new <a href="%s">Pro version of ACF</a>. With both personal and developer licenses available, premium functionality is more affordable and accessible than ever before!', 'acf'), esc_url('https://www.advancedcustomfields.com/pro')); ?></p>
</div>
<div>
<h3><?php _e("Powerful Features", 'acf'); ?></h3>
<p><?php _e("ACF PRO contains powerful features such as repeatable data, flexible content layouts, a beautiful gallery field and the ability to create extra admin options pages!", 'acf'); ?></p>
<p><?php printf(__('Read more about <a href="%s">ACF PRO features</a>.', 'acf'), esc_url('https://www.advancedcustomfields.com/pro')); ?></p>
</div>
<div>
<h3><?php _e("Easy Upgrading", 'acf'); ?></h3>
<p><?php _e('Upgrading to ACF PRO is easy. Simply purchase a license online and download the plugin!', 'acf'); ?></p>
<p><?php printf(__('We also wrote an <a href="%s">upgrade guide</a> to answer any questions, but if you do have one, please contact our support team via the <a href="%s">help desk</a>.', 'acf'), esc_url('https://www.advancedcustomfields.com/resources/upgrade-guide-acf-pro/'), esc_url('https://www.advancedcustomfields.com/support/')); ?></p>
</div>
</div>
</div>
<hr />
<div class="feature-section">
<h2><?php _e("New Features", 'acf'); ?> 🎉</h2>
<div class="acf-three-col">
<div>
<h3><?php _e("Link Field", 'acf'); ?></h3>
<p><?php _e("The Link field provides a simple way to select or define a link (url, title, target).", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Group Field", 'acf'); ?></h3>
<p><?php _e("The Group field provides a simple way to create a group of fields.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("oEmbed Field", 'acf'); ?></h3>
<p><?php _e("The oEmbed field allows an easy way to embed videos, images, tweets, audio, and other content.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Clone Field", 'acf'); ?> <span class="badge"><?php _e('Pro', 'acf'); ?></span></h3>
<p><?php _e("The clone field allows you to select and display existing fields.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("More AJAX", 'acf'); ?></h3>
<p><?php _e("More fields use AJAX powered search to speed up page loading.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Local JSON", 'acf'); ?></h3>
<p><?php _e("New auto export to JSON feature improves speed and allows for syncronisation.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Easy Import / Export", 'acf'); ?></h3>
<p><?php _e("Both import and export can easily be done through a new tools page.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("New Form Locations", 'acf'); ?></h3>
<p><?php _e("Fields can now be mapped to menus, menu items, comments, widgets and all user forms!", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("More Customization", 'acf'); ?></h3>
<p><?php _e("New PHP (and JS) actions and filters have been added to allow for more customization.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Fresh UI", 'acf'); ?></h3>
<p><?php _e("The entire plugin has had a design refresh including new field types, settings and design!", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("New Settings", 'acf'); ?></h3>
<p><?php _e("Field group settings have been added for Active, Label Placement, Instructions Placement and Description.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Better Front End Forms", 'acf'); ?></h3>
<p><?php _e("acf_form() can now create a new post on submission with lots of new settings.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Better Validation", 'acf'); ?></h3>
<p><?php _e("Form validation is now done via PHP + AJAX in favour of only JS.", 'acf'); ?></p>
</div>
<div>
<h3><?php _e("Moving Fields", 'acf'); ?></h3>
<p><?php _e("New field group functionality allows you to move a field between groups & parents.", 'acf'); ?></p>
</div>
<div><?php // intentional empty div for flex alignment ?></div>
</div>
</div>
<?php elseif( $active == 'changelog' ): ?>
<p class="about-description"><?php printf(__("We think you'll love the changes in %s.", 'acf'), $version); ?></p>
<?php
// extract changelog and parse markdown
$readme = file_get_contents( acf_get_path('readme.txt') );
$changelog = '';
if( preg_match( '/(= '.$version.' =)(.+?)(=|$)/s', $readme, $match ) && $match[2] ) {
$changelog = acf_parse_markdown( $match[2] );
}
echo acf_parse_markdown($changelog);
endif; ?>
</div>
@@ -0,0 +1,98 @@
<?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
?>
@@ -0,0 +1,54 @@
<?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
@@ -0,0 +1,41 @@
<?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
@@ -0,0 +1,184 @@
<?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;
}
/**
* set
*
* 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 ) {
$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() {
// Verify ajax request
if( !acf_verify_ajax() ) {
wp_send_json_error();
}
// Store data for has() and get() functions.
$this->request = wp_unslash($_REQUEST);
// Send response.
$this->send( $this->get_response( $this->request ) );
}
/**
* 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) ) {
wp_send_json_error(array( 'error' => $response->get_error_message() ));
// Return success.
} else {
wp_send_json_success($response);
}
}
}
endif; // class_exists check
?>
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,501 @@
<?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 ) {
// set to term name
$title = $term->name;
// allow for empty name
if( $title === '' ) {
$title = __('(no title)', 'acf');
}
// prepent ancestors indentation
if( is_taxonomy_hierarchical($term->taxonomy) ) {
$ancestors = get_ancestors( $term->term_id, $term->taxonomy );
$title = str_repeat('- ', count($ancestors)) . $title;
}
// return
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 array(
'taxonomy' => $taxonomy,
'slug' => $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
);
}
?>
@@ -0,0 +1,482 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('ACF_Assets') ) :
class ACF_Assets {
/** @var array Storage for translations */
var $text = array();
/** @var array Storage for data */
var $data = array();
/**
* __construct
*
* description
*
* @date 10/4/18
* @since 5.6.9
*
* @param void
* @return void
*/
function __construct() {
// actions
add_action('init', array($this, 'register_scripts'));
}
/**
* add_text
*
* description
*
* @date 13/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function add_text( $text ) {
foreach( (array) $text as $k => $v ) {
$this->text[ $k ] = $v;
}
}
/**
* add_data
*
* description
*
* @date 13/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function add_data( $data ) {
foreach( (array) $data as $k => $v ) {
$this->data[ $k ] = $v;
}
}
/**
* register_scripts
*
* description
*
* @date 13/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function register_scripts() {
// vars
$version = acf_get_setting('version');
$min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
// scripts
wp_register_script('acf-input', acf_get_url("assets/js/acf-input{$min}.js"), array('jquery', 'jquery-ui-sortable', 'jquery-ui-resizable'), $version );
wp_register_script('acf-field-group', acf_get_url("assets/js/acf-field-group{$min}.js"), array('acf-input'), $version );
// styles
wp_register_style('acf-global', acf_get_url('assets/css/acf-global.css'), array(), $version );
wp_register_style('acf-input', acf_get_url('assets/css/acf-input.css'), array('acf-global'), $version );
wp_register_style('acf-field-group', acf_get_url('assets/css/acf-field-group.css'), array('acf-input'), $version );
// action
do_action('acf/register_scripts', $version, $min);
}
/**
* enqueue_scripts
*
* Enqueue scripts for input
*
* @date 13/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function enqueue_scripts( $args = array() ) {
// run only once
if( acf_has_done('enqueue_scripts') ) {
return;
}
// defaults
$args = wp_parse_args($args, array(
// force tinymce editor to be enqueued
'uploader' => false,
// priority used for action callbacks, defaults to 20 which runs after defaults
'priority' => 20,
// action prefix
'context' => is_admin() ? 'admin' : 'wp'
));
// define actions
$actions = array(
'admin_enqueue_scripts' => $args['context'] . '_enqueue_scripts',
'admin_print_scripts' => $args['context'] . '_print_scripts',
'admin_head' => $args['context'] . '_head',
'admin_footer' => $args['context'] . '_footer',
'admin_print_footer_scripts' => $args['context'] . '_print_footer_scripts',
);
// fix customizer actions where head and footer are not available
if( $args['context'] == 'customize_controls' ) {
$actions['admin_head'] = $actions['admin_print_scripts'];
$actions['admin_footer'] = $actions['admin_print_footer_scripts'];
}
// add actions
foreach( $actions as $function => $action ) {
acf_maybe_add_action( $action, array($this, $function), $args['priority'] );
}
// enqueue uploader
// WP requires a lot of JS + inline scripes to create the media modal and should be avoioded when possible.
// - priority must be less than 10 to allow WP to enqueue
if( $args['uploader'] ) {
add_action($actions['admin_footer'], 'acf_enqueue_uploader', 5);
}
// localize text
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'),
// media
'Select.verb' => _x('Select', 'verb', 'acf'),
'Edit.verb' => _x('Edit', 'verb', 'acf'),
'Update.verb' => _x('Update', 'verb', 'acf'),
'Uploaded to this post' => __('Uploaded to this post', 'acf'),
'Expand Details' => __('Expand Details', 'acf'),
'Collapse Details' => __('Collapse Details', 'acf'),
'Restricted' => __('Restricted', 'acf'),
'All images' => __('All images', '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'),
// tooltip
'Are you sure?' => __('Are you sure?','acf'),
'Yes' => __('Yes','acf'),
'No' => __('No','acf'),
'Remove' => __('Remove','acf'),
'Cancel' => __('Cancel','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'),
// misc
'Edit field group' => __('Edit field group', 'acf'),
));
}
/**
* admin_enqueue_scripts
*
* description
*
* @date 16/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_enqueue_scripts() {
// enqueue
wp_enqueue_script('acf-input');
wp_enqueue_style('acf-input');
// vars
$text = array();
// actions
do_action('acf/enqueue_scripts');
do_action('acf/admin_enqueue_scripts');
do_action('acf/input/admin_enqueue_scripts');
// only include translated strings
foreach( $this->text as $k => $v ) {
if( str_replace('.verb', '', $k) !== $v ) {
$text[ $k ] = $v;
}
}
// localize text
if( $text ) {
wp_localize_script( 'acf-input', 'acfL10n', $text );
}
}
/**
* admin_print_scripts
*
* description
*
* @date 18/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_print_scripts() {
do_action('acf/admin_print_scripts');
}
/**
* admin_head
*
* description
*
* @date 16/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_head() {
// actions
do_action('acf/admin_head');
do_action('acf/input/admin_head');
}
/**
* admin_footer
*
* description
*
* @date 16/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_footer() {
// global
global $wp_version;
// get data
$data = wp_parse_args($this->data, array(
'screen' => acf_get_form_data('screen'),
'post_id' => acf_get_form_data('post_id'),
'nonce' => wp_create_nonce( 'acf_nonce' ),
'admin_url' => admin_url(),
'ajaxurl' => admin_url( 'admin-ajax.php' ),
'validation' => acf_get_form_data('validation'),
'wp_version' => $wp_version,
'acf_version' => acf_get_setting('version'),
'browser' => acf_get_browser(),
'locale' => acf_get_locale(),
'rtl' => is_rtl(),
'editor' => acf_is_block_editor() ? 'block' : 'classic'
));
// get l10n (old)
$l10n = apply_filters( 'acf/input/admin_l10n', array() );
// todo: force 'acf-input' script enqueue if not yet included
// - fixes potential timing issue if acf_enqueue_assest() was called during body
// localize data
?>
<script type="text/javascript">
acf.data = <?php echo wp_json_encode($data); ?>;
acf.l10n = <?php echo wp_json_encode($l10n); ?>;
</script>
<?php
// actions
do_action('acf/admin_footer');
do_action('acf/input/admin_footer');
// trigger prepare
?>
<script type="text/javascript">
acf.doAction('prepare');
</script>
<?php
}
/**
* admin_print_footer_scripts
*
* description
*
* @date 18/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_print_footer_scripts() {
do_action('acf/admin_print_footer_scripts');
}
/*
* enqueue_uploader
*
* This function will render a WP WYSIWYG and enqueue media
*
* @type function
* @date 27/10/2014
* @since 5.0.9
*
* @param n/a
* @return n/a
*/
function enqueue_uploader() {
// run only once
if( acf_has_done('enqueue_uploader') ) {
return;
}
// bail early if doing ajax
if( acf_is_ajax() ) {
return;
}
// enqueue media if user can upload
if( current_user_can('upload_files') ) {
wp_enqueue_media();
}
// create dummy editor
?>
<div id="acf-hidden-wp-editor" class="acf-hidden">
<?php wp_editor( '', 'acf_content' ); ?>
</div>
<?php
// action
do_action('acf/enqueue_uploader');
}
}
// instantiate
acf_new_instance('ACF_Assets');
endif; // class_exists check
/**
* acf_localize_text
*
* description
*
* @date 13/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_localize_text( $text ) {
return acf_get_instance('ACF_Assets')->add_text( $text );
}
/**
* acf_localize_data
*
* description
*
* @date 13/4/18
* @since 5.6.9
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_localize_data( $data ) {
return acf_get_instance('ACF_Assets')->add_data( $data );
}
/*
* acf_enqueue_scripts
*
*
*
* @type function
* @date 6/10/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function acf_enqueue_scripts( $args = array() ) {
return acf_get_instance('ACF_Assets')->enqueue_scripts( $args );
}
/*
* acf_enqueue_uploader
*
* This function will render a WP WYSIWYG and enqueue media
*
* @type function
* @date 27/10/2014
* @since 5.0.9
*
* @param n/a
* @return n/a
*/
function acf_enqueue_uploader() {
return acf_get_instance('ACF_Assets')->enqueue_uploader();
}
?>
@@ -0,0 +1,354 @@
<?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
@@ -0,0 +1,484 @@
<?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 );
}
@@ -0,0 +1,149 @@
<?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 );
}
@@ -0,0 +1,378 @@
<?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;
}
?>
@@ -0,0 +1,167 @@
<?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
?>
@@ -0,0 +1,292 @@
<?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
?>
@@ -0,0 +1,580 @@
<?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 ) {
return acf_get_field_type('select')->update_field( $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, true );
// 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
?>
@@ -0,0 +1,148 @@
<?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' => '',
);
}
/*
* 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() {
// globals
global $wp_scripts;
// register if not already (on front end)
// http://wordpress.stackexchange.com/questions/82718/how-do-i-implement-the-wordpress-iris-picker-into-my-plugin-on-the-front-end
if( !isset($wp_scripts->registered['iris']) ) {
// styles
wp_register_style('wp-color-picker', admin_url('css/color-picker.css'), array(), '', true);
// scripts
wp_register_script('iris', admin_url('js/iris.min.js'), array('jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch'), '1.0.7', true);
wp_register_script('wp-color-picker', admin_url('js/color-picker.min.js'), array('iris'), '', true);
// localize
wp_localize_script('wp-color-picker', 'wpColorPickerL10n', array(
'clear' => __('Clear', 'acf' ),
'defaultString' => __('Default', 'acf' ),
'pick' => __('Select Color', 'acf' ),
'current' => __('Current Color', 'acf' )
));
}
// enqueue
wp_enqueue_style('wp-color-picker');
wp_enqueue_script('wp-color-picker');
}
/*
* 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') );
// 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'
));
}
}
// initialize
acf_register_field_type( 'acf_field_color_picker' );
endif; // class_exists check
?>
@@ -0,0 +1,276 @@
<?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 ]) ) {
$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
?>
@@ -0,0 +1,257 @@
<?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 ) {
// format 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 to date and time
// the letter 'm' is used for date and minute in JS, so this must be done here in PHP
$formats = acf_split_date_time($field['display_format']);
// vars
$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,
);
// 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 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
?>
@@ -0,0 +1,161 @@
<?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',
));
}
}
// initialize
acf_register_field_type( 'acf_field_email' );
endif; // class_exists check
?>
@@ -0,0 +1,438 @@
<?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
?>
@@ -0,0 +1,314 @@
<?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 ) {
// validate value
if( empty($field['value']) ) {
$field['value'] = array();
}
// value
$field['value'] = wp_parse_args($field['value'], array(
'address' => '',
'lat' => '',
'lng' => ''
));
// default options
foreach( $this->default_values as $k => $v ) {
if( empty($field[ $k ]) ) {
$field[ $k ] = $v;
}
}
// vars
$atts = array(
'id' => $field['id'],
'class' => "acf-google-map {$field['class']}",
'data-lat' => $field['center_lat'],
'data-lng' => $field['center_lng'],
'data-zoom' => $field['zoom'],
);
// has value
if( $field['value']['address'] ) {
$atts['class'] .= ' -value';
}
?>
<div <?php acf_esc_attr_e($atts); ?>>
<div class="acf-hidden">
<?php foreach( $field['value'] as $k => $v ):
acf_hidden_input(array( 'name' => $field['name'].'['.$k.']', 'value' => $v, 'data-name' => $k ));
endforeach; ?>
</div>
<div class="title">
<div class="acf-actions -hover">
<a href="#" data-name="search" class="acf-icon -search grey" title="<?php _e("Search", 'acf'); ?>"></a><?php
?><a href="#" data-name="clear" class="acf-icon -cancel grey" title="<?php _e("Clear location", 'acf'); ?>"></a><?php
?><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($field['value']['address']); ?>" />
<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']
));
}
/*
* 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;
}
if( empty($value) || empty($value['lat']) || empty($value['lng']) ) {
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['lat']) ) {
$value = "";
}
// return
return $value;
}
}
// initialize
acf_register_field_type( 'acf_field_google_map' );
endif; // class_exists check
?>
@@ -0,0 +1,706 @@
<?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
*
* description
*
* @type function
* @date 11/03/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function prepare_field_for_export( $field ) {
// bail early if no sub fields
if( empty($field['sub_fields']) ) return $field;
// prepare
$field['sub_fields'] = acf_prepare_fields_for_export( $field['sub_fields'] );
// return
return $field;
}
/*
* prepare_field_for_import
*
* description
*
* @type function
* @date 11/03/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function prepare_field_for_import( $field ) {
// bail early if no sub fields
if( empty($field['sub_fields']) ) return $field;
// vars
$sub_fields = $field['sub_fields'];
// reset field setting
$field['sub_fields'] = array();
// loop
foreach( $sub_fields as &$sub_field ) {
$sub_field['parent'] = $field['key'];
}
// merge
array_unshift($sub_fields, $field);
// return
return $sub_fields;
}
/*
* 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
?>
@@ -0,0 +1,429 @@
<?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'),
));
}
/*
* 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');
// enqueue
if( $uploader == 'wp' ) {
acf_enqueue_uploader();
}
// vars
$url = '';
$alt = '';
$div = array(
'class' => 'acf-image-uploader',
'data-preview_size' => $field['preview_size'],
'data-library' => $field['library'],
'data-mime_types' => $field['mime_types'],
'data-uploader' => $uploader
);
// has value?
if( $field['value'] ) {
// update vars
$url = wp_get_attachment_image_src($field['value'], $field['preview_size']);
$alt = get_post_meta($field['value'], '_wp_attachment_image_alt', true);
// url exists
if( $url ) $url = $url[0];
// url exists
if( $url ) {
$div['class'] .= ' has-value';
}
}
// get size of preview value
$size = acf_get_image_size($field['preview_size']);
?>
<div <?php acf_esc_attr_e( $div ); ?>>
<?php acf_hidden_input(array( 'name' => $field['name'], 'value' => $field['value'] )); ?>
<div class="show-if-value image-wrap" <?php if( $size['width'] ): ?>style="<?php echo esc_attr('max-width: '.$size['width'].'px'); ?>"<?php endif; ?>>
<img data-name="image" src="<?php echo esc_url($url); ?>" alt="<?php echo esc_attr($alt); ?>"/>
<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
?>
@@ -0,0 +1,287 @@
<?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><?php
?><a class="acf-icon -pencil -clear acf-js-tooltip" data-name="edit" href="#" title="<?php _e('Edit', 'acf'); ?>"></a><?php
?><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
?>
@@ -0,0 +1,198 @@
<?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
?>
@@ -0,0 +1,304 @@
<?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
?>
@@ -0,0 +1,320 @@
<?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
?>
@@ -0,0 +1,77 @@
<?php
if( ! class_exists('acf_field_output') ) :
class acf_field_output extends acf_field {
/*
* __construct
*
* This function will setup the field type data
*
* @type function
* @date 5/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function initialize() {
// vars
$this->name = 'output';
$this->label = 'output';
$this->public = false;
$this->defaults = array(
'html' => false
);
}
/*
* render_field()
*
* Create the HTML interface for your field
*
* @param $field (array) the $field being rendered
*
* @type action
* @since 3.6
* @date 23/01/13
*
* @param $field (array) the $field being edited
* @return n/a
*/
function render_field( $field ) {
// bail early if no html
if( !$field['html'] ) return;
// html
if( is_string($field['html']) && !function_exists($field['html']) ) {
echo $field['html'];
// function
} else {
call_user_func_array($field['html'], array($field));
}
}
}
// initialize
acf_register_field_type( 'acf_field_output' );
endif; // class_exists check
?>
@@ -0,0 +1,663 @@
<?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 ) {
$archives = array();
$archives[] = array(
'id' => home_url(),
'text' => home_url()
);
foreach( $args['post_type'] as $post_type ) {
// vars
$archive_link = get_post_type_archive_link( $post_type );
// bail ealry if no link
if( !$archive_link ) continue;
// bail early if no search match
if( $is_search && stripos($archive_link, $s) === false ) continue;
// append
$archives[] = array(
'id' => $archive_link,
'text' => $archive_link
);
}
// append
$results[] = array(
'text' => __('Archives', 'acf'),
'children' => $archives
);
}
// 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']) ) {
$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
?>
@@ -0,0 +1,104 @@
<?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
?>
@@ -0,0 +1,603 @@
<?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']) ) {
$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
?>
@@ -0,0 +1,491 @@
<?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
$i = 0;
$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'];
// select value
$checked = '';
$value = strval($field['value']);
// selected choice
if( isset($field['choices'][ $value ]) ) {
$checked = $value;
// custom choice
} elseif( $field['other_choice'] && $value !== '' ) {
$checked = 'other';
// allow null
} elseif( $field['allow_null'] ) {
// do nothing
// select first input by default
} else {
$checked = key($field['choices']);
}
// ensure $checked is a string (could be an int)
$checked = strval($checked);
// other choice
if( $field['other_choice'] ) {
// vars
$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($input['disabled']);
$input['value'] = $field['value'];
}
// allow custom 'other' choice to be defined
if( !isset($field['choices']['other']) ) {
$field['choices']['other'] = '';
}
// append other choice
$field['choices']['other'] .= '</label><input type="text" ' . acf_esc_attr($input) . ' /><label>';
}
// bail early if no choices
if( empty($field['choices']) ) return;
// hiden input
$e .= acf_get_hidden_input( array('name' => $field['name']) );
// open
$e .= '<ul ' . acf_esc_attr($ul) . '>';
// foreach choices
foreach( $field['choices'] as $value => $label ) {
// ensure value is a string
$value = strval($value);
$class = '';
// increase counter
$i++;
// vars
$atts = array(
'type' => 'radio',
'id' => $field['id'],
'name' => $field['name'],
'value' => $value
);
// checked
if( $value === $checked ) {
$atts['checked'] = 'checked';
$class = ' class="selected"';
}
// deisabled
if( isset($field['disabled']) && acf_in_array($value, $field['disabled']) ) {
$atts['disabled'] = 'disabled';
}
// id (use crounter for each input)
if( $i > 1 ) {
$atts['id'] .= '-' . $value;
}
// append
$e .= '<li><label' . $class . '><input ' . acf_esc_attr( $atts ) . '/>' . $label . '</label></li>';
}
// close
$e .= '</ul>';
// return
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
?>
@@ -0,0 +1,214 @@
<?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 character length (+1 char if using decimals)
$len = strlen( (string) $field['max'] );
if( $atts['step'] < 1 ) $len++;
// 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
?>
@@ -0,0 +1,786 @@
<?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']) ) {
$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">
<span>
<?php acf_text_input( array('placeholder' => __("Search...",'acf'), 'data-filter' => 's') ); ?>
</span>
</div>
<?php endif;
/* post_type */
if( in_array('post_type', $filters) ): ?>
<div class="filter -post_type">
<span>
<?php acf_select_input( array('choices' => $filter_post_type_choices, 'data-filter' => 'post_type') ); ?>
</span>
</div>
<?php endif;
/* post_type */
if( in_array('taxonomy', $filters) ): ?>
<div class="filter -taxonomy">
<span>
<?php acf_select_input( array('choices' => $filter_taxonomy_choices, 'data-filter' => 'taxonomy') ); ?>
</span>
</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 $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 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;
}
// 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( '%s requires at least %s selection', '%s requires at least %s selections', $field['min'], 'acf' );
$valid = sprintf( $valid, $field['label'], $field['min'] );
}
// 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 ) {
// 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
?>
@@ -0,0 +1,637 @@
<?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 ) {
// ACF4 null
if( $value === 'null' ) return false;
// return
return $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);
// 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 ) {
// array
if( acf_is_array($value) ) {
foreach( $value as $i => $v ) {
$value[ $i ] = $this->format_value_single( $v, $post_id, $field );
}
} else {
$value = $this->format_value_single( $value, $post_id, $field );
}
// return
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
?>
@@ -0,0 +1,91 @@
<?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
?>
@@ -0,0 +1,164 @@
<?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
?>
@@ -0,0 +1,992 @@
<?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,
//'load_save_terms' => 0, // removed in 5.2.7
'return_format' => 'id',
'add_term' => 1, // 5.2.3
'load_terms' => 0, // 5.2.7
'save_terms' => 0 // 5.2.7
);
// 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']);
$args = apply_filters('acf/fields/taxonomy/query/name=' . $field['name'], $args, $field, $options['post_id'] );
$args = apply_filters('acf/fields/taxonomy/query/key=' . $field['key'], $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;
}
/*
* get_term_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_term_title( $term, $field, $post_id = 0 ) {
// get post_id
if( !$post_id ) $post_id = acf_get_form_data('post_id');
// vars
$title = '';
// ancestors
$ancestors = get_ancestors( $term->term_id, $field['taxonomy'] );
if( !empty($ancestors) ) {
$title .= str_repeat('- ', count($ancestors));
}
// title
$title .= $term->name;
// filters
$title = apply_filters('acf/fields/taxonomy/result', $title, $term, $field, $post_id);
$title = apply_filters('acf/fields/taxonomy/result/name=' . $field['_name'] , $title, $term, $field, $post_id);
$title = apply_filters('acf/fields/taxonomy/result/key=' . $field['key'], $title, $term, $field, $post_id);
// return
return $title;
}
/*
* 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'] ) {
// get terms
$info = acf_get_post_id_info($post_id);
$term_ids = wp_get_object_terms($info['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 ) {
// bail ealry if no terms
if( empty($this->save_post_terms) ) return;
// vars
$info = acf_get_post_id_info($post_id);
// loop
foreach( $this->save_post_terms as $taxonomy => $term_ids ){
// save
wp_set_object_terms( $info['id'], $term_ids, $taxonomy, false );
}
// reset array ( WP saves twice )
$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
?>
@@ -0,0 +1,171 @@
<?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'] && mb_strlen(wp_unslash($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
?>
@@ -0,0 +1,229 @@
<?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.
// Note: Due to the way strlen (and mb_strlen) work, line breaks count as two characters in PHP, but not in Javascript (or HTML).
// To avoid incorrectly calculating the length, replace double line breaks.
if( $field['maxlength'] && mb_strlen(str_replace("\r\n", "\n", wp_unslash($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
?>
@@ -0,0 +1,169 @@
<?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 ) {
// format value
$display_value = '';
if( $field['value'] ) {
$display_value = acf_format_date( $field['value'], $field['display_format'] );
}
// vars
$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,
);
// 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 ) {
// vars
$g_i_a = date('g:i a');
$H_i_s = date('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
?>
@@ -0,0 +1,279 @@
<?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
?>
@@ -0,0 +1,169 @@
<?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
?>
@@ -0,0 +1,583 @@
<?php
if( ! class_exists('acf_field_user') ) :
class acf_field_user 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 = 'user';
$this->label = __("User",'acf');
$this->category = 'relational';
$this->defaults = array(
'role' => '',
'multiple' => 0,
'allow_null' => 0,
'return_format' => 'array',
);
// extra
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'));
}
/*
* 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['users_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;
}
// role
if( !empty($field['role']) ) {
$args['role'] = acf_get_array( $field['role'] );
}
// search
if( $is_search ) {
// append to $args
$args['search'] = '*' . $options['s'] . '*';
// add reference
$this->field = $field;
// add filter to modify search colums
add_filter('user_search_columns', array($this, 'user_search_columns'), 10, 3);
}
// filters
$args = apply_filters("acf/fields/user/query", $args, $field, $options['post_id']);
$args = apply_filters("acf/fields/user/query/name={$field['_name']}", $args, $field, $options['post_id']);
$args = apply_filters("acf/fields/user/query/key={$field['key']}", $args, $field, $options['post_id']);
// get users
$groups = acf_get_grouped_users( $args );
// loop
if( !empty($groups) ) {
foreach( array_keys($groups) as $group_title ) {
// vars
$users = acf_extract_var( $groups, $group_title );
$data = array(
'text' => $group_title,
'children' => array()
);
// append users
foreach( array_keys($users) as $user_id ) {
$users[ $user_id ] = $this->get_result( $users[ $user_id ], $field, $options['post_id'] );
};
// order by search
if( $is_search && empty($args['orderby']) ) {
$users = acf_order_by_search( $users, $args['s'] );
}
// append to $data
foreach( $users as $id => $title ) {
$data['children'][] = array(
'id' => $id,
'text' => $title
);
}
// append to $r
$results[] = $data;
}
// optgroup or single
if( !empty($args['role']) && count($args['role']) == 1 ) {
$results = $results[0]['children'];
}
}
// vars
$response = array(
'results' => $results,
'limit' => $args['users_per_page']
);
// return
return $response;
}
/*
* get_result
*
* This function returns the HTML for a result
*
* @type function
* @date 1/11/2013
* @since 5.0.0
*
* @param $post (object)
* @param $field (array)
* @param $post_id (int) the post_id to which this value is saved to
* @return (string)
*/
function get_result( $user, $field, $post_id = 0 ) {
// get post_id
if( !$post_id ) $post_id = acf_get_form_data('post_id');
// vars
$result = $user->user_login;
// append name
if( $user->first_name ) {
$result .= ' (' . $user->first_name;
if( $user->last_name ) {
$result .= ' ' . $user->last_name;
}
$result .= ')';
}
// filters
$result = apply_filters("acf/fields/user/result", $result, $user, $field, $post_id);
$result = apply_filters("acf/fields/user/result/name={$field['_name']}", $result, $user, $field, $post_id);
$result = apply_filters("acf/fields/user/result/key={$field['key']}", $result, $user, $field, $post_id);
// return
return $result;
}
/*
* user_search_columns
*
* This function will modify the columns which the user AJAX search looks in
*
* @type function
* @date 17/06/2014
* @since 5.0.0
*
* @param $columns (array)
* @return $columns
*/
function user_search_columns( $columns, $search, $WP_User_Query ) {
// bail early if no field
if( empty($this->field) ) {
return $columns;
}
// vars
$field = $this->field;
// filter for 3rd party customization
$columns = apply_filters("acf/fields/user/search_columns", $columns, $search, $WP_User_Query, $field);
$columns = apply_filters("acf/fields/user/search_columns/name={$field['_name']}", $columns, $search, $WP_User_Query, $field);
$columns = apply_filters("acf/fields/user/search_columns/key={$field['key']}", $columns, $search, $WP_User_Query, $field);
// return
return $columns;
}
/*
* 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 ) {
// 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 );
}
/*
* render_field_settings()
*
* Create extra options for your field. This is rendered when editing a field.
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
*
* @type action
* @since 3.6
* @date 23/01/13
*
* @param $field - an array holding all the field's data
*/
function render_field_settings( $field ) {
acf_render_field_setting( $field, array(
'label' => __('Filter by role','acf'),
'instructions' => '',
'type' => 'select',
'name' => 'role',
'choices' => acf_get_pretty_user_roles(),
'multiple' => 1,
'ui' => 1,
'allow_null' => 1,
'placeholder' => __("All user roles",'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(
'array' => __("User Array",'acf'),
'object' => __("User Object",'acf'),
'id' => __("User ID",'acf'),
),
'layout' => 'horizontal',
));
}
/*
* 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;
}
/*
* 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 ) {
// 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;
}
}
// initialize
acf_register_field_type( 'acf_field_user' );
endif; // class_exists check
?>
@@ -0,0 +1,489 @@
<?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() {
// wp-includes/class-wp-embed.php
if( !empty($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 );
}
// wp-includes/default-filters.php
add_filter( 'acf_the_content', 'capital_P_dangit', 11 );
add_filter( 'acf_the_content', 'wptexturize' );
add_filter( 'acf_the_content', 'convert_smilies', 20 );
// Removed in 4.4
if( acf_version_compare('wp', '<', '4.4') ) {
add_filter( 'acf_the_content', 'convert_chars' );
}
add_filter( 'acf_the_content', 'wpautop' );
add_filter( 'acf_the_content', 'shortcode_unautop' );
// should only be for the_content (causes double image on attachment page)
//add_filter( 'acf_the_content', 'prepend_attachment' );
// Added in 4.4
if( function_exists('wp_make_content_images_responsive') ) {
add_filter( 'acf_the_content', 'wp_make_content_images_responsive' );
}
add_filter( 'acf_the_content', 'do_shortcode', 11);
}
/*
* 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;
$button = '';
// 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 tp upload
if( !current_user_can('upload_files') ) {
$field['media_upload'] = 0;
}
// mode
$switch_class = ($default_editor === 'html') ? 'html-active' : 'tmce-active';
// filter value for editor
remove_filter( 'acf_the_editor_content', 'format_for_editor', 10, 2 );
remove_filter( 'acf_the_editor_content', 'wp_htmledit_pre', 10, 1 );
remove_filter( 'acf_the_editor_content', 'wp_richedit_pre', 10, 1 );
// WP 4.3
if( acf_version_compare('wp', '>=', '4.3') ) {
add_filter( 'acf_the_editor_content', 'format_for_editor', 10, 2 );
$button = 'data-wp-editor-id="' . $id . '"';
// WP < 4.3
} else {
$function = ($default_editor === 'html') ? 'wp_htmledit_pre' : 'wp_richedit_pre';
add_filter('acf_the_editor_content', $function, 10, 1);
$button = 'onclick="switchEditors.switchto(this);"';
}
// filter
$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 $id; ?>-editor-tools" class="wp-editor-tools hide-if-no-js">
<?php if( $field['media_upload'] ): ?>
<div id="wp-<?php echo $id; ?>-media-buttons" class="wp-media-buttons">
<?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 $id; ?>-tmce" class="wp-switch-editor switch-tmce" <?php echo $button; ?> type="button"><?php echo __('Visual', 'acf'); ?></button>
<button id="<?php echo $id; ?>-html" class="wp-switch-editor switch-html" <?php echo $button; ?> 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 $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 initalized 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
?>
@@ -0,0 +1,277 @@
<?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
?>
@@ -0,0 +1,243 @@
<?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';
$args = array(
'attachment' => $post_id
);
// get field groups
$field_groups = acf_get_field_groups( $args );
// 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;
?>
@@ -0,0 +1,353 @@
<?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;
?>
@@ -0,0 +1,478 @@
<?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;
?>
@@ -0,0 +1,646 @@
<?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 = '' ) {
acf()->form_front->get_form( $id );
}
function acf_register_form( $args ) {
acf()->form_front->add_form( $args );
}
?>
@@ -0,0 +1,177 @@
<?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;
@@ -0,0 +1,395 @@
<?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 = acf_get_term_post_id( 'nav_menu', $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;
}
/*
* wp_edit_nav_menu_walker
*
* description
*
* @type function
* @date 26/5/17
* @since 5.6.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
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);
// include walker
if( class_exists('Walker_Nav_Menu_Edit') ) {
acf_include('includes/walkers/class-acf-walker-nav-menu-edit.php');
}
// return
return 'ACF_Walker_Nav_Menu_Edit';
}
/*
* 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 = acf_get_term_post_id( 'nav_menu', $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;
?>
@@ -0,0 +1,329 @@
<?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, $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;
?>
@@ -0,0 +1,415 @@
<?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 = acf_get_term_post_id( $taxonomy, 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 = acf_get_term_post_id( $term->taxonomy, $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 = acf_get_term_post_id( $taxonomy, $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;
?>
@@ -0,0 +1,370 @@
<?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_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
?>
@@ -0,0 +1,329 @@
<?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 ) {
// bail ealry if not valid (!customize + acf values + nonce)
if( isset($_POST['wp_customize']) || !isset($new_instance['acf']) || !acf_verify_nonce('widget') ) 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;
?>
@@ -0,0 +1,280 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_json') ) :
class acf_json {
function __construct() {
// update setting
acf_update_setting('save_json', get_stylesheet_directory() . '/acf-json');
acf_append_setting('load_json', get_stylesheet_directory() . '/acf-json');
// actions
add_action('acf/update_field_group', array($this, 'update_field_group'), 10, 1);
add_action('acf/untrash_field_group', array($this, 'update_field_group'), 10, 1);
add_action('acf/trash_field_group', array($this, 'delete_field_group'), 10, 1);
add_action('acf/delete_field_group', array($this, 'delete_field_group'), 10, 1);
add_action('acf/include_fields', array($this, 'include_json_folders'), 10, 0);
}
/*
* update_field_group
*
* This function is hooked into the acf/update_field_group action and will save all field group data to a .json file
*
* @type function
* @date 10/03/2014
* @since 5.0.0
*
* @param $field_group (array)
* @return n/a
*/
function update_field_group( $field_group ) {
// validate
if( !acf_get_setting('json') ) return;
// get fields
$field_group['fields'] = acf_get_fields( $field_group );
// save file
acf_write_json_field_group( $field_group );
}
/*
* delete_field_group
*
* This function will remove the field group .json file
*
* @type function
* @date 10/03/2014
* @since 5.0.0
*
* @param $field_group (array)
* @return n/a
*/
function delete_field_group( $field_group ) {
// validate
if( !acf_get_setting('json') ) return;
// WP appends '__trashed' to end of 'key' (post_name)
$field_group['key'] = str_replace('__trashed', '', $field_group['key']);
// delete
acf_delete_json_field_group( $field_group['key'] );
}
/*
* include_json_folders
*
* This function will include all registered .json files
*
* @type function
* @date 10/03/2014
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function include_json_folders() {
// validate
if( !acf_get_setting('json') ) return;
// vars
$paths = acf_get_setting('load_json');
// loop through and add to cache
foreach( $paths as $path ) {
$this->include_json_folder( $path );
}
}
/*
* include_json_folder
*
* This function will include all .json files within a folder
*
* @type function
* @date 1/5/17
* @since 5.5.13
*
* @param n/a
* @return n/a
*/
function include_json_folder( $path = '' ) {
// remove trailing slash
$path = untrailingslashit( $path );
// bail early if path does not exist
if( !is_dir($path) ) return false;
// open
$dir = opendir( $path );
// bail early if not valid
if( !$dir ) return false;
// loop over files
while(false !== ( $file = readdir($dir)) ) {
// validate type
if( pathinfo($file, PATHINFO_EXTENSION) !== 'json' ) continue;
// read json
$json = file_get_contents("{$path}/{$file}");
// validate json
if( empty($json) ) continue;
// decode
$json = json_decode($json, true);
// add local
$json['local'] = 'json';
// add field group
acf_add_local_field_group( $json );
}
// return
return true;
}
}
// initialize
acf()->json = new acf_json();
endif; // class_exists check
/*
* acf_write_json_field_group
*
* This function will save a field group to a json file within the current theme
*
* @type function
* @date 5/12/2014
* @since 5.1.5
*
* @param $field_group (array)
* @return (boolean)
*/
function acf_write_json_field_group( $field_group ) {
// vars
$path = acf_get_setting('save_json');
$file = $field_group['key'] . '.json';
// remove trailing slash
$path = untrailingslashit( $path );
// bail early if dir does not exist
if( !is_writable($path) ) return false;
// prepare for export
$id = acf_extract_var( $field_group, 'ID' );
$field_group = acf_prepare_field_group_for_export( $field_group );
// add modified time
$field_group['modified'] = get_post_modified_time('U', true, $id, true);
// write file
$f = fopen("{$path}/{$file}", 'w');
fwrite($f, acf_json_encode( $field_group ));
fclose($f);
// return
return true;
}
/*
* acf_delete_json_field_group
*
* This function will delete a json field group file
*
* @type function
* @date 5/12/2014
* @since 5.1.5
*
* @param $key (string)
* @return (boolean)
*/
function acf_delete_json_field_group( $key ) {
// vars
$path = acf_get_setting('save_json');
$file = $key . '.json';
// remove trailing slash
$path = untrailingslashit( $path );
// bail early if file does not exist
if( !is_readable("{$path}/{$file}") ) {
return false;
}
// remove file
unlink("{$path}/{$file}");
// return
return true;
}
?>
@@ -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_CN', // 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' );
@@ -0,0 +1,579 @@
<?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 void
*/
function acf_add_local_field_group( $field_group ) {
// Validate field group.
$field_group = acf_get_valid_field_group( $field_group );
// Bail early if field group already exists.
if( acf_is_local_field_group($field_group['key']) ) {
return;
}
// Extract fields from group.
$fields = acf_extract_var( $field_group, 'fields' );
// Add local reference (may be set to "json").
if( empty($field_group['local']) ) {
$field_group['local'] = 'php';
}
// Add to store
acf_get_local_store( 'groups' )->set( $field_group['key'], $field_group );
// Add fields
if( $fields ) {
// Add parent reference
foreach( $fields as $i => $field ) {
$fields[ $i ]['parent'] = $field_group['key'];
}
// Add fields.
acf_add_local_fields( $fields );
}
}
/**
* 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 args needed for import.
$field = wp_parse_args($field, array(
'key' => '',
'name' => '',
'type' => '',
'parent' => ''
));
// Ensure field has a key.
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 ) );
}
// Set menu order.
if( !isset($field['menu_order']) ) {
$field['menu_order'] = acf_count_local_fields( $field['parent'] );
}
// 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/get_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 );
?>
@@ -0,0 +1,254 @@
<?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 );
}
@@ -0,0 +1,372 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_locations') ) :
class acf_locations {
/** @var array Contains an array of location rule instances */
var $locations = 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() {
/* do nothing */
}
/*
* register_location
*
* This function will store a location rule class
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $instance (object)
* @return n/a
*/
function register_location( $class ) {
$instance = new $class();
$this->locations[ $instance->name ] = $instance;
}
/*
* get_rule
*
* This function will return a location rule class
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $name (string)
* @return (mixed)
*/
function get_location( $name ) {
return isset( $this->locations[$name] ) ? $this->locations[$name] : null;
}
/*
* get_rules
*
* This function will return a grouped array of location rules (category => name => label)
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param n/a
* @return (array)
*/
function get_locations() {
// vars
$groups = array();
$l10n = array(
'post' => __('Post', 'acf'),
'page' => __('Page', 'acf'),
'user' => __('User', 'acf'),
'forms' => __('Forms', 'acf'),
);
// loop
foreach( $this->locations as $location ) {
// bail ealry if not public
if( !$location->public ) continue;
// translate
$cat = $location->category;
$cat = isset( $l10n[$cat] ) ? $l10n[$cat] : $cat;
// append
$groups[ $cat ][ $location->name ] = $location->label;
}
// filter
$groups = apply_filters('acf/location/rule_types', $groups);
// return
return $groups;
}
}
// initialize
acf()->locations = new acf_locations();
endif; // class_exists check
/*
* acf_register_location_rule
*
* alias of acf()->locations->register_location()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_register_location_rule( $class ) {
return acf()->locations->register_location( $class );
}
/*
* acf_get_location_rule
*
* alias of acf()->locations->get_location()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_location_rule( $name ) {
return acf()->locations->get_location( $name );
}
/*
* acf_get_location_rule_types
*
* alias of acf()->locations->get_locations()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_location_rule_types() {
return acf()->locations->get_locations();
}
/**
* acf_validate_location_rule
*
* Returns a valid location rule array.
*
* @date 28/8/18
* @since 5.7.4
*
* @param $rule array The rule array.
* @return array
*/
function acf_validate_location_rule( $rule = false ) {
// defaults
$rule = wp_parse_args( $rule, array(
'id' => '',
'group' => '',
'param' => '',
'operator' => '==',
'value' => '',
));
// filter
$rule = apply_filters( "acf/location/validate_rule/type={$rule['param']}", $rule );
$rule = apply_filters( "acf/location/validate_rule", $rule);
// return
return $rule;
}
/*
* acf_get_location_rule_operators
*
* This function will return the operators for a given rule
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param $rule (array)
* @return (array)
*/
function acf_get_location_rule_operators( $rule ) {
// vars
$operators = array(
'==' => __("is equal to",'acf'),
'!=' => __("is not equal to",'acf'),
);
// filter
$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
return $operators;
}
/*
* acf_get_location_rule_values
*
* This function will return the values for a given rule
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param $rule (array)
* @return (array)
*/
function acf_get_location_rule_values( $rule ) {
// vars
$values = array();
// filter
$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
return $values;
}
/*
* acf_match_location_rule
*
* This function will match a given rule to the $screen
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param $rule (array)
* @param $screen (array)
* @return (boolean)
*/
function acf_match_location_rule( $rule, $screen, $field_group ) {
// vars
$result = false;
// filter
$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
return $result;
}
/*
* acf_get_location_screen
*
* This function will return a valid location screen array
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param $screen (array)
* @param $field_group (array)
* @return (array)
*/
function acf_get_location_screen( $screen = array(), $field_group = false ) {
// vars
$screen = wp_parse_args($screen, array(
'lang' => acf_get_setting('current_language'),
'ajax' => false
));
// filter for 3rd party customization
$screen = apply_filters('acf/location/screen', $screen, $field_group);
// return
return $screen;
}
/**
* acf_get_valid_location_rule
*
* Deprecated in 5.7.4. Use acf_validate_location_rule() instead.
*
* @date 30/5/17
* @since 5.6.0
*
* @param $rule array The rule array.
* @return array
*/
function acf_get_valid_location_rule( $rule ) {
return acf_validate_location_rule( $rule );
}
?>
@@ -0,0 +1,127 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_location_attachment') ) :
class acf_location_attachment extends acf_location {
/*
* __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 initialize() {
// vars
$this->name = 'attachment';
$this->label = __("Attachment",'acf');
$this->category = 'forms';
}
/*
* rule_match
*
* This function is used to match this location $rule to the current $screen
*
* @type function
* @date 3/01/13
* @since 3.5.7
*
* @param $match (boolean)
* @param $rule (array)
* @return $options (array)
*/
function rule_match( $result, $rule, $screen ) {
// vars
$attachment = acf_maybe_get( $screen, 'attachment' );
// validate
if( !$attachment ) return false;
// get attachment mime type
$mime_type = get_post_mime_type( $attachment );
// no specific mime
if( !strpos($rule['value'], '/') ) {
// explode into [0] => type, [1] => mime
$bits = explode('/', $mime_type);
// if type matches, fake the $mime_type to match
if( $rule['value'] === $bits[0] ) {
$mime_type = $rule['value'];
}
}
// match
return $this->compare( $mime_type, $rule );
}
/*
* rule_operators
*
* This function returns the available values for this rule type
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param n/a
* @return (array)
*/
function rule_values( $choices, $rule ) {
// vars
$mimes = get_allowed_mime_types();
$choices = array(
'all' => __('All', 'acf')
);
// loop
foreach( $mimes as $type => $mime ) {
$group = current( explode('/', $mime) );
$choices[ $group ][ $group ] = sprintf( __('All %s formats', 'acf'), $group);
$choices[ $group ][ $mime ] = "$type ($mime)";
}
// return
return $choices;
}
}
// initialize
acf_register_location_rule( 'acf_location_attachment' );
endif; // class_exists check
?>
@@ -0,0 +1,95 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_location_comment') ) :
class acf_location_comment extends acf_location {
/*
* __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 initialize() {
// vars
$this->name = 'comment';
$this->label = __("Comment",'acf');
$this->category = 'forms';
}
/*
* rule_match
*
* This function is used to match this location $rule to the current $screen
*
* @type function
* @date 3/01/13
* @since 3.5.7
*
* @param $match (boolean)
* @param $rule (array)
* @return $options (array)
*/
function rule_match( $result, $rule, $screen ) {
// vars
$comment = acf_maybe_get( $screen, 'comment' );
// bail early if not comment
if( !$comment ) return false;
// return
return $this->compare( $comment, $rule );
}
/*
* rule_operators
*
* This function returns the available values for this rule type
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param n/a
* @return (array)
*/
function rule_values( $choices, $rule ) {
// vars
$choices = array( 'all' => __('All', 'acf') );
$choices = array_merge( $choices, acf_get_pretty_post_types() );
// change this to post types that support comments
// return
return $choices;
}
}
// initialize
acf_register_location_rule( 'acf_location_comment' );
endif; // class_exists check
?>
@@ -0,0 +1,128 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_location_current_user_role') ) :
class acf_location_current_user_role extends acf_location {
/*
* __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 initialize() {
// vars
$this->name = 'current_user_role';
$this->label = __("Current User Role",'acf');
$this->category = 'user';
}
/*
* rule_match
*
* This function is used to match this location $rule to the current $screen
*
* @type function
* @date 3/01/13
* @since 3.5.7
*
* @param $match (boolean)
* @param $rule (array)
* @return $options (array)
*/
function rule_match( $result, $rule, $screen ) {
// bail early if not logged in
if( !is_user_logged_in() ) return false;
// vars
$user = wp_get_current_user();
// super_admin
if( $rule['value'] == 'super_admin' ) {
$result = is_super_admin( $user->ID );
// role
} else {
$result = in_array( $rule['value'], $user->roles );
}
// reverse if 'not equal to'
if( $rule['operator'] == '!=' ) {
$result = !$result;
}
// return
return $result;
}
/*
* rule_operators
*
* This function returns the available values for this rule type
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param n/a
* @return (array)
*/
function rule_values( $choices, $rule ) {
// global
global $wp_roles;
// specific roles
$choices = $wp_roles->get_names();
// multi-site
if( is_multisite() ) {
$prepend = array( 'super_admin' => __('Super Admin', 'acf') );
$choices = array_merge( $prepend, $choices );
}
// return
return $choices;
}
}
// initialize
acf_register_location_rule( 'acf_location_current_user_role' );
endif; // class_exists check
?>
@@ -0,0 +1,111 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_location_current_user') ) :
class acf_location_current_user extends acf_location {
/*
* __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 initialize() {
// vars
$this->name = 'current_user';
$this->label = __("Current User",'acf');
$this->category = 'user';
}
/*
* rule_match
*
* This function is used to match this location $rule to the current $screen
*
* @type function
* @date 3/01/13
* @since 3.5.7
*
* @param $match (boolean)
* @param $rule (array)
* @return $options (array)
*/
function rule_match( $result, $rule, $screen ) {
// logged in
if( $rule['value'] == 'logged_in' ) {
$result = is_user_logged_in();
// viewing_front
} elseif( $rule['value'] == 'viewing_front' ) {
$result = !is_admin();
// viewing_back
} elseif( $rule['value'] == 'viewing_back' ) {
$result = is_admin();
}
// reverse if 'not equal to'
if( $rule['operator'] == '!=' ) {
$result = !$result;
}
// return
return $result;
}
/*
* rule_operators
*
* This function returns the available values for this rule type
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param n/a
* @return (array)
*/
function rule_values( $choices, $rule ) {
return array(
'logged_in' => __('Logged in', 'acf'),
'viewing_front' => __('Viewing front end', 'acf'),
'viewing_back' => __('Viewing back end', 'acf')
);
}
}
// initialize
acf_register_location_rule( 'acf_location_current_user' );
endif; // class_exists check
?>
@@ -0,0 +1,104 @@
<?php
if( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
if( ! class_exists('acf_location_nav_menu_item') ) :
class acf_location_nav_menu_item extends acf_location {
/*
* __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 initialize() {
// vars
$this->name = 'nav_menu_item';
$this->label = __("Menu Item",'acf');
$this->category = 'forms';
}
/*
* rule_match
*
* This function is used to match this location $rule to the current $screen
*
* @type function
* @date 3/01/13
* @since 3.5.7
*
* @param $match (boolean)
* @param $rule (array)
* @return $options (array)
*/
function rule_match( $result, $rule, $screen ) {
// vars
$nav_menu_item = acf_maybe_get( $screen, 'nav_menu_item' );
// bail early if not nav_menu_item
if( !$nav_menu_item ) return false;
// append nav_menu data
if( !isset($screen['nav_menu']) ) {
$screen['nav_menu'] = acf_get_data('nav_menu_id');
}
// return
return acf_get_location_rule('nav_menu')->rule_match( $result, $rule, $screen );
}
/*
* rule_operators
*
* This function returns the available values for this rule type
*
* @type function
* @date 30/5/17
* @since 5.6.0
*
* @param n/a
* @return (array)
*/
function rule_values( $choices, $rule ) {
// get menu choices
$choices = acf_get_location_rule('nav_menu')->rule_values( $choices, $rule );
// append item types?
// dificult to get these details
// return
return $choices;
}
}
// initialize
acf_register_location_rule( 'acf_location_nav_menu_item' );
endif; // class_exists check
?>

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