PluginProbe
Advanced Custom Fields (ACF®) / 5.6.6
Advanced Custom Fields (ACF®) v5.6.6
6.8.9 6.8.8 6.8.7 6.8.6 6.8.5 6.8.4 6.8.3 6.8.2 6.8.1 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9 6.0.0 All 230 releases
advanced-custom-fields / includes / api / api-helpers.php
api-helpers.php
5,124 lines 82.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /*
4 * acf_is_array
5 *
6 * This function will return true for a non empty array
7 *
8 * @type function
9 * @date 6/07/2016
10 * @since 5.4.0
11 *
12 * @param $array (array)
13 * @return (boolean)
14 */
15
16 function acf_is_array( $array ) {
17
18 return ( is_array($array) && !empty($array) );
19
20 }
21
22
23 /*
24 * acf_is_empty
25 *
26 * This function will return true for an empty var (allows 0 as true)
27 *
28 * @type function
29 * @date 6/07/2016
30 * @since 5.4.0
31 *
32 * @param $value (mixed)
33 * @return (boolean)
34 */
35
36 function acf_is_empty( $value ) {
37
38 return ( empty($value) && !is_numeric($value) );
39
40 }
41
42
43 /*
44 * acf_get_setting
45 *
46 * alias of acf()->get_setting()
47 *
48 * @type function
49 * @date 28/09/13
50 * @since 5.0.0
51 *
52 * @param n/a
53 * @return n/a
54 */
55
56 function acf_get_setting( $name, $value = null ) {
57
58 return acf()->get_setting( $name, $value );
59
60 }
61
62
63 /*
64 * acf_update_setting
65 *
66 * alias of acf()->update_setting()
67 *
68 * @type function
69 * @date 28/09/13
70 * @since 5.0.0
71 *
72 * @param $name (string)
73 * @param $value (mixed)
74 * @return n/a
75 */
76
77 function acf_update_setting( $name, $value ) {
78
79 return acf()->update_setting( $name, $value );
80
81 }
82
83
84 /*
85 * acf_init
86 *
87 * alias of acf()->init()
88 *
89 * @type function
90 * @date 28/09/13
91 * @since 5.0.0
92 *
93 * @param n/a
94 * @return n/a
95 */
96
97 function acf_init() {
98
99 acf()->init();
100
101 }
102
103
104 /*
105 * acf_append_setting
106 *
107 * This function will add a value into the settings array found in the acf object
108 *
109 * @type function
110 * @date 28/09/13
111 * @since 5.0.0
112 *
113 * @param $name (string)
114 * @param $value (mixed)
115 * @return n/a
116 */
117
118 function acf_append_setting( $name, $value ) {
119
120 // vars
121 $setting = acf_get_setting( $name, array() );
122
123
124 // bail ealry if not array
125 if( !is_array($setting) ) return false;
126
127
128 // append
129 $setting[] = $value;
130
131
132 // update
133 acf_update_setting( $name, $setting );
134
135
136 // return
137 return true;
138
139 }
140
141
142 /*
143 * acf_get_compatibility
144 *
145 * This function will return true or false for a given compatibility setting
146 *
147 * @type function
148 * @date 20/01/2015
149 * @since 5.1.5
150 *
151 * @param $name (string)
152 * @return (boolean)
153 */
154
155 function acf_get_compatibility( $name ) {
156
157 return apply_filters( "acf/compatibility/{$name}", false );
158
159 }
160
161
162 /*
163 * acf_has_done
164 *
165 * This function will return true if this action has already been done
166 *
167 * @type function
168 * @date 16/12/2015
169 * @since 5.3.2
170 *
171 * @param $name (string)
172 * @return (boolean)
173 */
174
175 function acf_has_done( $name ) {
176
177 // vars
178 $setting = "_has_done_{$name}";
179
180
181 // return true if already done
182 if( acf_get_setting($setting) ) return true;
183
184
185 // update setting
186 acf_update_setting($setting, true);
187
188
189 // return
190 return false;
191
192 }
193
194
195 /*
196 * acf_get_path
197 *
198 * This function will return the path to a file within the ACF plugin folder
199 *
200 * @type function
201 * @date 28/09/13
202 * @since 5.0.0
203 *
204 * @param $path (string) the relative path from the root of the ACF plugin folder
205 * @return (string)
206 */
207
208 function acf_get_path( $path ) {
209
210 return ACF_PATH . $path;
211
212 }
213
214
215 /*
216 * acf_get_dir
217 *
218 * This function will return the url to a file within the ACF plugin folder
219 *
220 * @type function
221 * @date 28/09/13
222 * @since 5.0.0
223 *
224 * @param $path (string) the relative path from the root of the ACF plugin folder
225 * @return (string)
226 */
227
228 function acf_get_dir( $path ) {
229
230 return acf_get_setting('dir') . $path;
231
232 }
233
234
235 /*
236 * acf_include
237 *
238 * This function will include a file
239 *
240 * @type function
241 * @date 10/03/2014
242 * @since 5.0.0
243 *
244 * @param $post_id (int)
245 * @return $post_id (int)
246 */
247
248 function acf_include( $file ) {
249
250 $path = acf_get_path( $file );
251
252 if( file_exists($path) ) {
253
254 include_once( $path );
255
256 }
257
258 }
259
260
261 /*
262 * acf_get_external_path
263 *
264 * This function will return the path to a file within an external folder
265 *
266 * @type function
267 * @date 22/2/17
268 * @since 5.5.8
269 *
270 * @param $file (string)
271 * @param $path (string)
272 * @return (string)
273 */
274
275 function acf_get_external_path( $file, $path = '' ) {
276
277 return trailingslashit( dirname( $file ) ) . $path;
278
279 }
280
281
282 /*
283 * acf_get_external_dir
284 *
285 * This function will return the url to a file within an external folder
286 *
287 * @type function
288 * @date 22/2/17
289 * @since 5.5.8
290 *
291 * @param $file (string)
292 * @param $path (string)
293 * @return (string)
294 */
295
296 function acf_get_external_dir( $file, $path = '' ) {
297
298 // vars
299 $external_url = '';
300 $external_path = acf_get_external_path( $file, $path );
301 $wp_plugin_path = wp_normalize_path(WP_PLUGIN_DIR);
302 $wp_content_path = wp_normalize_path(WP_CONTENT_DIR);
303 $wp_path = wp_normalize_path(ABSPATH);
304
305
306 // wp-content/plugins
307 if( strpos($external_path, $wp_plugin_path) === 0 ) {
308
309 return str_replace($wp_plugin_path, plugins_url(), $external_path);
310
311 }
312
313
314 // wp-content
315 if( strpos($external_path, $wp_content_path) === 0 ) {
316
317 return str_replace($wp_content_path, content_url(), $external_path);
318
319 }
320
321
322 // return
323 return str_replace($wp_path, home_url(), $external_path);
324
325 }
326
327
328 /*
329 * acf_parse_args
330 *
331 * This function will merge together 2 arrays and also convert any numeric values to ints
332 *
333 * @type function
334 * @date 18/10/13
335 * @since 5.0.0
336 *
337 * @param $args (array)
338 * @param $defaults (array)
339 * @return $args (array)
340 */
341
342 function acf_parse_args( $args, $defaults = array() ) {
343
344 // parse args
345 $args = wp_parse_args( $args, $defaults );
346
347
348 // parse types
349 $args = acf_parse_types( $args );
350
351
352 // return
353 return $args;
354
355 }
356
357
358 /*
359 * acf_parse_types
360 *
361 * This function will convert any numeric values to int and trim strings
362 *
363 * @type function
364 * @date 18/10/13
365 * @since 5.0.0
366 *
367 * @param $var (mixed)
368 * @return $var (mixed)
369 */
370
371 function acf_parse_types( $array ) {
372
373 // return
374 return array_map( 'acf_parse_type', $array );
375
376 }
377
378
379 /*
380 * acf_parse_type
381 *
382 * description
383 *
384 * @type function
385 * @date 11/11/2014
386 * @since 5.0.9
387 *
388 * @param $post_id (int)
389 * @return $post_id (int)
390 */
391
392 function acf_parse_type( $v ) {
393
394 // bail early if not string
395 if( !is_string($v) ) return $v;
396
397
398 // trim
399 $v = trim($v);
400
401
402 // convert int (string) to int
403 if( is_numeric($v) && strval((int)$v) === $v ) {
404
405 $v = intval( $v );
406
407 }
408
409
410 // return
411 return $v;
412
413 }
414
415
416 /*
417 * acf_get_view
418 *
419 * This function will load in a file from the 'admin/views' folder and allow variables to be passed through
420 *
421 * @type function
422 * @date 28/09/13
423 * @since 5.0.0
424 *
425 * @param $view_name (string)
426 * @param $args (array)
427 * @return n/a
428 */
429
430 function acf_get_view( $path = '', $args = array() ) {
431
432 // allow view file name shortcut
433 if( substr($path, -4) !== '.php' ) {
434
435 $path = acf_get_path("includes/admin/views/{$path}.php");
436
437 }
438
439
440 // include
441 if( file_exists($path) ) {
442
443 extract( $args );
444 include( $path );
445
446 }
447
448 }
449
450
451 /*
452 * acf_merge_atts
453 *
454 * description
455 *
456 * @type function
457 * @date 2/11/2014
458 * @since 5.0.9
459 *
460 * @param $post_id (int)
461 * @return $post_id (int)
462 */
463
464 function acf_merge_atts( $atts, $extra = array() ) {
465
466 // bail ealry if no $extra
467 if( empty($extra) ) return $atts;
468
469
470 // trim
471 $extra = array_map('trim', $extra);
472 $extra = array_filter($extra);
473
474
475 // merge in new atts
476 foreach( $extra as $k => $v ) {
477
478 // append
479 if( $k == 'class' || $k == 'style' ) {
480
481 $atts[ $k ] .= ' ' . $v;
482
483 // merge
484 } else {
485
486 $atts[ $k ] = $v;
487
488 }
489
490 }
491
492
493 // return
494 return $atts;
495
496 }
497
498
499
500
501
502
503
504 /*
505 * acf_nonce_input
506 *
507 * This function will create a basic nonce input
508 *
509 * @type function
510 * @date 24/5/17
511 * @since 5.6.0
512 *
513 * @param $post_id (int)
514 * @return $post_id (int)
515 */
516
517 function acf_nonce_input( $nonce = '' ) {
518
519 echo '<input type="hidden" name="_acf_nonce" value="' . wp_create_nonce( $nonce ) . '" />';
520
521 }
522
523
524 /*
525 * acf_extract_var
526 *
527 * This function will remove the var from the array, and return the var
528 *
529 * @type function
530 * @date 2/10/13
531 * @since 5.0.0
532 *
533 * @param $array (array)
534 * @param $key (string)
535 * @return (mixed)
536 */
537
538 function acf_extract_var( &$array, $key, $default = null ) {
539
540 // check if exists
541 // - uses array_key_exists to extract NULL values (isset will fail)
542 if( is_array($array) && array_key_exists($key, $array) ) {
543
544 // store value
545 $v = $array[ $key ];
546
547
548 // unset
549 unset( $array[ $key ] );
550
551
552 // return
553 return $v;
554
555 }
556
557
558 // return
559 return $default;
560 }
561
562
563 /*
564 * acf_extract_vars
565 *
566 * This function will remove the vars from the array, and return the vars
567 *
568 * @type function
569 * @date 8/10/13
570 * @since 5.0.0
571 *
572 * @param $post_id (int)
573 * @return $post_id (int)
574 */
575
576 function acf_extract_vars( &$array, $keys ) {
577
578 $r = array();
579
580 foreach( $keys as $key ) {
581
582 $r[ $key ] = acf_extract_var( $array, $key );
583
584 }
585
586 return $r;
587 }
588
589
590 /*
591 * acf_get_sub_array
592 *
593 * This function will return a sub array of data
594 *
595 * @type function
596 * @date 15/03/2016
597 * @since 5.3.2
598 *
599 * @param $post_id (int)
600 * @return $post_id (int)
601 */
602
603 function acf_get_sub_array( $array, $keys ) {
604
605 $r = array();
606
607 foreach( $keys as $key ) {
608
609 $r[ $key ] = $array[ $key ];
610
611 }
612
613 return $r;
614
615 }
616
617
618 /*
619 * acf_get_post_types
620 *
621 * This function will return an array of available post types
622 *
623 * @type function
624 * @date 7/10/13
625 * @since 5.0.0
626 *
627 * @param $exclude (array)
628 * @param $include (array)
629 * @return (array)
630 */
631
632 function acf_get_post_types( $args = array() ) {
633
634 // vars
635 $exclude = acf_extract_var( $args, 'exclude', array() );
636 $return = array();
637
638
639 // get post types
640 $post_types = get_post_types( $args, 'objects' );
641
642
643 // remove ACF post types
644 $exclude[] = 'acf-field';
645 $exclude[] = 'acf-field-group';
646
647
648 // loop
649 foreach( $post_types as $i => $post_type ) {
650
651 // bail early if is exclude
652 if( in_array($i, $exclude) ) continue;
653
654
655 // bail early if is builtin (WP) private post type
656 // - nav_menu_item, revision, customize_changeset, etc
657 if( $post_type->_builtin && !$post_type->public ) continue;
658
659
660 // append
661 $return[] = $i;
662
663 }
664
665
666 // return
667 return $return;
668
669 }
670
671
672 function acf_get_pretty_post_types( $post_types = array() ) {
673
674 // get post types
675 if( empty($post_types) ) {
676
677 // get all custom post types
678 $post_types = acf_get_post_types();
679
680 }
681
682
683 // get labels
684 $ref = array();
685 $r = array();
686
687 foreach( $post_types as $post_type ) {
688
689 // vars
690 $label = acf_get_post_type_label($post_type);
691
692
693 // append to r
694 $r[ $post_type ] = $label;
695
696
697 // increase counter
698 if( !isset($ref[ $label ]) ) {
699
700 $ref[ $label ] = 0;
701
702 }
703
704 $ref[ $label ]++;
705 }
706
707
708 // get slugs
709 foreach( array_keys($r) as $i ) {
710
711 // vars
712 $post_type = $r[ $i ];
713
714 if( $ref[ $post_type ] > 1 ) {
715
716 $r[ $i ] .= ' (' . $i . ')';
717
718 }
719
720 }
721
722
723 // return
724 return $r;
725
726 }
727
728
729
730 /*
731 * acf_get_post_type_label
732 *
733 * This function will return a pretty label for a specific post_type
734 *
735 * @type function
736 * @date 5/07/2016
737 * @since 5.4.0
738 *
739 * @param $post_type (string)
740 * @return (string)
741 */
742
743 function acf_get_post_type_label( $post_type ) {
744
745 // vars
746 $label = $post_type;
747
748
749 // check that object exists
750 // - case exists when importing field group from another install and post type does not exist
751 if( post_type_exists($post_type) ) {
752
753 $obj = get_post_type_object($post_type);
754 $label = $obj->labels->singular_name;
755
756 }
757
758
759 // return
760 return $label;
761
762 }
763
764
765 /*
766 * acf_verify_nonce
767 *
768 * This function will look at the $_POST['_acf_nonce'] value and return true or false
769 *
770 * @type function
771 * @date 15/10/13
772 * @since 5.0.0
773 *
774 * @param $nonce (string)
775 * @return (boolean)
776 */
777
778 function acf_verify_nonce( $value) {
779
780 // vars
781 $nonce = acf_maybe_get_POST('_acf_nonce');
782
783
784 // bail early nonce does not match (post|user|comment|term)
785 if( !$nonce || !wp_verify_nonce($nonce, $value) ) return false;
786
787
788 // reset nonce (only allow 1 save)
789 $_POST['_acf_nonce'] = false;
790
791
792 // return
793 return true;
794
795 }
796
797
798 /*
799 * acf_verify_ajax
800 *
801 * This function will return true if the current AJAX request is valid
802 * It's action will also allow WPML to set the lang and avoid AJAX get_posts issues
803 *
804 * @type function
805 * @date 7/08/2015
806 * @since 5.2.3
807 *
808 * @param n/a
809 * @return (boolean)
810 */
811
812 function acf_verify_ajax() {
813
814 // vars
815 $action = acf_maybe_get_POST('action');
816 $nonce = acf_maybe_get_POST('nonce');
817
818
819 // bail early if not acf action
820 if( !$action || substr($action, 0, 3) !== 'acf' ) {
821 return false;
822 }
823
824
825 // bail early if not acf nonce
826 if( !$nonce || !wp_verify_nonce($nonce, 'acf_nonce') ) {
827 return false;
828 }
829
830
831 // action for 3rd party customization
832 do_action('acf/verify_ajax');
833
834
835 // return
836 return true;
837
838 }
839
840
841 /*
842 * acf_get_image_sizes
843 *
844 * This function will return an array of available image sizes
845 *
846 * @type function
847 * @date 23/10/13
848 * @since 5.0.0
849 *
850 * @param n/a
851 * @return (array)
852 */
853
854 function acf_get_image_sizes() {
855
856 // vars
857 $sizes = array(
858 'thumbnail' => __("Thumbnail",'acf'),
859 'medium' => __("Medium",'acf'),
860 'large' => __("Large",'acf')
861 );
862
863
864 // find all sizes
865 $all_sizes = get_intermediate_image_sizes();
866
867
868 // add extra registered sizes
869 if( !empty($all_sizes) ) {
870
871 foreach( $all_sizes as $size ) {
872
873 // bail early if already in array
874 if( isset($sizes[ $size ]) ) {
875
876 continue;
877
878 }
879
880
881 // append to array
882 $label = str_replace('-', ' ', $size);
883 $label = ucwords( $label );
884 $sizes[ $size ] = $label;
885
886 }
887
888 }
889
890
891 // add sizes
892 foreach( array_keys($sizes) as $s ) {
893
894 // vars
895 $data = acf_get_image_size($s);
896
897
898 // append
899 if( $data['width'] && $data['height'] ) {
900
901 $sizes[ $s ] .= ' (' . $data['width'] . ' x ' . $data['height'] . ')';
902
903 }
904
905 }
906
907
908 // add full end
909 $sizes['full'] = __("Full Size",'acf');
910
911
912 // filter for 3rd party customization
913 $sizes = apply_filters( 'acf/get_image_sizes', $sizes );
914
915
916 // return
917 return $sizes;
918
919 }
920
921 function acf_get_image_size( $s = '' ) {
922
923 // global
924 global $_wp_additional_image_sizes;
925
926
927 // rename for nicer code
928 $_sizes = $_wp_additional_image_sizes;
929
930
931 // vars
932 $data = array(
933 'width' => isset($_sizes[$s]['width']) ? $_sizes[$s]['width'] : get_option("{$s}_size_w"),
934 'height' => isset($_sizes[$s]['height']) ? $_sizes[$s]['height'] : get_option("{$s}_size_h")
935 );
936
937
938 // return
939 return $data;
940
941 }
942
943
944 /*
945 * acf_version_compare
946 *
947 * This function will compare version left v right
948 *
949 * @type function
950 * @date 21/11/16
951 * @since 5.5.0
952 *
953 * @param $compare (string)
954 * @param $version (string)
955 * @return (boolean)
956 */
957
958 function acf_version_compare( $left = 'wp', $compare = '>', $right = '1' ) {
959
960 // global
961 global $wp_version;
962
963
964 // wp
965 if( $left === 'wp' ) $left = $wp_version;
966
967
968 // remove '-beta1' or '-RC1'
969 $left = acf_get_full_version($left);
970 $right = acf_get_full_version($right);
971
972
973 // return
974 return version_compare( $left, $right, $compare );
975
976 }
977
978
979 /*
980 * acf_get_full_version
981 *
982 * This function will remove any '-beta1' or '-RC1' strings from a version
983 *
984 * @type function
985 * @date 24/11/16
986 * @since 5.5.0
987 *
988 * @param $version (string)
989 * @return (string)
990 */
991
992 function acf_get_full_version( $version = '1' ) {
993
994 // remove '-beta1' or '-RC1'
995 if( $pos = strpos($version, '-') ) {
996
997 $version = substr($version, 0, $pos);
998
999 }
1000
1001
1002 // return
1003 return $version;
1004
1005 }
1006
1007
1008 /*
1009 * acf_get_locale
1010 *
1011 * This function is a wrapper for the get_locale() function
1012 *
1013 * @type function
1014 * @date 16/12/16
1015 * @since 5.5.0
1016 *
1017 * @param n/a
1018 * @return (string)
1019 */
1020
1021 function acf_get_locale() {
1022
1023 return is_admin() && function_exists('get_user_locale') ? get_user_locale() : get_locale();
1024
1025 }
1026
1027
1028 /*
1029 * acf_get_terms
1030 *
1031 * This function is a wrapper for the get_terms() function
1032 *
1033 * @type function
1034 * @date 28/09/2016
1035 * @since 5.4.0
1036 *
1037 * @param $args (array)
1038 * @return (array)
1039 */
1040
1041 function acf_get_terms( $args ) {
1042
1043 // global
1044 global $wp_version;
1045
1046
1047 // vars
1048 $terms = array();
1049
1050
1051 // WP 4.5+
1052 if( version_compare($wp_version, '4.5', '>=' ) ) {
1053
1054 $terms = get_terms( $args );
1055
1056 // WP < 4.5
1057 } else {
1058
1059 $terms = get_terms( $args['taxonomy'], $args );
1060
1061 }
1062
1063
1064 // return
1065 return $terms;
1066
1067 }
1068
1069
1070 /*
1071 * acf_get_taxonomies
1072 *
1073 * This function will return an array of available taxonomies
1074 *
1075 * @type function
1076 * @date 7/10/13
1077 * @since 5.0.0
1078 *
1079 * @param n/a
1080 * @return (array)
1081 */
1082
1083 function acf_get_taxonomies() {
1084
1085 // get all taxonomies
1086 $taxonomies = get_taxonomies( false, 'objects' );
1087 $ignore = array( 'nav_menu', 'link_category' );
1088 $r = array();
1089
1090
1091 // populate $r
1092 foreach( $taxonomies as $taxonomy )
1093 {
1094 if( in_array($taxonomy->name, $ignore) )
1095 {
1096 continue;
1097
1098 }
1099
1100 $r[ $taxonomy->name ] = $taxonomy->name; //"{$taxonomy->labels->singular_name}"; // ({$taxonomy->name})
1101 }
1102
1103
1104 // return
1105 return $r;
1106
1107 }
1108
1109
1110 function acf_get_pretty_taxonomies( $taxonomies = array() ) {
1111
1112 // get post types
1113 if( empty($taxonomies) ) {
1114
1115 // get all custom post types
1116 $taxonomies = acf_get_taxonomies();
1117
1118 }
1119
1120
1121 // get labels
1122 $ref = array();
1123 $r = array();
1124
1125 foreach( array_keys($taxonomies) as $i ) {
1126
1127 // vars
1128 $taxonomy = acf_extract_var( $taxonomies, $i);
1129 $obj = get_taxonomy( $taxonomy );
1130 $name = $obj->labels->singular_name;
1131
1132
1133 // append to r
1134 $r[ $taxonomy ] = $name;
1135
1136
1137 // increase counter
1138 if( !isset($ref[ $name ]) ) {
1139
1140 $ref[ $name ] = 0;
1141
1142 }
1143
1144 $ref[ $name ]++;
1145 }
1146
1147
1148 // get slugs
1149 foreach( array_keys($r) as $i ) {
1150
1151 // vars
1152 $taxonomy = $r[ $i ];
1153
1154 if( $ref[ $taxonomy ] > 1 ) {
1155
1156 $r[ $i ] .= ' (' . $i . ')';
1157
1158 }
1159
1160 }
1161
1162
1163 // return
1164 return $r;
1165
1166 }
1167
1168
1169 /*
1170 * acf_get_taxonomy_terms
1171 *
1172 * This function will return an array of available taxonomy terms
1173 *
1174 * @type function
1175 * @date 7/10/13
1176 * @since 5.0.0
1177 *
1178 * @param $taxonomies (array)
1179 * @return (array)
1180 */
1181
1182 function acf_get_taxonomy_terms( $taxonomies = array() ) {
1183
1184 // force array
1185 $taxonomies = acf_get_array( $taxonomies );
1186
1187
1188 // get pretty taxonomy names
1189 $taxonomies = acf_get_pretty_taxonomies( $taxonomies );
1190
1191
1192 // vars
1193 $r = array();
1194
1195
1196 // populate $r
1197 foreach( array_keys($taxonomies) as $taxonomy ) {
1198
1199 // vars
1200 $label = $taxonomies[ $taxonomy ];
1201 $is_hierarchical = is_taxonomy_hierarchical( $taxonomy );
1202 $terms = acf_get_terms(array(
1203 'taxonomy' => $taxonomy,
1204 'hide_empty' => false
1205 ));
1206
1207
1208 // bail early i no terms
1209 if( empty($terms) ) continue;
1210
1211
1212 // sort into hierachial order!
1213 if( $is_hierarchical ) {
1214
1215 $terms = _get_term_children( 0, $terms, $taxonomy );
1216
1217 }
1218
1219
1220 // add placeholder
1221 $r[ $label ] = array();
1222
1223
1224 // add choices
1225 foreach( $terms as $term ) {
1226
1227 $k = "{$taxonomy}:{$term->slug}";
1228 $r[ $label ][ $k ] = acf_get_term_title( $term );
1229
1230 }
1231
1232 }
1233
1234
1235 // return
1236 return $r;
1237
1238 }
1239
1240
1241 function acf_get_term_title( $term ) {
1242
1243 // title
1244 $title = $term->name;
1245
1246
1247 // empty
1248 if( $title === '' ) {
1249
1250 $title = __('(no title)', 'acf');
1251
1252 }
1253
1254
1255 // ancestors
1256 if( is_taxonomy_hierarchical($term->taxonomy) ) {
1257
1258 $ancestors = get_ancestors( $term->term_id, $term->taxonomy );
1259
1260 $title = str_repeat('- ', count($ancestors)) . $title;
1261
1262 }
1263
1264
1265 // return
1266 return $title;
1267
1268 }
1269
1270
1271 /*
1272 * acf_decode_taxonomy_terms
1273 *
1274 * This function decodes the $taxonomy:$term strings into a nested array
1275 *
1276 * @type function
1277 * @date 27/02/2014
1278 * @since 5.0.0
1279 *
1280 * @param $terms (array)
1281 * @return (array)
1282 */
1283
1284 function acf_decode_taxonomy_terms( $strings = false ) {
1285
1286 // bail early if no terms
1287 if( empty($strings) ) return false;
1288
1289
1290 // vars
1291 $terms = array();
1292
1293
1294 // loop
1295 foreach( $strings as $string ) {
1296
1297 // vars
1298 $data = acf_decode_taxonomy_term( $string );
1299 $taxonomy = $data['taxonomy'];
1300 $term = $data['term'];
1301
1302
1303 // create empty array
1304 if( !isset($terms[ $taxonomy ]) ) {
1305
1306 $terms[ $taxonomy ] = array();
1307
1308 }
1309
1310
1311 // append
1312 $terms[ $taxonomy ][] = $term;
1313
1314 }
1315
1316
1317 // return
1318 return $terms;
1319
1320 }
1321
1322
1323 /*
1324 * acf_decode_taxonomy_term
1325 *
1326 * This function will return the taxonomy and term slug for a given value
1327 *
1328 * @type function
1329 * @date 31/03/2014
1330 * @since 5.0.0
1331 *
1332 * @param $string (string)
1333 * @return (array)
1334 */
1335
1336 function acf_decode_taxonomy_term( $value ) {
1337
1338 // vars
1339 $data = array(
1340 'taxonomy' => '',
1341 'term' => ''
1342 );
1343
1344
1345 // int
1346 if( is_numeric($value) ) {
1347
1348 $data['term'] = $value;
1349
1350 // string
1351 } elseif( is_string($value) ) {
1352
1353 $value = explode(':', $value);
1354 $data['taxonomy'] = isset($value[0]) ? $value[0] : '';
1355 $data['term'] = isset($value[1]) ? $value[1] : '';
1356
1357 // error
1358 } else {
1359
1360 return false;
1361
1362 }
1363
1364
1365 // allow for term_id (Used by ACF v4)
1366 if( is_numeric($data['term']) ) {
1367
1368 // global
1369 global $wpdb;
1370
1371
1372 // find taxonomy
1373 if( !$data['taxonomy'] ) {
1374
1375 $data['taxonomy'] = $wpdb->get_var( $wpdb->prepare("SELECT taxonomy FROM $wpdb->term_taxonomy WHERE term_id = %d LIMIT 1", $data['term']) );
1376
1377 }
1378
1379
1380 // find term (may have numeric slug '123')
1381 $term = get_term_by( 'slug', $data['term'], $data['taxonomy'] );
1382
1383
1384 // attempt get term via ID (ACF4 uses ID)
1385 if( !$term ) $term = get_term( $data['term'], $data['taxonomy'] );
1386
1387
1388 // bail early if no term
1389 if( !$term ) return false;
1390
1391
1392 // update
1393 $data['taxonomy'] = $term->taxonomy;
1394 $data['term'] = $term->slug;
1395
1396 }
1397
1398
1399 // return
1400 return $data;
1401
1402 }
1403
1404
1405 /*
1406 * acf_get_array
1407 *
1408 * This function will force a variable to become an array
1409 *
1410 * @type function
1411 * @date 4/02/2014
1412 * @since 5.0.0
1413 *
1414 * @param $var (mixed)
1415 * @return (array)
1416 */
1417
1418 function acf_get_array( $var = false, $delimiter = '' ) {
1419
1420 // array
1421 if( is_array($var) ) {
1422 return $var;
1423 }
1424
1425
1426 // bail early if empty
1427 if( acf_is_empty($var) ) {
1428 return array();
1429 }
1430
1431
1432 // string
1433 if( is_string($var) && $delimiter ) {
1434 return explode($delimiter, $var);
1435 }
1436
1437
1438 // place in array
1439 return (array) $var;
1440
1441 }
1442
1443
1444 /*
1445 * acf_get_numeric
1446 *
1447 * This function will return numeric values
1448 *
1449 * @type function
1450 * @date 15/07/2016
1451 * @since 5.4.0
1452 *
1453 * @param $value (mixed)
1454 * @return (mixed)
1455 */
1456
1457 function acf_get_numeric( $value = '' ) {
1458
1459 // vars
1460 $numbers = array();
1461 $is_array = is_array($value);
1462
1463
1464 // loop
1465 foreach( (array) $value as $v ) {
1466
1467 if( is_numeric($v) ) $numbers[] = (int) $v;
1468
1469 }
1470
1471
1472 // bail early if is empty
1473 if( empty($numbers) ) return false;
1474
1475
1476 // convert array
1477 if( !$is_array ) $numbers = $numbers[0];
1478
1479
1480 // return
1481 return $numbers;
1482
1483 }
1484
1485
1486 /*
1487 * acf_get_posts
1488 *
1489 * This function will return an array of posts making sure the order is correct
1490 *
1491 * @type function
1492 * @date 3/03/2015
1493 * @since 5.1.5
1494 *
1495 * @param $args (array)
1496 * @return (array)
1497 */
1498
1499 function acf_get_posts( $args = array() ) {
1500
1501 // vars
1502 $posts = array();
1503
1504
1505 // defaults
1506 // leave suppress_filters as true becuase we don't want any plugins to modify the query as we know exactly what
1507 $args = wp_parse_args( $args, array(
1508 'posts_per_page' => -1,
1509 'post_type' => '',
1510 'post_status' => 'any',
1511 'update_post_meta_cache' => false,
1512 'update_post_term_cache' => false
1513 ));
1514
1515
1516 // post type
1517 if( empty($args['post_type']) ) {
1518
1519 $args['post_type'] = acf_get_post_types();
1520
1521 }
1522
1523
1524 // validate post__in
1525 if( $args['post__in'] ) {
1526
1527 // force value to array
1528 $args['post__in'] = acf_get_array( $args['post__in'] );
1529
1530
1531 // convert to int
1532 $args['post__in'] = array_map('intval', $args['post__in']);
1533
1534
1535 // add filter to remove post_type
1536 // use 'query' filter so that 'suppress_filters' can remain true
1537 //add_filter('query', '_acf_query_remove_post_type');
1538
1539
1540 // order by post__in
1541 $args['orderby'] = 'post__in';
1542
1543 }
1544
1545
1546 // load posts in 1 query to save multiple DB calls from following code
1547 $posts = get_posts($args);
1548
1549
1550 // remove this filter (only once)
1551 //remove_filter('query', '_acf_query_remove_post_type');
1552
1553
1554 // validate order
1555 if( $posts && $args['post__in'] ) {
1556
1557 // vars
1558 $order = array();
1559
1560
1561 // generate sort order
1562 foreach( $posts as $i => $post ) {
1563
1564 $order[ $i ] = array_search($post->ID, $args['post__in']);
1565
1566 }
1567
1568
1569 // sort
1570 array_multisort($order, $posts);
1571
1572 }
1573
1574
1575 // return
1576 return $posts;
1577
1578 }
1579
1580
1581 /*
1582 * _acf_query_remove_post_type
1583 *
1584 * This function will remove the 'wp_posts.post_type' WHERE clause completely
1585 * When using 'post__in', this clause is unneccessary and slow.
1586 *
1587 * @type function
1588 * @date 4/03/2015
1589 * @since 5.1.5
1590 *
1591 * @param $sql (string)
1592 * @return $sql
1593 */
1594
1595 function _acf_query_remove_post_type( $sql ) {
1596
1597 // global
1598 global $wpdb;
1599
1600
1601 // bail ealry if no 'wp_posts.ID IN'
1602 if( strpos($sql, "$wpdb->posts.ID IN") === false ) {
1603
1604 return $sql;
1605
1606 }
1607
1608
1609 // get bits
1610 $glue = 'AND';
1611 $bits = explode($glue, $sql);
1612
1613
1614 // loop through $where and remove any post_type queries
1615 foreach( $bits as $i => $bit ) {
1616
1617 if( strpos($bit, "$wpdb->posts.post_type") !== false ) {
1618
1619 unset( $bits[ $i ] );
1620
1621 }
1622
1623 }
1624
1625
1626 // join $where back together
1627 $sql = implode($glue, $bits);
1628
1629
1630 // return
1631 return $sql;
1632
1633 }
1634
1635
1636 /*
1637 * acf_get_grouped_posts
1638 *
1639 * This function will return all posts grouped by post_type
1640 * This is handy for select settings
1641 *
1642 * @type function
1643 * @date 27/02/2014
1644 * @since 5.0.0
1645 *
1646 * @param $args (array)
1647 * @return (array)
1648 */
1649
1650 function acf_get_grouped_posts( $args ) {
1651
1652 // vars
1653 $data = array();
1654
1655
1656 // defaults
1657 $args = wp_parse_args( $args, array(
1658 'posts_per_page' => -1,
1659 'paged' => 0,
1660 'post_type' => 'post',
1661 'orderby' => 'menu_order title',
1662 'order' => 'ASC',
1663 'post_status' => 'any',
1664 'suppress_filters' => false,
1665 'update_post_meta_cache' => false,
1666 ));
1667
1668
1669 // find array of post_type
1670 $post_types = acf_get_array( $args['post_type'] );
1671 $post_types_labels = acf_get_pretty_post_types($post_types);
1672 $is_single_post_type = ( count($post_types) == 1 );
1673
1674
1675 // attachment doesn't work if it is the only item in an array
1676 if( $is_single_post_type) {
1677 $args['post_type'] = current($post_types);
1678 }
1679
1680
1681 // add filter to orderby post type
1682 if( !$is_single_post_type ) {
1683 add_filter('posts_orderby', '_acf_orderby_post_type', 10, 2);
1684 }
1685
1686
1687 // get posts
1688 $posts = get_posts( $args );
1689
1690
1691 // remove this filter (only once)
1692 if( !$is_single_post_type ) {
1693 remove_filter('posts_orderby', '_acf_orderby_post_type', 10, 2);
1694 }
1695
1696
1697 // loop
1698 foreach( $post_types as $post_type ) {
1699
1700 // vars
1701 $this_posts = array();
1702 $this_group = array();
1703
1704
1705 // populate $this_posts
1706 foreach( $posts as $post ) {
1707 if( $post->post_type == $post_type ) {
1708 $this_posts[] = $post;
1709 }
1710 }
1711
1712
1713 // bail early if no posts for this post type
1714 if( empty($this_posts) ) continue;
1715
1716
1717 // sort into hierachial order!
1718 // this will fail if a search has taken place because parents wont exist
1719 if( is_post_type_hierarchical($post_type) && empty($args['s'])) {
1720
1721 // vars
1722 $post_id = $this_posts[0]->ID;
1723 $parent_id = acf_maybe_get($args, 'post_parent', 0);
1724 $offset = 0;
1725 $length = count($this_posts);
1726
1727
1728 // get all posts from this post type
1729 $all_posts = get_posts(array_merge($args, array(
1730 'posts_per_page' => -1,
1731 'paged' => 0,
1732 'post_type' => $post_type
1733 )));
1734
1735
1736 // find starting point (offset)
1737 foreach( $all_posts as $i => $post ) {
1738 if( $post->ID == $post_id ) {
1739 $offset = $i;
1740 break;
1741 }
1742 }
1743
1744
1745 // order posts
1746 $ordered_posts = get_page_children($parent_id, $all_posts);
1747
1748
1749 // compare aray lengths
1750 // if $ordered_posts is smaller than $all_posts, WP has lost posts during the get_page_children() function
1751 // this is possible when get_post( $args ) filter out parents (via taxonomy, meta and other search parameters)
1752 if( count($ordered_posts) == count($all_posts) ) {
1753 $this_posts = array_slice($ordered_posts, $offset, $length);
1754 }
1755
1756 }
1757
1758
1759 // populate $this_posts
1760 foreach( $this_posts as $post ) {
1761 $this_group[ $post->ID ] = $post;
1762 }
1763
1764
1765 // group by post type
1766 $label = $post_types_labels[ $post_type ];
1767 $data[ $label ] = $this_group;
1768
1769 }
1770
1771
1772 // return
1773 return $data;
1774
1775 }
1776
1777
1778 function _acf_orderby_post_type( $ordeby, $wp_query ) {
1779
1780 // global
1781 global $wpdb;
1782
1783
1784 // get post types
1785 $post_types = $wp_query->get('post_type');
1786
1787
1788 // prepend SQL
1789 if( is_array($post_types) ) {
1790
1791 $post_types = implode("','", $post_types);
1792 $ordeby = "FIELD({$wpdb->posts}.post_type,'$post_types')," . $ordeby;
1793
1794 }
1795
1796
1797 // return
1798 return $ordeby;
1799
1800 }
1801
1802
1803 function acf_get_post_title( $post = 0, $is_search = false ) {
1804
1805 // vars
1806 $post = get_post($post);
1807 $title = '';
1808 $prepend = '';
1809 $append = '';
1810
1811
1812 // bail early if no post
1813 if( !$post ) return '';
1814
1815
1816 // title
1817 $title = get_the_title( $post->ID );
1818
1819
1820 // empty
1821 if( $title === '' ) {
1822
1823 $title = __('(no title)', 'acf');
1824
1825 }
1826
1827
1828 // status
1829 if( get_post_status( $post->ID ) != "publish" ) {
1830
1831 $append .= ' (' . get_post_status( $post->ID ) . ')';
1832
1833 }
1834
1835
1836 // ancestors
1837 if( $post->post_type !== 'attachment' ) {
1838
1839 // get ancestors
1840 $ancestors = get_ancestors( $post->ID, $post->post_type );
1841 $prepend .= str_repeat('- ', count($ancestors));
1842
1843
1844 // add parent
1845 /*
1846 removed in 5.6.5 as not used by the UI
1847 if( $is_search && !empty($ancestors) ) {
1848
1849 // reverse
1850 $ancestors = array_reverse($ancestors);
1851
1852
1853 // convert id's into titles
1854 foreach( $ancestors as $i => $id ) {
1855
1856 $ancestors[ $i ] = get_the_title( $id );
1857
1858 }
1859
1860
1861 // append
1862 $append .= ' | ' . __('Parent', 'acf') . ': ' . implode(' / ', $ancestors);
1863
1864 }
1865 */
1866
1867 }
1868
1869
1870 // merge
1871 $title = $prepend . $title . $append;
1872
1873
1874 // return
1875 return $title;
1876
1877 }
1878
1879
1880 function acf_order_by_search( $array, $search ) {
1881
1882 // vars
1883 $weights = array();
1884 $needle = strtolower( $search );
1885
1886
1887 // add key prefix
1888 foreach( array_keys($array) as $k ) {
1889
1890 $array[ '_' . $k ] = acf_extract_var( $array, $k );
1891
1892 }
1893
1894
1895 // add search weight
1896 foreach( $array as $k => $v ) {
1897
1898 // vars
1899 $weight = 0;
1900 $haystack = strtolower( $v );
1901 $strpos = strpos( $haystack, $needle );
1902
1903
1904 // detect search match
1905 if( $strpos !== false ) {
1906
1907 // set eright to length of match
1908 $weight = strlen( $search );
1909
1910
1911 // increase weight if match starts at begining of string
1912 if( $strpos == 0 ) {
1913
1914 $weight++;
1915
1916 }
1917
1918 }
1919
1920
1921 // append to wights
1922 $weights[ $k ] = $weight;
1923
1924 }
1925
1926
1927 // sort the array with menu_order ascending
1928 array_multisort( $weights, SORT_DESC, $array );
1929
1930
1931 // remove key prefix
1932 foreach( array_keys($array) as $k ) {
1933
1934 $array[ substr($k,1) ] = acf_extract_var( $array, $k );
1935
1936 }
1937
1938
1939 // return
1940 return $array;
1941 }
1942
1943
1944 /*
1945 * acf_get_pretty_user_roles
1946 *
1947 * description
1948 *
1949 * @type function
1950 * @date 23/02/2016
1951 * @since 5.3.2
1952 *
1953 * @param $post_id (int)
1954 * @return $post_id (int)
1955 */
1956
1957 function acf_get_pretty_user_roles( $allowed = false ) {
1958
1959 // vars
1960 $editable_roles = get_editable_roles();
1961 $allowed = acf_get_array($allowed);
1962 $roles = array();
1963
1964
1965 // loop
1966 foreach( $editable_roles as $role_name => $role_details ) {
1967
1968 // bail early if not allowed
1969 if( !empty($allowed) && !in_array($role_name, $allowed) ) continue;
1970
1971
1972 // append
1973 $roles[ $role_name ] = translate_user_role( $role_details['name'] );
1974
1975 }
1976
1977
1978 // return
1979 return $roles;
1980
1981 }
1982
1983
1984 /*
1985 * acf_get_grouped_users
1986 *
1987 * This function will return all users grouped by role
1988 * This is handy for select settings
1989 *
1990 * @type function
1991 * @date 27/02/2014
1992 * @since 5.0.0
1993 *
1994 * @param $args (array)
1995 * @return (array)
1996 */
1997
1998 function acf_get_grouped_users( $args = array() ) {
1999
2000 // vars
2001 $r = array();
2002
2003
2004 // defaults
2005 $args = wp_parse_args( $args, array(
2006 'users_per_page' => -1,
2007 'paged' => 0,
2008 'role' => '',
2009 'orderby' => 'login',
2010 'order' => 'ASC',
2011 ));
2012
2013
2014 // offset
2015 $i = 0;
2016 $min = 0;
2017 $max = 0;
2018 $users_per_page = acf_extract_var($args, 'users_per_page');
2019 $paged = acf_extract_var($args, 'paged');
2020
2021 if( $users_per_page > 0 ) {
2022
2023 // prevent paged from being -1
2024 $paged = max(0, $paged);
2025
2026
2027 // set min / max
2028 $min = (($paged-1) * $users_per_page) + 1; // 1, 11
2029 $max = ($paged * $users_per_page); // 10, 20
2030
2031 }
2032
2033
2034 // find array of post_type
2035 $user_roles = acf_get_pretty_user_roles($args['role']);
2036
2037
2038 // fix role
2039 if( is_array($args['role']) ) {
2040
2041 // global
2042 global $wp_version, $wpdb;
2043
2044
2045 // vars
2046 $roles = acf_extract_var($args, 'role');
2047
2048
2049 // new WP has role__in
2050 if( version_compare($wp_version, '4.4', '>=' ) ) {
2051
2052 $args['role__in'] = $roles;
2053
2054 // old WP doesn't have role__in
2055 } else {
2056
2057 // vars
2058 $blog_id = get_current_blog_id();
2059 $meta_query = array( 'relation' => 'OR' );
2060
2061
2062 // loop
2063 foreach( $roles as $role ) {
2064
2065 $meta_query[] = array(
2066 'key' => $wpdb->get_blog_prefix( $blog_id ) . 'capabilities',
2067 'value' => '"' . $role . '"',
2068 'compare' => 'LIKE',
2069 );
2070
2071 }
2072
2073
2074 // append
2075 $args['meta_query'] = $meta_query;
2076
2077 }
2078
2079 }
2080
2081
2082 // get posts
2083 $users = get_users( $args );
2084
2085
2086 // loop
2087 foreach( $user_roles as $user_role_name => $user_role_label ) {
2088
2089 // vars
2090 $this_users = array();
2091 $this_group = array();
2092
2093
2094 // populate $this_posts
2095 foreach( array_keys($users) as $key ) {
2096
2097 // bail ealry if not correct role
2098 if( !in_array($user_role_name, $users[ $key ]->roles) ) continue;
2099
2100
2101 // extract user
2102 $user = acf_extract_var( $users, $key );
2103
2104
2105 // increase
2106 $i++;
2107
2108
2109 // bail ealry if too low
2110 if( $min && $i < $min ) continue;
2111
2112
2113 // bail early if too high (don't bother looking at any more users)
2114 if( $max && $i > $max ) break;
2115
2116
2117 // group by post type
2118 $this_users[ $user->ID ] = $user;
2119
2120
2121 }
2122
2123
2124 // bail early if no posts for this post type
2125 if( empty($this_users) ) continue;
2126
2127
2128 // append
2129 $r[ $user_role_label ] = $this_users;
2130
2131 }
2132
2133
2134 // return
2135 return $r;
2136
2137 }
2138
2139
2140 /*
2141 * acf_json_encode
2142 *
2143 * This function will return pretty JSON for all PHP versions
2144 *
2145 * @type function
2146 * @date 6/03/2014
2147 * @since 5.0.0
2148 *
2149 * @param $json (array)
2150 * @return (string)
2151 */
2152
2153 function acf_json_encode( $json ) {
2154
2155 // PHP at least 5.4
2156 if( version_compare(PHP_VERSION, '5.4.0', '>=') ) {
2157
2158 return json_encode($json, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
2159
2160 }
2161
2162
2163
2164 // PHP less than 5.4
2165 $json = json_encode($json);
2166
2167
2168 // http://snipplr.com/view.php?codeview&id=60559
2169 $result = '';
2170 $pos = 0;
2171 $strLen = strlen($json);
2172 $indentStr = " ";
2173 $newLine = "\n";
2174 $prevChar = '';
2175 $outOfQuotes = true;
2176
2177 for ($i=0; $i<=$strLen; $i++) {
2178
2179 // Grab the next character in the string.
2180 $char = substr($json, $i, 1);
2181
2182 // Are we inside a quoted string?
2183 if ($char == '"' && $prevChar != '\\') {
2184 $outOfQuotes = !$outOfQuotes;
2185
2186 // If this character is the end of an element,
2187 // output a new line and indent the next line.
2188 } else if(($char == '}' || $char == ']') && $outOfQuotes) {
2189 $result .= $newLine;
2190 $pos --;
2191 for ($j=0; $j<$pos; $j++) {
2192 $result .= $indentStr;
2193 }
2194 }
2195
2196 // Add the character to the result string.
2197 $result .= $char;
2198
2199 // If this character is ':' adda space after it
2200 if($char == ':' && $outOfQuotes) {
2201 $result .= ' ';
2202 }
2203
2204 // If the last character was the beginning of an element,
2205 // output a new line and indent the next line.
2206 if (($char == ',' || $char == '{' || $char == '[') && $outOfQuotes) {
2207 $result .= $newLine;
2208 if ($char == '{' || $char == '[') {
2209 $pos ++;
2210 }
2211
2212 for ($j = 0; $j < $pos; $j++) {
2213 $result .= $indentStr;
2214 }
2215 }
2216
2217 $prevChar = $char;
2218 }
2219
2220
2221 // return
2222 return $result;
2223
2224 }
2225
2226
2227 /*
2228 * acf_str_exists
2229 *
2230 * This function will return true if a sub string is found
2231 *
2232 * @type function
2233 * @date 1/05/2014
2234 * @since 5.0.0
2235 *
2236 * @param $needle (string)
2237 * @param $haystack (string)
2238 * @return (boolean)
2239 */
2240
2241 function acf_str_exists( $needle, $haystack ) {
2242
2243 // return true if $haystack contains the $needle
2244 if( is_string($haystack) && strpos($haystack, $needle) !== false ) {
2245
2246 return true;
2247
2248 }
2249
2250
2251 // return
2252 return false;
2253 }
2254
2255
2256 /*
2257 * acf_debug
2258 *
2259 * description
2260 *
2261 * @type function
2262 * @date 2/05/2014
2263 * @since 5.0.0
2264 *
2265 * @param $post_id (int)
2266 * @return $post_id (int)
2267 */
2268
2269 function acf_debug() {
2270
2271 // vars
2272 $args = func_get_args();
2273 $s = array_shift($args);
2274 $o = '';
2275 $nl = "\r\n";
2276
2277
2278 // start script
2279 $o .= '<script type="text/javascript">' . $nl;
2280
2281 $o .= 'console.log("' . $s . '"';
2282
2283 if( !empty($args) ) {
2284
2285 foreach( $args as $arg ) {
2286
2287 if( is_object($arg) || is_array($arg) ) {
2288
2289 $arg = json_encode($arg);
2290
2291 } elseif( is_bool($arg) ) {
2292
2293 $arg = $arg ? 'true' : 'false';
2294
2295 }elseif( is_string($arg) ) {
2296
2297 $arg = '"' . $arg . '"';
2298
2299 }
2300
2301 $o .= ', ' . $arg;
2302
2303 }
2304 }
2305
2306 $o .= ');' . $nl;
2307
2308
2309 // end script
2310 $o .= '</script>' . $nl;
2311
2312
2313 // echo
2314 echo $o;
2315 }
2316
2317 function acf_debug_start() {
2318
2319 acf_update_setting( 'debug_start', memory_get_usage());
2320
2321 }
2322
2323 function acf_debug_end() {
2324
2325 $start = acf_get_setting( 'debug_start' );
2326 $end = memory_get_usage();
2327
2328 return $end - $start;
2329
2330 }
2331
2332
2333 /*
2334 * acf_encode_choices
2335 *
2336 * description
2337 *
2338 * @type function
2339 * @date 4/06/2014
2340 * @since 5.0.0
2341 *
2342 * @param $post_id (int)
2343 * @return $post_id (int)
2344 */
2345
2346 function acf_encode_choices( $array = array(), $show_keys = true ) {
2347
2348 // bail early if not array (maybe a single string)
2349 if( !is_array($array) ) return $array;
2350
2351
2352 // bail early if empty array
2353 if( empty($array) ) return '';
2354
2355
2356 // vars
2357 $string = '';
2358
2359
2360 // if allowed to show keys (good for choices, not for default values)
2361 if( $show_keys ) {
2362
2363 // loop
2364 foreach( $array as $k => $v ) {
2365
2366 // ignore if key and value are the same
2367 if( strval($k) == strval($v) ) continue;
2368
2369
2370 // show key in the value
2371 $array[ $k ] = $k . ' : ' . $v;
2372
2373 }
2374
2375 }
2376
2377
2378 // implode
2379 $string = implode("\n", $array);
2380
2381
2382 // return
2383 return $string;
2384
2385 }
2386
2387 function acf_decode_choices( $string = '', $array_keys = false ) {
2388
2389 // bail early if already array
2390 if( is_array($string) ) {
2391
2392 return $string;
2393
2394 // allow numeric values (same as string)
2395 } elseif( is_numeric($string) ) {
2396
2397 // do nothing
2398
2399 // bail early if not a string
2400 } elseif( !is_string($string) ) {
2401
2402 return array();
2403
2404 // bail early if is empty string
2405 } elseif( $string === '' ) {
2406
2407 return array();
2408
2409 }
2410
2411
2412 // vars
2413 $array = array();
2414
2415
2416 // explode
2417 $lines = explode("\n", $string);
2418
2419
2420 // key => value
2421 foreach( $lines as $line ) {
2422
2423 // vars
2424 $k = trim($line);
2425 $v = trim($line);
2426
2427
2428 // look for ' : '
2429 if( acf_str_exists(' : ', $line) ) {
2430
2431 $line = explode(' : ', $line);
2432
2433 $k = trim($line[0]);
2434 $v = trim($line[1]);
2435
2436 }
2437
2438
2439 // append
2440 $array[ $k ] = $v;
2441
2442 }
2443
2444
2445 // return only array keys? (good for checkbox default_value)
2446 if( $array_keys ) {
2447
2448 return array_keys($array);
2449
2450 }
2451
2452
2453 // return
2454 return $array;
2455
2456 }
2457
2458
2459 /*
2460 * acf_str_replace
2461 *
2462 * This function will replace an array of strings much like str_replace
2463 * The difference is the extra logic to avoid replacing a string that has alread been replaced
2464 * This is very useful for replacing date characters as they overlap with eachother
2465 *
2466 * @type function
2467 * @date 21/06/2016
2468 * @since 5.3.8
2469 *
2470 * @param $post_id (int)
2471 * @return $post_id (int)
2472 */
2473
2474 function acf_str_replace( $string = '', $search_replace = array() ) {
2475
2476 // vars
2477 $ignore = array();
2478
2479
2480 // remove potential empty search to avoid PHP error
2481 unset($search_replace['']);
2482
2483
2484 // loop over conversions
2485 foreach( $search_replace as $search => $replace ) {
2486
2487 // ignore this search, it was a previous replace
2488 if( in_array($search, $ignore) ) continue;
2489
2490
2491 // bail early if subsctring not found
2492 if( strpos($string, $search) === false ) continue;
2493
2494
2495 // replace
2496 $string = str_replace($search, $replace, $string);
2497
2498
2499 // append to ignore
2500 $ignore[] = $replace;
2501
2502 }
2503
2504
2505 // return
2506 return $string;
2507
2508 }
2509
2510
2511 /*
2512 * date & time formats
2513 *
2514 * These settings contain an association of format strings from PHP => JS
2515 *
2516 * @type function
2517 * @date 21/06/2016
2518 * @since 5.3.8
2519 *
2520 * @param n/a
2521 * @return n/a
2522 */
2523
2524 acf_update_setting('php_to_js_date_formats', array(
2525
2526 // Year
2527 'Y' => 'yy', // Numeric, 4 digits 1999, 2003
2528 'y' => 'y', // Numeric, 2 digits 99, 03
2529
2530
2531 // Month
2532 'm' => 'mm', // Numeric, with leading zeros 01–12
2533 'n' => 'm', // Numeric, without leading zeros 1–12
2534 'F' => 'MM', // Textual full January – December
2535 'M' => 'M', // Textual three letters Jan - Dec
2536
2537
2538 // Weekday
2539 'l' => 'DD', // Full name (lowercase 'L') Sunday – Saturday
2540 'D' => 'D', // Three letter name Mon – Sun
2541
2542
2543 // Day of Month
2544 'd' => 'dd', // Numeric, with leading zeros 01–31
2545 'j' => 'd', // Numeric, without leading zeros 1–31
2546 'S' => '', // The English suffix for the day of the month st, nd or th in the 1st, 2nd or 15th.
2547
2548 ));
2549
2550 acf_update_setting('php_to_js_time_formats', array(
2551
2552 'a' => 'tt', // Lowercase Ante meridiem and Post meridiem am or pm
2553 'A' => 'TT', // Uppercase Ante meridiem and Post meridiem AM or PM
2554 'h' => 'hh', // 12-hour format of an hour with leading zeros 01 through 12
2555 'g' => 'h', // 12-hour format of an hour without leading zeros 1 through 12
2556 'H' => 'HH', // 24-hour format of an hour with leading zeros 00 through 23
2557 'G' => 'H', // 24-hour format of an hour without leading zeros 0 through 23
2558 'i' => 'mm', // Minutes with leading zeros 00 to 59
2559 's' => 'ss', // Seconds, with leading zeros 00 through 59
2560
2561 ));
2562
2563
2564 /*
2565 * acf_split_date_time
2566 *
2567 * This function will split a format string into seperate date and time
2568 *
2569 * @type function
2570 * @date 26/05/2016
2571 * @since 5.3.8
2572 *
2573 * @param $date_time (string)
2574 * @return $formats (array)
2575 */
2576
2577 function acf_split_date_time( $date_time = '' ) {
2578
2579 // vars
2580 $php_date = acf_get_setting('php_to_js_date_formats');
2581 $php_time = acf_get_setting('php_to_js_time_formats');
2582 $chars = str_split($date_time);
2583 $type = 'date';
2584
2585
2586 // default
2587 $data = array(
2588 'date' => '',
2589 'time' => ''
2590 );
2591
2592
2593 // loop
2594 foreach( $chars as $i => $c ) {
2595
2596 // find type
2597 // - allow misc characters to append to previous type
2598 if( isset($php_date[ $c ]) ) {
2599
2600 $type = 'date';
2601
2602 } elseif( isset($php_time[ $c ]) ) {
2603
2604 $type = 'time';
2605
2606 }
2607
2608
2609 // append char
2610 $data[ $type ] .= $c;
2611
2612 }
2613
2614
2615 // trim
2616 $data['date'] = trim($data['date']);
2617 $data['time'] = trim($data['time']);
2618
2619
2620 // return
2621 return $data;
2622
2623 }
2624
2625
2626 /*
2627 * acf_convert_date_to_php
2628 *
2629 * This fucntion converts a date format string from JS to PHP
2630 *
2631 * @type function
2632 * @date 20/06/2014
2633 * @since 5.0.0
2634 *
2635 * @param $date (string)
2636 * @return (string)
2637 */
2638
2639 function acf_convert_date_to_php( $date = '' ) {
2640
2641 // vars
2642 $php_to_js = acf_get_setting('php_to_js_date_formats');
2643 $js_to_php = array_flip($php_to_js);
2644
2645
2646 // return
2647 return acf_str_replace( $date, $js_to_php );
2648
2649 }
2650
2651 /*
2652 * acf_convert_date_to_js
2653 *
2654 * This fucntion converts a date format string from PHP to JS
2655 *
2656 * @type function
2657 * @date 20/06/2014
2658 * @since 5.0.0
2659 *
2660 * @param $date (string)
2661 * @return (string)
2662 */
2663
2664 function acf_convert_date_to_js( $date = '' ) {
2665
2666 // vars
2667 $php_to_js = acf_get_setting('php_to_js_date_formats');
2668
2669
2670 // return
2671 return acf_str_replace( $date, $php_to_js );
2672
2673 }
2674
2675
2676 /*
2677 * acf_convert_time_to_php
2678 *
2679 * This fucntion converts a time format string from JS to PHP
2680 *
2681 * @type function
2682 * @date 20/06/2014
2683 * @since 5.0.0
2684 *
2685 * @param $time (string)
2686 * @return (string)
2687 */
2688
2689 function acf_convert_time_to_php( $time = '' ) {
2690
2691 // vars
2692 $php_to_js = acf_get_setting('php_to_js_time_formats');
2693 $js_to_php = array_flip($php_to_js);
2694
2695
2696 // return
2697 return acf_str_replace( $time, $js_to_php );
2698
2699 }
2700
2701
2702 /*
2703 * acf_convert_time_to_js
2704 *
2705 * This fucntion converts a date format string from PHP to JS
2706 *
2707 * @type function
2708 * @date 20/06/2014
2709 * @since 5.0.0
2710 *
2711 * @param $time (string)
2712 * @return (string)
2713 */
2714
2715 function acf_convert_time_to_js( $time = '' ) {
2716
2717 // vars
2718 $php_to_js = acf_get_setting('php_to_js_time_formats');
2719
2720
2721 // return
2722 return acf_str_replace( $time, $php_to_js );
2723
2724 }
2725
2726
2727 /*
2728 * acf_update_user_setting
2729 *
2730 * description
2731 *
2732 * @type function
2733 * @date 15/07/2014
2734 * @since 5.0.0
2735 *
2736 * @param $post_id (int)
2737 * @return $post_id (int)
2738 */
2739
2740 function acf_update_user_setting( $name, $value ) {
2741
2742 // get current user id
2743 $user_id = get_current_user_id();
2744
2745
2746 // get user settings
2747 $settings = get_user_meta( $user_id, 'acf_user_settings', true );
2748
2749
2750 // ensure array
2751 $settings = acf_get_array($settings);
2752
2753
2754 // delete setting (allow 0 to save)
2755 if( acf_is_empty($value) ) {
2756
2757 unset($settings[ $name ]);
2758
2759 // append setting
2760 } else {
2761
2762 $settings[ $name ] = $value;
2763
2764 }
2765
2766
2767 // update user data
2768 return update_metadata('user', $user_id, 'acf_user_settings', $settings);
2769
2770 }
2771
2772
2773 /*
2774 * acf_get_user_setting
2775 *
2776 * description
2777 *
2778 * @type function
2779 * @date 15/07/2014
2780 * @since 5.0.0
2781 *
2782 * @param $post_id (int)
2783 * @return $post_id (int)
2784 */
2785
2786 function acf_get_user_setting( $name = '', $default = false ) {
2787
2788 // get current user id
2789 $user_id = get_current_user_id();
2790
2791
2792 // get user settings
2793 $settings = get_user_meta( $user_id, 'acf_user_settings', true );
2794
2795
2796 // ensure array
2797 $settings = acf_get_array($settings);
2798
2799
2800 // bail arly if no settings
2801 if( !isset($settings[$name]) ) return $default;
2802
2803
2804 // return
2805 return $settings[$name];
2806
2807 }
2808
2809
2810 /*
2811 * acf_in_array
2812 *
2813 * description
2814 *
2815 * @type function
2816 * @date 22/07/2014
2817 * @since 5.0.0
2818 *
2819 * @param $post_id (int)
2820 * @return $post_id (int)
2821 */
2822
2823 function acf_in_array( $value = '', $array = false ) {
2824
2825 // bail early if not array
2826 if( !is_array($array) ) return false;
2827
2828
2829 // find value in array
2830 return in_array($value, $array);
2831
2832 }
2833
2834
2835 /*
2836 * acf_get_valid_post_id
2837 *
2838 * This function will return a valid post_id based on the current screen / parameter
2839 *
2840 * @type function
2841 * @date 8/12/2013
2842 * @since 5.0.0
2843 *
2844 * @param $post_id (mixed)
2845 * @return $post_id (mixed)
2846 */
2847
2848 function acf_get_valid_post_id( $post_id = 0 ) {
2849
2850 // vars
2851 $_post_id = $post_id;
2852
2853
2854 // if not $post_id, load queried object
2855 if( !$post_id ) {
2856
2857 // try for global post (needed for setup_postdata)
2858 $post_id = (int) get_the_ID();
2859
2860
2861 // try for current screen
2862 if( !$post_id ) {
2863
2864 $post_id = get_queried_object();
2865
2866 }
2867
2868 }
2869
2870
2871 // $post_id may be an object
2872 if( is_object($post_id) ) {
2873
2874 // post
2875 if( isset($post_id->post_type, $post_id->ID) ) {
2876
2877 $post_id = $post_id->ID;
2878
2879 // user
2880 } elseif( isset($post_id->roles, $post_id->ID) ) {
2881
2882 $post_id = 'user_' . $post_id->ID;
2883
2884 // term
2885 } elseif( isset($post_id->taxonomy, $post_id->term_id) ) {
2886
2887 $post_id = acf_get_term_post_id( $post_id->taxonomy, $post_id->term_id );
2888
2889 // comment
2890 } elseif( isset($post_id->comment_ID) ) {
2891
2892 $post_id = 'comment_' . $post_id->comment_ID;
2893
2894 // default
2895 } else {
2896
2897 $post_id = 0;
2898
2899 }
2900
2901 }
2902
2903
2904 // allow for option == options
2905 if( $post_id === 'option' ) {
2906
2907 $post_id = 'options';
2908
2909 }
2910
2911
2912 // append language code
2913 if( $post_id == 'options' ) {
2914
2915 $dl = acf_get_setting('default_language');
2916 $cl = acf_get_setting('current_language');
2917
2918 if( $cl && $cl !== $dl ) {
2919
2920 $post_id .= '_' . $cl;
2921
2922 }
2923
2924 }
2925
2926
2927
2928 // filter for 3rd party
2929 $post_id = apply_filters('acf/validate_post_id', $post_id, $_post_id);
2930
2931
2932 // return
2933 return $post_id;
2934
2935 }
2936
2937
2938
2939 /*
2940 * acf_get_post_id_info
2941 *
2942 * This function will return the type and id for a given $post_id string
2943 *
2944 * @type function
2945 * @date 2/07/2016
2946 * @since 5.4.0
2947 *
2948 * @param $post_id (mixed)
2949 * @return $info (array)
2950 */
2951
2952 function acf_get_post_id_info( $post_id = 0 ) {
2953
2954 // vars
2955 $info = array(
2956 'type' => 'post',
2957 'id' => 0
2958 );
2959
2960 // bail early if no $post_id
2961 if( !$post_id ) return $info;
2962
2963
2964 // check cache
2965 // - this function will most likely be called multiple times (saving loading fields from post)
2966 //$cache_key = "get_post_id_info/post_id={$post_id}";
2967
2968 //if( acf_isset_cache($cache_key) ) return acf_get_cache($cache_key);
2969
2970
2971 // numeric
2972 if( is_numeric($post_id) ) {
2973
2974 $info['id'] = (int) $post_id;
2975
2976 // string
2977 } elseif( is_string($post_id) ) {
2978
2979 // vars
2980 $glue = '_';
2981 $type = explode($glue, $post_id);
2982 $id = array_pop($type);
2983 $type = implode($glue, $type);
2984 $meta = array('post', 'user', 'comment', 'term');
2985
2986
2987 // check if is taxonomy (ACF < 5.5)
2988 // - avoid scenario where taxonomy exists with name of meta type
2989 if( !in_array($type, $meta) && acf_isset_termmeta($type) ) $type = 'term';
2990
2991
2992 // meta
2993 if( is_numeric($id) && in_array($type, $meta) ) {
2994
2995 $info['type'] = $type;
2996 $info['id'] = (int) $id;
2997
2998 // option
2999 } else {
3000
3001 $info['type'] = 'option';
3002 $info['id'] = $post_id;
3003
3004 }
3005
3006 }
3007
3008
3009 // update cache
3010 //acf_set_cache($cache_key, $info);
3011
3012
3013 // return
3014 return $info;
3015
3016 }
3017
3018
3019 /*
3020
3021 acf_log( acf_get_post_id_info(4) );
3022
3023 acf_log( acf_get_post_id_info('post_4') );
3024
3025 acf_log( acf_get_post_id_info('user_123') );
3026
3027 acf_log( acf_get_post_id_info('term_567') );
3028
3029 acf_log( acf_get_post_id_info('category_204') );
3030
3031 acf_log( acf_get_post_id_info('comment_6') );
3032
3033 acf_log( acf_get_post_id_info('options_lol!') );
3034
3035 acf_log( acf_get_post_id_info('option') );
3036
3037 acf_log( acf_get_post_id_info('options') );
3038
3039 */
3040
3041
3042 /*
3043 * acf_isset_termmeta
3044 *
3045 * This function will return true if the termmeta table exists
3046 * https://developer.wordpress.org/reference/functions/get_term_meta/
3047 *
3048 * @type function
3049 * @date 3/09/2016
3050 * @since 5.4.0
3051 *
3052 * @param $post_id (int)
3053 * @return $post_id (int)
3054 */
3055
3056 function acf_isset_termmeta( $taxonomy = '' ) {
3057
3058 // bail ealry if no table
3059 if( get_option('db_version') < 34370 ) return false;
3060
3061
3062 // check taxonomy
3063 if( $taxonomy && !taxonomy_exists($taxonomy) ) return false;
3064
3065
3066 // return
3067 return true;
3068
3069 }
3070
3071
3072 /*
3073 * acf_get_term_post_id
3074 *
3075 * This function will return a valid post_id string for a given term and taxonomy
3076 *
3077 * @type function
3078 * @date 6/2/17
3079 * @since 5.5.6
3080 *
3081 * @param $taxonomy (string)
3082 * @param $term_id (int)
3083 * @return (string)
3084 */
3085
3086 function acf_get_term_post_id( $taxonomy, $term_id ) {
3087
3088 // WP < 4.4
3089 if( !acf_isset_termmeta() ) {
3090
3091 return $taxonomy . '_' . $term_id;
3092
3093 }
3094
3095
3096 // return
3097 return 'term_' . $term_id;
3098
3099 }
3100
3101
3102 /*
3103 * acf_upload_files
3104 *
3105 * This function will walk througfh the $_FILES data and upload each found
3106 *
3107 * @type function
3108 * @date 25/10/2014
3109 * @since 5.0.9
3110 *
3111 * @param $ancestors (array) an internal parameter, not required
3112 * @return n/a
3113 */
3114
3115 function acf_upload_files( $ancestors = array() ) {
3116
3117 // vars
3118 $file = array(
3119 'name' => '',
3120 'type' => '',
3121 'tmp_name' => '',
3122 'error' => '',
3123 'size' => ''
3124 );
3125
3126
3127 // populate with $_FILES data
3128 foreach( array_keys($file) as $k ) {
3129
3130 $file[ $k ] = $_FILES['acf'][ $k ];
3131
3132 }
3133
3134
3135 // walk through ancestors
3136 if( !empty($ancestors) ) {
3137
3138 foreach( $ancestors as $a ) {
3139
3140 foreach( array_keys($file) as $k ) {
3141
3142 $file[ $k ] = $file[ $k ][ $a ];
3143
3144 }
3145
3146 }
3147
3148 }
3149
3150
3151 // is array?
3152 if( is_array($file['name']) ) {
3153
3154 foreach( array_keys($file['name']) as $k ) {
3155
3156 $_ancestors = array_merge($ancestors, array($k));
3157
3158 acf_upload_files( $_ancestors );
3159
3160 }
3161
3162 return;
3163
3164 }
3165
3166
3167 // bail ealry if file has error (no file uploaded)
3168 if( $file['error'] ) {
3169
3170 return;
3171
3172 }
3173
3174
3175 // assign global _acfuploader for media validation
3176 $_POST['_acfuploader'] = end($ancestors);
3177
3178
3179 // file found!
3180 $attachment_id = acf_upload_file( $file );
3181
3182
3183 // update $_POST
3184 array_unshift($ancestors, 'acf');
3185 acf_update_nested_array( $_POST, $ancestors, $attachment_id );
3186
3187 }
3188
3189
3190 /*
3191 * acf_upload_file
3192 *
3193 * This function will uploade a $_FILE
3194 *
3195 * @type function
3196 * @date 27/10/2014
3197 * @since 5.0.9
3198 *
3199 * @param $uploaded_file (array) array found from $_FILE data
3200 * @return $id (int) new attachment ID
3201 */
3202
3203 function acf_upload_file( $uploaded_file ) {
3204
3205 // required
3206 //require_once( ABSPATH . "/wp-load.php" ); // WP should already be loaded
3207 require_once( ABSPATH . "/wp-admin/includes/media.php" ); // video functions
3208 require_once( ABSPATH . "/wp-admin/includes/file.php" );
3209 require_once( ABSPATH . "/wp-admin/includes/image.php" );
3210
3211
3212 // required for wp_handle_upload() to upload the file
3213 $upload_overrides = array( 'test_form' => false );
3214
3215
3216 // upload
3217 $file = wp_handle_upload( $uploaded_file, $upload_overrides );
3218
3219
3220 // bail ealry if upload failed
3221 if( isset($file['error']) ) {
3222
3223 return $file['error'];
3224
3225 }
3226
3227
3228 // vars
3229 $url = $file['url'];
3230 $type = $file['type'];
3231 $file = $file['file'];
3232 $filename = basename($file);
3233
3234
3235 // Construct the object array
3236 $object = array(
3237 'post_title' => $filename,
3238 'post_mime_type' => $type,
3239 'guid' => $url,
3240 'context' => 'acf-upload'
3241 );
3242
3243 // Save the data
3244 $id = wp_insert_attachment($object, $file);
3245
3246 // Add the meta-data
3247 wp_update_attachment_metadata( $id, wp_generate_attachment_metadata( $id, $file ) );
3248
3249 /** This action is documented in wp-admin/custom-header.php */
3250 do_action( 'wp_create_file_in_uploads', $file, $id ); // For replication
3251
3252 // return new ID
3253 return $id;
3254
3255 }
3256
3257
3258 /*
3259 * acf_update_nested_array
3260 *
3261 * This function will update a nested array value. Useful for modifying the $_POST array
3262 *
3263 * @type function
3264 * @date 27/10/2014
3265 * @since 5.0.9
3266 *
3267 * @param $array (array) target array to be updated
3268 * @param $ancestors (array) array of keys to navigate through to find the child
3269 * @param $value (mixed) The new value
3270 * @return (boolean)
3271 */
3272
3273 function acf_update_nested_array( &$array, $ancestors, $value ) {
3274
3275 // if no more ancestors, update the current var
3276 if( empty($ancestors) ) {
3277
3278 $array = $value;
3279
3280 // return
3281 return true;
3282
3283 }
3284
3285
3286 // shift the next ancestor from the array
3287 $k = array_shift( $ancestors );
3288
3289
3290 // if exists
3291 if( isset($array[ $k ]) ) {
3292
3293 return acf_update_nested_array( $array[ $k ], $ancestors, $value );
3294
3295 }
3296
3297
3298 // return
3299 return false;
3300 }
3301
3302
3303 /*
3304 * acf_is_screen
3305 *
3306 * This function will return true if all args are matched for the current screen
3307 *
3308 * @type function
3309 * @date 9/12/2014
3310 * @since 5.1.5
3311 *
3312 * @param $post_id (int)
3313 * @return $post_id (int)
3314 */
3315
3316 function acf_is_screen( $id = '' ) {
3317
3318 // bail early if not defined
3319 if( !function_exists('get_current_screen') ) return false;
3320
3321
3322 // vars
3323 $current_screen = get_current_screen();
3324
3325
3326 // bail early if no screen
3327 if( !$current_screen ) return false;
3328
3329
3330 // return
3331 return ($id === $current_screen->id);
3332
3333 }
3334
3335
3336 /*
3337 * acf_maybe_get
3338 *
3339 * This function will return a var if it exists in an array
3340 *
3341 * @type function
3342 * @date 9/12/2014
3343 * @since 5.1.5
3344 *
3345 * @param $array (array) the array to look within
3346 * @param $key (key) the array key to look for. Nested values may be found using '/'
3347 * @param $default (mixed) the value returned if not found
3348 * @return $post_id (int)
3349 */
3350
3351 function acf_maybe_get( $array = array(), $key = 0, $default = null ) {
3352
3353 return isset( $array[$key] ) ? $array[$key] : $default;
3354
3355 }
3356
3357 function acf_maybe_get_POST( $key = '', $default = null ) {
3358
3359 return isset( $_POST[$key] ) ? $_POST[$key] : $default;
3360
3361 }
3362
3363 function acf_maybe_get_GET( $key = '', $default = null ) {
3364
3365 return isset( $_GET[$key] ) ? $_GET[$key] : $default;
3366
3367 }
3368
3369
3370 /*
3371 * acf_get_attachment
3372 *
3373 * This function will return an array of attachment data
3374 *
3375 * @type function
3376 * @date 5/01/2015
3377 * @since 5.1.5
3378 *
3379 * @param $post (mixed) either post ID or post object
3380 * @return (array)
3381 */
3382
3383 function acf_get_attachment( $post ) {
3384
3385 // post
3386 $post = get_post($post);
3387
3388
3389 // bail early if no post
3390 if( !$post ) return false;
3391
3392
3393 // vars
3394 $thumb_id = 0;
3395 $id = $post->ID;
3396 $a = array(
3397 'ID' => $id,
3398 'id' => $id,
3399 'title' => $post->post_title,
3400 'filename' => wp_basename( $post->guid ),
3401 'url' => wp_get_attachment_url( $id ),
3402 'alt' => get_post_meta($id, '_wp_attachment_image_alt', true),
3403 'author' => $post->post_author,
3404 'description' => $post->post_content,
3405 'caption' => $post->post_excerpt,
3406 'name' => $post->post_name,
3407 'date' => $post->post_date_gmt,
3408 'modified' => $post->post_modified_gmt,
3409 'mime_type' => $post->post_mime_type,
3410 'type' => acf_maybe_get( explode('/', $post->post_mime_type), 0, '' ),
3411 'icon' => wp_mime_type_icon( $id )
3412 );
3413
3414
3415 // video may use featured image
3416 if( $a['type'] === 'image' ) {
3417
3418 $thumb_id = $id;
3419 $src = wp_get_attachment_image_src( $id, 'full' );
3420
3421 $a['url'] = $src[0];
3422 $a['width'] = $src[1];
3423 $a['height'] = $src[2];
3424
3425
3426 } elseif( $a['type'] === 'audio' || $a['type'] === 'video' ) {
3427
3428 // video dimentions
3429 if( $a['type'] == 'video' ) {
3430
3431 $meta = wp_get_attachment_metadata( $id );
3432 $a['width'] = acf_maybe_get($meta, 'width', 0);
3433 $a['height'] = acf_maybe_get($meta, 'height', 0);
3434
3435 }
3436
3437
3438 // feature image
3439 if( $featured_id = get_post_thumbnail_id($id) ) {
3440
3441 $thumb_id = $featured_id;
3442
3443 }
3444
3445 }
3446
3447
3448 // sizes
3449 if( $thumb_id ) {
3450
3451 // find all image sizes
3452 if( $sizes = get_intermediate_image_sizes() ) {
3453
3454 $a['sizes'] = array();
3455
3456 foreach( $sizes as $size ) {
3457
3458 // url
3459 $src = wp_get_attachment_image_src( $thumb_id, $size );
3460
3461 // add src
3462 $a['sizes'][ $size ] = $src[0];
3463 $a['sizes'][ $size . '-width' ] = $src[1];
3464 $a['sizes'][ $size . '-height' ] = $src[2];
3465
3466 }
3467
3468 }
3469
3470 }
3471
3472
3473 // return
3474 return $a;
3475
3476 }
3477
3478
3479 /*
3480 * acf_get_truncated
3481 *
3482 * This function will truncate and return a string
3483 *
3484 * @type function
3485 * @date 8/08/2014
3486 * @since 5.0.0
3487 *
3488 * @param $text (string)
3489 * @param $length (int)
3490 * @return (string)
3491 */
3492
3493 function acf_get_truncated( $text, $length = 64 ) {
3494
3495 // vars
3496 $text = trim($text);
3497 $the_length = strlen( $text );
3498
3499
3500 // cut
3501 $return = substr( $text, 0, ($length - 3) );
3502
3503
3504 // ...
3505 if( $the_length > ($length - 3) ) {
3506
3507 $return .= '...';
3508
3509 }
3510
3511
3512 // return
3513 return $return;
3514
3515 }
3516
3517
3518 /*
3519 * acf_get_current_url
3520 *
3521 * This function will return the current URL
3522 *
3523 * @type function
3524 * @date 23/01/2015
3525 * @since 5.1.5
3526 *
3527 * @param n/a
3528 * @return (string)
3529 */
3530
3531 function acf_get_current_url() {
3532
3533 // vars
3534 $home = home_url();
3535 $url = home_url($_SERVER['REQUEST_URI']);
3536
3537
3538 // test
3539 //$home = 'http://acf5/dev/wp-admin';
3540 //$url = $home . '/dev/wp-admin/api-template/acf_form';
3541
3542
3543 // explode url (4th bit is the sub folder)
3544 $bits = explode('/', $home, 4);
3545
3546
3547 /*
3548 Array (
3549 [0] => http:
3550 [1] =>
3551 [2] => acf5
3552 [3] => dev
3553 )
3554 */
3555
3556
3557 // handle sub folder
3558 if( !empty($bits[3]) ) {
3559
3560 $find = '/' . $bits[3];
3561 $pos = strpos($url, $find);
3562 $length = strlen($find);
3563
3564 if( $pos !== false ) {
3565
3566 $url = substr_replace($url, '', $pos, $length);
3567
3568 }
3569
3570 }
3571
3572
3573 // return
3574 return $url;
3575
3576 }
3577
3578
3579 /*
3580 * acf_current_user_can_admin
3581 *
3582 * This function will return true if the current user can administrate the ACF field groups
3583 *
3584 * @type function
3585 * @date 9/02/2015
3586 * @since 5.1.5
3587 *
3588 * @param $post_id (int)
3589 * @return $post_id (int)
3590 */
3591
3592 function acf_current_user_can_admin() {
3593
3594 if( acf_get_setting('show_admin') && current_user_can(acf_get_setting('capability')) ) {
3595
3596 return true;
3597
3598 }
3599
3600
3601 // return
3602 return false;
3603
3604 }
3605
3606
3607 /*
3608 * acf_get_filesize
3609 *
3610 * This function will return a numeric value of bytes for a given filesize string
3611 *
3612 * @type function
3613 * @date 18/02/2015
3614 * @since 5.1.5
3615 *
3616 * @param $size (mixed)
3617 * @return (int)
3618 */
3619
3620 function acf_get_filesize( $size = 1 ) {
3621
3622 // vars
3623 $unit = 'MB';
3624 $units = array(
3625 'TB' => 4,
3626 'GB' => 3,
3627 'MB' => 2,
3628 'KB' => 1,
3629 );
3630
3631
3632 // look for $unit within the $size parameter (123 KB)
3633 if( is_string($size) ) {
3634
3635 // vars
3636 $custom = strtoupper( substr($size, -2) );
3637
3638 foreach( $units as $k => $v ) {
3639
3640 if( $custom === $k ) {
3641
3642 $unit = $k;
3643 $size = substr($size, 0, -2);
3644
3645 }
3646
3647 }
3648
3649 }
3650
3651
3652 // calc bytes
3653 $bytes = floatval($size) * pow(1024, $units[$unit]);
3654
3655
3656 // return
3657 return $bytes;
3658
3659 }
3660
3661
3662 /*
3663 * acf_format_filesize
3664 *
3665 * This function will return a formatted string containing the filesize and unit
3666 *
3667 * @type function
3668 * @date 18/02/2015
3669 * @since 5.1.5
3670 *
3671 * @param $size (mixed)
3672 * @return (int)
3673 */
3674
3675 function acf_format_filesize( $size = 1 ) {
3676
3677 // convert
3678 $bytes = acf_get_filesize( $size );
3679
3680
3681 // vars
3682 $units = array(
3683 'TB' => 4,
3684 'GB' => 3,
3685 'MB' => 2,
3686 'KB' => 1,
3687 );
3688
3689
3690 // loop through units
3691 foreach( $units as $k => $v ) {
3692
3693 $result = $bytes / pow(1024, $v);
3694
3695 if( $result >= 1 ) {
3696
3697 return $result . ' ' . $k;
3698
3699 }
3700
3701 }
3702
3703
3704 // return
3705 return $bytes . ' B';
3706
3707 }
3708
3709
3710 /*
3711 * acf_get_valid_terms
3712 *
3713 * This function will replace old terms with new split term ids
3714 *
3715 * @type function
3716 * @date 27/02/2015
3717 * @since 5.1.5
3718 *
3719 * @param $terms (int|array)
3720 * @param $taxonomy (string)
3721 * @return $terms
3722 */
3723
3724 function acf_get_valid_terms( $terms = false, $taxonomy = 'category' ) {
3725
3726 // force into array
3727 $terms = acf_get_array($terms);
3728
3729
3730 // force ints
3731 $terms = array_map('intval', $terms);
3732
3733
3734 // bail early if function does not yet exist or
3735 if( !function_exists('wp_get_split_term') || empty($terms) ) {
3736
3737 return $terms;
3738
3739 }
3740
3741
3742 // attempt to find new terms
3743 foreach( $terms as $i => $term_id ) {
3744
3745 $new_term_id = wp_get_split_term($term_id, $taxonomy);
3746
3747 if( $new_term_id ) {
3748
3749 $terms[ $i ] = $new_term_id;
3750
3751 }
3752
3753 }
3754
3755
3756 // return
3757 return $terms;
3758
3759 }
3760
3761
3762 /*
3763 * acf_esc_html_deep
3764 *
3765 * Navigates through an array and escapes html from the values.
3766 *
3767 * @type function
3768 * @date 10/06/2015
3769 * @since 5.2.7
3770 *
3771 * @param $value (mixed)
3772 * @return $value
3773 */
3774
3775 /*
3776 function acf_esc_html_deep( $value ) {
3777
3778 // array
3779 if( is_array($value) ) {
3780
3781 $value = array_map('acf_esc_html_deep', $value);
3782
3783 // object
3784 } elseif( is_object($value) ) {
3785
3786 $vars = get_object_vars( $value );
3787
3788 foreach( $vars as $k => $v ) {
3789
3790 $value->{$k} = acf_esc_html_deep( $v );
3791
3792 }
3793
3794 // string
3795 } elseif( is_string($value) ) {
3796
3797 $value = esc_html($value);
3798
3799 }
3800
3801
3802 // return
3803 return $value;
3804
3805 }
3806 */
3807
3808
3809 /*
3810 * acf_validate_attachment
3811 *
3812 * This function will validate an attachment based on a field's resrictions and return an array of errors
3813 *
3814 * @type function
3815 * @date 3/07/2015
3816 * @since 5.2.3
3817 *
3818 * @param $attachment (array) attachment data. Cahnges based on context
3819 * @param $field (array) field settings containing restrictions
3820 * @param $context (string) $file is different when uploading / preparing
3821 * @return $errors (array)
3822 */
3823
3824 function acf_validate_attachment( $attachment, $field, $context = 'prepare' ) {
3825
3826 // vars
3827 $errors = array();
3828 $file = array(
3829 'type' => '',
3830 'width' => 0,
3831 'height' => 0,
3832 'size' => 0
3833 );
3834
3835
3836 // upload
3837 if( $context == 'upload' ) {
3838
3839 // vars
3840 $file['type'] = pathinfo($attachment['name'], PATHINFO_EXTENSION);
3841 $file['size'] = filesize($attachment['tmp_name']);
3842
3843 if( strpos($attachment['type'], 'image') !== false ) {
3844
3845 $size = getimagesize($attachment['tmp_name']);
3846 $file['width'] = acf_maybe_get($size, 0);
3847 $file['height'] = acf_maybe_get($size, 1);
3848
3849 }
3850
3851 // prepare
3852 } elseif( $context == 'prepare' ) {
3853
3854 $file['type'] = pathinfo($attachment['url'], PATHINFO_EXTENSION);
3855 $file['size'] = acf_maybe_get($attachment, 'filesizeInBytes', 0);
3856 $file['width'] = acf_maybe_get($attachment, 'width', 0);
3857 $file['height'] = acf_maybe_get($attachment, 'height', 0);
3858
3859 // custom
3860 } else {
3861
3862 $file = array_merge($file, $attachment);
3863 $file['type'] = pathinfo($attachment['url'], PATHINFO_EXTENSION);
3864
3865 }
3866
3867
3868 // image
3869 if( $file['width'] || $file['height'] ) {
3870
3871 // width
3872 $min_width = (int) acf_maybe_get($field, 'min_width', 0);
3873 $max_width = (int) acf_maybe_get($field, 'max_width', 0);
3874
3875 if( $file['width'] ) {
3876
3877 if( $min_width && $file['width'] < $min_width ) {
3878
3879 // min width
3880 $errors['min_width'] = sprintf(__('Image width must be at least %dpx.', 'acf'), $min_width );
3881
3882 } elseif( $max_width && $file['width'] > $max_width ) {
3883
3884 // min width
3885 $errors['max_width'] = sprintf(__('Image width must not exceed %dpx.', 'acf'), $max_width );
3886
3887 }
3888
3889 }
3890
3891
3892 // height
3893 $min_height = (int) acf_maybe_get($field, 'min_height', 0);
3894 $max_height = (int) acf_maybe_get($field, 'max_height', 0);
3895
3896 if( $file['height'] ) {
3897
3898 if( $min_height && $file['height'] < $min_height ) {
3899
3900 // min height
3901 $errors['min_height'] = sprintf(__('Image height must be at least %dpx.', 'acf'), $min_height );
3902
3903 } elseif( $max_height && $file['height'] > $max_height ) {
3904
3905 // min height
3906 $errors['max_height'] = sprintf(__('Image height must not exceed %dpx.', 'acf'), $max_height );
3907
3908 }
3909
3910 }
3911
3912 }
3913
3914
3915 // file size
3916 if( $file['size'] ) {
3917
3918 $min_size = acf_maybe_get($field, 'min_size', 0);
3919 $max_size = acf_maybe_get($field, 'max_size', 0);
3920
3921 if( $min_size && $file['size'] < acf_get_filesize($min_size) ) {
3922
3923 // min width
3924 $errors['min_size'] = sprintf(__('File size must be at least %s.', 'acf'), acf_format_filesize($min_size) );
3925
3926 } elseif( $max_size && $file['size'] > acf_get_filesize($max_size) ) {
3927
3928 // min width
3929 $errors['max_size'] = sprintf(__('File size must must not exceed %s.', 'acf'), acf_format_filesize($max_size) );
3930
3931 }
3932
3933 }
3934
3935
3936 // file type
3937 if( $file['type'] ) {
3938
3939 $mime_types = acf_maybe_get($field, 'mime_types', '');
3940
3941 // lower case
3942 $file['type'] = strtolower($file['type']);
3943 $mime_types = strtolower($mime_types);
3944
3945
3946 // explode
3947 $mime_types = str_replace(array(' ', '.'), '', $mime_types);
3948 $mime_types = explode(',', $mime_types); // split pieces
3949 $mime_types = array_filter($mime_types); // remove empty pieces
3950
3951 if( !empty($mime_types) && !in_array($file['type'], $mime_types) ) {
3952
3953 // glue together last 2 types
3954 if( count($mime_types) > 1 ) {
3955
3956 $last1 = array_pop($mime_types);
3957 $last2 = array_pop($mime_types);
3958
3959 $mime_types[] = $last2 . ' ' . __('or', 'acf') . ' ' . $last1;
3960
3961 }
3962
3963 $errors['mime_types'] = sprintf(__('File type must be %s.', 'acf'), implode(', ', $mime_types) );
3964
3965 }
3966
3967 }
3968
3969
3970 // filter for 3rd party customization
3971 $errors = apply_filters("acf/validate_attachment", $errors, $file, $attachment, $field, $context);
3972 $errors = apply_filters("acf/validate_attachment/type={$field['type']}", $errors, $file, $attachment, $field, $context );
3973 $errors = apply_filters("acf/validate_attachment/name={$field['name']}", $errors, $file, $attachment, $field, $context );
3974 $errors = apply_filters("acf/validate_attachment/key={$field['key']}", $errors, $file, $attachment, $field, $context );
3975
3976
3977 // return
3978 return $errors;
3979
3980 }
3981
3982
3983 /*
3984 * _acf_settings_uploader
3985 *
3986 * Dynamic logic for uploader setting
3987 *
3988 * @type function
3989 * @date 7/05/2015
3990 * @since 5.2.3
3991 *
3992 * @param $uploader (string)
3993 * @return $uploader
3994 */
3995
3996 add_filter('acf/settings/uploader', '_acf_settings_uploader');
3997
3998 function _acf_settings_uploader( $uploader ) {
3999
4000 // if can't upload files
4001 if( !current_user_can('upload_files') ) {
4002
4003 $uploader = 'basic';
4004
4005 }
4006
4007
4008 // return
4009 return $uploader;
4010 }
4011
4012
4013 /*
4014 * acf_translate_keys
4015 *
4016 * description
4017 *
4018 * @type function
4019 * @date 7/12/2015
4020 * @since 5.3.2
4021 *
4022 * @param $post_id (int)
4023 * @return $post_id (int)
4024 */
4025
4026 /*
4027 function acf_translate_keys( $array, $keys ) {
4028
4029 // bail early if no keys
4030 if( empty($keys) ) return $array;
4031
4032
4033 // translate
4034 foreach( $keys as $k ) {
4035
4036 // bail ealry if not exists
4037 if( !isset($array[ $k ]) ) continue;
4038
4039
4040 // translate
4041 $array[ $k ] = acf_translate( $array[ $k ] );
4042
4043 }
4044
4045
4046 // return
4047 return $array;
4048
4049 }
4050 */
4051
4052
4053 /*
4054 * acf_translate
4055 *
4056 * This function will translate a string using the new 'l10n_textdomain' setting
4057 * Also works for arrays which is great for fields - select -> choices
4058 *
4059 * @type function
4060 * @date 4/12/2015
4061 * @since 5.3.2
4062 *
4063 * @param $string (mixed) string or array containins strings to be translated
4064 * @return $string
4065 */
4066
4067 function acf_translate( $string ) {
4068
4069 // vars
4070 $l10n = acf_get_setting('l10n');
4071 $textdomain = acf_get_setting('l10n_textdomain');
4072
4073
4074 // bail early if not enabled
4075 if( !$l10n ) return $string;
4076
4077
4078 // bail early if no textdomain
4079 if( !$textdomain ) return $string;
4080
4081
4082 // is array
4083 if( is_array($string) ) {
4084
4085 return array_map('acf_translate', $string);
4086
4087 }
4088
4089
4090 // bail early if not string
4091 if( !is_string($string) ) return $string;
4092
4093
4094 // bail early if empty
4095 if( $string === '' ) return $string;
4096
4097
4098 // allow for var_export export
4099 if( acf_get_setting('l10n_var_export') ){
4100
4101 // bail early if already translated
4102 if( substr($string, 0, 7) === '!!__(!!' ) return $string;
4103
4104
4105 // return
4106 return "!!__(!!'" . $string . "!!', !!'" . $textdomain . "!!')!!";
4107
4108 }
4109
4110
4111 // vars
4112 return __( $string, $textdomain );
4113
4114 }
4115
4116
4117 /*
4118 * acf_maybe_add_action
4119 *
4120 * This function will determine if the action has already run before adding / calling the function
4121 *
4122 * @type function
4123 * @date 13/01/2016
4124 * @since 5.3.2
4125 *
4126 * @param $post_id (int)
4127 * @return $post_id (int)
4128 */
4129
4130 function acf_maybe_add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) {
4131
4132 // if action has already run, execute it
4133 // - if currently doing action, allow $tag to be added as per usual to allow $priority ordering needed for 3rd party asset compatibility
4134 if( did_action($tag) && !doing_action($tag) ) {
4135
4136 call_user_func( $function_to_add );
4137
4138 // if action has not yet run, add it
4139 } else {
4140
4141 add_action( $tag, $function_to_add, $priority, $accepted_args );
4142
4143 }
4144
4145 }
4146
4147
4148 /*
4149 * acf_is_row_collapsed
4150 *
4151 * This function will return true if the field's row is collapsed
4152 *
4153 * @type function
4154 * @date 2/03/2016
4155 * @since 5.3.2
4156 *
4157 * @param $post_id (int)
4158 * @return $post_id (int)
4159 */
4160
4161 function acf_is_row_collapsed( $field_key = '', $row_index = 0 ) {
4162
4163 // collapsed
4164 $collapsed = acf_get_user_setting('collapsed_' . $field_key, '');
4165
4166
4167 // cookie fallback ( version < 5.3.2 )
4168 if( $collapsed === '' ) {
4169
4170 $collapsed = acf_extract_var($_COOKIE, "acf_collapsed_{$field_key}", '');
4171 $collapsed = str_replace('|', ',', $collapsed);
4172
4173
4174 // update
4175 acf_update_user_setting( 'collapsed_' . $field_key, $collapsed );
4176
4177 }
4178
4179
4180 // explode
4181 $collapsed = explode(',', $collapsed);
4182 $collapsed = array_filter($collapsed, 'is_numeric');
4183
4184
4185 // collapsed class
4186 return in_array($row_index, $collapsed);
4187
4188 }
4189
4190
4191 /*
4192 * acf_get_attachment_image
4193 *
4194 * description
4195 *
4196 * @type function
4197 * @date 24/10/16
4198 * @since 5.5.0
4199 *
4200 * @param $post_id (int)
4201 * @return $post_id (int)
4202 */
4203
4204 function acf_get_attachment_image( $attachment_id = 0, $size = 'thumbnail' ) {
4205
4206 // vars
4207 $url = wp_get_attachment_image_src($attachment_id, 'thumbnail');
4208 $alt = get_post_meta($attachment_id, '_wp_attachment_image_alt', true);
4209
4210
4211 // bail early if no url
4212 if( !$url ) return '';
4213
4214
4215 // return
4216 $value = '<img src="' . $url . '" alt="' . $alt . '" />';
4217
4218 }
4219
4220
4221 /*
4222 * acf_get_post_thumbnail
4223 *
4224 * This function will return a thumbail image url for a given post
4225 *
4226 * @type function
4227 * @date 3/05/2016
4228 * @since 5.3.8
4229 *
4230 * @param $post (obj)
4231 * @param $size (mixed)
4232 * @return (string)
4233 */
4234
4235 function acf_get_post_thumbnail( $post = null, $size = 'thumbnail' ) {
4236
4237 // vars
4238 $data = array(
4239 'url' => '',
4240 'type' => '',
4241 'html' => ''
4242 );
4243
4244
4245 // post
4246 $post = get_post($post);
4247
4248
4249 // bail early if no post
4250 if( !$post ) return $data;
4251
4252
4253 // vars
4254 $thumb_id = $post->ID;
4255 $mime_type = acf_maybe_get(explode('/', $post->post_mime_type), 0);
4256
4257
4258 // attachment
4259 if( $post->post_type === 'attachment' ) {
4260
4261 // change $thumb_id
4262 if( $mime_type === 'audio' || $mime_type === 'video' ) {
4263
4264 $thumb_id = get_post_thumbnail_id($post->ID);
4265
4266 }
4267
4268 // post
4269 } else {
4270
4271 $thumb_id = get_post_thumbnail_id($post->ID);
4272
4273 }
4274
4275
4276 // try url
4277 $data['url'] = wp_get_attachment_image_src($thumb_id, $size);
4278 $data['url'] = acf_maybe_get($data['url'], 0);
4279
4280
4281 // default icon
4282 if( !$data['url'] && $post->post_type === 'attachment' ) {
4283
4284 $data['url'] = wp_mime_type_icon($post->ID);
4285 $data['type'] = 'icon';
4286
4287 }
4288
4289
4290 // html
4291 $data['html'] = '<img src="' . $data['url'] . '" alt="" />';
4292
4293
4294 // return
4295 return $data;
4296
4297 }
4298
4299
4300 /*
4301 * acf_get_browser
4302 *
4303 * This functino will return the browser string for major browsers
4304 *
4305 * @type function
4306 * @date 17/01/2014
4307 * @since 5.0.0
4308 *
4309 * @param n/a
4310 * @return (string)
4311 */
4312
4313 function acf_get_browser() {
4314
4315 // vars
4316 $agent = $_SERVER['HTTP_USER_AGENT'];
4317
4318
4319 // browsers
4320 $browsers = array(
4321 'Firefox' => 'firefox',
4322 'Trident' => 'msie',
4323 'MSIE' => 'msie',
4324 'Edge' => 'edge',
4325 'Chrome' => 'chrome',
4326 'Safari' => 'safari',
4327 );
4328
4329
4330 // loop
4331 foreach( $browsers as $k => $v ) {
4332
4333 if( strpos($agent, $k) !== false ) return $v;
4334
4335 }
4336
4337
4338 // return
4339 return '';
4340
4341 }
4342
4343
4344 /*
4345 * acf_is_ajax
4346 *
4347 * This function will reutrn true if performing a wp ajax call
4348 *
4349 * @type function
4350 * @date 7/06/2016
4351 * @since 5.3.8
4352 *
4353 * @param n/a
4354 * @return (boolean)
4355 */
4356
4357 function acf_is_ajax( $action = '' ) {
4358
4359 // vars
4360 $is_ajax = false;
4361
4362
4363 // check if is doing ajax
4364 if( defined('DOING_AJAX') && DOING_AJAX ) {
4365
4366 $is_ajax = true;
4367
4368 }
4369
4370
4371 // check $action
4372 if( $action && acf_maybe_get($_POST, 'action') !== $action ) {
4373
4374 $is_ajax = false;
4375
4376 }
4377
4378
4379 // return
4380 return $is_ajax;
4381
4382 }
4383
4384
4385
4386
4387 /*
4388 * acf_format_date
4389 *
4390 * This function will accept a date value and return it in a formatted string
4391 *
4392 * @type function
4393 * @date 16/06/2016
4394 * @since 5.3.8
4395 *
4396 * @param $value (string)
4397 * @return $format (string)
4398 */
4399
4400 function acf_format_date( $value, $format ) {
4401
4402 // bail early if no value
4403 if( !$value ) return $value;
4404
4405
4406 // vars
4407 $unixtimestamp = 0;
4408
4409
4410 // numeric (either unix or YYYYMMDD)
4411 if( is_numeric($value) && strlen($value) !== 8 ) {
4412
4413 $unixtimestamp = $value;
4414
4415 } else {
4416
4417 $unixtimestamp = strtotime($value);
4418
4419 }
4420
4421
4422 // return
4423 return date_i18n($format, $unixtimestamp);
4424
4425 }
4426
4427
4428 /*
4429 * acf_log
4430 *
4431 * description
4432 *
4433 * @type function
4434 * @date 24/06/2016
4435 * @since 5.3.8
4436 *
4437 * @param $post_id (int)
4438 * @return $post_id (int)
4439 */
4440
4441 function acf_log() {
4442
4443 // vars
4444 $log = '';
4445 $args = func_get_args();
4446
4447
4448 // loop
4449 foreach( $args as $i => $arg ) {
4450
4451 if( is_array($arg) || is_object($arg) ) {
4452
4453 $arg = print_r($arg, true);
4454
4455 } elseif( is_bool($arg) ) {
4456
4457 $arg = ( $arg ? 'true' : 'false' ) . ' (bool)';
4458
4459 }
4460
4461
4462 // update
4463 $args[ $i ] = $arg;
4464
4465 }
4466
4467
4468 // log
4469 error_log( implode(' ', $args) );
4470
4471 }
4472
4473
4474 /*
4475 * acf_doing
4476 *
4477 * This function will tell ACF what task it is doing
4478 *
4479 * @type function
4480 * @date 28/06/2016
4481 * @since 5.3.8
4482 *
4483 * @param $event (string)
4484 * @param context (string)
4485 * @return n/a
4486 */
4487
4488 function acf_doing( $event = '', $context = '' ) {
4489
4490 acf_update_setting( 'doing', $event );
4491 acf_update_setting( 'doing_context', $context );
4492
4493 }
4494
4495
4496 /*
4497 * acf_is_doing
4498 *
4499 * This function can be used to state what ACF is doing, or to check
4500 *
4501 * @type function
4502 * @date 28/06/2016
4503 * @since 5.3.8
4504 *
4505 * @param $event (string)
4506 * @param context (string)
4507 * @return (boolean)
4508 */
4509
4510 function acf_is_doing( $event = '', $context = '' ) {
4511
4512 // vars
4513 $doing = false;
4514
4515
4516 // task
4517 if( acf_get_setting('doing') === $event ) {
4518
4519 $doing = true;
4520
4521 }
4522
4523
4524 // context
4525 if( $context && acf_get_setting('doing_context') !== $context ) {
4526
4527 $doing = false;
4528
4529 }
4530
4531
4532 // return
4533 return $doing;
4534
4535 }
4536
4537
4538 /*
4539 * acf_is_plugin_active
4540 *
4541 * This function will return true if the ACF plugin is active
4542 * - May be included within a theme or other plugin
4543 *
4544 * @type function
4545 * @date 13/07/2016
4546 * @since 5.4.0
4547 *
4548 * @param $basename (int)
4549 * @return $post_id (int)
4550 */
4551
4552
4553 function acf_is_plugin_active() {
4554
4555 // vars
4556 $basename = acf_get_setting('basename');
4557
4558
4559 // ensure is_plugin_active() exists (not on frontend)
4560 if( !function_exists('is_plugin_active') ) {
4561
4562 include_once( ABSPATH . 'wp-admin/includes/plugin.php' );
4563
4564 }
4565
4566
4567 // return
4568 return is_plugin_active($basename);
4569
4570 }
4571
4572
4573 /*
4574 * acf_enable_filter
4575 *
4576 * This function will enable a filter
4577 *
4578 * @type function
4579 * @date 15/07/2016
4580 * @since 5.4.0
4581 *
4582 * @param $post_id (int)
4583 * @return $post_id (int)
4584 */
4585
4586 function acf_enable_filter( $filter = '' ) {
4587
4588 // get filters
4589 $filters = acf_get_setting('_filters', array());
4590
4591
4592 // append
4593 $filters[ $filter ] = true;
4594
4595
4596 // update
4597 acf_update_setting('_filters', $filters);
4598
4599 }
4600
4601
4602 /*
4603 * acf_disable_filter
4604 *
4605 * This function will disable a filter
4606 *
4607 * @type function
4608 * @date 15/07/2016
4609 * @since 5.4.0
4610 *
4611 * @param $post_id (int)
4612 * @return $post_id (int)
4613 */
4614
4615 function acf_disable_filter( $filter = '' ) {
4616
4617 // get filters
4618 $filters = acf_get_setting('_filters', array());
4619
4620
4621 // append
4622 $filters[ $filter ] = false;
4623
4624
4625 // update
4626 acf_update_setting('_filters', $filters);
4627
4628 }
4629
4630
4631 /*
4632 * acf_enable_filters
4633 *
4634 * ACF uses filters to modify field group and field data
4635 * This function will enable them allowing ACF to interact with all data
4636 *
4637 * @type function
4638 * @date 14/07/2016
4639 * @since 5.4.0
4640 *
4641 * @param $post_id (int)
4642 * @return $post_id (int)
4643 */
4644
4645 function acf_enable_filters() {
4646
4647 // get filters
4648 $filters = acf_get_setting('_filters', array());
4649
4650
4651 // loop
4652 foreach( array_keys($filters) as $k ) {
4653
4654 $filters[ $k ] = true;
4655
4656 }
4657
4658
4659 // update
4660 acf_update_setting('_filters', $filters);
4661
4662 }
4663
4664
4665 /*
4666 * acf_disable_filters
4667 *
4668 * ACF uses filters to modify field group and field data
4669 * This function will disable them allowing ACF to interact only with raw DB data
4670 *
4671 * @type function
4672 * @date 14/07/2016
4673 * @since 5.4.0
4674 *
4675 * @param $post_id (int)
4676 * @return $post_id (int)
4677 */
4678
4679 function acf_disable_filters() {
4680
4681 // get filters
4682 $filters = acf_get_setting('_filters', array());
4683
4684
4685 // loop
4686 foreach( array_keys($filters) as $k ) {
4687
4688 $filters[ $k ] = false;
4689
4690 }
4691
4692
4693 // update
4694 acf_update_setting('_filters', $filters);
4695
4696 }
4697
4698
4699 /*
4700 * acf_is_filter_enabled
4701 *
4702 * ACF uses filters to modify field group and field data
4703 * This function will return true if they are enabled
4704 *
4705 * @type function
4706 * @date 14/07/2016
4707 * @since 5.4.0
4708 *
4709 * @param $post_id (int)
4710 * @return $post_id (int)
4711 */
4712
4713 function acf_is_filter_enabled( $filter = '' ) {
4714
4715 // get filters
4716 $filters = acf_get_setting('_filters', array());
4717
4718
4719 // bail early if not set
4720 return empty( $filters[ $filter ] ) ? false : true;
4721
4722 }
4723
4724
4725 /*
4726 * acf_send_ajax_results
4727 *
4728 * This function will print JSON data for a Select2 AJAX query
4729 *
4730 * @type function
4731 * @date 19/07/2016
4732 * @since 5.4.0
4733 *
4734 * @param $response (array)
4735 * @return n/a
4736 */
4737
4738 function acf_send_ajax_results( $response ) {
4739
4740 // validate
4741 $response = wp_parse_args($response, array(
4742 'results' => false,
4743 'more' => false,
4744 'limit' => 0
4745 ));
4746
4747
4748 // limit
4749 if( $response['limit'] && $response['results']) {
4750
4751 // vars
4752 $total = 0;
4753
4754 foreach( $response['results'] as $result ) {
4755
4756 // parent
4757 $total++;
4758
4759
4760 // children
4761 if( !empty($result['children']) ) {
4762
4763 $total += count( $result['children'] );
4764
4765 }
4766
4767 }
4768
4769
4770 // calc
4771 if( $total >= $response['limit'] ) {
4772
4773 $response['more'] = true;
4774
4775 }
4776
4777 }
4778
4779
4780 // return
4781 wp_send_json( $response );
4782
4783 }
4784
4785
4786 /*
4787 * acf_is_sequential_array
4788 *
4789 * This function will return true if the array contains only numeric keys
4790 *
4791 * @source http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
4792 * @type function
4793 * @date 9/09/2016
4794 * @since 5.4.0
4795 *
4796 * @param $array (array)
4797 * @return (boolean)
4798 */
4799
4800 function acf_is_sequential_array( $array ) {
4801
4802 // bail ealry if not array
4803 if( !is_array($array) ) return false;
4804
4805
4806 // loop
4807 foreach( $array as $key => $value ) {
4808
4809 // bail ealry if is string
4810 if( is_string($key) ) return false;
4811
4812 }
4813
4814
4815 // return
4816 return true;
4817
4818 }
4819
4820
4821 /*
4822 * acf_is_associative_array
4823 *
4824 * This function will return true if the array contains one or more string keys
4825 *
4826 * @source http://stackoverflow.com/questions/173400/how-to-check-if-php-array-is-associative-or-sequential
4827 * @type function
4828 * @date 9/09/2016
4829 * @since 5.4.0
4830 *
4831 * @param $array (array)
4832 * @return (boolean)
4833 */
4834
4835 function acf_is_associative_array( $array ) {
4836
4837 // bail ealry if not array
4838 if( !is_array($array) ) return false;
4839
4840
4841 // loop
4842 foreach( $array as $key => $value ) {
4843
4844 // bail ealry if is string
4845 if( is_string($key) ) return true;
4846
4847 }
4848
4849
4850 // return
4851 return false;
4852
4853 }
4854
4855
4856 /*
4857 * acf_add_array_key_prefix
4858 *
4859 * This function will add a prefix to all array keys
4860 * Useful to preserve numeric keys when performing array_multisort
4861 *
4862 * @type function
4863 * @date 15/09/2016
4864 * @since 5.4.0
4865 *
4866 * @param $array (array)
4867 * @param $prefix (string)
4868 * @return (array)
4869 */
4870
4871 function acf_add_array_key_prefix( $array, $prefix ) {
4872
4873 // vars
4874 $array2 = array();
4875
4876
4877 // loop
4878 foreach( $array as $k => $v ) {
4879
4880 $k2 = $prefix . $k;
4881 $array2[ $k2 ] = $v;
4882
4883 }
4884
4885
4886 // return
4887 return $array2;
4888
4889 }
4890
4891
4892 /*
4893 * acf_remove_array_key_prefix
4894 *
4895 * This function will remove a prefix to all array keys
4896 * Useful to preserve numeric keys when performing array_multisort
4897 *
4898 * @type function
4899 * @date 15/09/2016
4900 * @since 5.4.0
4901 *
4902 * @param $array (array)
4903 * @param $prefix (string)
4904 * @return (array)
4905 */
4906
4907 function acf_remove_array_key_prefix( $array, $prefix ) {
4908
4909 // vars
4910 $array2 = array();
4911 $l = strlen($prefix);
4912
4913
4914 // loop
4915 foreach( $array as $k => $v ) {
4916
4917 $k2 = (substr($k, 0, $l) === $prefix) ? substr($k, $l) : $k;
4918 $array2[ $k2 ] = $v;
4919
4920 }
4921
4922
4923 // return
4924 return $array2;
4925
4926 }
4927
4928
4929
4930
4931 add_filter("acf/settings/slug", '_acf_settings_slug');
4932
4933 function _acf_settings_slug( $v ) {
4934
4935 $basename = acf_get_setting('basename');
4936 $slug = explode('/', $basename);
4937 $slug = current($slug);
4938
4939 return $slug;
4940 }
4941
4942
4943
4944
4945 /*
4946 * acf_strip_protocol
4947 *
4948 * This function will remove the proticol from a url
4949 * Used to allow licences to remain active if a site is switched to https
4950 *
4951 * @type function
4952 * @date 10/01/2017
4953 * @since 5.5.4
4954 * @author Aaron
4955 *
4956 * @param $url (string)
4957 * @return (string)
4958 */
4959
4960 function acf_strip_protocol( $url ) {
4961
4962 // strip the protical
4963 return str_replace(array('http://','https://'), '', $url);
4964
4965 }
4966
4967
4968 /*
4969 * acf_connect_attachment_to_post
4970 *
4971 * This function will connect an attacment (image etc) to the post
4972 * Used to connect attachements uploaded directly to media that have not been attaced to a post
4973 *
4974 * @type function
4975 * @date 11/01/2017
4976 * @since 5.5.4
4977 *
4978 * @param $attachment_id (int)
4979 * @param $post_id (int)
4980 * @return (boolean)
4981 */
4982
4983 function acf_connect_attachment_to_post( $attachment_id = 0, $post_id = 0 ) {
4984
4985 // bail ealry if $attachment_id is not valid
4986 if( !$attachment_id || !is_numeric($attachment_id) ) return false;
4987
4988
4989 // bail ealry if $post_id is not valid
4990 if( !$post_id || !is_numeric($post_id) ) return false;
4991
4992
4993 // vars
4994 $post = get_post( $attachment_id );
4995
4996
4997 // check if valid post
4998 if( $post && $post->post_type == 'attachment' && $post->post_parent == 0 ) {
4999
5000 // update
5001 wp_update_post( array('ID' => $post->ID, 'post_parent' => $post_id) );
5002
5003
5004 // return
5005 return true;
5006
5007 }
5008
5009
5010 // return
5011 return true;
5012
5013 }
5014
5015
5016 /*
5017 * acf_encrypt
5018 *
5019 * This function will encrypt a string using PHP
5020 * https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/
5021 *
5022 * @type function
5023 * @date 27/2/17
5024 * @since 5.5.8
5025 *
5026 * @param $data (string)
5027 * @return (string)
5028 */
5029
5030
5031 function acf_encrypt( $data = '' ) {
5032
5033 // bail ealry if no encrypt function
5034 if( !function_exists('openssl_encrypt') ) return base64_encode($data);
5035
5036
5037 // generate a key
5038 $key = wp_hash('acf_encrypt');
5039
5040
5041 // Generate an initialization vector
5042 $iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length('aes-256-cbc'));
5043
5044
5045 // Encrypt the data using AES 256 encryption in CBC mode using our encryption key and initialization vector.
5046 $encrypted_data = openssl_encrypt($data, 'aes-256-cbc', $key, 0, $iv);
5047
5048
5049 // The $iv is just as important as the key for decrypting, so save it with our encrypted data using a unique separator (::)
5050 return base64_encode($encrypted_data . '::' . $iv);
5051
5052 }
5053
5054
5055 /*
5056 * acf_decrypt
5057 *
5058 * This function will decrypt an encrypted string using PHP
5059 * https://bhoover.com/using-php-openssl_encrypt-openssl_decrypt-encrypt-decrypt-data/
5060 *
5061 * @type function
5062 * @date 27/2/17
5063 * @since 5.5.8
5064 *
5065 * @param $data (string)
5066 * @return (string)
5067 */
5068
5069 function acf_decrypt( $data = '' ) {
5070
5071 // bail ealry if no decrypt function
5072 if( !function_exists('openssl_decrypt') ) return base64_decode($data);
5073
5074
5075 // generate a key
5076 $key = wp_hash('acf_encrypt');
5077
5078
5079 // To decrypt, split the encrypted data from our IV - our unique separator used was "::"
5080 list($encrypted_data, $iv) = explode('::', base64_decode($data), 2);
5081
5082
5083 // decrypt
5084 return openssl_decrypt($encrypted_data, 'aes-256-cbc', $key, 0, $iv);
5085
5086 }
5087
5088
5089 /*
5090 * acf_get_post_templates
5091 *
5092 * This function will return an array of all post templates (including parent theme templates)
5093 *
5094 * @type function
5095 * @date 29/8/17
5096 * @since 5.6.2
5097 *
5098 * @param n/a
5099 * @return (array)
5100 */
5101
5102 function acf_get_post_templates() {
5103
5104 // vars
5105 $post_types = acf_get_post_types();
5106 $post_templates = array();
5107
5108
5109 // loop
5110 foreach( $post_types as $post_type ) {
5111 $post_templates[ $post_type ] = wp_get_theme()->get_page_templates(null, $post_type);
5112 }
5113
5114
5115 // remove empty templates
5116 $post_templates = array_filter( $post_templates );
5117
5118
5119 // return
5120 return $post_templates;
5121
5122 }
5123
5124 ?>