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