web/wp-content/plugins/acf-extended/includes/acfe-helper-functions.php (529 lines of code) (raw):

<?php if(!defined('ABSPATH')){ exit; } /** * acfe_array_get * * Search within array using dot mapping * * @param $array * @param $key * @param $default * * @return mixed|null */ function acfe_array_get($array, $key, $default = null){ if(empty($key) && !is_numeric($key)){ return $array; } if(!is_array($key)){ $key = explode('.', $key); } $count = count($key); $i=-1; foreach($key as $segment){ $i++; if(isset($array[ $segment ])){ if($i+1 === $count){ return $array[ $segment ]; } unset($key[ $i ]); return acfe_array_get($array[ $segment ], $key, $default); } } return $default; } /** * acfe_array_set * * @param $array * @param $keys * @param $value * * @return array|mixed */ function acfe_array_set(&$array, $keys, $value = null){ if(func_num_args() === 2){ return $array = $keys; } if(!is_array($keys)){ $keys = explode('.', $keys); } foreach($keys as $i => $key){ if(count($keys) === 1){ break; } unset($keys[ $i ]); // If the key doesn't exist at this depth, we will just create an empty array // to hold the next value, allowing us to create the arrays to hold final // values at the correct depth. Then we'll keep digging into the array. if(!isset($array[ $key ]) || !is_array($array[ $key ])){ if(empty($key) && acf_is_sequential_array($array)){ $array[] = array(); $key = key(array_slice($array, -1, 1, true)); }else{ $array[ $key ] = array(); } } $array = &$array[ $key ]; } // if segment finish with "." $final = array_shift($keys); if(empty($final) && !is_numeric($final) && acf_is_sequential_array($array)){ $array[] = $value; }else{ $array[ $final ] = $value; } return $array; } /** * acfe_array_unset * * @param $array * @param $keys * * @return array|mixed */ function acfe_array_unset(&$array, $keys){ $original = &$array; $keys = (array) $keys; if(count($keys) === 0){ return $array; } foreach($keys as $key){ // if the exact key exists in the top-level, remove it if(array_key_exists($key, $array)){ unset($array[ $key ]); continue; } $parts = explode('.', $key); // clean up before each pass $array = &$original; while(count($parts) > 1){ $part = array_shift($parts); if (isset($array[$part]) && is_array($array[$part])) { $array = &$array[$part]; } else { continue 2; } } unset($array[ array_shift($parts) ]); } return $array; } /** * acfe_maybe_get * * Similar to acf_maybe_get() but also works with OBJECTS * * @param array $array * @param int $key * @param null $default * * @return mixed|null */ function acfe_maybe_get($array = array(), $key = 0, $default = null){ if(is_object($array)){ return isset($array->{$key}) ? $array->{$key} : $default; } return acf_maybe_get($array, $key, $default); } /** * acfe_maybe_get_REQUEST * * Similar to acf_maybe_get_POST() but works with $_REQUEST * * @param string $key * @param null $default * * @return mixed|null */ function acfe_maybe_get_REQUEST($key = '', $default = null){ return isset($_REQUEST[ $key ]) ? $_REQUEST[ $key ] : $default; } /** * acfe_is_json * * Check if the string is a json input * https://stackoverflow.com/a/6041773 * * @param $string * * @return bool */ function acfe_is_json($string){ // in case string = 1 or not string if(is_numeric($string) || !is_string($string)){ return false; } // decode json_decode($string); // check if decode has errors return json_last_error() == JSON_ERROR_NONE; } /** * acfe_is_html * * Check if string is html * https://subinsb.com/php-check-if-string-is-html/ * * @param $string * * @return bool */ function acfe_is_html($string){ return $string !== strip_tags($string); } /** * acfe_array_keys_r * * Array Keys Recursive * * @param $array * * @return int[]|string[] */ function acfe_array_keys_r($array){ $keys = array_keys($array); foreach($array as $i){ if(is_array($i)){ $keys = array_merge($keys, acfe_array_keys_r($i)); } } return $keys; } /** * acfe_starts_with * * Check if a strings starts with something * * @param $haystack * @param $needle * * @return bool */ function acfe_starts_with($haystack, $needle){ // make sure $haystack is a string // substr deprecated non-string since php 8.0 if(!is_string($haystack)){ return false; } $length = strlen($needle); return substr($haystack, 0, $length) === $needle; } /** * acfe_ends_with * * Check if a strings ends with something * * @param $haystack * @param $needle * * @return bool */ function acfe_ends_with($haystack, $needle){ $length = strlen($needle); if($length === 0){ return true; } // make sure $haystack is a string // substr deprecated non-string since php 8.0 if(!is_string($haystack)){ return false; } return substr($haystack, -$length) === $needle; } /** * acfe_prefix_array_keys * * Prefix array keys recursively ignoring numeric keys * * @param $array * @param $prefix * @param $ignore * * @return array */ function acfe_prefix_array_keys($array, $prefix, $ignore = array(), $recursive = true){ // vars $array2 = array(); // loop foreach($array as $k => $v){ if(is_numeric($k)){ $k2 = $k; $array2[ $k2 ] = $v; }else{ $k2 = $prefix . $k; // ignore if($ignore && in_array($k, $ignore)){ $k2 = $k; } $array2[ $k2 ] = $v; } // recursive sub array if($recursive){ if(is_array($array2[ $k2 ])){ $array2[ $k2 ] = acfe_prefix_array_keys($array2[ $k2 ], $prefix, $ignore, $recursive); } } } // return return $array2; } /** * acfe_unprefix_array_keys * * Prefix array keys recursively ignoring numeric keys * * @param $array * @param $prefix * @param $ignore * * @return array */ function acfe_unprefix_array_keys($array, $prefix, $ignore = array(), $recursive = true){ // vars $array2 = array(); // loop foreach($array as $k => $v){ if(is_numeric($k)){ $k2 = $k; $array2[ $k2 ] = $v; }else{ $k2 = acfe_starts_with($k, $prefix) ? substr($k, strlen($prefix)) : $k; if($ignore && in_array($k, $ignore)){ $k2 = $k; } $array2[ $k2 ] = $v; } // recursive sub array if($recursive){ if(is_array($array2[ $k2 ])){ $array2[ $k2 ] = acfe_unprefix_array_keys($array2[ $k2 ], $prefix, $ignore, $recursive); } } } // return return $array2; } /** * acfe_map_array_keys * * Map array keys recursively, allowing to update a row key. * Return false in callback to remove the row. * * @param $array * @param $func * * @return array|false */ function acfe_map_array_keys($array, $func){ // validate array if(!is_array($array)){ return $array; } // vars $array2 = false; // loop foreach($array as $k => $v){ // callback $k2 = call_user_func($func, $k, $v); // remove the row if($k2 === false){ continue; // allow row and don't process sub array }elseif($k2 === true){ $array2 = acf_get_array($array2); $array2[ $k ] = $v; // allow row and process sub array }else{ $array2 = acf_get_array($array2); $array2[ $k2 ] = $v; // recursive sub array if(is_array($array2[ $k2 ])){ $array2[ $k2 ] = acfe_map_array_keys($array2[ $k2 ], $func); if($array2[ $k2 ] === false){ unset($array2[ $k2 ]); } if(is_array($array2) && empty($array2)){ $array2 = false; } } } } // return return $array2; } /** * acfe_filter_acf_values_by_keys * * @param $acf * @param $field_keys * * @return array|false */ function acfe_filter_acf_values_by_keys($acf, $field_keys){ $acf = acf_get_array($acf); $field_keys = acf_get_array($field_keys); $filtered_keys = $field_keys; foreach($field_keys as $field_key){ $field = acf_get_field($field_key); if($field && $field['type'] === 'clone' && $field['display'] === 'seamless' && $field['sub_fields']){ $sub_fields = $field['sub_fields']; $sub_fields = wp_list_pluck($sub_fields, 'key'); if($sub_fields){ $filtered_keys = array_merge($filtered_keys, $sub_fields); } } } $acf = acfe_map_array_keys($acf, function($key, $value) use($filtered_keys){ // top level key found // allow row and ignore sub array if(in_array($key, $filtered_keys, true)){ return true; } // sub array key not found and value is not array (so no sub array available) // do not allow row and ignore sub array if(!is_array($value) && !in_array($key, $filtered_keys, true)){ return false; } // process sub array return $key; }); return $acf; } /** * acfe_get_value_from_acf_values_by_key * * @param $acf * @param $field_key * * @return mixed|null */ function acfe_get_value_from_acf_values_by_key($acf, $field_key){ // vars $value = null; $acf = acf_get_array($acf); // seamless clone rule $field = acf_get_field($field_key); $is_seamless = false; if($field && $field['type'] === 'clone' && $field['display'] === 'seamless'){ $value = array(); $is_seamless = true; } // loop values acfe_map_array_keys($acf, function($k, $v) use($field_key, $is_seamless, &$value){ if($is_seamless){ if(acfe_starts_with($k, "{$field_key}_")){ $value[ $k ] = $v; } }else{ // found key if($k === $field_key){ $value = $v; } } // continue loop return $k; }); if($is_seamless && empty($value)){ $value = null; } // return return $value; } /** * acfe_array_insert_before * * Insert data before a specific array key * * @param $key * @param array $array * @param $new_key * @param $new_value * * @return array */ function acfe_array_insert_before($array, $key, $new_key, $new_value = null){ if(!is_array($array) || !isset($array[ $key ])){ return $array; } $is_sequential = acf_is_sequential_array($array); $new_array = array(); foreach($array as $k => $value){ if($k === $key){ if($is_sequential){ $new_value = $new_value === null ? $new_key : $new_value; $new_array[] = $new_value; }else{ if($new_value === null && is_array($new_key)){ reset($new_key); $new_value = current($new_key); $new_key = key($new_key); } $new_array[ $new_key ] = $new_value; } } if($is_sequential){ $new_array[] = $value; }else{ $new_array[ $k ] = $value; } } return $new_array; } /** * acfe_array_insert_after * * Insert data after a specific array key * * @param $key * @param array $array * @param $new_key * @param $new_value * * @return array */ function acfe_array_insert_after($array, $key, $new_key, $new_value = null){ if(!is_array($array) || !isset($array[ $key ])){ return $array; } $is_sequential = acf_is_sequential_array($array); $new_array = array(); foreach($array as $k => $value){ if($is_sequential){ $new_array[] = $value; }else{ $new_array[ $k ] = $value; } if($k === $key){ if($is_sequential){ $new_value = $new_value === null ? $new_key : $new_value; $new_array[] = $new_value; }else{ if($new_value === null && is_array($new_key)){ reset($new_key); $new_value = current($new_key); $new_key = key($new_key); } $new_array[ $new_key ] = $new_value; } } } return $new_array; } /** * acfe_array_move * * Move the array key from position $a to $b * * @param $array * @param $a * @param $b */ function acfe_array_move(&$array, $a, $b){ $out = array_splice($array, $a, 1); array_splice($array, $b, 0, $out); } /** * acfe_parse_args_r * * parse arguments recursively * * @param $a * @param $b * * @return array */ function acfe_parse_args_r(&$a, $b){ $a = (array) $a; $b = (array) $b; $r = $b; foreach($a as $k => &$v){ if(is_array($v) && isset($r[ $k ]) && is_array($r[ $k ]) && acf_is_associative_array($r[ $k ])){ $r[ $k ] = acfe_parse_args_r($v, $r[ $k ]); }else{ $r[ $k ] = $v; } } return $r; } /** * acfe_add_validation_error * * Similar to acf_add_validation_error() but allows to use field name or field key * * @param string $selector * @param string $message * * @return mixed */ function acfe_add_validation_error($selector = '', $message = ''){ // general error if(empty($selector)){ return acf_add_validation_error('', $message); } // selector is a field key if(acf_is_field_key($selector)){ return add_filter("acf/validate_value/key={$selector}", function() use($message){ return $message; }); } // get field by name $field = acf_get_field($selector); // check form data // todo: make it more clean if($form = acf_get_form_data('acfe/form')){ // vars $fields = array(); $field_groups = acf_get_array($form['field_groups']); // loop field groups foreach($field_groups as $key){ $fields = array_merge($fields, acf_get_fields($key)); } foreach($fields as $_field){ // field name is different if($_field['name'] !== $selector){ continue; } // assign field $field = $_field; break; } } // check active loop $row = acf_get_loop(); // exclude acfe form actions if($row && acf_maybe_get($row, 'selector') !== 'acfe_form_actions'){ // get sub field $field = acf_get_sub_field($selector, $row['field']); } // field not found: add general error if(!$field){ return acf_add_validation_error('', $message); } // add validation error add_filter("acf/validate_value/key={$field['key']}", function() use($message){ return $message; }); return false; } /** * acfe_number_suffix * * Adds 1"st", 2"nd", 3"rd" to number * * @param $num * * @return string */ function acfe_number_suffix($num){ if(!in_array(($num % 100), array(11, 12, 13))){ switch($num % 10){ case 1: return $num . 'st'; case 2: return $num . 'nd'; case 3: return $num . 'rd'; } } return $num . 'th'; } /** * acfe_array_to_string * * Convert an array to string * * @param array $array * * @return array|false|mixed|string */ function acfe_array_to_string($array = array()){ // check type if(is_array($array)){ // loop foreach($array as $val){ if(is_string($val) || is_numeric($val) || is_bool($val)){ return $val; } } // no valid value return false; } // default return $array; } /** * acfe_is_dev * * Check if the developer mode is enabled * * @return bool */ function acfe_is_dev(){ // deprecated if(defined('ACFE_dev')){ acfe_deprecated_constant('ACFE_dev', '0.8.8.7', 'ACFE_DEV'); return ACFE_dev; } return acf_get_setting('acfe/dev', false) || (defined('ACFE_DEV') && ACFE_DEV); } /** * acfe_is_super_dev * * Only for awesome developers! * * @return bool */ function acfe_is_super_dev(){ // deprecated if(defined('ACFE_super_dev')){ acfe_deprecated_constant('ACFE_super_dev', '0.8.8.7', 'ACFE_SUPER_DEV'); return ACFE_super_dev; } return acf_get_setting('acfe/super_dev', false) || (defined('ACFE_SUPER_DEV') && ACFE_SUPER_DEV); } /** * acfe_is_post_type_reserved * * Check if the post type is reserved * * @param $post_type * * @return bool */ function acfe_is_post_type_reserved($post_type){ // restricted post types $reserved = acfe_get_setting('reserved_post_types', array()); return in_array($post_type, $reserved); } /** * acfe_is_post_type_reserved_dev * * Check if the post type is reserved in dev mode * * @param $post_type * * @return bool */ function acfe_is_post_type_reserved_dev($post_type){ // restricted post types $reserved = acfe_get_setting('reserved_post_types', array()); return !acfe_is_super_dev() && in_array($post_type, $reserved); } /** * acfe_is_taxonomy_reserved * * Check if the taxonomy is reserved * * @param $taxonomy * * @return bool */ function acfe_is_taxonomy_reserved($taxonomy){ // restricted post types $reserved = acfe_get_setting('reserved_taxonomies', array()); return in_array($taxonomy, $reserved); } /** * acfe_is_taxonomy_reserved_dev * * Check if the taxonomy is reserved in dev mode * * @param $taxonomy * * @return bool */ function acfe_is_taxonomy_reserved_dev($taxonomy){ // restricted post types $reserved = acfe_get_setting('reserved_taxonomies', array()); return !acfe_is_super_dev() && in_array($taxonomy, $reserved); } /** * acfe_update_setting * * Similar to acf_update_setting() but with the 'acfe' prefix * * @param $name * @param $value * * @return bool|true */ function acfe_update_setting($name, $value){ return acf_update_setting("acfe/{$name}", $value); } /** * acfe_append_setting * * Similar to acf_append_setting() but with the 'acfe' prefix * * @param $name * @param $value * * @return bool|true */ function acfe_append_setting($name, $value){ return acf_append_setting("acfe/{$name}", $value); } /** * acfe_get_setting * * Similar to acf_get_setting() but with the 'acfe' prefix * * @param $name * @param null $value * * @return mixed|void */ function acfe_get_setting($name, $value = null){ return acf_get_setting("acfe/{$name}", $value); } /** * acfe_unset * * Safely remove an array key * * @param $array * @param $key */ function acfe_unset(&$array, $key){ if(isset($array[ $key ])){ unset($array[ $key ]); } } /** * acfe_unarray * * Retrieve and return only the first value of an array * * @param $val * * @return false|mixed */ function acfe_unarray($val){ if(is_array($val)){ return reset($val); } return $val; } /** * acfe_get_ip * @return mixed */ function acfe_get_ip(){ $ip = false; // http client if(!empty($_SERVER['HTTP_CLIENT_IP'])){ $ip = filter_var(wp_unslash($_SERVER['HTTP_CLIENT_IP']), FILTER_VALIDATE_IP); // proxy pass }elseif(!empty($_SERVER['HTTP_X_FORWARDED_FOR'])){ // can include more than 1 ip, first is the public one. $ips = explode(',', wp_unslash($_SERVER['HTTP_X_FORWARDED_FOR'])); if(is_array($ips)){ $ip = filter_var($ips[0], FILTER_VALIDATE_IP); } // remote addr }elseif(!empty($_SERVER['REMOTE_ADDR'])){ $ip = filter_var(wp_unslash($_SERVER['REMOTE_ADDR']), FILTER_VALIDATE_IP); } // default $ip = $ip !== false ? $ip : '127.0.0.1'; // fix potential csv return $ip_array = explode(',', $ip); $ip_array = array_map('trim', $ip_array); // return return $ip_array[0]; } /** * acfe_var_export * * export php code * * @param $code * @param $esc * * @return array|string|string[]|null */ function acfe_var_export($code, $esc = true){ $str_replace = array( " " => " ", "'!!__(!!\'" => "__('", "!!\', !!\'" => "', '", "!!\')!!'" => "')", "array (" => "array(", " NULL," => " null,", ); $preg_replace = array( '/([ \r\n]+?)array/' => ' array', '/array\(\n\)/' => 'array()', '/array\(\n([ ]+)\)/' => 'array()', '/[0-9]+ => /' => '', //'/[0-9]+ => array/' => 'array', ); // code $code = var_export($code, 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 if($esc){ $code = esc_textarea($code); } // return return $code; } /** * acfe_parse_types * * cousin of acf_parse_type() but also handle 'false' | 'true' | 'null' values * * @param $v * @param $filters * * @return array|bool|int|mixed|string|null */ function acfe_parse_types($v, $filters = array('trim', 'int', 'bool', 'null')){ // validate filters $filters = acf_get_array($filters); // check array if(is_array($v) && !empty($v)){ $v = array_map(function($v) use($filters){ return acfe_parse_types($v, $filters); }, $v); // check if string }elseif(is_string($v)){ // trim ('word ' = 'word') if(in_array('trim', $filters)){ $v = trim($v); } // convert int strings to int ('123' = 123) if(in_array('int', $filters) && is_numeric($v) && strval(intval($v)) === $v){ $v = intval($v); // convert ('false' = false) }elseif(in_array('bool', $filters) && strtolower($v) === 'false'){ $v = false; // convert ('true' = true) }elseif(in_array('bool', $filters) && strtolower($v) === 'true'){ $v = true; // convert ('null' = null) }elseif(in_array('null', $filters) && strtolower($v) === 'null'){ $v = null; } } // return return $v; } /** * acfe_unparse_types * * reverse of acfe_parse_types * * @param $v * @param $filters * * @return array|mixed|string */ function acfe_unparse_types($v, $filters = array('int', 'bool', 'null')){ // validate filters $filters = acf_get_array($filters); // check array if(is_array($v) && !empty($v)){ $v = array_map(function($v) use($filters){ return acfe_unparse_types($v, $filters); }, $v); // others }else{ // convert int strings to int (123 = '123') if(in_array('int', $filters) && is_int($v)){ $v = strval($v); // convert (false = 'false') }elseif(in_array('bool', $filters) && $v === false){ $v = 'false'; // convert (true = 'true') }elseif(in_array('bool', $filters) && $v === true){ $v = 'true'; // convert (null = 'null') }elseif(in_array('null', $filters) && $v === null){ $v = 'null'; } } // return return $v; } /** * acfe_redirect * * @param $location * @param $status * * @return void */ function acfe_redirect($location, $status = 302){ // filter $redirect = apply_filters('acfe/redirect', $location, $status); if($redirect){ wp_redirect($location); exit; } } /** * acfe_doing_action * * Returns the current priority of a running action. * From acf_doing_action(), but also works with ACF 5.8 * * @param $action * * @return false|int */ function acfe_doing_action($action){ global $wp_filter; if(isset($wp_filter[ $action ])){ return $wp_filter[ $action ]->current_priority(); } return false; } /** * acfe_str_replace_first * * @param $search * @param $replace * @param $subject * @param $delete bool Should delete the other occurrences of the search string * * @return array|mixed|string|string[] */ function acfe_str_replace_first($search, $replace, $subject, $delete = false){ $pos = strpos($subject, $search); if($pos !== false){ $subject = substr_replace($subject, $replace, $pos, strlen($search)); if($delete){ $subject = str_replace($search, '', $subject); } } return $subject; }