PluginProbe
Virtue/Ascend/Pinnacle Toolkit / 2.9
Virtue/Ascend/Pinnacle Toolkit v2.9
trunk 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2.0 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 2.9 3.0 3.1 3.2 3.3 3.4 3.7 3.8 All 47 releases
virtue-toolkit / cmb / init.php

init.php in Virtue/Ascend/Pinnacle Toolkit 2.9, at cmb/init.php

1,187 lines 35.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 Script Name: Custom Metaboxes and Fields
4 Contributors: WebDevStudios (@webdevstudios / webdevstudios.com)
5 Justin Sternberg (@jtsternberg / dsgnwrks.pro)
6 Jared Atchison (@jaredatch / jaredatchison.com)
7 Bill Erickson (@billerickson / billerickson.net)
8 Andrew Norcross (@norcross / andrewnorcross.com)
9 Description: This will create metaboxes with custom fields that will blow your mind.
10 Version: 1.2.0
11 */
12
13 /**
14 * Released under the GPL license
15 * http://www.opensource.org/licenses/gpl-license.php
16 *
17 * This is an add-on for WordPress
18 * http://wordpress.org/
19 *
20 * **********************************************************************
21 * This program is free software; you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation; either version 2 of the License, or
24 * (at your option) any later version.
25 *
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
30 * **********************************************************************
31 */
32
33 /************************************************************************
34 You should not edit the code below or things might explode!
35 *************************************************************************/
36
37 // Autoload helper classes
38 spl_autoload_register('cmb_Meta_Box::autoload_helpers');
39
40 $meta_boxes = array();
41 $meta_boxes = apply_filters( 'cmb_meta_boxes', $meta_boxes );
42 foreach ( $meta_boxes as $meta_box ) {
43 $my_box = new cmb_Meta_Box( $meta_box );
44 }
45
46 define( 'CMB_META_BOX_URL', cmb_Meta_Box::get_meta_box_url() );
47
48 /**
49 * Create meta boxes
50 */
51 class cmb_Meta_Box {
52
53 /**
54 * Current version number
55 * @var string
56 * @since 1.0.0
57 */
58 const CMB_VERSION = '1.2.0';
59
60 /**
61 * Metabox Config array
62 * @var array
63 * @since 0.9.0
64 */
65 protected $_meta_box;
66
67 /**
68 * Metabox Defaults
69 * @var array
70 * @since 1.0.1
71 */
72 protected static $mb_defaults = array(
73 'id' => '',
74 'title' => '',
75 'type' => '',
76 'pages' => array(), // Post type
77 'context' => 'normal',
78 'priority' => 'high',
79 'show_names' => true, // Show field names on the left
80 'show_on' => array( 'key' => false, 'value' => false ), // Specific post IDs or page templates to display this metabox
81 'cmb_styles' => true, // Include cmb bundled stylesheet
82 'fields' => array(),
83 );
84
85 /**
86 * Metabox Form ID
87 * @var string
88 * @since 0.9.4
89 */
90 protected $form_id = 'post';
91
92 /**
93 * Current field config array
94 * @var array
95 * @since 1.0.0
96 */
97 public static $field = array();
98
99 /**
100 * Object ID for metabox meta retrieving/saving
101 * @var int
102 * @since 1.0.0
103 */
104 protected static $object_id = 0;
105
106 /**
107 * Type of object being saved. (e.g., post, user, or comment)
108 * @var string
109 * @since 1.0.0
110 */
111 protected static $object_type = '';
112
113 /**
114 * Whether scripts/styles have been enqueued yet
115 * @var bool
116 * @since 1.0.0
117 */
118 protected static $is_enqueued = false;
119
120 /**
121 * Whether CMB nonce has been added to the page. (oly add once)
122 * @var bool
123 * @since 1.2.0
124 */
125 protected static $nonce_added = false;
126
127 /**
128 * Type of object specified by the metabox Config
129 * @var string
130 * @since 1.0.0
131 */
132 protected static $mb_object_type = 'post';
133
134 /**
135 * Array of all options from manage-options metaboxes
136 * @var array
137 * @since 1.0.0
138 */
139 protected static $options = array();
140
141 /**
142 * List of fields that are changed/updated on save
143 * @var array
144 * @since 1.1.0
145 */
146 protected static $updated = array();
147
148 /**
149 * Get started
150 */
151 function __construct( $meta_box ) {
152
153 $meta_box = self::set_mb_defaults( $meta_box );
154
155 $allow_frontend = apply_filters( 'cmb_allow_frontend', true, $meta_box );
156
157 if ( ! is_admin() && ! $allow_frontend )
158 return;
159
160 $this->_meta_box = $meta_box;
161
162 self::set_mb_type( $meta_box );
163
164 $types = wp_list_pluck( $meta_box['fields'], 'type' );
165 $upload = in_array( 'file', $types ) || in_array( 'file_list', $types );
166
167 global $pagenow;
168
169 $show_filters = 'cmb_Meta_Box_Show_Filters';
170 foreach ( get_class_methods( $show_filters ) as $filter ) {
171 add_filter( 'cmb_show_on', array( $show_filters, $filter ), 10, 2 );
172 }
173
174 // register our scripts and styles for cmb
175 add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ), 8 );
176
177 if ( self::get_object_type() == 'post' ) {
178 add_action( 'admin_menu', array( $this, 'add_metaboxes' ) );
179 add_action( 'add_attachment', array( $this, 'save_post' ) );
180 add_action( 'edit_attachment', array( $this, 'save_post' ) );
181 add_action( 'save_post', array( $this, 'save_post' ), 10, 2 );
182 add_action( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) );
183
184 if ( $upload && in_array( $pagenow, array( 'page.php', 'page-new.php', 'post.php', 'post-new.php' ) ) ) {
185 add_action( 'admin_head', array( $this, 'add_post_enctype' ) );
186 }
187
188 }
189 if ( self::get_object_type() == 'user' ) {
190
191 $priority = 10;
192 if ( isset( $meta_box['priority'] ) ) {
193 if ( is_numeric( $meta_box['priority'] ) )
194 $priority = $meta_box['priority'];
195 elseif ( $meta_box['priority'] == 'high' )
196 $priority = 5;
197 elseif ( $meta_box['priority'] == 'low' )
198 $priority = 20;
199 }
200 add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority );
201 add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority );
202
203 add_action( 'personal_options_update', array( $this, 'save_user' ) );
204 add_action( 'edit_user_profile_update', array( $this, 'save_user' ) );
205 if ( $upload && in_array( $pagenow, array( 'profile.php', 'user-edit.php' ) ) ) {
206 $this->form_id = 'your-profile';
207 add_action( 'admin_head', array( $this, 'add_post_enctype' ) );
208 }
209 }
210
211 }
212
213 /**
214 * Autoloads files with classes when needed
215 * @since 1.0.0
216 * @param string $class_name Name of the class being requested
217 */
218 public static function autoload_helpers( $class_name ) {
219 if ( class_exists( $class_name, false ) )
220 return;
221
222 // for PHP versions < 5.3
223 $dir = dirname( __FILE__ );
224
225 $file = "$dir/helpers/$class_name.php";
226 if ( file_exists( $file ) )
227 @include( $file );
228 }
229
230 /**
231 * Registers scripts and styles for CMB
232 * @since 1.0.0
233 */
234 public function register_scripts() {
235
236 // Should only be run once
237 if ( self::$is_enqueued )
238 return;
239
240 global $wp_version;
241 // Only use minified files if SCRIPT_DEBUG is off
242 $min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min';
243
244 // scripts required for cmb
245 $scripts = array( 'jquery', 'jquery-ui-core', 'cmb-datepicker', /*'media-upload', */'cmb-timepicker' );
246 // styles required for cmb
247 $styles = array();
248
249 // if we're 3.5 or later, user wp-color-picker
250 if ( 3.5 <= $wp_version ) {
251 $scripts[] = 'wp-color-picker';
252 $styles[] = 'wp-color-picker';
253 if ( ! is_admin() ) {
254 // we need to register colorpicker on the front-end
255 wp_register_script( 'iris', admin_url( 'js/iris.min.js' ), array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), self::CMB_VERSION );
256 wp_register_script( 'wp-color-picker', admin_url( 'js/color-picker.min.js' ), array( 'iris' ), self::CMB_VERSION );
257 wp_localize_script( 'wp-color-picker', 'wpColorPickerL10n', array(
258 'clear' => __( 'Clear' ),
259 'defaultString' => __( 'Default' ),
260 'pick' => __( 'Select Color' ),
261 'current' => __( 'Current Color' ),
262 ) );
263 }
264 } else {
265 // otherwise use the older 'farbtastic'
266 $scripts[] = 'farbtastic';
267 $styles[] = 'farbtastic';
268 }
269 wp_register_script( 'cmb-datepicker', CMB_META_BOX_URL . 'js/jquery.datePicker.min.js' );
270 wp_register_script( 'cmb-timepicker', CMB_META_BOX_URL . 'js/jquery.timePicker.min.js' );
271 wp_register_script( 'cmb-scripts', CMB_META_BOX_URL .'js/cmb'. $min .'.js', $scripts, self::CMB_VERSION );
272
273 wp_enqueue_media();
274
275 wp_localize_script( 'cmb-scripts', 'cmb_l10', apply_filters( 'cmb_localized_data', array(
276 'ajax_nonce' => wp_create_nonce( 'ajax_nonce' ),
277 'script_debug' => defined('SCRIPT_DEBUG') && SCRIPT_DEBUG,
278 'new_admin_style' => version_compare( $wp_version, '3.7', '>' ),
279 'object_type' => self::get_object_type(),
280 'upload_file' => 'Use this file',
281 'remove_image' => 'Remove Image',
282 'remove_file' => 'Remove',
283 'file' => 'File:',
284 'download' => 'Download',
285 'ajaxurl' => admin_url( '/admin-ajax.php' ),
286 'up_arrow' => '[ ↑ ]&nbsp;',
287 'down_arrow' => '&nbsp;[ ↓ ]',
288 'check_toggle' => __( 'Select / Deselect All', 'cmb' ),
289 ) ) );
290
291 wp_register_style( 'cmb-styles', CMB_META_BOX_URL . 'style'. $min .'.css', $styles );
292
293 // Ok, we've enqueued our scripts/styles
294 self::$is_enqueued = true;
295 }
296
297 /**
298 * Enqueues scripts and styles for CMB
299 * @since 1.0.0
300 */
301 public function do_scripts( $hook ) {
302 // only enqueue our scripts/styles on the proper pages
303 if ( $hook == 'post.php' || $hook == 'post-new.php' || $hook == 'page-new.php' || $hook == 'page.php' ) {
304 wp_enqueue_script( 'cmb-scripts' );
305
306 // default is to show cmb styles on post pages
307 if ( $this->_meta_box['cmb_styles'] )
308 wp_enqueue_style( 'cmb-styles' );
309 }
310 }
311
312 /**
313 * Add encoding attribute
314 */
315 public function add_post_enctype() {
316 echo '
317 <script type="text/javascript">
318 jQuery(document).ready(function(){
319 jQuery("#'. $this->form_id .'").attr("enctype", "multipart/form-data");
320 jQuery("#'. $this->form_id .'").attr("encoding", "multipart/form-data");
321 });
322 </script>';
323 }
324
325 /**
326 * Add metaboxes (to 'post' object type)
327 */
328 public function add_metaboxes() {
329
330 foreach ( $this->_meta_box['pages'] as $page ) {
331 if ( apply_filters( 'cmb_show_on', true, $this->_meta_box ) )
332 add_meta_box( $this->_meta_box['id'], $this->_meta_box['title'], array( $this, 'post_metabox' ), $page, $this->_meta_box['context'], $this->_meta_box['priority']) ;
333 }
334 }
335
336 /**
337 * Display metaboxes for a post object
338 * @since 1.0.0
339 */
340 public function post_metabox() {
341 if ( ! $this->_meta_box )
342 return;
343
344 self::show_form( $this->_meta_box, get_the_ID(), 'post' );
345
346 }
347
348 /**
349 * Display metaboxes for a user object
350 * @since 1.0.0
351 */
352 public function user_metabox() {
353 if ( ! $this->_meta_box )
354 return;
355
356 if ( 'user' != self::set_mb_type( $this->_meta_box ) )
357 return;
358
359 if ( ! apply_filters( 'cmb_show_on', true, $this->_meta_box ) )
360 return;
361
362 wp_enqueue_script( 'cmb-scripts' );
363
364 // default is to NOT show cmb styles on user profile page
365 if ( $this->_meta_box['cmb_styles'] != false )
366 wp_enqueue_style( 'cmb-styles' );
367
368 self::show_form( $this->_meta_box );
369
370 }
371
372 /**
373 * Loops through and displays fields
374 * @since 1.0.0
375 * @param array $meta_box Metabox config array
376 * @param int $object_id Object ID
377 * @param string $object_type Type of object being saved. (e.g., post, user, or comment)
378 */
379 public static function show_form( $meta_box, $object_id = 0, $object_type = '' ) {
380 $meta_box = self::set_mb_defaults( $meta_box );
381 // Set/get type
382 $object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) );
383 // Set/get ID
384 $object_id = self::set_object_id( $object_id ? $object_id : self::get_object_id() );
385
386 // Add nonce only once per page.
387 if ( ! self::$nonce_added ) {
388 wp_nonce_field( self::nonce(), 'wp_meta_box_nonce', false, true );
389 self::$nonce_added = true;
390 }
391
392 // Use nonce for verification
393 echo "\n<!-- Begin CMB Fields -->\n";
394 do_action( 'cmb_before_table', $meta_box, $object_id, $object_type );
395 echo '<table class="form-table cmb_metabox">';
396
397 foreach ( $meta_box['fields'] as $field_args ) {
398
399 $field_args['context'] = $meta_box['context'];
400
401 if ( 'group' == $field_args['type'] ) {
402
403 if ( ! isset( $field_args['show_names'] ) ) {
404 $field_args['show_names'] = $meta_box['show_names'];
405 }
406 self::render_group( $field_args );
407 } else {
408
409 $field_args['show_names'] = $meta_box['show_names'];
410 // Render default fields
411 $field = new cmb_Meta_Box_field( $field_args );
412 $field->render_field();
413 }
414 }
415 echo '</table>';
416 do_action( 'cmb_after_table', $meta_box, $object_id, $object_type );
417 echo "\n<!-- End CMB Fields -->\n";
418
419 }
420
421 /**
422 * Render a repeatable group
423 */
424 public static function render_group( $args ) {
425 if ( ! isset( $args['id'], $args['fields'] ) || ! is_array( $args['fields'] ) )
426 return;
427
428 $args['count'] = 0;
429 $field_group = new cmb_Meta_Box_field( $args );
430 $desc = $field_group->args( 'description' );
431 $label = $field_group->args( 'name' );
432 $sortable = $field_group->options( 'sortable' ) ? ' sortable' : '';
433 $group_val = (array) $field_group->value();
434 $nrows = count( $group_val );
435 $remove_disabled = $nrows <= 1 ? 'disabled="disabled" ' : '';
436
437 echo '<tr><td colspan="2"><table id="', $field_group->id(), '_repeat" class="repeatable-group'. $sortable .'" style="width:100%;">';
438 if ( $desc || $label ) {
439 echo '<tr><th>';
440 if ( $label )
441 echo '<h2 class="cmb-group-name">'. $label .'</h2>';
442 if ( $desc )
443 echo '<p class="cmb_metabox_description">'. $desc .'</p>';
444 echo '</th></tr>';
445 }
446
447 if ( ! empty( $group_val ) ) {
448
449 foreach ( $group_val as $iterator => $field_id ) {
450 self::render_group_row( $field_group, $remove_disabled );
451 }
452 } else {
453 self::render_group_row( $field_group, $remove_disabled );
454 }
455
456 echo '<tr><td><p class="add-row"><button data-selector="', $field_group->id() ,'_repeat" data-grouptitle="', $field_group->options( 'group_title' ) ,'" class="add-group-row button">'. $field_group->options( 'add_button' ) .'</button></p></td></tr>';
457
458 echo '</table></td></tr>';
459
460 }
461
462 public static function render_group_row( $field_group, $remove_disabled ) {
463
464 echo '
465 <tr class="repeatable-grouping" data-iterator="'. $field_group->count() .'">
466 <td>
467 <table class="cmb-nested-table" style="width: 100%;">';
468 if ( $field_group->options( 'group_title' ) ) {
469 echo '
470 <tr class="cmb-group-title">
471 <th colspan="2">
472 ', sprintf( '<h4>%1$s</h4>', $field_group->replace_hash( $field_group->options( 'group_title' ) ) ), '
473 <th>
474 </tr>
475 ';
476 }
477 // Render repeatable group fields
478 foreach ( array_values( $field_group->args( 'fields' ) ) as $field_args ) {
479 $field_args['show_names'] = $field_group->args( 'show_names' );
480 $field_args['context'] = $field_group->args( 'context' );
481 $field = new cmb_Meta_Box_field( $field_args, $field_group );
482 $field->render_field();
483 }
484 echo '
485 <tr>
486 <td class="remove-row" colspan="2">
487 <button '. $remove_disabled .'data-selector="'. $field_group->id() .'_repeat" class="button remove-group-row alignright">'. $field_group->options( 'remove_button' ) .'</button>
488 </td>
489 </tr>
490 </table>
491 </td>
492 </tr>
493 ';
494
495 $field_group->args['count']++;
496 }
497
498 /**
499 * Save data from metabox
500 */
501 public function save_post( $post_id, $post = false ) {
502
503 $post_type = $post ? $post->post_type : get_post_type( $post_id );
504
505 // check permissions
506 if (
507 // check nonce
508 ! isset( $_POST['wp_meta_box_nonce'] )
509 || ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() )
510 // check if autosave
511 || defined('DOING_AUTOSAVE' ) && DOING_AUTOSAVE
512 // check user editing permissions
513 || ( 'page' == $_POST['post_type'] && ! current_user_can( 'edit_page', $post_id ) )
514 || ! current_user_can( 'edit_post', $post_id )
515 // get the metabox post_types & compare it to this post_type
516 || ! in_array( $post_type, $this->_meta_box['pages'] )
517 )
518 return $post_id;
519
520 self::save_fields( $this->_meta_box, $post_id, 'post' );
521 }
522
523 /**
524 * Save data from metabox
525 */
526 public function save_user( $user_id ) {
527
528 // check permissions
529 // @todo more hardening?
530 if (
531 // check nonce
532 ! isset( $_POST['wp_meta_box_nonce'] )
533 || ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() )
534 )
535 return $user_id;
536
537 self::save_fields( $this->_meta_box, $user_id, 'user' );
538 }
539
540 /**
541 * Loops through and saves field data
542 * @since 1.0.0
543 * @param array $meta_box Metabox config array
544 * @param int $object_id Object ID
545 * @param string $object_type Type of object being saved. (e.g., post, user, or comment)
546 */
547 public static function save_fields( $meta_box, $object_id, $object_type = '' ) {
548 $meta_box = self::set_mb_defaults( $meta_box );
549
550 $meta_box['show_on'] = empty( $meta_box['show_on'] ) ? array( 'key' => false, 'value' => false ) : $meta_box['show_on'];
551
552 self::set_object_id( $object_id );
553 // Set/get type
554 $object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) );
555
556 if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) )
557 return;
558
559 // save field ids of those that are updated
560 self::$updated = array();
561
562 foreach ( $meta_box['fields'] as $field_args ) {
563
564 if ( 'group' == $field_args['type'] ) {
565 self::save_group( $field_args );
566 } else {
567 // Save default fields
568 $field = new cmb_Meta_Box_field( $field_args );
569 self::save_field( self::sanitize_field( $field ), $field );
570 }
571
572 }
573
574 // If options page, save the updated options
575 if ( $object_type == 'options-page' )
576 self::save_option( $object_id );
577
578 do_action( "cmb_save_{$object_type}_fields", $object_id, $meta_box['id'], self::$updated, $meta_box );
579
580 }
581
582 /**
583 * Save a repeatable group
584 */
585 public static function save_group( $args ) {
586 if ( ! isset( $args['id'], $args['fields'], $_POST[ $args['id'] ] ) || ! is_array( $args['fields'] ) )
587 return;
588
589 $field_group = new cmb_Meta_Box_field( $args );
590 $base_id = $field_group->id();
591 $old = $field_group->get_data();
592 $group_vals = $_POST[ $base_id ];
593 $saved = array();
594 $is_updated = false;
595 $field_group->index = 0;
596
597 // $group_vals[0]['color'] = '333';
598 foreach ( array_values( $field_group->fields() ) as $field_args ) {
599 $field = new cmb_Meta_Box_field( $field_args, $field_group );
600 $sub_id = $field->id( true );
601
602 foreach ( (array) $group_vals as $field_group->index => $post_vals ) {
603
604 // Get value
605 $new_val = isset( $group_vals[ $field_group->index ][ $sub_id ] )
606 ? $group_vals[ $field_group->index ][ $sub_id ]
607 : false;
608
609 // Sanitize
610 $new_val = self::sanitize_field( $field, $new_val, $field_group->index );
611
612 if ( 'file' == $field->type() && is_array( $new_val ) ) {
613 // Add image ID to the array stack
614 $saved[ $field_group->index ][ $new_val['field_id'] ] = $new_val['attach_id'];
615 // Reset var to url string
616 $new_val = $new_val['url'];
617 }
618
619 // Get old value
620 $old_val = is_array( $old ) && isset( $old[ $field_group->index ][ $sub_id ] )
621 ? $old[ $field_group->index ][ $sub_id ]
622 : false;
623
624 $is_updated = ( ! empty( $new_val ) && $new_val != $old_val );
625 $is_removed = ( empty( $new_val ) && ! empty( $old_val ) );
626 // Compare values and add to `$updated` array
627 if ( $is_updated || $is_removed )
628 self::$updated[] = $base_id .'::'. $field_group->index .'::'. $sub_id;
629
630 // Add to `$saved` array
631 $saved[ $field_group->index ][ $sub_id ] = $new_val;
632
633 }
634 $saved[ $field_group->index ] = array_filter( $saved[ $field_group->index ] );
635 }
636 $saved = array_filter( $saved );
637
638 $field_group->update_data( $saved, true );
639 }
640
641 public static function sanitize_field( $field, $new_value = null ) {
642
643 $new_value = null !== $new_value
644 ? $new_value
645 : ( isset( $_POST[ $field->id( true ) ] ) ? $_POST[ $field->id( true ) ] : null );
646
647 if ( $field->args( 'repeatable' ) && is_array( $new_value ) ) {
648 // Remove empties
649 $new_value = array_filter( $new_value );
650 }
651
652 // Check if this metabox field has a registered validation callback, or perform default sanitization
653 return $field->sanitization_cb( $new_value );
654 }
655
656 public static function save_field( $new_value, $field ) {
657 $name = $field->id();
658 $old = $field->get_data();
659
660 // if ( $field->args( 'multiple' ) && ! $field->args( 'repeatable' ) && ! $field->group ) {
661 // $field->remove_data();
662 // if ( ! empty( $new_value ) ) {
663 // foreach ( $new_value as $add_new ) {
664 // self::$updated[] = $name;
665 // $field->update_data( $add_new, $name, false );
666 // }
667 // }
668 // } else
669 if ( ! empty( $new_value ) && $new_value != $old ) {
670 self::$updated[] = $name;
671 return $field->update_data( $new_value );
672 } elseif ( empty( $new_value ) ) {
673 if ( ! empty( $old ) )
674 self::$updated[] = $name;
675 return $field->remove_data();
676 }
677 }
678
679 /**
680 * Get object id from global space if no id is provided
681 * @since 1.0.0
682 * @param integer $object_id Object ID
683 * @return integer $object_id Object ID
684 */
685 public static function get_object_id( $object_id = 0 ) {
686
687 if ( $object_id )
688 return $object_id;
689
690 if ( self::$object_id )
691 return self::$object_id;
692
693 // Try to get our object ID from the global space
694 switch ( self::get_object_type() ) {
695 case 'user':
696 $object_id = isset( $GLOBALS['user_ID'] ) ? $GLOBALS['user_ID'] : $object_id;
697 $object_id = isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id;
698 break;
699
700 default:
701 $object_id = isset( $GLOBALS['post']->ID ) ? $GLOBALS['post']->ID : $object_id;
702 $object_id = isset( $_REQUEST['post'] ) ? $_REQUEST['post'] : $object_id;
703 break;
704 }
705
706 // reset to id or 0
707 self::set_object_id( $object_id ? $object_id : 0 );
708
709 return self::$object_id;
710 }
711
712 /**
713 * Explicitly Set object id
714 * @since 1.0.0
715 * @param integer $object_id Object ID
716 * @return integer $object_id Object ID
717 */
718 public static function set_object_id( $object_id ) {
719 return self::$object_id = $object_id;
720 }
721
722 /**
723 * Sets the $object_type based on metabox settings
724 * @since 1.0.0
725 * @param array|string $meta_box Metabox config array or explicit setting
726 * @return string Object type
727 */
728 public static function set_mb_type( $meta_box ) {
729
730 if ( is_string( $meta_box ) ) {
731 self::$mb_object_type = $meta_box;
732 return self::get_mb_type();
733 }
734
735 if ( ! isset( $meta_box['pages'] ) )
736 return self::get_mb_type();
737
738 $type = false;
739 // check if 'pages' is a string
740 if ( self::is_options_page_mb( $meta_box ) )
741 $type = 'options-page';
742 // check if 'pages' is a string
743 elseif ( is_string( $meta_box['pages'] ) )
744 $type = $meta_box['pages'];
745 // if it's an array of one, extract it
746 elseif ( is_array( $meta_box['pages'] ) && count( $meta_box['pages'] === 1 ) )
747 $type = is_string( end( $meta_box['pages'] ) ) ? end( $meta_box['pages'] ) : false;
748
749 if ( !$type )
750 return self::get_mb_type();
751
752 // Get our object type
753 if ( 'user' == $type )
754 self::$mb_object_type = 'user';
755 elseif ( 'comment' == $type )
756 self::$mb_object_type = 'comment';
757 elseif ( 'options-page' == $type )
758 self::$mb_object_type = 'options-page';
759 else
760 self::$mb_object_type = 'post';
761
762 return self::get_mb_type();
763 }
764
765 /**
766 * Determines if metabox is for an options page
767 * @since 1.0.1
768 * @param array $meta_box Metabox config array
769 * @return boolean True/False
770 */
771 public static function is_options_page_mb( $meta_box ) {
772 return ( isset( $meta_box['show_on']['key'] ) && 'options-page' === $meta_box['show_on']['key'] );
773 }
774
775 /**
776 * Returns the object type
777 * @since 1.0.0
778 * @return string Object type
779 */
780 public static function get_object_type() {
781 if ( self::$object_type )
782 return self::$object_type;
783
784 global $pagenow;
785
786 if (
787 $pagenow == 'user-edit.php'
788 || $pagenow == 'profile.php'
789 )
790 self::set_object_type( 'user' );
791
792 elseif (
793 $pagenow == 'edit-comments.php'
794 || $pagenow == 'comment.php'
795 )
796 self::set_object_type( 'comment' );
797 else
798 self::set_object_type( 'post' );
799
800 return self::$object_type;
801 }
802
803 /**
804 * Sets the object type
805 * @since 1.0.0
806 * @return string Object type
807 */
808 public static function set_object_type( $object_type ) {
809 return self::$object_type = $object_type;
810 }
811
812 /**
813 * Returns the object type
814 * @since 1.0.0
815 * @return string Object type
816 */
817 public static function get_mb_type() {
818 return self::$mb_object_type;
819 }
820
821 /**
822 * Returns the nonce value for wp_meta_box_nonce
823 * @since 1.0.0
824 * @return string Nonce value
825 */
826 public static function nonce() {
827 return basename( __FILE__ );
828 }
829
830 /**
831 * Defines the url which is used to load local resources.
832 * This may need to be filtered for local Window installations.
833 * If resources do not load, please check the wiki for details.
834 * @since 1.0.1
835 * @return string URL to CMB resources
836 */
837 public static function get_meta_box_url() {
838
839 if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) {
840 // Windows
841 $content_dir = str_replace( '/', DIRECTORY_SEPARATOR, WP_CONTENT_DIR );
842 $content_url = str_replace( $content_dir, WP_CONTENT_URL, dirname(__FILE__) );
843 $cmb_url = str_replace( DIRECTORY_SEPARATOR, '/', $content_url );
844
845 } else {
846 $cmb_url = str_replace(
847 array(WP_CONTENT_DIR, WP_PLUGIN_DIR),
848 array(WP_CONTENT_URL, WP_PLUGIN_URL),
849 dirname( __FILE__ )
850 );
851 }
852 $cmb_url = set_url_scheme( $cmb_url );
853
854 return trailingslashit( apply_filters('cmb_meta_box_url', $cmb_url ) );
855 }
856
857 /**
858 * Fills in empty metabox parameters with defaults
859 * @since 1.0.1
860 * @param array $meta_box Metabox config array
861 * @return array Modified Metabox config array
862 */
863 public static function set_mb_defaults( $meta_box ) {
864 return wp_parse_args( $meta_box, self::$mb_defaults );
865 }
866
867 /**
868 * Removes an option from an option array
869 * @since 1.0.1
870 * @param string $option_key Option key
871 * @param string $field_id Option array field key
872 * @return array Modified options
873 */
874 public static function remove_option( $option_key, $field_id ) {
875
876 self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ];
877
878 if ( isset( self::$options[ $option_key ][ $field_id ] ) )
879 unset( self::$options[ $option_key ][ $field_id ] );
880
881 return self::$options[ $option_key ];
882 }
883
884 /**
885 * Retrieves an option from an option array
886 * @since 1.0.1
887 * @param string $option_key Option key
888 * @param string $field_id Option array field key
889 * @return array Options array or specific field
890 */
891 public static function get_option( $option_key, $field_id = '' ) {
892
893 self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ];
894
895 if ( $field_id ) {
896 return isset( self::$options[ $option_key ][ $field_id ] ) ? self::$options[ $option_key ][ $field_id ] : false;
897 }
898
899 return self::$options[ $option_key ];
900 }
901
902 /**
903 * Updates Option data
904 * @since 1.0.1
905 * @param string $option_key Option key
906 * @param string $field_id Option array field key
907 * @param mixed $value Value to update data with
908 * @param bool $single Whether data should be an array
909 * @return array Modified options
910 */
911 public static function update_option( $option_key, $field_id, $value, $single = true ) {
912
913 if ( ! $single ) {
914 // If multiple, add to array
915 self::$options[ $option_key ][ $field_id ][] = $value;
916 } else {
917 self::$options[ $option_key ][ $field_id ] = $value;
918 }
919
920 return self::$options[ $option_key ];
921 }
922
923 /**
924 * Retrieve option value based on name of option.
925 * @uses apply_filters() Calls 'cmb_override_option_get_$option_key' hook to allow
926 * overwriting the option value to be retrieved.
927 *
928 * @since 1.0.1
929 * @param string $option Name of option to retrieve. Expected to not be SQL-escaped.
930 * @param mixed $default Optional. Default value to return if the option does not exist.
931 * @return mixed Value set for the option.
932 */
933 public static function _get_option( $option_key, $default = false ) {
934
935 $test_get = apply_filters( "cmb_override_option_get_$option_key", 'cmb_no_override_option_get', $default );
936
937 if ( $test_get !== 'cmb_no_override_option_get' )
938 return $test_get;
939
940 // If no override, get the option
941 return get_option( $option_key, $default );
942 }
943
944 /**
945 * Saves the option array
946 * Needs to be run after finished using remove/update_option
947 * @uses apply_filters() Calls 'cmb_override_option_save_$option_key' hook to allow
948 * overwriting the option value to be stored.
949 *
950 * @since 1.0.1
951 * @param string $option_key Option key
952 * @return boolean Success/Failure
953 */
954 public static function save_option( $option_key ) {
955
956 $to_save = self::get_option( $option_key );
957
958 $test_save = apply_filters( "cmb_override_option_save_$option_key", 'cmb_no_override_option_save', $to_save );
959
960 if ( $test_save !== 'cmb_no_override_option_save' )
961 return $test_save;
962
963 // If no override, update the option
964 return update_option( $option_key, $to_save );
965 }
966
967 /**
968 * Utility method that returns a timezone string representing the default timezone for the site.
969 *
970 * Roughly copied from WordPress, as get_option('timezone_string') will return
971 * and empty string if no value has beens set on the options page.
972 * A timezone string is required by the wp_timezone_choice() used by the
973 * select_timezone field.
974 *
975 * @since 1.0.0
976 * @return string Timezone string
977 */
978 public static function timezone_string() {
979 $current_offset = get_option( 'gmt_offset' );
980 $tzstring = get_option( 'timezone_string' );
981
982 if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists
983 if ( 0 == $current_offset )
984 $tzstring = 'UTC+0';
985 elseif ( $current_offset < 0 )
986 $tzstring = 'UTC' . $current_offset;
987 else
988 $tzstring = 'UTC+' . $current_offset;
989 }
990
991 return $tzstring;
992 }
993
994 /**
995 * Utility method that returns time string offset by timezone
996 * @since 1.0.0
997 * @param string $tzstring Time string
998 * @return string Offset time string
999 */
1000 public static function timezone_offset( $tzstring ) {
1001 if ( ! empty( $tzstring ) && is_string( $tzstring ) ) {
1002 if ( substr( $tzstring, 0, 3 ) === 'UTC' ) {
1003 $tzstring = str_replace( array( ':15',':30',':45' ), array( '.25','.5','.75' ), $tzstring );
1004 return intval( floatval( substr( $tzstring, 3 ) ) * HOUR_IN_SECONDS );
1005 }
1006
1007 $date_time_zone_selected = new DateTimeZone( $tzstring );
1008 $tz_offset = timezone_offset_get( $date_time_zone_selected, date_create() );
1009
1010 return $tz_offset;
1011 }
1012
1013 return 0;
1014 }
1015
1016 /**
1017 * Utility method that attempts to get an attachment's ID by it's url
1018 * @since 1.0.0
1019 * @param string $img_url Attachment url
1020 * @return mixed Attachment ID or false
1021 */
1022 public static function image_id_from_url( $img_url ) {
1023 global $wpdb;
1024
1025 $img_url = esc_url_raw( $img_url );
1026 // Get just the file name
1027 if ( false !== strpos( $img_url, '/' ) ) {
1028 $explode = explode( '/', $img_url );
1029 $img_url = end( $explode );
1030 }
1031
1032 // And search for a fuzzy match of the file name
1033 $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid LIKE '%%%s%%' LIMIT 1;", $img_url ) );
1034
1035 // If we found an attachement ID, return it
1036 if ( !empty( $attachment ) && is_array( $attachment ) )
1037 return $attachment[0];
1038
1039 // No luck
1040 return false;
1041 }
1042
1043 }
1044
1045 // Handle oembed Ajax
1046 add_action( 'wp_ajax_cmb_oembed_handler', array( 'cmb_Meta_Box_ajax', 'oembed_handler' ) );
1047 add_action( 'wp_ajax_nopriv_cmb_oembed_handler', array( 'cmb_Meta_Box_ajax', 'oembed_handler' ) );
1048
1049 /**
1050 * A helper function to get an option from a CMB options array
1051 * @since 1.0.1
1052 * @param string $option_key Option key
1053 * @param string $field_id Option array field key
1054 * @return array Options array or specific field
1055 */
1056 function cmb_get_option( $option_key, $field_id = '' ) {
1057 return cmb_Meta_Box::get_option( $option_key, $field_id );
1058 }
1059
1060 /**
1061 * Get a CMB field object.
1062 * @since 1.1.0
1063 * @param array $field_args Field arguments
1064 * @param int $object_id Object ID
1065 * @param string $object_type Type of object being saved. (e.g., post, user, or comment)
1066 * @return object cmb_Meta_Box_field object
1067 */
1068 function cmb_get_field( $field_args, $object_id = 0, $object_type = 'post' ) {
1069 // Default to the loop post ID
1070 $object_id = $object_id ? $object_id : get_the_ID();
1071 cmb_Meta_Box::set_object_id( $object_id );
1072 cmb_Meta_Box::set_object_type( $object_type );
1073 // Send back field object
1074 return new cmb_Meta_Box_field( $field_args );
1075 }
1076
1077 /**
1078 * Get a field's value.
1079 * @since 1.1.0
1080 * @param array $field_args Field arguments
1081 * @param int $object_id Object ID
1082 * @param string $object_type Type of object being saved. (e.g., post, user, comment, or options-page)
1083 * @return mixed Maybe escaped value
1084 */
1085 function cmb_get_field_value( $field_args, $object_id = 0, $object_type = 'post' ) {
1086 $field = cmb_get_field( $field_args, $object_id, $object_type );
1087 return $field->escaped_value();
1088 }
1089
1090 /**
1091 * Loop and output multiple metaboxes
1092 * @since 1.0.0
1093 * @param array $meta_boxes Metaboxes config array
1094 * @param int $object_id Object ID
1095 */
1096 function cmb_print_metaboxes( $meta_boxes, $object_id ) {
1097 foreach ( (array) $meta_boxes as $meta_box ) {
1098 cmb_print_metabox( $meta_box, $object_id );
1099 }
1100 }
1101
1102 /**
1103 * Output a metabox
1104 * @since 1.0.0
1105 * @param array $meta_box Metabox config array
1106 * @param int $object_id Object ID
1107 */
1108 function cmb_print_metabox( $meta_box, $object_id ) {
1109 $cmb = new cmb_Meta_Box( $meta_box );
1110 if ( $cmb ) {
1111
1112 cmb_Meta_Box::set_object_id( $object_id );
1113
1114 if ( ! wp_script_is( 'cmb-scripts', 'registered' ) )
1115 $cmb->register_scripts();
1116
1117 wp_enqueue_script( 'cmb-scripts' );
1118
1119 // default is to show cmb styles
1120 if ( $meta_box['cmb_styles'] != false )
1121 wp_enqueue_style( 'cmb-styles' );
1122
1123 cmb_Meta_Box::show_form( $meta_box );
1124 }
1125
1126 }
1127
1128 /**
1129 * Saves a particular metabox's fields
1130 * @since 1.0.0
1131 * @param array $meta_box Metabox config array
1132 * @param int $object_id Object ID
1133 */
1134 function cmb_save_metabox_fields( $meta_box, $object_id ) {
1135 cmb_Meta_Box::save_fields( $meta_box, $object_id );
1136 }
1137
1138 /**
1139 * Display a metabox form & save it on submission
1140 * @since 1.0.0
1141 * @param array $meta_box Metabox config array
1142 * @param int $object_id Object ID
1143 * @param boolean $return Whether to return or echo form
1144 * @return string CMB html form markup
1145 */
1146 function cmb_metabox_form( $meta_box, $object_id, $echo = true ) {
1147
1148 $meta_box = cmb_Meta_Box::set_mb_defaults( $meta_box );
1149
1150 // Make sure form should be shown
1151 if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) )
1152 return '';
1153
1154 // Make sure that our object type is explicitly set by the metabox config
1155 cmb_Meta_Box::set_object_type( cmb_Meta_Box::set_mb_type( $meta_box ) );
1156
1157 // Save the metabox if it's been submitted
1158 // check permissions
1159 // @todo more hardening?
1160 if (
1161 // check nonce
1162 isset( $_POST['submit-cmb'], $_POST['object_id'], $_POST['wp_meta_box_nonce'] )
1163 && wp_verify_nonce( $_POST['wp_meta_box_nonce'], cmb_Meta_Box::nonce() )
1164 && $_POST['object_id'] == $object_id
1165 )
1166 cmb_save_metabox_fields( $meta_box, $object_id );
1167
1168 // Show specific metabox form
1169
1170 // Get cmb form
1171 ob_start();
1172 cmb_print_metabox( $meta_box, $object_id );
1173 $form = ob_get_contents();
1174 ob_end_clean();
1175
1176 $form_format = apply_filters( 'cmb_frontend_form_format', '<form class="cmb-form" method="post" id="%s" enctype="multipart/form-data" encoding="multipart/form-data"><input type="hidden" name="object_id" value="%s">%s<input type="submit" name="submit-cmb" value="%s" class="button-primary"></form>', $object_id, $meta_box, $form );
1177
1178 $form = sprintf( $form_format, $meta_box['id'], $object_id, $form, __( 'Save' ) );
1179
1180 if ( $echo )
1181 echo $form;
1182
1183 return $form;
1184 }
1185
1186 // End. That's it, folks! //
1187