PluginProbe
Advanced Custom Fields (ACF®) / 4.4.10
Advanced Custom Fields (ACF®) v4.4.10
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 / acf.php
acf.php
964 lines 20.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Plugin Name: Advanced Custom Fields
4 Plugin URI: http://www.advancedcustomfields.com/
5 Description: Customise WordPress with powerful, professional and intuitive fields
6 Version: 4.4.10
7 Author: Elliot Condon
8 Author URI: http://www.elliotcondon.com/
9 License: GPL
10 Copyright: Elliot Condon
11 */
12
13 if( !class_exists('acf') ):
14
15 class acf
16 {
17 // vars
18 var $settings;
19
20
21 /*
22 * Constructor
23 *
24 * This function will construct all the neccessary actions, filters and functions for the ACF plugin to work
25 *
26 * @type function
27 * @date 23/06/12
28 * @since 1.0.0
29 *
30 * @param N/A
31 * @return N/A
32 */
33
34 function __construct()
35 {
36 // helpers
37 add_filter('acf/helpers/get_path', array($this, 'helpers_get_path'), 1, 1);
38 add_filter('acf/helpers/get_dir', array($this, 'helpers_get_dir'), 1, 1);
39
40
41 // vars
42 $this->settings = array(
43 'path' => apply_filters('acf/helpers/get_path', __FILE__),
44 'dir' => apply_filters('acf/helpers/get_dir', __FILE__),
45 'hook' => basename( dirname( __FILE__ ) ) . '/' . basename( __FILE__ ),
46 'version' => '4.4.10',
47 'upgrade_version' => '3.4.1',
48 'include_3rd_party' => false
49 );
50
51
52 // set text domain
53 load_textdomain('acf', $this->settings['path'] . 'lang/acf-' . get_locale() . '.mo');
54
55
56 // actions
57 add_action('init', array($this, 'init'), 1);
58 add_action('acf/pre_save_post', array($this, 'save_post_lock'), 0);
59 add_action('acf/pre_save_post', array($this, 'save_post_unlock'), 999);
60 add_action('acf/save_post', array($this, 'save_post_lock'), 0);
61 add_action('acf/save_post', array($this, 'save_post'), 10);
62 add_action('acf/save_post', array($this, 'save_post_unlock'), 999);
63 add_action('acf/create_fields', array($this, 'create_fields'), 1, 2);
64
65
66 // filters
67 add_filter('acf/get_info', array($this, 'get_info'), 1, 1);
68 add_filter('acf/parse_types', array($this, 'parse_types'), 1, 1);
69 add_filter('acf/get_post_types', array($this, 'get_post_types'), 1, 3);
70 add_filter('acf/get_taxonomies_for_select', array($this, 'get_taxonomies_for_select'), 1, 2);
71 add_filter('acf/get_image_sizes', array($this, 'get_image_sizes'), 1, 1);
72 add_filter('acf/get_post_id', array($this, 'get_post_id'), 1, 1);
73
74
75 // includes
76 $this->include_before_theme();
77 add_action('after_setup_theme', array($this, 'include_after_theme'), 1);
78 add_action('after_setup_theme', array($this, 'include_3rd_party'), 1);
79
80 }
81
82
83 /*
84 * helpers_get_path
85 *
86 * This function will calculate the path to a file
87 *
88 * @type function
89 * @date 30/01/13
90 * @since 3.6.0
91 *
92 * @param $file (file) a reference to the file
93 * @return (string)
94 */
95
96 function helpers_get_path( $file )
97 {
98 return trailingslashit(dirname($file));
99 }
100
101
102 /*
103 * helpers_get_dir
104 *
105 * This function will calculate the directory (URL) to a file
106 *
107 * @type function
108 * @date 30/01/13
109 * @since 3.6.0
110 *
111 * @param $file (file) a reference to the file
112 * @return (string)
113 */
114
115 function helpers_get_dir( $file )
116 {
117 $dir = trailingslashit(dirname($file));
118 $count = 0;
119
120
121 // sanitize for Win32 installs
122 $dir = str_replace('\\' ,'/', $dir);
123
124
125 // if file is in plugins folder
126 $wp_plugin_dir = str_replace('\\' ,'/', WP_PLUGIN_DIR);
127 $dir = str_replace($wp_plugin_dir, plugins_url(), $dir, $count);
128
129
130 if( $count < 1 )
131 {
132 // if file is in wp-content folder
133 $wp_content_dir = str_replace('\\' ,'/', WP_CONTENT_DIR);
134 $dir = str_replace($wp_content_dir, content_url(), $dir, $count);
135 }
136
137
138 if( $count < 1 )
139 {
140 // if file is in ??? folder
141 $wp_dir = str_replace('\\' ,'/', ABSPATH);
142 $dir = str_replace($wp_dir, site_url('/'), $dir);
143 }
144
145
146 return $dir;
147 }
148
149
150 /*
151 * acf/get_post_id
152 *
153 * A helper function to filter the post_id variable.
154 *
155 * @type filter
156 * @date 27/05/13
157 *
158 * @param {mixed} $post_id
159 * @return {mixed} $post_id
160 */
161
162 function get_post_id( $post_id ) {
163
164 // if not $post_id, load queried object
165 if( !$post_id ) {
166
167 // try for global post (needed for setup_postdata)
168 $post_id = (int) get_the_ID();
169
170
171 // try for current screen
172 if( !$post_id ) {
173
174 $post_id = get_queried_object();
175
176 }
177
178 }
179
180
181 // $post_id may be an object
182 if( is_object($post_id) ) {
183
184 // user
185 if( isset($post_id->roles, $post_id->ID) ) {
186
187 $post_id = 'user_' . $post_id->ID;
188
189 // term
190 } elseif( isset($post_id->taxonomy, $post_id->term_id) ) {
191
192 $post_id = $post_id->taxonomy . '_' . $post_id->term_id;
193
194 // comment
195 } elseif( isset($post_id->comment_ID) ) {
196
197 $post_id = 'comment_' . $post_id->comment_ID;
198
199 // post
200 } elseif( isset($post_id->ID) ) {
201
202 $post_id = $post_id->ID;
203
204 // default
205 } else {
206
207 $post_id = 0;
208
209 }
210
211 }
212
213
214 // allow for option == options
215 if( $post_id === 'option' ) {
216
217 $post_id = 'options';
218
219 }
220
221
222 /*
223 * Override for preview
224 *
225 * If the $_GET['preview_id'] is set, then the user wants to see the preview data.
226 * There is also the case of previewing a page with post_id = 1, but using get_field
227 * to load data from another post_id.
228 * In this case, we need to make sure that the autosave revision is actually related
229 * to the $post_id variable. If they match, then the autosave data will be used, otherwise,
230 * the user wants to load data from a completely different post_id
231 */
232
233 if( isset($_GET['preview_id']) ) {
234
235 $autosave = wp_get_post_autosave( $_GET['preview_id'] );
236
237 if( $autosave && $autosave->post_parent == $post_id ) {
238
239 $post_id = (int) $autosave->ID;
240
241 }
242
243 }
244
245
246 // return
247 return $post_id;
248 }
249
250
251 /*
252 * get_info
253 *
254 * This function will return a setting from the settings array
255 *
256 * @type function
257 * @date 24/01/13
258 * @since 3.6.0
259 *
260 * @param $i (string) the setting to get
261 * @return (mixed)
262 */
263
264 function get_info( $i )
265 {
266 // vars
267 $return = false;
268
269
270 // specific
271 if( isset($this->settings[ $i ]) )
272 {
273 $return = $this->settings[ $i ];
274 }
275
276
277 // all
278 if( $i == 'all' )
279 {
280 $return = $this->settings;
281 }
282
283
284 // return
285 return $return;
286 }
287
288
289 /*
290 * parse_types
291 *
292 * @description: helper function to set the 'types' of variables
293 * @since: 2.0.4
294 * @created: 9/12/12
295 */
296
297 function parse_types( $value )
298 {
299 // vars
300 $restricted = array(
301 'label',
302 'name',
303 '_name',
304 'value',
305 'instructions'
306 );
307
308
309 // is value another array?
310 if( is_array($value) )
311 {
312 foreach( $value as $k => $v )
313 {
314 // bail early for restricted pieces
315 if( in_array($k, $restricted, true) )
316 {
317 continue;
318 }
319
320
321 // filter piece
322 $value[ $k ] = apply_filters( 'acf/parse_types', $v );
323 }
324 }
325 else
326 {
327 // string
328 if( is_string($value) )
329 {
330 $value = trim( $value );
331 }
332
333
334 // numbers
335 if( is_numeric($value) )
336 {
337 // check for non numeric characters
338 if( preg_match('/[^0-9]/', $value) )
339 {
340 // leave value if it contains such characters: . + - e
341 //$value = floatval( $value );
342 }
343 else
344 {
345 $value = intval( $value );
346 }
347 }
348 }
349
350
351 // return
352 return $value;
353 }
354
355
356 /*
357 * include_before_theme
358 *
359 * This function will include core files before the theme's functions.php file has been excecuted.
360 *
361 * @type action (plugins_loaded)
362 * @date 3/09/13
363 * @since 4.3.0
364 *
365 * @param N/A
366 * @return N/A
367 */
368
369 function include_before_theme()
370 {
371 // incudes
372 include_once('core/api.php');
373
374 include_once('core/controllers/input.php');
375 include_once('core/controllers/location.php');
376 include_once('core/controllers/field_group.php');
377
378
379 // admin only includes
380 if( is_admin() )
381 {
382 include_once('core/controllers/post.php');
383 include_once('core/controllers/revisions.php');
384 include_once('core/controllers/everything_fields.php');
385 include_once('core/controllers/field_groups.php');
386 }
387
388
389 // register fields
390 include_once('core/fields/_functions.php');
391 include_once('core/fields/_base.php');
392
393 include_once('core/fields/text.php');
394 include_once('core/fields/textarea.php');
395 include_once('core/fields/number.php');
396 include_once('core/fields/email.php');
397 include_once('core/fields/password.php');
398
399 include_once('core/fields/wysiwyg.php');
400 include_once('core/fields/image.php');
401 include_once('core/fields/file.php');
402
403 include_once('core/fields/select.php');
404 include_once('core/fields/checkbox.php');
405 include_once('core/fields/radio.php');
406 include_once('core/fields/true_false.php');
407
408 include_once('core/fields/page_link.php');
409 include_once('core/fields/post_object.php');
410 include_once('core/fields/relationship.php');
411 include_once('core/fields/taxonomy.php');
412 include_once('core/fields/user.php');
413
414 include_once('core/fields/google-map.php');
415 include_once('core/fields/date_picker/date_picker.php');
416 include_once('core/fields/color_picker.php');
417
418 include_once('core/fields/message.php');
419 include_once('core/fields/tab.php');
420
421 }
422
423
424 /*
425 * include_3rd_party
426 *
427 * This function will include 3rd party add-ons
428 *
429 * @type function
430 * @date 29/01/2014
431 * @since 5.0.0
432 *
433 * @param N/A
434 * @return N/A
435 */
436
437 function include_3rd_party() {
438
439 // run only once
440 if( $this->settings['include_3rd_party'] )
441 {
442 return false;
443 }
444
445
446 // update setting
447 $this->settings['include_3rd_party'] = true;
448
449
450 // include 3rd party fields
451 do_action('acf/register_fields');
452
453 }
454
455
456 /*
457 * include_after_theme
458 *
459 * This function will include core files after the theme's functions.php file has been excecuted.
460 *
461 * @type action (after_setup_theme)
462 * @date 3/09/13
463 * @since 4.3.0
464 *
465 * @param N/A
466 * @return N/A
467 */
468
469 function include_after_theme() {
470
471 // bail early if user has defined LITE_MODE as true
472 if( defined('ACF_LITE') && ACF_LITE )
473 {
474 return;
475 }
476
477
478 // admin only includes
479 if( is_admin() )
480 {
481 include_once('core/controllers/export.php');
482 include_once('core/controllers/addons.php');
483 include_once('core/controllers/third_party.php');
484 include_once('core/controllers/upgrade.php');
485 }
486
487 }
488
489
490 /*
491 * init
492 *
493 * This function is called during the 'init' action and will do things such as:
494 * create post_type, register scripts, add actions / filters
495 *
496 * @type action (init)
497 * @date 23/06/12
498 * @since 1.0.0
499 *
500 * @param N/A
501 * @return N/A
502 */
503
504 function init()
505 {
506
507 // Create ACF post type
508 $labels = array(
509 'name' => __( 'Field&nbsp;Groups', 'acf' ),
510 'singular_name' => __( 'Advanced Custom Fields', 'acf' ),
511 'add_new' => __( 'Add New' , 'acf' ),
512 'add_new_item' => __( 'Add New Field Group' , 'acf' ),
513 'edit_item' => __( 'Edit Field Group' , 'acf' ),
514 'new_item' => __( 'New Field Group' , 'acf' ),
515 'view_item' => __('View Field Group', 'acf'),
516 'search_items' => __('Search Field Groups', 'acf'),
517 'not_found' => __('No Field Groups found', 'acf'),
518 'not_found_in_trash' => __('No Field Groups found in Trash', 'acf'),
519 );
520
521 register_post_type('acf', array(
522 'labels' => $labels,
523 'public' => false,
524 'show_ui' => true,
525 '_builtin' => false,
526 'capability_type' => 'page',
527 'hierarchical' => true,
528 'rewrite' => false,
529 'query_var' => "acf",
530 'supports' => array(
531 'title',
532 ),
533 'show_in_menu' => false,
534 ));
535
536
537 // min
538 $min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
539
540
541 // register acf scripts
542 $scripts = array();
543 $scripts[] = array(
544 'handle' => 'acf-field-group',
545 'src' => $this->settings['dir'] . "js/field-group{$min}.js",
546 'deps' => array('jquery')
547 );
548 $scripts[] = array(
549 'handle' => 'acf-input',
550 'src' => $this->settings['dir'] . "js/input{$min}.js",
551 'deps' => array('jquery', 'jquery-ui-core', 'jquery-ui-datepicker')
552 );
553
554
555 foreach( $scripts as $script )
556 {
557 wp_register_script( $script['handle'], $script['src'], $script['deps'], $this->settings['version'] );
558 }
559
560
561 // register acf styles
562 $styles = array(
563 'acf' => $this->settings['dir'] . 'css/acf.css',
564 'acf-field-group' => $this->settings['dir'] . 'css/field-group.css',
565 'acf-global' => $this->settings['dir'] . 'css/global.css',
566 'acf-input' => $this->settings['dir'] . 'css/input.css',
567 'acf-datepicker' => $this->settings['dir'] . 'core/fields/date_picker/style.date_picker.css',
568 );
569
570 foreach( $styles as $k => $v )
571 {
572 wp_register_style( $k, $v, false, $this->settings['version'] );
573 }
574
575
576 // bail early if user has defined LITE_MODE as true
577 if( defined('ACF_LITE') && ACF_LITE )
578 {
579 return;
580 }
581
582
583 // admin only
584 if( is_admin() )
585 {
586 add_action('admin_menu', array($this,'admin_menu'));
587 add_action('admin_head', array($this,'admin_head'));
588 add_filter('post_updated_messages', array($this, 'post_updated_messages'));
589 }
590 }
591
592
593 /*
594 * admin_menu
595 *
596 * @description:
597 * @since 1.0.0
598 * @created: 23/06/12
599 */
600
601 function admin_menu()
602 {
603 add_menu_page(__("Custom Fields",'acf'), __("Custom Fields",'acf'), 'manage_options', 'edit.php?post_type=acf', false, false, '80.025');
604 }
605
606
607 /*
608 * post_updated_messages
609 *
610 * @description: messages for saving a field group
611 * @since 1.0.0
612 * @created: 23/06/12
613 */
614
615 function post_updated_messages( $messages )
616 {
617 global $post, $post_ID;
618
619 $messages['acf'] = array(
620 0 => '', // Unused. Messages start at index 1.
621 1 => __('Field group updated.', 'acf'),
622 2 => __('Custom field updated.', 'acf'),
623 3 => __('Custom field deleted.', 'acf'),
624 4 => __('Field group updated.', 'acf'),
625 /* translators: %s: date and time of the revision */
626 5 => isset($_GET['revision']) ? sprintf( __('Field group restored to revision from %s', 'acf'), wp_post_revision_title( (int) $_GET['revision'], false ) ) : false,
627 6 => __('Field group published.', 'acf'),
628 7 => __('Field group saved.', 'acf'),
629 8 => __('Field group submitted.', 'acf'),
630 9 => __('Field group scheduled for.', 'acf'),
631 10 => __('Field group draft updated.', 'acf'),
632 );
633
634 return $messages;
635 }
636
637
638 /*--------------------------------------------------------------------------------------
639 *
640 * admin_head
641 *
642 * @author Elliot Condon
643 * @since 1.0.0
644 *
645 *-------------------------------------------------------------------------------------*/
646
647 function admin_head()
648 {
649 ?>
650 <style type="text/css">
651 #adminmenu #toplevel_page_edit-post_type-acf a[href="edit.php?post_type=acf&page=acf-upgrade"]{ display: none; }
652 #adminmenu #toplevel_page_edit-post_type-acf .wp-menu-image { background-position: 1px -33px; }
653 #adminmenu #toplevel_page_edit-post_type-acf:hover .wp-menu-image,
654 #adminmenu #toplevel_page_edit-post_type-acf.wp-menu-open .wp-menu-image { background-position: 1px -1px; }
655 </style>
656 <?php
657 }
658
659
660 /*
661 * get_taxonomies_for_select
662 *
663 * @description:
664 * @since: 3.6
665 * @created: 27/01/13
666 */
667
668 function get_taxonomies_for_select( $choices, $simple_value = false )
669 {
670 // vars
671 $post_types = get_post_types();
672
673
674 if($post_types)
675 {
676 foreach($post_types as $post_type)
677 {
678 $post_type_object = get_post_type_object($post_type);
679 $taxonomies = get_object_taxonomies($post_type);
680 if($taxonomies)
681 {
682 foreach($taxonomies as $taxonomy)
683 {
684 if(!is_taxonomy_hierarchical($taxonomy)) continue;
685 $terms = get_terms($taxonomy, array('hide_empty' => false));
686 if($terms)
687 {
688 foreach($terms as $term)
689 {
690 $value = $taxonomy . ':' . $term->term_id;
691
692 if( $simple_value )
693 {
694 $value = $term->term_id;
695 }
696
697 $choices[$post_type_object->label . ': ' . $taxonomy][$value] = $term->name;
698 }
699 }
700 }
701 }
702 }
703 }
704
705 return $choices;
706 }
707
708
709 /*
710 * get_post_types
711 *
712 * @description:
713 * @since: 3.5.5
714 * @created: 16/12/12
715 */
716
717 function get_post_types( $post_types, $exclude = array(), $include = array() )
718 {
719 // get all custom post types
720 $post_types = array_merge($post_types, get_post_types());
721
722
723 // core include / exclude
724 $acf_includes = array_merge( array(), $include );
725 $acf_excludes = array_merge( array( 'acf', 'revision', 'nav_menu_item' ), $exclude );
726
727
728 // include
729 foreach( $acf_includes as $p )
730 {
731 if( post_type_exists($p) )
732 {
733 $post_types[ $p ] = $p;
734 }
735 }
736
737
738 // exclude
739 foreach( $acf_excludes as $p )
740 {
741 unset( $post_types[ $p ] );
742 }
743
744
745 return $post_types;
746
747 }
748
749
750 /*
751 * get_image_sizes
752 *
753 * @description: returns an array holding all the image sizes
754 * @since 3.2.8
755 * @created: 6/07/12
756 */
757
758 function get_image_sizes( $sizes )
759 {
760 // find all sizes
761 $all_sizes = get_intermediate_image_sizes();
762
763
764 // define default sizes
765 $sizes = array_merge($sizes, array(
766 'thumbnail' => __("Thumbnail",'acf'),
767 'medium' => __("Medium",'acf'),
768 'large' => __("Large",'acf'),
769 'full' => __("Full",'acf')
770 ));
771
772
773 // add extra registered sizes
774 foreach( $all_sizes as $size )
775 {
776 if( !isset($sizes[ $size ]) )
777 {
778 $sizes[ $size ] = ucwords( str_replace('-', ' ', $size) );
779 }
780 }
781
782
783 // return array
784 return $sizes;
785 }
786
787
788 /*
789 * render_fields_for_input
790 *
791 * @description:
792 * @since 3.1.6
793 * @created: 23/06/12
794 */
795
796 function create_fields( $fields, $post_id )
797 {
798 if( is_array($fields) ){ foreach( $fields as $field ){
799
800 // if they didn't select a type, skip this field
801 if( !$field || !$field['type'] || $field['type'] == 'null' )
802 {
803 continue;
804 }
805
806
807 // set value
808 if( !isset($field['value']) )
809 {
810 $field['value'] = apply_filters('acf/load_value', false, $post_id, $field);
811 $field['value'] = apply_filters('acf/format_value', $field['value'], $post_id, $field);
812 }
813
814
815 // required
816 $required_class = "";
817 $required_label = "";
818
819 if( $field['required'] )
820 {
821 $required_class = ' required';
822 $required_label = ' <span class="required">*</span>';
823 }
824
825
826 echo '<div id="acf-' . $field['name'] . '" class="field field_type-' . $field['type'] . ' field_key-' . $field['key'] . $required_class . '" data-field_name="' . $field['name'] . '" data-field_key="' . $field['key'] . '" data-field_type="' . $field['type'] . '">';
827
828 echo '<p class="label">';
829 echo '<label for="' . $field['id'] . '">' . $field['label'] . $required_label . '</label>';
830 echo $field['instructions'];
831 echo '</p>';
832
833 $field['name'] = 'fields[' . $field['key'] . ']';
834 do_action('acf/create_field', $field, $post_id);
835
836 echo '</div>';
837
838 }}
839
840 }
841
842
843 /*
844 * save_post_lock
845 *
846 * This action sets a global variable which locks the ACF save functions to this ID.
847 * This prevents an inifinite loop if a user was to hook into the save and create a new post
848 *
849 * @type function
850 * @date 16/07/13
851 *
852 * @param {int} $post_id
853 * @return {int} $post_id
854 */
855
856 function save_post_lock( $post_id )
857 {
858 $GLOBALS['acf_save_lock'] = $post_id;
859
860 return $post_id;
861 }
862
863
864 /*
865 * save_post_unlock
866 *
867 * This action sets a global variable which unlocks the ACF save functions to this ID.
868 * This prevents an inifinite loop if a user was to hook into the save and create a new post
869 *
870 * @type function
871 * @date 16/07/13
872 *
873 * @param {int} $post_id
874 * @return {int} $post_id
875 */
876
877 function save_post_unlock( $post_id )
878 {
879 $GLOBALS['acf_save_lock'] = false;
880
881 return $post_id;
882 }
883
884
885 /*
886 * save_post
887 *
888 * @description:
889 * @since: 3.6
890 * @created: 28/01/13
891 */
892
893 function save_post( $post_id )
894 {
895
896 // load from post
897 if( !isset($_POST['fields']) )
898 {
899 return $post_id;
900 }
901
902
903 // loop through and save
904 if( !empty($_POST['fields']) )
905 {
906 // loop through and save $_POST data
907 foreach( $_POST['fields'] as $k => $v )
908 {
909 // get field
910 $f = apply_filters('acf/load_field', false, $k );
911
912 // update field
913 do_action('acf/update_value', $v, $post_id, $f );
914
915 }
916 // foreach($fields as $key => $value)
917 }
918 // if($fields)
919
920
921 return $post_id;
922 }
923
924
925 }
926
927
928 /*
929 * acf
930 *
931 * The main function responsible for returning the one true acf Instance to functions everywhere.
932 * Use this function like you would a global variable, except without needing to declare the global.
933 *
934 * Example: <?php $acf = acf(); ?>
935 *
936 * @type function
937 * @date 4/09/13
938 * @since 4.3.0
939 *
940 * @param N/A
941 * @return (object)
942 */
943
944 function acf()
945 {
946 global $acf;
947
948 if( !isset($acf) )
949 {
950 $acf = new acf();
951 }
952
953 return $acf;
954 }
955
956
957 // initialize
958 acf();
959
960
961 endif; // class_exists check
962
963 ?>
964