wp_back/wp-content/plugins/advanced-custom-fields/includes/api/api-helpers.php
2024-05-20 15:37:46 +03:00

4673 lines
88 KiB
PHP
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?php
/*
* acf_is_array
*
* This function will return true for a non empty array
*
* @type function
* @date 6/07/2016
* @since 5.4.0
*
* @param $array (array)
* @return (boolean)
*/
function acf_is_array( $array ) {
return ( is_array( $array ) && ! empty( $array ) );
}
/**
* acf_has_setting
*
* alias of acf()->has_setting()
*
* @date 2/2/18
* @since 5.6.5
*
* @param n/a
* @return n/a
*/
function acf_has_setting( $name = '' ) {
return acf()->has_setting( $name );
}
/**
* acf_raw_setting
*
* alias of acf()->get_setting()
*
* @date 2/2/18
* @since 5.6.5
*
* @param n/a
* @return n/a
*/
function acf_raw_setting( $name = '' ) {
return acf()->get_setting( $name );
}
/*
* acf_update_setting
*
* alias of acf()->update_setting()
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param $name (string)
* @param $value (mixed)
* @return n/a
*/
function acf_update_setting( $name, $value ) {
// validate name
$name = acf_validate_setting( $name );
// update
return acf()->update_setting( $name, $value );
}
/**
* acf_validate_setting
*
* Returns the changed setting name if available.
*
* @date 2/2/18
* @since 5.6.5
*
* @param n/a
* @return n/a
*/
function acf_validate_setting( $name = '' ) {
return apply_filters( 'acf/validate_setting', $name );
}
/*
* acf_get_setting
*
* alias of acf()->get_setting()
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function acf_get_setting( $name, $value = null ) {
// validate name
$name = acf_validate_setting( $name );
// check settings
if ( acf_has_setting( $name ) ) {
$value = acf_raw_setting( $name );
}
// filter
$value = apply_filters( "acf/settings/{$name}", $value );
// return
return $value;
}
/**
* Return an array of ACF's internal post type names
*
* @since 6.1
* @return array An array of ACF's internal post type names
*/
function acf_get_internal_post_types() {
return array( 'acf-field-group', 'acf-post-type', 'acf-taxonomy', 'acf-ui-options-page' );
}
/*
* acf_append_setting
*
* This function will add a value into the settings array found in the acf object
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param $name (string)
* @param $value (mixed)
* @return n/a
*/
function acf_append_setting( $name, $value ) {
// vars
$setting = acf_raw_setting( $name );
// bail early if not array
if ( ! is_array( $setting ) ) {
$setting = array();
}
// append
$setting[] = $value;
// update
return acf_update_setting( $name, $setting );
}
/**
* acf_get_data
*
* Returns data.
*
* @date 28/09/13
* @since 5.0.0
*
* @param string $name
* @return mixed
*/
function acf_get_data( $name ) {
return acf()->get_data( $name );
}
/**
* acf_set_data
*
* Sets data.
*
* @date 28/09/13
* @since 5.0.0
*
* @param string $name
* @param mixed $value
* @return n/a
*/
function acf_set_data( $name, $value ) {
return acf()->set_data( $name, $value );
}
/**
* Appends data to an existing key.
*
* @date 11/06/2020
* @since 5.9.0
*
* @param string $name The data name.
* @return array $data The data array.
*/
function acf_append_data( $name, $data ) {
$prev_data = acf()->get_data( $name );
if ( is_array( $prev_data ) ) {
$data = array_merge( $prev_data, $data );
}
acf()->set_data( $name, $data );
}
/*
* acf_init
*
* alias of acf()->init()
*
* @type function
* @date 28/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function acf_init() {
acf()->init();
}
/*
* acf_has_done
*
* This function will return true if this action has already been done
*
* @type function
* @date 16/12/2015
* @since 5.3.2
*
* @param $name (string)
* @return (boolean)
*/
function acf_has_done( $name ) {
// return true if already done
if ( acf_raw_setting( "has_done_{$name}" ) ) {
return true;
}
// update setting and return
acf_update_setting( "has_done_{$name}", true );
return false;
}
/*
* acf_get_external_path
*
* This function will return the path to a file within an external folder
*
* @type function
* @date 22/2/17
* @since 5.5.8
*
* @param $file (string)
* @param $path (string)
* @return (string)
*/
function acf_get_external_path( $file, $path = '' ) {
return plugin_dir_path( $file ) . $path;
}
/*
* acf_get_external_dir
*
* This function will return the url to a file within an external folder
*
* @type function
* @date 22/2/17
* @since 5.5.8
*
* @param $file (string)
* @param $path (string)
* @return (string)
*/
function acf_get_external_dir( $file, $path = '' ) {
return acf_plugin_dir_url( $file ) . $path;
}
/**
* acf_plugin_dir_url
*
* This function will calculate the url to a plugin folder.
* Different to the WP plugin_dir_url(), this function can calculate for urls outside of the plugins folder (theme include).
*
* @date 13/12/17
* @since 5.6.8
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_plugin_dir_url( $file ) {
// vars
$path = plugin_dir_path( $file );
$path = wp_normalize_path( $path );
// check plugins
$check_path = wp_normalize_path( realpath( WP_PLUGIN_DIR ) );
if ( strpos( $path, $check_path ) === 0 ) {
return str_replace( $check_path, plugins_url(), $path );
}
// check wp-content
$check_path = wp_normalize_path( realpath( WP_CONTENT_DIR ) );
if ( strpos( $path, $check_path ) === 0 ) {
return str_replace( $check_path, content_url(), $path );
}
// check root
$check_path = wp_normalize_path( realpath( ABSPATH ) );
if ( strpos( $path, $check_path ) === 0 ) {
return str_replace( $check_path, site_url( '/' ), $path );
}
// return
return plugin_dir_url( $file );
}
/*
* acf_parse_args
*
* This function will merge together 2 arrays and also convert any numeric values to ints
*
* @type function
* @date 18/10/13
* @since 5.0.0
*
* @param $args (array)
* @param $defaults (array)
* @return $args (array)
*/
function acf_parse_args( $args, $defaults = array() ) {
// parse args
$args = wp_parse_args( $args, $defaults );
// parse types
$args = acf_parse_types( $args );
// return
return $args;
}
/*
* acf_parse_types
*
* This function will convert any numeric values to int and trim strings
*
* @type function
* @date 18/10/13
* @since 5.0.0
*
* @param $var (mixed)
* @return $var (mixed)
*/
function acf_parse_types( $array ) {
return array_map( 'acf_parse_type', $array );
}
/*
* acf_parse_type
*
* description
*
* @type function
* @date 11/11/2014
* @since 5.0.9
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_parse_type( $v ) {
// Check if is string.
if ( is_string( $v ) ) {
// Trim ("Word " = "Word").
$v = trim( $v );
// Convert int strings to int ("123" = 123).
if ( is_numeric( $v ) && strval( intval( $v ) ) === $v ) {
$v = intval( $v );
}
}
// return.
return $v;
}
/**
* This function will load in a file from the 'admin/views' folder and allow variables to be passed through
*
* @date 28/09/13
* @since 5.0.0
*
* @param string $view_path
* @param array $view_args
*
* @return void
*/
function acf_get_view( $view_path = '', $view_args = array() ) {
// allow view file name shortcut
if ( substr( $view_path, -4 ) !== '.php' ) {
$view_path = acf_get_path( "includes/admin/views/{$view_path}.php" );
}
// include
if ( file_exists( $view_path ) ) {
// Use `EXTR_SKIP` here to prevent `$view_path` from being accidentally/maliciously overridden.
extract( $view_args, EXTR_SKIP );
include $view_path;
}
}
/*
* acf_merge_atts
*
* description
*
* @type function
* @date 2/11/2014
* @since 5.0.9
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_merge_atts( $atts, $extra = array() ) {
// bail early if no $extra
if ( empty( $extra ) ) {
return $atts;
}
// trim
$extra = array_map( 'trim', $extra );
$extra = array_filter( $extra );
// merge in new atts
foreach ( $extra as $k => $v ) {
// append
if ( $k == 'class' || $k == 'style' ) {
$atts[ $k ] .= ' ' . $v;
// merge
} else {
$atts[ $k ] = $v;
}
}
// return
return $atts;
}
/*
* acf_nonce_input
*
* This function will create a basic nonce input
*
* @type function
* @date 24/5/17
* @since 5.6.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_nonce_input( $nonce = '' ) {
echo '<input type="hidden" name="_acf_nonce" value="' . wp_create_nonce( $nonce ) . '" />';
}
/*
* acf_extract_var
*
* This function will remove the var from the array, and return the var
*
* @type function
* @date 2/10/13
* @since 5.0.0
*
* @param $array (array)
* @param $key (string)
* @return (mixed)
*/
function acf_extract_var( &$array, $key, $default = null ) {
// check if exists
// - uses array_key_exists to extract NULL values (isset will fail)
if ( is_array( $array ) && array_key_exists( $key, $array ) ) {
// store value
$v = $array[ $key ];
// unset
unset( $array[ $key ] );
// return
return $v;
}
// return
return $default;
}
/*
* acf_extract_vars
*
* This function will remove the vars from the array, and return the vars
*
* @type function
* @date 8/10/13
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_extract_vars( &$array, $keys ) {
$r = array();
foreach ( $keys as $key ) {
$r[ $key ] = acf_extract_var( $array, $key );
}
return $r;
}
/*
* acf_get_sub_array
*
* This function will return a sub array of data
*
* @type function
* @date 15/03/2016
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_get_sub_array( $array, $keys ) {
$r = array();
foreach ( $keys as $key ) {
$r[ $key ] = $array[ $key ];
}
return $r;
}
/**
* Returns an array of post type names.
*
* @date 7/10/13
* @since 5.0.0
*
* @param array $args Optional. An array of key => value arguments to match against the post type objects. Default empty array.
* @return array A list of post type names.
*/
function acf_get_post_types( $args = array() ) {
$post_types = array();
// extract special arg
$exclude = acf_extract_var( $args, 'exclude', array() );
$exclude[] = 'acf-field';
$exclude[] = 'acf-field-group';
$exclude[] = 'acf-post-type';
$exclude[] = 'acf-taxonomy';
$exclude[] = 'acf-ui-options-page';
// Get post type objects.
$objects = get_post_types( $args, 'objects' );
foreach ( $objects as $i => $object ) {
// Bail early if is exclude.
if ( in_array( $i, $exclude ) ) {
continue;
}
// Bail early if is builtin (WP) private post type
// i.e. nav_menu_item, revision, customize_changeset, etc.
if ( $object->_builtin && ! $object->public ) {
continue;
}
$post_types[] = $i;
}
return apply_filters( 'acf/get_post_types', $post_types, $args );
}
function acf_get_pretty_post_types( $post_types = array() ) {
// get post types
if ( empty( $post_types ) ) {
// get all custom post types
$post_types = acf_get_post_types();
}
// get labels
$ref = array();
$r = array();
foreach ( $post_types as $post_type ) {
// vars
$label = acf_get_post_type_label( $post_type );
// append to r
$r[ $post_type ] = $label;
// increase counter
if ( ! isset( $ref[ $label ] ) ) {
$ref[ $label ] = 0;
}
$ref[ $label ]++;
}
// get slugs
foreach ( array_keys( $r ) as $i ) {
// vars
$post_type = $r[ $i ];
if ( $ref[ $post_type ] > 1 ) {
$r[ $i ] .= ' (' . $i . ')';
}
}
// return
return $r;
}
/**
* Function acf_get_post_stati()
*
* Returns an array of post status names.
*
* @date 01/24/23
* @since 6.1.0
*
* @param array $args Optional. An array of key => value arguments to match against the post status objects. Default empty array.
* @return array A list of post status names.
*/
function acf_get_post_stati( $args = array() ) {
$args['internal'] = false;
$post_statuses = get_post_stati( $args );
unset( $post_statuses['acf-disabled'] );
$post_statuses = (array) apply_filters( 'acf/get_post_stati', $post_statuses, $args );
return $post_statuses;
}
/**
* Function acf_get_pretty_post_statuses()
*
* Returns a clean array of post status names.
*
* @date 02/16/23
* @since 6.1.0
*
* @param array $post_statuses Optional. An array of post status objects. Default empty array.
* @return array An array of post status names.
*/
function acf_get_pretty_post_statuses( $post_statuses = array() ) {
// Get all post statuses.
$post_statuses = array_merge( $post_statuses, acf_get_post_stati() );
$ref = array();
$result = array();
foreach ( $post_statuses as $post_status ) {
$label = acf_get_post_status_label( $post_status );
$result[ $post_status ] = $label;
if ( ! isset( $ref[ $label ] ) ) {
$ref[ $label ] = 0;
}
$ref[ $label ]++;
}
foreach ( array_keys( $result ) as $i ) {
$post_status = $result[ $i ];
if ( $ref[ $post_status ] > 1 ) {
$result[ $i ] .= ' (' . $i . ')';
}
}
return $result;
}
/*
* acf_get_post_type_label
*
* This function will return a pretty label for a specific post_type
*
* @type function
* @date 5/07/2016
* @since 5.4.0
*
* @param $post_type (string)
* @return (string)
*/
function acf_get_post_type_label( $post_type ) {
// vars
$label = $post_type;
// check that object exists
// - case exists when importing field group from another install and post type does not exist
if ( post_type_exists( $post_type ) ) {
$obj = get_post_type_object( $post_type );
$label = $obj->labels->singular_name;
}
// return
return $label;
}
/**
* Function acf_get_post_status_label()
*
* This function will return a pretty label for a specific post_status
*
* @type function
* @date 01/24/2023
* @since 6.1.0
*
* @param string $post_status The post status.
* @return string The post status label.
*/
function acf_get_post_status_label( $post_status ) {
$label = $post_status;
$obj = get_post_status_object( $post_status );
$label = is_object( $obj ) ? $obj->label : '';
return $label;
}
/*
* acf_verify_nonce
*
* This function will look at the $_POST['_acf_nonce'] value and return true or false
*
* @type function
* @date 15/10/13
* @since 5.0.0
*
* @param $nonce (string)
* @return (boolean)
*/
function acf_verify_nonce( $value ) {
// vars
$nonce = acf_maybe_get_POST( '_acf_nonce' );
// bail early nonce does not match (post|user|comment|term)
if ( ! $nonce || ! wp_verify_nonce( $nonce, $value ) ) {
return false;
}
// reset nonce (only allow 1 save)
$_POST['_acf_nonce'] = false;
// return
return true;
}
/*
* acf_verify_ajax
*
* This function will return true if the current AJAX request is valid
* It's action will also allow WPML to set the lang and avoid AJAX get_posts issues
*
* @type function
* @date 7/08/2015
* @since 5.2.3
*
* @param n/a
* @return (boolean)
*/
function acf_verify_ajax() {
// bail early if not acf nonce
if ( empty( $_REQUEST['nonce'] ) || ! wp_verify_nonce( sanitize_text_field( $_REQUEST['nonce'] ), 'acf_nonce' ) ) {
return false;
}
// action for 3rd party customization
do_action( 'acf/verify_ajax' );
// return
return true;
}
/*
* acf_get_image_sizes
*
* This function will return an array of available image sizes
*
* @type function
* @date 23/10/13
* @since 5.0.0
*
* @param n/a
* @return (array)
*/
function acf_get_image_sizes() {
// vars
$sizes = array(
'thumbnail' => __( 'Thumbnail', 'acf' ),
'medium' => __( 'Medium', 'acf' ),
'large' => __( 'Large', 'acf' ),
);
// find all sizes
$all_sizes = get_intermediate_image_sizes();
// add extra registered sizes
if ( ! empty( $all_sizes ) ) {
foreach ( $all_sizes as $size ) {
// bail early if already in array
if ( isset( $sizes[ $size ] ) ) {
continue;
}
// append to array
$label = str_replace( '-', ' ', $size );
$label = ucwords( $label );
$sizes[ $size ] = $label;
}
}
// add sizes
foreach ( array_keys( $sizes ) as $s ) {
// vars
$data = acf_get_image_size( $s );
// append
if ( $data['width'] && $data['height'] ) {
$sizes[ $s ] .= ' (' . $data['width'] . ' x ' . $data['height'] . ')';
}
}
// add full end
$sizes['full'] = __( 'Full Size', 'acf' );
// filter for 3rd party customization
$sizes = apply_filters( 'acf/get_image_sizes', $sizes );
// return
return $sizes;
}
function acf_get_image_size( $s = '' ) {
// global
global $_wp_additional_image_sizes;
// rename for nicer code
$_sizes = $_wp_additional_image_sizes;
// vars
$data = array(
'width' => isset( $_sizes[ $s ]['width'] ) ? $_sizes[ $s ]['width'] : get_option( "{$s}_size_w" ),
'height' => isset( $_sizes[ $s ]['height'] ) ? $_sizes[ $s ]['height'] : get_option( "{$s}_size_h" ),
);
// return
return $data;
}
/**
* acf_version_compare
*
* Similar to the version_compare() function but with extra functionality.
*
* @date 21/11/16
* @since 5.5.0
*
* @param string $left The left version number.
* @param string $compare The compare operator.
* @param string $right The right version number.
* @return bool
*/
function acf_version_compare( $left = '', $compare = '>', $right = '' ) {
// Detect 'wp' placeholder.
if ( $left === 'wp' ) {
global $wp_version;
$left = $wp_version;
}
// Return result.
return version_compare( $left, $right, $compare );
}
/*
* acf_get_full_version
*
* This function will remove any '-beta1' or '-RC1' strings from a version
*
* @type function
* @date 24/11/16
* @since 5.5.0
*
* @param $version (string)
* @return (string)
*/
function acf_get_full_version( $version = '1' ) {
// remove '-beta1' or '-RC1'
if ( $pos = strpos( $version, '-' ) ) {
$version = substr( $version, 0, $pos );
}
// return
return $version;
}
/*
* acf_get_terms
*
* This function is a wrapper for the get_terms() function
*
* @type function
* @date 28/09/2016
* @since 5.4.0
*
* @param $args (array)
* @return (array)
*/
function acf_get_terms( $args ) {
// defaults
$args = wp_parse_args(
$args,
array(
'taxonomy' => null,
'hide_empty' => false,
'update_term_meta_cache' => false,
)
);
// return
return get_terms( $args );
}
/*
* acf_get_taxonomy_terms
*
* This function will return an array of available taxonomy terms
*
* @type function
* @date 7/10/13
* @since 5.0.0
*
* @param $taxonomies (array)
* @return (array)
*/
function acf_get_taxonomy_terms( $taxonomies = array() ) {
// force array
$taxonomies = acf_get_array( $taxonomies );
// get pretty taxonomy names
$taxonomies = acf_get_pretty_taxonomies( $taxonomies );
// vars
$r = array();
// populate $r
foreach ( array_keys( $taxonomies ) as $taxonomy ) {
// vars
$label = $taxonomies[ $taxonomy ];
$is_hierarchical = is_taxonomy_hierarchical( $taxonomy );
$terms = acf_get_terms(
array(
'taxonomy' => $taxonomy,
'hide_empty' => false,
)
);
// bail early i no terms
if ( empty( $terms ) ) {
continue;
}
// sort into hierachial order!
if ( $is_hierarchical ) {
$terms = _get_term_children( 0, $terms, $taxonomy );
}
// add placeholder
$r[ $label ] = array();
// add choices
foreach ( $terms as $term ) {
$k = "{$taxonomy}:{$term->slug}";
$r[ $label ][ $k ] = acf_get_term_title( $term );
}
}
// return
return $r;
}
/*
* acf_decode_taxonomy_terms
*
* This function decodes the $taxonomy:$term strings into a nested array
*
* @type function
* @date 27/02/2014
* @since 5.0.0
*
* @param $terms (array)
* @return (array)
*/
function acf_decode_taxonomy_terms( $strings = false ) {
// bail early if no terms
if ( empty( $strings ) ) {
return false;
}
// vars
$terms = array();
// loop
foreach ( $strings as $string ) {
// vars
$data = acf_decode_taxonomy_term( $string );
$taxonomy = $data['taxonomy'];
$term = $data['term'];
// create empty array
if ( ! isset( $terms[ $taxonomy ] ) ) {
$terms[ $taxonomy ] = array();
}
// append
$terms[ $taxonomy ][] = $term;
}
// return
return $terms;
}
/*
* acf_decode_taxonomy_term
*
* This function will return the taxonomy and term slug for a given value
*
* @type function
* @date 31/03/2014
* @since 5.0.0
*
* @param $string (string)
* @return (array)
*/
function acf_decode_taxonomy_term( $value ) {
// vars
$data = array(
'taxonomy' => '',
'term' => '',
);
// int
if ( is_numeric( $value ) ) {
$data['term'] = $value;
// string
} elseif ( is_string( $value ) ) {
$value = explode( ':', $value );
$data['taxonomy'] = isset( $value[0] ) ? $value[0] : '';
$data['term'] = isset( $value[1] ) ? $value[1] : '';
// error
} else {
return false;
}
// allow for term_id (Used by ACF v4)
if ( is_numeric( $data['term'] ) ) {
// global
global $wpdb;
// find taxonomy
if ( ! $data['taxonomy'] ) {
$data['taxonomy'] = $wpdb->get_var( $wpdb->prepare( "SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d LIMIT 1", $data['term'] ) );
}
// find term (may have numeric slug '123')
$term = get_term_by( 'slug', $data['term'], $data['taxonomy'] );
// attempt get term via ID (ACF4 uses ID)
if ( ! $term ) {
$term = get_term( $data['term'], $data['taxonomy'] );
}
// bail early if no term
if ( ! $term ) {
return false;
}
// update
$data['taxonomy'] = $term->taxonomy;
$data['term'] = $term->slug;
}
// return
return $data;
}
/**
* acf_array
*
* Casts the value into an array.
*
* @date 9/1/19
* @since 5.7.10
*
* @param mixed $val The value to cast.
* @return array
*/
function acf_array( $val = array() ) {
return (array) $val;
}
/**
* Returns a non-array value.
*
* @date 11/05/2020
* @since 5.8.10
*
* @param mixed $val The value to review.
* @return mixed
*/
function acf_unarray( $val ) {
if ( is_array( $val ) ) {
return reset( $val );
}
return $val;
}
/*
* acf_get_array
*
* This function will force a variable to become an array
*
* @type function
* @date 4/02/2014
* @since 5.0.0
*
* @param $var (mixed)
* @return (array)
*/
function acf_get_array( $var = false, $delimiter = '' ) {
// array
if ( is_array( $var ) ) {
return $var;
}
// bail early if empty
if ( acf_is_empty( $var ) ) {
return array();
}
// string
if ( is_string( $var ) && $delimiter ) {
return explode( $delimiter, $var );
}
// place in array
return (array) $var;
}
/*
* acf_get_numeric
*
* This function will return numeric values
*
* @type function
* @date 15/07/2016
* @since 5.4.0
*
* @param $value (mixed)
* @return (mixed)
*/
function acf_get_numeric( $value = '' ) {
// vars
$numbers = array();
$is_array = is_array( $value );
// loop
foreach ( (array) $value as $v ) {
if ( is_numeric( $v ) ) {
$numbers[] = (int) $v;
}
}
// bail early if is empty
if ( empty( $numbers ) ) {
return false;
}
// convert array
if ( ! $is_array ) {
$numbers = $numbers[0];
}
// return
return $numbers;
}
/**
* acf_get_posts
*
* Similar to the get_posts() function but with extra functionality.
*
* @date 3/03/15
* @since 5.1.5
*
* @param array $args The query args.
* @return array
*/
function acf_get_posts( $args = array() ) {
// Vars.
$posts = array();
// Apply default args.
$args = wp_parse_args(
$args,
array(
'posts_per_page' => -1,
'post_type' => '',
'post_status' => 'any',
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
)
);
// Avoid default 'post' post_type by providing all public types.
if ( ! $args['post_type'] ) {
$args['post_type'] = acf_get_post_types();
}
if ( ! $args['post_status'] ) {
$args['post_status'] = acf_get_post_stati();
}
// Check if specifc post ID's have been provided.
if ( $args['post__in'] ) {
// Clean value into an array of IDs.
$args['post__in'] = array_map( 'intval', acf_array( $args['post__in'] ) );
}
/**
* Filters the args used in `acf_get_posts()` that are passed to `get_posts()`.
*
* @since 6.1.7
*
* @param array $args The args passed to `get_posts()`.
*/
$args = apply_filters( 'acf/acf_get_posts/args', $args );
// Query posts.
$posts = get_posts( $args );
// Remove any potential empty results.
$posts = array_filter( $posts );
// Manually order results.
if ( $posts && $args['post__in'] ) {
$order = array();
foreach ( $posts as $i => $post ) {
$order[ $i ] = array_search( $post->ID, $args['post__in'] );
}
array_multisort( $order, $posts );
}
/**
* Filters the results found in the `acf_get_posts()` function.
*
* @since 6.1.7
*
* @param array $posts The results from the `get_posts()` call.
*/
return apply_filters( 'acf/acf_get_posts/results', $posts );
}
/*
* _acf_query_remove_post_type
*
* This function will remove the 'wp_posts.post_type' WHERE clause completely
* When using 'post__in', this clause is unneccessary and slow.
*
* @type function
* @date 4/03/2015
* @since 5.1.5
*
* @param $sql (string)
* @return $sql
*/
function _acf_query_remove_post_type( $sql ) {
// global
global $wpdb;
// bail early if no 'wp_posts.ID IN'
if ( strpos( $sql, "$wpdb->posts.ID IN" ) === false ) {
return $sql;
}
// get bits
$glue = 'AND';
$bits = explode( $glue, $sql );
// loop through $where and remove any post_type queries
foreach ( $bits as $i => $bit ) {
if ( strpos( $bit, "$wpdb->posts.post_type" ) !== false ) {
unset( $bits[ $i ] );
}
}
// join $where back together
$sql = implode( $glue, $bits );
// return
return $sql;
}
/*
* acf_get_grouped_posts
*
* This function will return all posts grouped by post_type
* This is handy for select settings
*
* @type function
* @date 27/02/2014
* @since 5.0.0
*
* @param $args (array)
* @return (array)
*/
function acf_get_grouped_posts( $args ) {
// vars
$data = array();
// defaults
$args = wp_parse_args(
$args,
array(
'posts_per_page' => -1,
'paged' => 0,
'post_type' => 'post',
'orderby' => 'menu_order title',
'order' => 'ASC',
'post_status' => 'any',
'suppress_filters' => false,
'update_post_meta_cache' => false,
)
);
// find array of post_type
$post_types = acf_get_array( $args['post_type'] );
$post_types_labels = acf_get_pretty_post_types( $post_types );
$is_single_post_type = ( count( $post_types ) == 1 );
// attachment doesn't work if it is the only item in an array
if ( $is_single_post_type ) {
$args['post_type'] = reset( $post_types );
}
// add filter to orderby post type
if ( ! $is_single_post_type ) {
add_filter( 'posts_orderby', '_acf_orderby_post_type', 10, 2 );
}
// get posts
$posts = get_posts( $args );
// remove this filter (only once)
if ( ! $is_single_post_type ) {
remove_filter( 'posts_orderby', '_acf_orderby_post_type', 10, 2 );
}
// loop
foreach ( $post_types as $post_type ) {
// vars
$this_posts = array();
$this_group = array();
// populate $this_posts
foreach ( $posts as $post ) {
if ( $post->post_type == $post_type ) {
$this_posts[] = $post;
}
}
// bail early if no posts for this post type
if ( empty( $this_posts ) ) {
continue;
}
// sort into hierachial order!
// this will fail if a search has taken place because parents wont exist
if ( is_post_type_hierarchical( $post_type ) && empty( $args['s'] ) ) {
// vars
$post_id = $this_posts[0]->ID;
$parent_id = acf_maybe_get( $args, 'post_parent', 0 );
$offset = 0;
$length = count( $this_posts );
// get all posts from this post type
$all_posts = get_posts(
array_merge(
$args,
array(
'posts_per_page' => -1,
'paged' => 0,
'post_type' => $post_type,
)
)
);
// find starting point (offset)
foreach ( $all_posts as $i => $post ) {
if ( $post->ID == $post_id ) {
$offset = $i;
break;
}
}
// order posts
$ordered_posts = get_page_children( $parent_id, $all_posts );
// 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_posts ) == count( $all_posts ) ) {
$this_posts = array_slice( $ordered_posts, $offset, $length );
}
}
// populate $this_posts
foreach ( $this_posts as $post ) {
$this_group[ $post->ID ] = $post;
}
// group by post type
$label = $post_types_labels[ $post_type ];
$data[ $label ] = $this_group;
}
// return
return $data;
}
function _acf_orderby_post_type( $ordeby, $wp_query ) {
// global
global $wpdb;
// get post types
$post_types = $wp_query->get( 'post_type' );
// prepend SQL
if ( is_array( $post_types ) ) {
$post_types = implode( "','", $post_types );
$ordeby = "FIELD({$wpdb->posts}.post_type,'$post_types')," . $ordeby;
}
// return
return $ordeby;
}
function acf_get_post_title( $post = 0, $is_search = false ) {
// vars
$post = get_post( $post );
$title = '';
$prepend = '';
$append = '';
// bail early if no post
if ( ! $post ) {
return '';
}
// title
$title = get_the_title( $post->ID );
// empty
if ( $title === '' ) {
$title = __( '(no title)', 'acf' );
}
// status
if ( get_post_status( $post->ID ) != 'publish' ) {
$append .= ' (' . get_post_status( $post->ID ) . ')';
}
// ancestors
if ( $post->post_type !== 'attachment' ) {
// get ancestors
$ancestors = get_ancestors( $post->ID, $post->post_type );
$prepend .= str_repeat( '- ', count( $ancestors ) );
// add parent
/*
removed in 5.6.5 as not used by the UI
if( $is_search && !empty($ancestors) ) {
// reverse
$ancestors = array_reverse($ancestors);
// convert id's into titles
foreach( $ancestors as $i => $id ) {
$ancestors[ $i ] = get_the_title( $id );
}
// append
$append .= ' | ' . __('Parent', 'acf') . ': ' . implode(' / ', $ancestors);
}
*/
}
// merge
$title = $prepend . $title . $append;
// return
return $title;
}
function acf_order_by_search( $array, $search ) {
// vars
$weights = array();
$needle = strtolower( $search );
// add key prefix
foreach ( array_keys( $array ) as $k ) {
$array[ '_' . $k ] = acf_extract_var( $array, $k );
}
// add search weight
foreach ( $array as $k => $v ) {
// vars
$weight = 0;
$haystack = strtolower( $v );
$strpos = strpos( $haystack, $needle );
// detect search match
if ( $strpos !== false ) {
// set eright to length of match
$weight = strlen( $search );
// increase weight if match starts at begining of string
if ( $strpos == 0 ) {
$weight++;
}
}
// append to wights
$weights[ $k ] = $weight;
}
// sort the array with menu_order ascending
array_multisort( $weights, SORT_DESC, $array );
// remove key prefix
foreach ( array_keys( $array ) as $k ) {
$array[ substr( $k, 1 ) ] = acf_extract_var( $array, $k );
}
// return
return $array;
}
/*
* acf_get_pretty_user_roles
*
* description
*
* @type function
* @date 23/02/2016
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_get_pretty_user_roles( $allowed = false ) {
// vars
$editable_roles = get_editable_roles();
$allowed = acf_get_array( $allowed );
$roles = array();
// loop
foreach ( $editable_roles as $role_name => $role_details ) {
// bail early if not allowed
if ( ! empty( $allowed ) && ! in_array( $role_name, $allowed ) ) {
continue;
}
// append
$roles[ $role_name ] = translate_user_role( $role_details['name'] );
}
// return
return $roles;
}
/*
* acf_get_grouped_users
*
* This function will return all users grouped by role
* This is handy for select settings
*
* @type function
* @date 27/02/2014
* @since 5.0.0
*
* @param $args (array)
* @return (array)
*/
function acf_get_grouped_users( $args = array() ) {
// vars
$r = array();
// defaults
$args = wp_parse_args(
$args,
array(
'users_per_page' => -1,
'paged' => 0,
'role' => '',
'orderby' => 'login',
'order' => 'ASC',
)
);
// offset
$i = 0;
$min = 0;
$max = 0;
$users_per_page = acf_extract_var( $args, 'users_per_page' );
$paged = acf_extract_var( $args, 'paged' );
if ( $users_per_page > 0 ) {
// prevent paged from being -1
$paged = max( 0, $paged );
// set min / max
$min = ( ( $paged - 1 ) * $users_per_page ) + 1; // 1, 11
$max = ( $paged * $users_per_page ); // 10, 20
}
// find array of post_type
$user_roles = acf_get_pretty_user_roles( $args['role'] );
// fix role
if ( is_array( $args['role'] ) ) {
// global
global $wp_version, $wpdb;
// vars
$roles = acf_extract_var( $args, 'role' );
// new WP has role__in
if ( version_compare( $wp_version, '4.4', '>=' ) ) {
$args['role__in'] = $roles;
// old WP doesn't have role__in
} else {
// vars
$blog_id = get_current_blog_id();
$meta_query = array( 'relation' => 'OR' );
// loop
foreach ( $roles as $role ) {
$meta_query[] = array(
'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
'value' => '"' . $role . '"',
'compare' => 'LIKE',
);
}
// append
$args['meta_query'] = $meta_query;
}
}
// get posts
$users = get_users( $args );
// loop
foreach ( $user_roles as $user_role_name => $user_role_label ) {
// vars
$this_users = array();
$this_group = array();
// populate $this_posts
foreach ( array_keys( $users ) as $key ) {
// bail early if not correct role
if ( ! in_array( $user_role_name, $users[ $key ]->roles ) ) {
continue;
}
// extract user
$user = acf_extract_var( $users, $key );
// increase
$i++;
// bail early if too low
if ( $min && $i < $min ) {
continue;
}
// bail early if too high (don't bother looking at any more users)
if ( $max && $i > $max ) {
break;
}
// group by post type
$this_users[ $user->ID ] = $user;
}
// bail early if no posts for this post type
if ( empty( $this_users ) ) {
continue;
}
// append
$r[ $user_role_label ] = $this_users;
}
// return
return $r;
}
/**
* acf_json_encode
*
* Returns json_encode() ready for file / database use.
*
* @date 29/4/19
* @since 5.0.0
*
* @param array $json The array of data to encode.
* @return string
*/
function acf_json_encode( $json ) {
return json_encode( $json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE );
}
/*
* acf_str_exists
*
* This function will return true if a sub string is found
*
* @type function
* @date 1/05/2014
* @since 5.0.0
*
* @param $needle (string)
* @param $haystack (string)
* @return (boolean)
*/
function acf_str_exists( $needle, $haystack ) {
// return true if $haystack contains the $needle
if ( is_string( $haystack ) && strpos( $haystack, $needle ) !== false ) {
return true;
}
// return
return false;
}
/*
* acf_debug
*
* description
*
* @type function
* @date 2/05/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_debug() {
// vars
$args = func_get_args();
$s = array_shift( $args );
$o = '';
$nl = "\r\n";
// start script
$o .= '<script type="text/javascript">' . $nl;
$o .= 'console.log("' . $s . '"';
if ( ! empty( $args ) ) {
foreach ( $args as $arg ) {
if ( is_object( $arg ) || is_array( $arg ) ) {
$arg = json_encode( $arg );
} elseif ( is_bool( $arg ) ) {
$arg = $arg ? 'true' : 'false';
} elseif ( is_string( $arg ) ) {
$arg = '"' . $arg . '"';
}
$o .= ', ' . $arg;
}
}
$o .= ');' . $nl;
// end script
$o .= '</script>' . $nl;
// echo
echo $o;
}
function acf_debug_start() {
acf_update_setting( 'debug_start', memory_get_usage() );
}
function acf_debug_end() {
$start = acf_get_setting( 'debug_start' );
$end = memory_get_usage();
return $end - $start;
}
/*
* acf_encode_choices
*
* description
*
* @type function
* @date 4/06/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_encode_choices( $array = array(), $show_keys = true ) {
// bail early if not array (maybe a single string)
if ( ! is_array( $array ) ) {
return $array;
}
// bail early if empty array
if ( empty( $array ) ) {
return '';
}
// vars
$string = '';
// if allowed to show keys (good for choices, not for default values)
if ( $show_keys ) {
// loop
foreach ( $array as $k => $v ) {
// ignore if key and value are the same
if ( strval( $k ) == strval( $v ) ) {
continue;
}
// show key in the value
$array[ $k ] = $k . ' : ' . $v;
}
}
// implode
$string = implode( "\n", $array );
// return
return $string;
}
function acf_decode_choices( $string = '', $array_keys = false ) {
// bail early if already array
if ( is_array( $string ) ) {
return $string;
// allow numeric values (same as string)
} elseif ( is_numeric( $string ) ) {
// do nothing
// bail early if not a string
} elseif ( ! is_string( $string ) ) {
return array();
// bail early if is empty string
} elseif ( $string === '' ) {
return array();
}
// vars
$array = array();
// explode
$lines = explode( "\n", $string );
// key => value
foreach ( $lines as $line ) {
// vars
$k = trim( $line );
$v = trim( $line );
// look for ' : '
if ( acf_str_exists( ' : ', $line ) ) {
$line = explode( ' : ', $line );
$k = trim( $line[0] );
$v = trim( $line[1] );
}
// append
$array[ $k ] = $v;
}
// return only array keys? (good for checkbox default_value)
if ( $array_keys ) {
return array_keys( $array );
}
// return
return $array;
}
/*
* acf_str_replace
*
* This function will replace an array of strings much like str_replace
* The difference is the extra logic to avoid replacing a string that has alread been replaced
* This is very useful for replacing date characters as they overlap with eachother
*
* @type function
* @date 21/06/2016
* @since 5.3.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_str_replace( $string = '', $search_replace = array() ) {
// vars
$ignore = array();
// remove potential empty search to avoid PHP error
unset( $search_replace[''] );
// loop over conversions
foreach ( $search_replace as $search => $replace ) {
// ignore this search, it was a previous replace
if ( in_array( $search, $ignore ) ) {
continue;
}
// bail early if subsctring not found
if ( strpos( $string, $search ) === false ) {
continue;
}
// replace
$string = str_replace( $search, $replace, $string );
// append to ignore
$ignore[] = $replace;
}
// return
return $string;
}
/*
* date & time formats
*
* These settings contain an association of format strings from PHP => JS
*
* @type function
* @date 21/06/2016
* @since 5.3.8
*
* @param n/a
* @return n/a
*/
acf_update_setting(
'php_to_js_date_formats',
array(
// Year
'Y' => 'yy', // Numeric, 4 digits 1999, 2003
'y' => 'y', // Numeric, 2 digits 99, 03
// Month
'm' => 'mm', // Numeric, with leading zeros 0112
'n' => 'm', // Numeric, without leading zeros 112
'F' => 'MM', // Textual full January December
'M' => 'M', // Textual three letters Jan - Dec
// Weekday
'l' => 'DD', // Full name (lowercase 'L') Sunday Saturday
'D' => 'D', // Three letter name Mon Sun
// Day of Month
'd' => 'dd', // Numeric, with leading zeros 0131
'j' => 'd', // Numeric, without leading zeros 131
'S' => '', // The English suffix for the day of the month st, nd or th in the 1st, 2nd or 15th.
)
);
acf_update_setting(
'php_to_js_time_formats',
array(
'a' => 'tt', // Lowercase Ante meridiem and Post meridiem am or pm
'A' => 'TT', // Uppercase Ante meridiem and Post meridiem AM or PM
'h' => 'hh', // 12-hour format of an hour with leading zeros 01 through 12
'g' => 'h', // 12-hour format of an hour without leading zeros 1 through 12
'H' => 'HH', // 24-hour format of an hour with leading zeros 00 through 23
'G' => 'H', // 24-hour format of an hour without leading zeros 0 through 23
'i' => 'mm', // Minutes with leading zeros 00 to 59
's' => 'ss', // Seconds, with leading zeros 00 through 59
)
);
/*
* acf_split_date_time
*
* This function will split a format string into seperate date and time
*
* @type function
* @date 26/05/2016
* @since 5.3.8
*
* @param $date_time (string)
* @return $formats (array)
*/
function acf_split_date_time( $date_time = '' ) {
// vars
$php_date = acf_get_setting( 'php_to_js_date_formats' );
$php_time = acf_get_setting( 'php_to_js_time_formats' );
$chars = str_split( $date_time );
$type = 'date';
// default
$data = array(
'date' => '',
'time' => '',
);
// loop
foreach ( $chars as $i => $c ) {
// find type
// - allow misc characters to append to previous type
if ( isset( $php_date[ $c ] ) ) {
$type = 'date';
} elseif ( isset( $php_time[ $c ] ) ) {
$type = 'time';
}
// append char
$data[ $type ] .= $c;
}
// trim
$data['date'] = trim( $data['date'] );
$data['time'] = trim( $data['time'] );
// return
return $data;
}
/*
* acf_convert_date_to_php
*
* This fucntion converts a date format string from JS to PHP
*
* @type function
* @date 20/06/2014
* @since 5.0.0
*
* @param $date (string)
* @return (string)
*/
function acf_convert_date_to_php( $date = '' ) {
// vars
$php_to_js = acf_get_setting( 'php_to_js_date_formats' );
$js_to_php = array_flip( $php_to_js );
// return
return acf_str_replace( $date, $js_to_php );
}
/*
* acf_convert_date_to_js
*
* This fucntion converts a date format string from PHP to JS
*
* @type function
* @date 20/06/2014
* @since 5.0.0
*
* @param $date (string)
* @return (string)
*/
function acf_convert_date_to_js( $date = '' ) {
// vars
$php_to_js = acf_get_setting( 'php_to_js_date_formats' );
// return
return acf_str_replace( $date, $php_to_js );
}
/*
* acf_convert_time_to_php
*
* This fucntion converts a time format string from JS to PHP
*
* @type function
* @date 20/06/2014
* @since 5.0.0
*
* @param $time (string)
* @return (string)
*/
function acf_convert_time_to_php( $time = '' ) {
// vars
$php_to_js = acf_get_setting( 'php_to_js_time_formats' );
$js_to_php = array_flip( $php_to_js );
// return
return acf_str_replace( $time, $js_to_php );
}
/*
* acf_convert_time_to_js
*
* This fucntion converts a date format string from PHP to JS
*
* @type function
* @date 20/06/2014
* @since 5.0.0
*
* @param $time (string)
* @return (string)
*/
function acf_convert_time_to_js( $time = '' ) {
// vars
$php_to_js = acf_get_setting( 'php_to_js_time_formats' );
// return
return acf_str_replace( $time, $php_to_js );
}
/*
* acf_update_user_setting
*
* description
*
* @type function
* @date 15/07/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_update_user_setting( $name, $value ) {
// get current user id
$user_id = get_current_user_id();
// get user settings
$settings = get_user_meta( $user_id, 'acf_user_settings', true );
// ensure array
$settings = acf_get_array( $settings );
// delete setting (allow 0 to save)
if ( acf_is_empty( $value ) ) {
unset( $settings[ $name ] );
// append setting
} else {
$settings[ $name ] = $value;
}
// update user data
return update_metadata( 'user', $user_id, 'acf_user_settings', $settings );
}
/*
* acf_get_user_setting
*
* description
*
* @type function
* @date 15/07/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_get_user_setting( $name = '', $default = false ) {
// get current user id
$user_id = get_current_user_id();
// get user settings
$settings = get_user_meta( $user_id, 'acf_user_settings', true );
// ensure array
$settings = acf_get_array( $settings );
// bail arly if no settings
if ( ! isset( $settings[ $name ] ) ) {
return $default;
}
// return
return $settings[ $name ];
}
/*
* acf_in_array
*
* description
*
* @type function
* @date 22/07/2014
* @since 5.0.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_in_array( $value = '', $array = false ) {
// bail early if not array
if ( ! is_array( $array ) ) {
return false;
}
// find value in array
return in_array( $value, $array );
}
/*
* acf_get_valid_post_id
*
* This function will return a valid post_id based on the current screen / parameter
*
* @type function
* @date 8/12/2013
* @since 5.0.0
*
* @param $post_id (mixed)
* @return $post_id (mixed)
*/
function acf_get_valid_post_id( $post_id = 0 ) {
// allow filter to short-circuit load_value logic
$preload = apply_filters( 'acf/pre_load_post_id', null, $post_id );
if ( $preload !== null ) {
return $preload;
}
// vars
$_post_id = $post_id;
// if not $post_id, load queried object
if ( ! $post_id ) {
// try for global post (needed for setup_postdata)
$post_id = (int) get_the_ID();
// try for current screen
if ( ! $post_id ) {
$post_id = get_queried_object();
}
}
// $post_id may be an object.
// todo: Compare class types instead.
if ( is_object( $post_id ) ) {
// post
if ( isset( $post_id->post_type, $post_id->ID ) ) {
$post_id = $post_id->ID;
// user
} elseif ( isset( $post_id->roles, $post_id->ID ) ) {
$post_id = 'user_' . $post_id->ID;
// term
} elseif ( isset( $post_id->taxonomy, $post_id->term_id ) ) {
$post_id = 'term_' . $post_id->term_id;
// comment
} elseif ( isset( $post_id->comment_ID ) ) {
$post_id = 'comment_' . $post_id->comment_ID;
// default
} else {
$post_id = 0;
}
}
// allow for option == options
if ( $post_id === 'option' ) {
$post_id = 'options';
}
// append language code
if ( $post_id == 'options' ) {
$dl = acf_get_setting( 'default_language' );
$cl = acf_get_setting( 'current_language' );
if ( $cl && $cl !== $dl ) {
$post_id .= '_' . $cl;
}
}
// filter for 3rd party
$post_id = apply_filters( 'acf/validate_post_id', $post_id, $_post_id );
// return
return $post_id;
}
/*
* acf_get_post_id_info
*
* This function will return the type and id for a given $post_id string
*
* @type function
* @date 2/07/2016
* @since 5.4.0
*
* @param $post_id (mixed)
* @return $info (array)
*/
function acf_get_post_id_info( $post_id = 0 ) {
// vars
$info = array(
'type' => 'post',
'id' => 0,
);
// bail early if no $post_id
if ( ! $post_id ) {
return $info;
}
// check cache
// - this function will most likely be called multiple times (saving loading fields from post)
// $cache_key = "get_post_id_info/post_id={$post_id}";
// if( acf_isset_cache($cache_key) ) return acf_get_cache($cache_key);
// numeric
if ( is_numeric( $post_id ) ) {
$info['id'] = (int) $post_id;
// string
} elseif ( is_string( $post_id ) ) {
// vars
$glue = '_';
$type = explode( $glue, $post_id );
$id = array_pop( $type );
$type = implode( $glue, $type );
$meta = array( 'post', 'user', 'comment', 'term' );
// check if is taxonomy (ACF < 5.5)
// - avoid scenario where taxonomy exists with name of meta type
if ( ! in_array( $type, $meta ) && acf_isset_termmeta( $type ) ) {
$type = 'term';
}
// meta
if ( is_numeric( $id ) && in_array( $type, $meta ) ) {
$info['type'] = $type;
$info['id'] = (int) $id;
// option
} else {
$info['type'] = 'option';
$info['id'] = $post_id;
}
}
// update cache
// acf_set_cache($cache_key, $info);
// filter
$info = apply_filters( 'acf/get_post_id_info', $info, $post_id );
// return
return $info;
}
/*
acf_log( acf_get_post_id_info(4) );
acf_log( acf_get_post_id_info('post_4') );
acf_log( acf_get_post_id_info('user_123') );
acf_log( acf_get_post_id_info('term_567') );
acf_log( acf_get_post_id_info('category_204') );
acf_log( acf_get_post_id_info('comment_6') );
acf_log( acf_get_post_id_info('options_lol!') );
acf_log( acf_get_post_id_info('option') );
acf_log( acf_get_post_id_info('options') );
*/
/*
* acf_isset_termmeta
*
* This function will return true if the termmeta table exists
* https://developer.wordpress.org/reference/functions/get_term_meta/
*
* @type function
* @date 3/09/2016
* @since 5.4.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_isset_termmeta( $taxonomy = '' ) {
// bail early if no table
if ( get_option( 'db_version' ) < 34370 ) {
return false;
}
// check taxonomy
if ( $taxonomy && ! taxonomy_exists( $taxonomy ) ) {
return false;
}
// return
return true;
}
/**
* This function will walk through the $_FILES data and upload each found.
*
* @date 25/10/2014
* @since 5.0.9
*
* @param array $ancestors An internal parameter, not required.
* @return void
*/
function acf_upload_files( $ancestors = array() ) {
$file = acf_sanitize_files_array( $_FILES['acf'] );
// walk through ancestors
if ( ! empty( $ancestors ) ) {
foreach ( $ancestors as $a ) {
foreach ( array_keys( $file ) as $k ) {
$file[ $k ] = $file[ $k ][ $a ];
}
}
}
// is array?
if ( is_array( $file['name'] ) ) {
foreach ( array_keys( $file['name'] ) as $k ) {
$_ancestors = array_merge( $ancestors, array( $k ) );
acf_upload_files( $_ancestors );
}
return;
}
// Bail early if file has error (no file uploaded).
if ( $file['error'] ) {
return;
}
$field_key = end( $ancestors );
$nonce_name = $field_key . '_file_nonce';
if ( empty( $_REQUEST['acf'][ $nonce_name ] ) || ! wp_verify_nonce( sanitize_text_field( $_REQUEST['acf'][ $nonce_name ] ), 'acf/file_uploader_nonce/' . $field_key ) ) {
return;
}
// Assign global _acfuploader for media validation.
$_POST['_acfuploader'] = $field_key;
// file found!
$attachment_id = acf_upload_file( $file );
// update $_POST
array_unshift( $ancestors, 'acf' );
acf_update_nested_array( $_POST, $ancestors, $attachment_id );
}
/*
* acf_upload_file
*
* This function will uploade a $_FILE
*
* @type function
* @date 27/10/2014
* @since 5.0.9
*
* @param $uploaded_file (array) array found from $_FILE data
* @return $id (int) new attachment ID
*/
function acf_upload_file( $uploaded_file ) {
// required
// require_once( ABSPATH . "/wp-load.php" ); // WP should already be loaded
require_once ABSPATH . '/wp-admin/includes/media.php'; // video functions
require_once ABSPATH . '/wp-admin/includes/file.php';
require_once ABSPATH . '/wp-admin/includes/image.php';
// required for wp_handle_upload() to upload the file
$upload_overrides = array( 'test_form' => false );
// upload
$file = wp_handle_upload( $uploaded_file, $upload_overrides );
// bail early if upload failed
if ( isset( $file['error'] ) ) {
return $file['error'];
}
// vars
$url = $file['url'];
$type = $file['type'];
$file = $file['file'];
$filename = basename( $file );
// Construct the object array
$object = array(
'post_title' => $filename,
'post_mime_type' => $type,
'guid' => $url,
);
// Save the data
$id = wp_insert_attachment( $object, $file );
// Add the meta-data
wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
/** This action is documented in wp-admin/custom-header.php */
do_action( 'wp_create_file_in_uploads', $file, $id ); // For replication
// return new ID
return $id;
}
/*
* acf_update_nested_array
*
* This function will update a nested array value. Useful for modifying the $_POST array
*
* @type function
* @date 27/10/2014
* @since 5.0.9
*
* @param $array (array) target array to be updated
* @param $ancestors (array) array of keys to navigate through to find the child
* @param $value (mixed) The new value
* @return (boolean)
*/
function acf_update_nested_array( &$array, $ancestors, $value ) {
// if no more ancestors, update the current var
if ( empty( $ancestors ) ) {
$array = $value;
// return
return true;
}
// shift the next ancestor from the array
$k = array_shift( $ancestors );
// if exists
if ( isset( $array[ $k ] ) ) {
return acf_update_nested_array( $array[ $k ], $ancestors, $value );
}
// return
return false;
}
/*
* acf_is_screen
*
* This function will return true if all args are matched for the current screen
*
* @type function
* @date 9/12/2014
* @since 5.1.5
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_is_screen( $id = '' ) {
// bail early if not defined
if ( ! function_exists( 'get_current_screen' ) ) {
return false;
}
// vars
$current_screen = get_current_screen();
// no screen
if ( ! $current_screen ) {
return false;
// array
} elseif ( is_array( $id ) ) {
return in_array( $current_screen->id, $id );
// string
} else {
return ( $id === $current_screen->id );
}
}
/*
* acf_maybe_get
*
* This function will return a var if it exists in an array
*
* @type function
* @date 9/12/2014
* @since 5.1.5
*
* @param $array (array) the array to look within
* @param $key (key) the array key to look for. Nested values may be found using '/'
* @param $default (mixed) the value returned if not found
* @return $post_id (int)
*/
function acf_maybe_get( $array = array(), $key = 0, $default = null ) {
return isset( $array[ $key ] ) ? $array[ $key ] : $default;
}
function acf_maybe_get_POST( $key = '', $default = null ) {
return isset( $_POST[ $key ] ) ? acf_sanitize_request_args( $_POST[ $key ] ) : $default; // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.NonceVerification.Missing -- Checked elsewhere.
}
function acf_maybe_get_GET( $key = '', $default = null ) {
return isset( $_GET[ $key ] ) ? acf_sanitize_request_args( $_GET[ $key ] ) : $default; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Checked elsewhere.
}
/**
* Returns an array of attachment data.
*
* @date 05/01/2015
* @since 5.1.5
*
* @param int|WP_Post The attachment ID or object.
* @return array|false
*/
function acf_get_attachment( $attachment ) {
// Allow filter to short-circuit load attachment logic.
// Alternatively, this filter may be used to switch blogs for multisite media functionality.
$response = apply_filters( 'acf/pre_load_attachment', null, $attachment );
if ( $response !== null ) {
return $response;
}
// Get the attachment post object.
$attachment = get_post( $attachment );
if ( ! $attachment ) {
return false;
}
if ( $attachment->post_type !== 'attachment' ) {
return false;
}
// Load various attachment details.
$meta = wp_get_attachment_metadata( $attachment->ID );
$attached_file = get_attached_file( $attachment->ID );
if ( strpos( $attachment->post_mime_type, '/' ) !== false ) {
list( $type, $subtype ) = explode( '/', $attachment->post_mime_type );
} else {
list( $type, $subtype ) = array( $attachment->post_mime_type, '' );
}
// Generate response.
$response = array(
'ID' => $attachment->ID,
'id' => $attachment->ID,
'title' => $attachment->post_title,
'filename' => wp_basename( $attached_file ),
'filesize' => 0,
'url' => wp_get_attachment_url( $attachment->ID ),
'link' => get_attachment_link( $attachment->ID ),
'alt' => get_post_meta( $attachment->ID, '_wp_attachment_image_alt', true ),
'author' => $attachment->post_author,
'description' => $attachment->post_content,
'caption' => $attachment->post_excerpt,
'name' => $attachment->post_name,
'status' => $attachment->post_status,
'uploaded_to' => $attachment->post_parent,
'date' => $attachment->post_date_gmt,
'modified' => $attachment->post_modified_gmt,
'menu_order' => $attachment->menu_order,
'mime_type' => $attachment->post_mime_type,
'type' => $type,
'subtype' => $subtype,
'icon' => wp_mime_type_icon( $attachment->ID ),
);
// Append filesize data.
if ( isset( $meta['filesize'] ) ) {
$response['filesize'] = $meta['filesize'];
} elseif ( file_exists( $attached_file ) ) {
$response['filesize'] = filesize( $attached_file );
}
// Restrict the loading of image "sizes".
$sizes_id = 0;
// Type specific logic.
switch ( $type ) {
case 'image':
$sizes_id = $attachment->ID;
$src = wp_get_attachment_image_src( $attachment->ID, 'full' );
if ( $src ) {
$response['url'] = $src[0];
$response['width'] = $src[1];
$response['height'] = $src[2];
}
break;
case 'video':
$response['width'] = acf_maybe_get( $meta, 'width', 0 );
$response['height'] = acf_maybe_get( $meta, 'height', 0 );
if ( $featured_id = get_post_thumbnail_id( $attachment->ID ) ) {
$sizes_id = $featured_id;
}
break;
case 'audio':
if ( $featured_id = get_post_thumbnail_id( $attachment->ID ) ) {
$sizes_id = $featured_id;
}
break;
}
// Load array of image sizes.
if ( $sizes_id ) {
$sizes = get_intermediate_image_sizes();
$sizes_data = array();
foreach ( $sizes as $size ) {
$src = wp_get_attachment_image_src( $sizes_id, $size );
if ( $src ) {
$sizes_data[ $size ] = $src[0];
$sizes_data[ $size . '-width' ] = $src[1];
$sizes_data[ $size . '-height' ] = $src[2];
}
}
$response['sizes'] = $sizes_data;
}
/**
* Filters the attachment $response after it has been loaded.
*
* @date 16/06/2020
* @since 5.9.0
*
* @param array $response Array of loaded attachment data.
* @param WP_Post $attachment Attachment object.
* @param array|false $meta Array of attachment meta data, or false if there is none.
*/
return apply_filters( 'acf/load_attachment', $response, $attachment, $meta );
}
/**
* This function will truncate and return a string
*
* @date 8/08/2014
* @since 5.0.0
*
* @param string $text The text to truncate.
* @param int $length The number of characters to allow in the string.
*
* @return string
*/
function acf_get_truncated( $text, $length = 64 ) {
$text = trim( $text );
$the_length = function_exists( 'mb_strlen' ) ? mb_strlen( $text ) : strlen( $text );
$cut_length = $length - 3;
$return = function_exists( 'mb_substr' ) ? mb_substr( $text, 0, $cut_length ) : substr( $text, 0, $cut_length );
if ( $the_length > $cut_length ) {
$return .= '...';
}
return $return;
}
/*
* acf_current_user_can_admin
*
* This function will return true if the current user can administrate the ACF field groups
*
* @type function
* @date 9/02/2015
* @since 5.1.5
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_current_user_can_admin() {
if ( acf_get_setting( 'show_admin' ) && current_user_can( acf_get_setting( 'capability' ) ) ) {
return true;
}
// return
return false;
}
/*
* acf_get_filesize
*
* This function will return a numeric value of bytes for a given filesize string
*
* @type function
* @date 18/02/2015
* @since 5.1.5
*
* @param $size (mixed)
* @return (int)
*/
function acf_get_filesize( $size = 1 ) {
// vars
$unit = 'MB';
$units = array(
'TB' => 4,
'GB' => 3,
'MB' => 2,
'KB' => 1,
);
// look for $unit within the $size parameter (123 KB)
if ( is_string( $size ) ) {
// vars
$custom = strtoupper( substr( $size, -2 ) );
foreach ( $units as $k => $v ) {
if ( $custom === $k ) {
$unit = $k;
$size = substr( $size, 0, -2 );
}
}
}
// calc bytes
$bytes = floatval( $size ) * pow( 1024, $units[ $unit ] );
// return
return $bytes;
}
/*
* acf_format_filesize
*
* This function will return a formatted string containing the filesize and unit
*
* @type function
* @date 18/02/2015
* @since 5.1.5
*
* @param $size (mixed)
* @return (int)
*/
function acf_format_filesize( $size = 1 ) {
// convert
$bytes = acf_get_filesize( $size );
// vars
$units = array(
'TB' => 4,
'GB' => 3,
'MB' => 2,
'KB' => 1,
);
// loop through units
foreach ( $units as $k => $v ) {
$result = $bytes / pow( 1024, $v );
if ( $result >= 1 ) {
return $result . ' ' . $k;
}
}
// return
return $bytes . ' B';
}
/*
* acf_get_valid_terms
*
* This function will replace old terms with new split term ids
*
* @type function
* @date 27/02/2015
* @since 5.1.5
*
* @param $terms (int|array)
* @param $taxonomy (string)
* @return $terms
*/
function acf_get_valid_terms( $terms = false, $taxonomy = 'category' ) {
// force into array
$terms = acf_get_array( $terms );
// force ints
$terms = array_map( 'intval', $terms );
// bail early if function does not yet exist or
if ( ! function_exists( 'wp_get_split_term' ) || empty( $terms ) ) {
return $terms;
}
// attempt to find new terms
foreach ( $terms as $i => $term_id ) {
$new_term_id = wp_get_split_term( $term_id, $taxonomy );
if ( $new_term_id ) {
$terms[ $i ] = $new_term_id;
}
}
// return
return $terms;
}
/*
* acf_validate_attachment
*
* This function will validate an attachment based on a field's restrictions and return an array of errors
*
* @type function
* @date 3/07/2015
* @since 5.2.3
*
* @param $attachment (array) attachment data. Changes based on context
* @param $field (array) field settings containing restrictions
* @param $context (string) $file is different when uploading / preparing
* @return $errors (array)
*/
function acf_validate_attachment( $attachment, $field, $context = 'prepare' ) {
// vars
$errors = array();
$file = array(
'type' => '',
'width' => 0,
'height' => 0,
'size' => 0,
);
// upload
if ( $context == 'upload' ) {
// vars
$file['type'] = pathinfo( $attachment['name'], PATHINFO_EXTENSION );
$file['size'] = filesize( $attachment['tmp_name'] );
if ( strpos( $attachment['type'], 'image' ) !== false ) {
$size = getimagesize( $attachment['tmp_name'] );
$file['width'] = acf_maybe_get( $size, 0 );
$file['height'] = acf_maybe_get( $size, 1 );
}
// prepare
} elseif ( $context == 'prepare' ) {
$use_path = isset( $attachment['filename'] ) ? $attachment['filename'] : $attachment['url'];
$file['type'] = pathinfo( $use_path, PATHINFO_EXTENSION );
$file['size'] = acf_maybe_get( $attachment, 'filesizeInBytes', 0 );
$file['width'] = acf_maybe_get( $attachment, 'width', 0 );
$file['height'] = acf_maybe_get( $attachment, 'height', 0 );
// custom
} else {
$file = array_merge( $file, $attachment );
$use_path = isset( $attachment['filename'] ) ? $attachment['filename'] : $attachment['url'];
$file['type'] = pathinfo( $use_path, PATHINFO_EXTENSION );
}
// image
if ( $file['width'] || $file['height'] ) {
// width
$min_width = (int) acf_maybe_get( $field, 'min_width', 0 );
$max_width = (int) acf_maybe_get( $field, 'max_width', 0 );
if ( $file['width'] ) {
if ( $min_width && $file['width'] < $min_width ) {
// min width
$errors['min_width'] = sprintf( __( 'Image width must be at least %dpx.', 'acf' ), $min_width );
} elseif ( $max_width && $file['width'] > $max_width ) {
// min width
$errors['max_width'] = sprintf( __( 'Image width must not exceed %dpx.', 'acf' ), $max_width );
}
}
// height
$min_height = (int) acf_maybe_get( $field, 'min_height', 0 );
$max_height = (int) acf_maybe_get( $field, 'max_height', 0 );
if ( $file['height'] ) {
if ( $min_height && $file['height'] < $min_height ) {
// min height
$errors['min_height'] = sprintf( __( 'Image height must be at least %dpx.', 'acf' ), $min_height );
} elseif ( $max_height && $file['height'] > $max_height ) {
// min height
$errors['max_height'] = sprintf( __( 'Image height must not exceed %dpx.', 'acf' ), $max_height );
}
}
}
// file size
if ( $file['size'] ) {
$min_size = acf_maybe_get( $field, 'min_size', 0 );
$max_size = acf_maybe_get( $field, 'max_size', 0 );
if ( $min_size && $file['size'] < acf_get_filesize( $min_size ) ) {
// min width
$errors['min_size'] = sprintf( __( 'File size must be at least %s.', 'acf' ), acf_format_filesize( $min_size ) );
} elseif ( $max_size && $file['size'] > acf_get_filesize( $max_size ) ) {
// min width
$errors['max_size'] = sprintf( __( 'File size must not exceed %s.', 'acf' ), acf_format_filesize( $max_size ) );
}
}
// file type
if ( $file['type'] ) {
$mime_types = acf_maybe_get( $field, 'mime_types', '' );
// lower case
$file['type'] = strtolower( $file['type'] );
$mime_types = strtolower( $mime_types );
// explode
$mime_types = str_replace( array( ' ', '.' ), '', $mime_types );
$mime_types = explode( ',', $mime_types ); // split pieces
$mime_types = array_filter( $mime_types ); // remove empty pieces
if ( ! empty( $mime_types ) && ! in_array( $file['type'], $mime_types ) ) {
// glue together last 2 types
if ( count( $mime_types ) > 1 ) {
$last1 = array_pop( $mime_types );
$last2 = array_pop( $mime_types );
$mime_types[] = $last2 . ' ' . __( 'or', 'acf' ) . ' ' . $last1;
}
$errors['mime_types'] = sprintf( __( 'File type must be %s.', 'acf' ), implode( ', ', $mime_types ) );
}
}
/**
* Filters the errors for a file before it is uploaded or displayed in the media modal.
*
* @date 3/07/2015
* @since 5.2.3
*
* @param array $errors An array of errors.
* @param array $file An array of data for a single file.
* @param array $attachment An array of attachment data which differs based on the context.
* @param array $field The field array.
* @param string $context The curent context (uploading, preparing)
*/
$errors = apply_filters( "acf/validate_attachment/type={$field['type']}", $errors, $file, $attachment, $field, $context );
$errors = apply_filters( "acf/validate_attachment/name={$field['_name']}", $errors, $file, $attachment, $field, $context );
$errors = apply_filters( "acf/validate_attachment/key={$field['key']}", $errors, $file, $attachment, $field, $context );
$errors = apply_filters( 'acf/validate_attachment', $errors, $file, $attachment, $field, $context );
// return
return $errors;
}
/*
* _acf_settings_uploader
*
* Dynamic logic for uploader setting
*
* @type function
* @date 7/05/2015
* @since 5.2.3
*
* @param $uploader (string)
* @return $uploader
*/
add_filter( 'acf/settings/uploader', '_acf_settings_uploader' );
function _acf_settings_uploader( $uploader ) {
// if can't upload files
if ( ! current_user_can( 'upload_files' ) ) {
$uploader = 'basic';
}
// return
return $uploader;
}
/*
* acf_translate_keys
*
* description
*
* @type function
* @date 7/12/2015
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
/*
function acf_translate_keys( $array, $keys ) {
// bail early if no keys
if( empty($keys) ) return $array;
// translate
foreach( $keys as $k ) {
// bail early if not exists
if( !isset($array[ $k ]) ) continue;
// translate
$array[ $k ] = acf_translate( $array[ $k ] );
}
// return
return $array;
}
*/
/*
* acf_translate
*
* This function will translate a string using the new 'l10n_textdomain' setting
* Also works for arrays which is great for fields - select -> choices
*
* @type function
* @date 4/12/2015
* @since 5.3.2
*
* @param $string (mixed) string or array containins strings to be translated
* @return $string
*/
function acf_translate( $string ) {
// vars
$l10n = acf_get_setting( 'l10n' );
$textdomain = acf_get_setting( 'l10n_textdomain' );
// bail early if not enabled
if ( ! $l10n ) {
return $string;
}
// bail early if no textdomain
if ( ! $textdomain ) {
return $string;
}
// is array
if ( is_array( $string ) ) {
return array_map( 'acf_translate', $string );
}
// bail early if not string
if ( ! is_string( $string ) ) {
return $string;
}
// bail early if empty
if ( $string === '' ) {
return $string;
}
// allow for var_export export
if ( acf_get_setting( 'l10n_var_export' ) ) {
// bail early if already translated
if ( substr( $string, 0, 7 ) === '!!__(!!' ) {
return $string;
}
// return
return "!!__(!!'" . $string . "!!', !!'" . $textdomain . "!!')!!";
}
// vars
return __( $string, $textdomain );
}
/*
* acf_maybe_add_action
*
* This function will determine if the action has already run before adding / calling the function
*
* @type function
* @date 13/01/2016
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_maybe_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
// if action has already run, execute it
// - if currently doing action, allow $tag to be added as per usual to allow $priority ordering needed for 3rd party asset compatibility
if ( did_action( $tag ) && ! doing_action( $tag ) ) {
call_user_func( $function_to_add );
// if action has not yet run, add it
} else {
add_action( $tag, $function_to_add, $priority, $accepted_args );
}
}
/*
* acf_is_row_collapsed
*
* This function will return true if the field's row is collapsed
*
* @type function
* @date 2/03/2016
* @since 5.3.2
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_is_row_collapsed( $field_key = '', $row_index = 0 ) {
// collapsed
$collapsed = acf_get_user_setting( 'collapsed_' . $field_key, '' );
// cookie fallback ( version < 5.3.2 )
if ( $collapsed === '' ) {
$collapsed = acf_extract_var( $_COOKIE, "acf_collapsed_{$field_key}", '' );
$collapsed = str_replace( '|', ',', $collapsed );
// update
acf_update_user_setting( 'collapsed_' . $field_key, $collapsed );
}
// explode
$collapsed = explode( ',', $collapsed );
$collapsed = array_filter( $collapsed, 'is_numeric' );
// collapsed class
return in_array( $row_index, $collapsed );
}
/*
* acf_get_attachment_image
*
* description
*
* @type function
* @date 24/10/16
* @since 5.5.0
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_get_attachment_image( $attachment_id = 0, $size = 'thumbnail' ) {
// vars
$url = wp_get_attachment_image_src( $attachment_id, 'thumbnail' );
$alt = get_post_meta( $attachment_id, '_wp_attachment_image_alt', true );
// bail early if no url
if ( ! $url ) {
return '';
}
// return
$value = '<img src="' . $url . '" alt="' . $alt . '" />';
}
/*
* acf_get_post_thumbnail
*
* This function will return a thumbail image url for a given post
*
* @type function
* @date 3/05/2016
* @since 5.3.8
*
* @param $post (obj)
* @param $size (mixed)
* @return (string)
*/
function acf_get_post_thumbnail( $post = null, $size = 'thumbnail' ) {
// vars
$data = array(
'url' => '',
'type' => '',
'html' => '',
);
// post
$post = get_post( $post );
// bail early if no post
if ( ! $post ) {
return $data;
}
// vars
$thumb_id = $post->ID;
$mime_type = acf_maybe_get( explode( '/', $post->post_mime_type ), 0 );
// attachment
if ( $post->post_type === 'attachment' ) {
// change $thumb_id
if ( $mime_type === 'audio' || $mime_type === 'video' ) {
$thumb_id = get_post_thumbnail_id( $post->ID );
}
// post
} else {
$thumb_id = get_post_thumbnail_id( $post->ID );
}
// try url
$data['url'] = wp_get_attachment_image_src( $thumb_id, $size );
$data['url'] = acf_maybe_get( $data['url'], 0 );
// default icon
if ( ! $data['url'] && $post->post_type === 'attachment' ) {
$data['url'] = wp_mime_type_icon( $post->ID );
$data['type'] = 'icon';
}
// html
$data['html'] = '<img src="' . $data['url'] . '" alt="" />';
// return
return $data;
}
/**
* acf_get_browser
*
* Returns the name of the current browser.
*
* @date 17/01/2014
* @since 5.0.0
*
* @param void
* @return string
*/
function acf_get_browser() {
// Check server var.
if ( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
$agent = sanitize_text_field( $_SERVER['HTTP_USER_AGENT'] );
// Loop over search terms.
$browsers = array(
'Firefox' => 'firefox',
'Trident' => 'msie',
'MSIE' => 'msie',
'Edge' => 'edge',
'Chrome' => 'chrome',
'Safari' => 'safari',
);
foreach ( $browsers as $k => $v ) {
if ( strpos( $agent, $k ) !== false ) {
return $v;
}
}
}
// Return default.
return '';
}
/*
* acf_is_ajax
*
* This function will reutrn true if performing a wp ajax call
*
* @type function
* @date 7/06/2016
* @since 5.3.8
*
* @param n/a
* @return (boolean)
*/
function acf_is_ajax( $action = '' ) {
// vars
$is_ajax = false;
// check if is doing ajax
if ( defined( 'DOING_AJAX' ) && DOING_AJAX ) {
$is_ajax = true;
}
// phpcs:disable WordPress.Security.NonceVerification.Missing
// check $action
if ( $action && acf_maybe_get( $_POST, 'action' ) !== $action ) {
// phpcs:enable WordPress.Security.NonceVerification.Missing
$is_ajax = false;
}
// return
return $is_ajax;
}
/*
* acf_format_date
*
* This function will accept a date value and return it in a formatted string
*
* @type function
* @date 16/06/2016
* @since 5.3.8
*
* @param $value (string)
* @return $format (string)
*/
function acf_format_date( $value, $format ) {
// bail early if no value
if ( ! $value ) {
return $value;
}
// vars
$unixtimestamp = 0;
// numeric (either unix or YYYYMMDD)
if ( is_numeric( $value ) && strlen( $value ) !== 8 ) {
$unixtimestamp = $value;
} else {
$unixtimestamp = strtotime( $value );
}
// return
return date_i18n( $format, $unixtimestamp );
}
/**
* acf_clear_log
*
* Deletes the debug.log file.
*
* @date 21/1/19
* @since 5.7.10
*
* @param type $var Description. Default.
* @return type Description.
*/
function acf_clear_log() {
unlink( WP_CONTENT_DIR . '/debug.log' );
}
/*
* acf_log
*
* description
*
* @type function
* @date 24/06/2016
* @since 5.3.8
*
* @param $post_id (int)
* @return $post_id (int)
*/
function acf_log() {
// vars
$args = func_get_args();
// loop
foreach ( $args as $i => $arg ) {
// array | object
if ( is_array( $arg ) || is_object( $arg ) ) {
$arg = print_r( $arg, true );
// bool
} elseif ( is_bool( $arg ) ) {
$arg = 'bool(' . ( $arg ? 'true' : 'false' ) . ')';
}
// update
$args[ $i ] = $arg;
}
// log
error_log( implode( ' ', $args ) );
}
/**
* acf_dev_log
*
* Used to log variables only if ACF_DEV is defined
*
* @date 25/8/18
* @since 5.7.4
*
* @param mixed
* @return void
*/
function acf_dev_log() {
if ( defined( 'ACF_DEV' ) && ACF_DEV ) {
call_user_func_array( 'acf_log', func_get_args() );
}
}
/*
* acf_doing
*
* This function will tell ACF what task it is doing
*
* @type function
* @date 28/06/2016
* @since 5.3.8
*
* @param $event (string)
* @param context (string)
* @return n/a
*/
function acf_doing( $event = '', $context = '' ) {
acf_update_setting( 'doing', $event );
acf_update_setting( 'doing_context', $context );
}
/*
* acf_is_doing
*
* This function can be used to state what ACF is doing, or to check
*
* @type function
* @date 28/06/2016
* @since 5.3.8
*
* @param $event (string)
* @param context (string)
* @return (boolean)
*/
function acf_is_doing( $event = '', $context = '' ) {
// vars
$doing = false;
// task
if ( acf_get_setting( 'doing' ) === $event ) {
$doing = true;
}
// context
if ( $context && acf_get_setting( 'doing_context' ) !== $context ) {
$doing = false;
}
// return
return $doing;
}
/*
* acf_is_plugin_active
*
* This function will return true if the ACF plugin is active
* - May be included within a theme or other plugin
*
* @type function
* @date 13/07/2016
* @since 5.4.0
*
* @param $basename (int)
* @return $post_id (int)
*/
function acf_is_plugin_active() {
// vars
$basename = acf_get_setting( 'basename' );
// ensure is_plugin_active() exists (not on frontend)
if ( ! function_exists( 'is_plugin_active' ) ) {
include_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// return
return is_plugin_active( $basename );
}
/*
* acf_send_ajax_results
*
* This function will print JSON data for a Select2 AJAX query
*
* @type function
* @date 19/07/2016
* @since 5.4.0
*
* @param $response (array)
* @return n/a
*/
function acf_send_ajax_results( $response ) {
// validate
$response = wp_parse_args(
$response,
array(
'results' => array(),
'more' => false,
'limit' => 0,
)
);
// limit
if ( $response['limit'] && $response['results'] ) {
// vars
$total = 0;
foreach ( $response['results'] as $result ) {
// parent
$total++;
// children
if ( ! empty( $result['children'] ) ) {
$total += count( $result['children'] );
}
}
// calc
if ( $total >= $response['limit'] ) {
$response['more'] = true;
}
}
// return
wp_send_json( $response );
}
/*
* acf_is_sequential_array
*
* This function will return true if the array contains only numeric keys
*
* @source http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
* @type function
* @date 9/09/2016
* @since 5.4.0
*
* @param $array (array)
* @return (boolean)
*/
function acf_is_sequential_array( $array ) {
// bail early if not array
if ( ! is_array( $array ) ) {
return false;
}
// loop
foreach ( $array as $key => $value ) {
// bail early if is string
if ( is_string( $key ) ) {
return false;
}
}
// return
return true;
}
/*
* acf_is_associative_array
*
* This function will return true if the array contains one or more string keys
*
* @source http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
* @type function
* @date 9/09/2016
* @since 5.4.0
*
* @param $array (array)
* @return (boolean)
*/
function acf_is_associative_array( $array ) {
// bail early if not array
if ( ! is_array( $array ) ) {
return false;
}
// loop
foreach ( $array as $key => $value ) {
// bail early if is string
if ( is_string( $key ) ) {
return true;
}
}
// return
return false;
}
/*
* acf_add_array_key_prefix
*
* This function will add a prefix to all array keys
* Useful to preserve numeric keys when performing array_multisort
*
* @type function
* @date 15/09/2016
* @since 5.4.0
*
* @param $array (array)
* @param $prefix (string)
* @return (array)
*/
function acf_add_array_key_prefix( $array, $prefix ) {
// vars
$array2 = array();
// loop
foreach ( $array as $k => $v ) {
$k2 = $prefix . $k;
$array2[ $k2 ] = $v;
}
// return
return $array2;
}
/*
* acf_remove_array_key_prefix
*
* This function will remove a prefix to all array keys
* Useful to preserve numeric keys when performing array_multisort
*
* @type function
* @date 15/09/2016
* @since 5.4.0
*
* @param $array (array)
* @param $prefix (string)
* @return (array)
*/
function acf_remove_array_key_prefix( $array, $prefix ) {
// vars
$array2 = array();
$l = strlen( $prefix );
// loop
foreach ( $array as $k => $v ) {
$k2 = ( substr( $k, 0, $l ) === $prefix ) ? substr( $k, $l ) : $k;
$array2[ $k2 ] = $v;
}
// return
return $array2;
}
/*
* acf_strip_protocol
*
* This function will remove the proticol from a url
* Used to allow licenses to remain active if a site is switched to https
*
* @type function
* @date 10/01/2017
* @since 5.5.4
* @author Aaron
*
* @param $url (string)
* @return (string)
*/
function acf_strip_protocol( $url ) {
// strip the protical
return str_replace( array( 'http://', 'https://' ), '', $url );
}
/*
* acf_connect_attachment_to_post
*
* This function will connect an attacment (image etc) to the post
* Used to connect attachements uploaded directly to media that have not been attaced to a post
*
* @type function
* @date 11/01/2017
* @since 5.8.0 Added filter to prevent connection.
* @since 5.5.4
*
* @param int $attachment_id The attachment ID.
* @param int $post_id The post ID.
* @return bool True if attachment was connected.
*/
function acf_connect_attachment_to_post( $attachment_id = 0, $post_id = 0 ) {
// bail early if $attachment_id is not valid.
if ( ! $attachment_id || ! is_numeric( $attachment_id ) ) {
return false;
}
// bail early if $post_id is not valid.
if ( ! $post_id || ! is_numeric( $post_id ) ) {
return false;
}
/**
* Filters whether or not to connect the attachment.
*
* @date 8/11/18
* @since 5.8.0
*
* @param bool $bool Returning false will prevent the connection. Default true.
* @param int $attachment_id The attachment ID.
* @param int $post_id The post ID.
*/
if ( ! apply_filters( 'acf/connect_attachment_to_post', true, $attachment_id, $post_id ) ) {
return false;
}
// vars
$post = get_post( $attachment_id );
// Check if is valid post.
if ( $post && $post->post_type == 'attachment' && $post->post_parent == 0 ) {
// update
wp_update_post(
array(
'ID' => $post->ID,
'post_parent' => $post_id,
)
);
// return
return true;
}
// return
return true;
}
/*
* acf_encrypt
*
* This function will encrypt a string using PHP
* https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/
*
* @type function
* @date 27/2/17
* @since 5.5.8
*
* @param $data (string)
* @return (string)
*/
function acf_encrypt( $data = '' ) {
// bail early if no encrypt function
if ( ! function_exists( 'openssl_encrypt' ) ) {
return base64_encode( $data );
}
// generate a key
$key = wp_hash( 'acf_encrypt' );
// Generate an initialization vector
$iv = openssl_random_pseudo_bytes( openssl_cipher_iv_length( 'aes-256-cbc' ) );
// Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
$encrypted_data = openssl_encrypt( $data, 'aes-256-cbc', $key, 0, $iv );
// The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
return base64_encode( $encrypted_data . '::' . $iv );
}
/*
* acf_decrypt
*
* This function will decrypt an encrypted string using PHP
* https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/
*
* @type function
* @date 27/2/17
* @since 5.5.8
*
* @param $data (string)
* @return (string)
*/
function acf_decrypt( $data = '' ) {
// bail early if no decrypt function
if ( ! function_exists( 'openssl_decrypt' ) ) {
return base64_decode( $data );
}
// generate a key
$key = wp_hash( 'acf_encrypt' );
// To decrypt, split the encrypted data from our IV - our unique separator used was "::"
list($encrypted_data, $iv) = explode( '::', base64_decode( $data ), 2 );
// decrypt
return openssl_decrypt( $encrypted_data, 'aes-256-cbc', $key, 0, $iv );
}
/**
* acf_parse_markdown
*
* A very basic regex-based Markdown parser function based off [slimdown](https://gist.github.com/jbroadway/2836900).
*
* @date 6/8/18
* @since 5.7.2
*
* @param string $text The string to parse.
* @return string
*/
function acf_parse_markdown( $text = '' ) {
// trim
$text = trim( $text );
// rules
$rules = array(
'/=== (.+?) ===/' => '<h2>$1</h2>', // headings
'/== (.+?) ==/' => '<h3>$1</h3>', // headings
'/= (.+?) =/' => '<h4>$1</h4>', // headings
'/\[([^\[]+)\]\(([^\)]+)\)/' => '<a href="$2">$1</a>', // links
'/(\*\*)(.*?)\1/' => '<strong>$2</strong>', // bold
'/(\*)(.*?)\1/' => '<em>$2</em>', // intalic
'/`(.*?)`/' => '<code>$1</code>', // inline code
'/\n\*(.*)/' => "\n<ul>\n\t<li>$1</li>\n</ul>", // ul lists
'/\n[0-9]+\.(.*)/' => "\n<ol>\n\t<li>$1</li>\n</ol>", // ol lists
'/<\/ul>\s?<ul>/' => '', // fix extra ul
'/<\/ol>\s?<ol>/' => '', // fix extra ol
);
foreach ( $rules as $k => $v ) {
$text = preg_replace( $k, $v, $text );
}
// autop
$text = wpautop( $text );
// return
return $text;
}
/**
* acf_get_sites
*
* Returns an array of sites for a network.
*
* @date 29/08/2016
* @since 5.4.0
*
* @param void
* @return array
*/
function acf_get_sites() {
$results = array();
$sites = get_sites( array( 'number' => 0 ) );
if ( $sites ) {
foreach ( $sites as $site ) {
$results[] = get_site( $site )->to_array();
}
}
return $results;
}
/**
* acf_convert_rules_to_groups
*
* Converts an array of rules from ACF4 to an array of groups for ACF5
*
* @date 25/8/18
* @since 5.7.4
*
* @param array $rules An array of rules.
* @param string $anyorall The anyorall setting used in ACF4. Defaults to 'any'.
* @return array
*/
function acf_convert_rules_to_groups( $rules, $anyorall = 'any' ) {
// vars
$groups = array();
$index = 0;
// loop
foreach ( $rules as $rule ) {
// extract vars
$group = acf_extract_var( $rule, 'group_no' );
$order = acf_extract_var( $rule, 'order_no' );
// calculate group if not defined
if ( $group === null ) {
$group = $index;
// use $anyorall to determine if a new group is needed
if ( $anyorall == 'any' ) {
$index++;
}
}
// calculate order if not defined
if ( $order === null ) {
$order = isset( $groups[ $group ] ) ? count( $groups[ $group ] ) : 0;
}
// append to group
$groups[ $group ][ $order ] = $rule;
// sort groups
ksort( $groups[ $group ] );
}
// sort groups
ksort( $groups );
// return
return $groups;
}
/**
* acf_register_ajax
*
* Regsiters an ajax callback.
*
* @date 5/10/18
* @since 5.7.7
*
* @param string $name The ajax action name.
* @param array $callback The callback function or array.
* @param bool $public Whether to allow access to non logged in users.
* @return void
*/
function acf_register_ajax( $name = '', $callback = false, $public = false ) {
// vars
$action = "acf/ajax/$name";
// add action for logged-in users
add_action( "wp_ajax_$action", $callback );
// add action for non logged-in users
if ( $public ) {
add_action( "wp_ajax_nopriv_$action", $callback );
}
}
/**
* acf_str_camel_case
*
* Converts a string into camelCase.
* Thanks to https://stackoverflow.com/questions/31274782/convert-array-keys-from-underscore-case-to-camelcase-recursively
*
* @date 24/10/18
* @since 5.8.0
*
* @param string $string The string ot convert.
* @return string
*/
function acf_str_camel_case( $string = '' ) {
return lcfirst( str_replace( ' ', '', ucwords( str_replace( '_', ' ', $string ) ) ) );
}
/**
* acf_array_camel_case
*
* Converts all aray keys to camelCase.
*
* @date 24/10/18
* @since 5.8.0
*
* @param array $array The array to convert.
* @return array
*/
function acf_array_camel_case( $array = array() ) {
$array2 = array();
foreach ( $array as $k => $v ) {
$array2[ acf_str_camel_case( $k ) ] = $v;
}
return $array2;
}
/**
* Returns true if the current screen is using the block editor.
*
* @date 13/12/18
* @since 5.8.0
*
* @return bool
*/
function acf_is_block_editor() {
if ( function_exists( 'get_current_screen' ) ) {
$screen = get_current_screen();
if ( $screen && method_exists( $screen, 'is_block_editor' ) ) {
return $screen->is_block_editor();
}
}
return false;
}
/**
* Return an array of the WordPress reserved terms
*
* @since 6.1
*
* @return array The WordPress reserved terms list.
*/
function acf_get_wp_reserved_terms() {
return array( 'action', 'attachment', 'attachment_id', 'author', 'author_name', 'calendar', 'cat', 'category', 'category__and', 'category__in', 'category__not_in', 'category_name', 'comments_per_page', 'comments_popup', 'custom', 'customize_messenger_channel', 'customized', 'cpage', 'day', 'debug', 'embed', 'error', 'exact', 'feed', 'fields', 'hour', 'link_category', 'm', 'minute', 'monthnum', 'more', 'name', 'nav_menu', 'nonce', 'nopaging', 'offset', 'order', 'orderby', 'p', 'page', 'page_id', 'paged', 'pagename', 'pb', 'perm', 'post', 'post__in', 'post__not_in', 'post_format', 'post_mime_type', 'post_status', 'post_tag', 'post_type', 'posts', 'posts_per_archive_page', 'posts_per_page', 'preview', 'robots', 's', 'search', 'second', 'sentence', 'showposts', 'static', 'status', 'subpost', 'subpost_id', 'tag', 'tag__and', 'tag__in', 'tag__not_in', 'tag_id', 'tag_slug__and', 'tag_slug__in', 'taxonomy', 'tb', 'term', 'terms', 'theme', 'title', 'type', 'types', 'w', 'withcomments', 'withoutcomments', 'year' );
}