cmb_Meta_Box

The BuddyPress Profile Tabs cmb Meta Box class.

Defined (1)

The class is defined in the following location(s).

/admin/includes/CMBF/init.php  
  1. class cmb_Meta_Box { 
  2.  
  3. /** 
  4. * Current version number 
  5. * @var string 
  6. * @since 1.0.0 
  7. */ 
  8. const CMB_VERSION = '1.2.0'; 
  9.  
  10. /** 
  11. * Metabox Config array 
  12. * @var array 
  13. * @since 0.9.0 
  14. */ 
  15. protected $_meta_box; 
  16.  
  17. /** 
  18. * Metabox Defaults 
  19. * @var array 
  20. * @since 1.0.1 
  21. */ 
  22. protected static $mb_defaults = array( 
  23. 'id' => '',  
  24. 'title' => '',  
  25. 'type' => '',  
  26. 'pages' => array(), // Post type 
  27. 'context' => 'normal',  
  28. 'priority' => 'high',  
  29. 'show_names' => true, // Show field names on the left 
  30. 'show_on' => array( 'key' => false, 'value' => false ), // Specific post IDs or page templates to display this metabox 
  31. 'cmb_styles' => true, // Include cmb bundled stylesheet 
  32. 'fields' => array(),  
  33. ); 
  34.  
  35. /** 
  36. * Metabox Form ID 
  37. * @var string 
  38. * @since 0.9.4 
  39. */ 
  40. protected $form_id = 'post'; 
  41.  
  42. /** 
  43. * Current field config array 
  44. * @var array 
  45. * @since 1.0.0 
  46. */ 
  47. public static $field = array(); 
  48.  
  49. /** 
  50. * Object ID for metabox meta retrieving/saving 
  51. * @var int 
  52. * @since 1.0.0 
  53. */ 
  54. protected static $object_id = 0; 
  55.  
  56. /** 
  57. * Type of object being saved. (e.g., post, user, or comment) 
  58. * @var string 
  59. * @since 1.0.0 
  60. */ 
  61. protected static $object_type = ''; 
  62.  
  63. /** 
  64. * Whether scripts/styles have been enqueued yet 
  65. * @var bool 
  66. * @since 1.0.0 
  67. */ 
  68. protected static $is_enqueued = false; 
  69.  
  70. /** 
  71. * Whether CMB nonce has been added to the page. (oly add once) 
  72. * @var bool 
  73. * @since 1.2.0 
  74. */ 
  75. protected static $nonce_added = false; 
  76.  
  77. /** 
  78. * Type of object specified by the metabox Config 
  79. * @var string 
  80. * @since 1.0.0 
  81. */ 
  82. protected static $mb_object_type = 'post'; 
  83.  
  84. /** 
  85. * Array of all options from manage-options metaboxes 
  86. * @var array 
  87. * @since 1.0.0 
  88. */ 
  89. protected static $options = array(); 
  90.  
  91. /** 
  92. * List of fields that are changed/updated on save 
  93. * @var array 
  94. * @since 1.1.0 
  95. */ 
  96. protected static $updated = array(); 
  97.  
  98. /** 
  99. * Get started 
  100. */ 
  101. function __construct( $meta_box ) { 
  102.  
  103. $meta_box = self::set_mb_defaults( $meta_box ); 
  104.  
  105. $allow_frontend = apply_filters( 'cmb_allow_frontend', true, $meta_box ); 
  106.  
  107. if ( ! is_admin() && ! $allow_frontend ) 
  108. return; 
  109.  
  110. $this->_meta_box = $meta_box; 
  111.  
  112. self::set_mb_type( $meta_box ); 
  113.  
  114. $types = wp_list_pluck( $meta_box['fields'], 'type' ); 
  115. $upload = in_array( 'file', $types ) || in_array( 'file_list', $types ); 
  116.  
  117. global $pagenow; 
  118.  
  119. $show_filters = 'cmb_Meta_Box_Show_Filters'; 
  120. foreach ( get_class_methods( $show_filters ) as $filter ) { 
  121. add_filter( 'cmb_show_on', array( $show_filters, $filter ), 10, 2 ); 
  122.  
  123. // register our scripts and styles for cmb 
  124. add_action( 'admin_enqueue_scripts', array( $this, 'register_scripts' ), 8 ); 
  125.  
  126. if ( self::get_object_type() == 'post' ) { 
  127. add_action( 'admin_menu', array( $this, 'add_metaboxes' ) ); 
  128. add_action( 'add_attachment', array( $this, 'save_post' ) ); 
  129. add_action( 'edit_attachment', array( $this, 'save_post' ) ); 
  130. add_action( 'save_post', array( $this, 'save_post' ), 10, 2 ); 
  131. add_action( 'admin_enqueue_scripts', array( $this, 'do_scripts' ) ); 
  132.  
  133. if ( $upload && in_array( $pagenow, array( 'page.php', 'page-new.php', 'post.php', 'post-new.php' ) ) ) { 
  134. add_action( 'admin_head', array( $this, 'add_post_enctype' ) ); 
  135.  
  136. if ( self::get_object_type() == 'user' ) { 
  137.  
  138. $priority = 10; 
  139. if ( isset( $meta_box['priority'] ) ) { 
  140. if ( is_numeric( $meta_box['priority'] ) ) 
  141. $priority = $meta_box['priority']; 
  142. elseif ( $meta_box['priority'] == 'high' ) 
  143. $priority = 5; 
  144. elseif ( $meta_box['priority'] == 'low' ) 
  145. $priority = 20; 
  146. add_action( 'show_user_profile', array( $this, 'user_metabox' ), $priority ); 
  147. add_action( 'edit_user_profile', array( $this, 'user_metabox' ), $priority ); 
  148.  
  149. add_action( 'personal_options_update', array( $this, 'save_user' ) ); 
  150. add_action( 'edit_user_profile_update', array( $this, 'save_user' ) ); 
  151. if ( $upload && in_array( $pagenow, array( 'profile.php', 'user-edit.php' ) ) ) { 
  152. $this->form_id = 'your-profile'; 
  153. add_action( 'admin_head', array( $this, 'add_post_enctype' ) ); 
  154.  
  155.  
  156. /** 
  157. * Autoloads files with classes when needed 
  158. * @since 1.0.0 
  159. * @param string $class_name Name of the class being requested 
  160. */ 
  161. public static function autoload_helpers( $class_name ) { 
  162. if ( class_exists( $class_name, false ) ) 
  163. return; 
  164.  
  165. // for PHP versions < 5.3 
  166. $dir = dirname( __FILE__ ); 
  167.  
  168. $file = "$dir/helpers/$class_name.php"; 
  169. if ( file_exists( $file ) ) 
  170. @include( $file ); 
  171.  
  172. /** 
  173. * Registers scripts and styles for CMB 
  174. * @since 1.0.0 
  175. */ 
  176. public function register_scripts() { 
  177.  
  178. // Should only be run once 
  179. if ( self::$is_enqueued ) 
  180. return; 
  181.  
  182. global $wp_version; 
  183. // Only use minified files if SCRIPT_DEBUG is off 
  184. $min = defined('SCRIPT_DEBUG') && SCRIPT_DEBUG ? '' : '.min'; 
  185.  
  186. // scripts required for cmb 
  187. $scripts = array( 'jquery', 'jquery-ui-core', 'cmb-datepicker', /**'media-upload', */'cmb-timepicker' ); 
  188. // styles required for cmb 
  189. $styles = array(); 
  190.  
  191. // if we're 3.5 or later, user wp-color-picker 
  192. if ( 3.5 <= $wp_version ) { 
  193. $scripts[] = 'wp-color-picker'; 
  194. $styles[] = 'wp-color-picker'; 
  195. if ( ! is_admin() ) { 
  196. // we need to register colorpicker on the front-end 
  197. wp_register_script( 'iris', admin_url( 'js/iris.min.js' ), array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), self::CMB_VERSION ); 
  198. wp_register_script( 'wp-color-picker', admin_url( 'js/color-picker.min.js' ), array( 'iris' ), self::CMB_VERSION ); 
  199. wp_localize_script( 'wp-color-picker', 'wpColorPickerL10n', array( 
  200. 'clear' => __( 'Clear' ),  
  201. 'defaultString' => __( 'Default' ),  
  202. 'pick' => __( 'Select Color' ),  
  203. 'current' => __( 'Current Color' ),  
  204. ) ); 
  205. } else { 
  206. // otherwise use the older 'farbtastic' 
  207. $scripts[] = 'farbtastic'; 
  208. $styles[] = 'farbtastic'; 
  209. wp_register_script( 'cmb-datepicker', CMB_META_BOX_URL . 'js/jquery.datePicker.min.js' ); 
  210. wp_register_script( 'cmb-timepicker', CMB_META_BOX_URL . 'js/jquery.timePicker.min.js' ); 
  211. wp_register_script( 'cmb-scripts', CMB_META_BOX_URL .'js/cmb'. $min .'.js', $scripts, self::CMB_VERSION ); 
  212.  
  213. wp_enqueue_media(); 
  214.  
  215. wp_localize_script( 'cmb-scripts', 'cmb_l10', apply_filters( 'cmb_localized_data', array( 
  216. 'ajax_nonce' => wp_create_nonce( 'ajax_nonce' ),  
  217. 'script_debug' => defined('SCRIPT_DEBUG') && SCRIPT_DEBUG,  
  218. 'new_admin_style' => version_compare( $wp_version, '3.7', '>' ),  
  219. 'object_type' => self::get_object_type(),  
  220. 'upload_file' => 'Use this file',  
  221. 'remove_image' => 'Remove Image',  
  222. 'remove_file' => 'Remove',  
  223. 'file' => 'File:',  
  224. 'download' => 'Download',  
  225. 'ajaxurl' => admin_url( '/admin-ajax.php' ),  
  226. 'up_arrow' => '[ * ] ',  
  227. 'down_arrow' => ' [ * ]',  
  228. 'check_toggle' => __( 'Select / Deselect All', 'cmb' ),  
  229. ) ) ); 
  230.  
  231. wp_register_style( 'cmb-styles', CMB_META_BOX_URL . 'style'. $min .'.css', $styles ); 
  232.  
  233. // Ok, we've enqueued our scripts/styles 
  234. self::$is_enqueued = true; 
  235.  
  236. /** 
  237. * Enqueues scripts and styles for CMB 
  238. * @since 1.0.0 
  239. */ 
  240. public function do_scripts( $hook ) { 
  241. // only enqueue our scripts/styles on the proper pages 
  242. if ( $hook == 'post.php' || $hook == 'post-new.php' || $hook == 'page-new.php' || $hook == 'page.php' ) { 
  243. wp_enqueue_script( 'cmb-scripts' ); 
  244.  
  245. // default is to show cmb styles on post pages 
  246. if ( $this->_meta_box['cmb_styles'] ) 
  247. wp_enqueue_style( 'cmb-styles' ); 
  248.  
  249. /** 
  250. * Add encoding attribute 
  251. */ 
  252. public function add_post_enctype() { 
  253. echo ' 
  254. <script type="text/javascript"> 
  255. jQuery(document).ready(function() { 
  256. jQuery("#'. $this->form_id .'").attr("enctype", "multipart/form-data"); 
  257. jQuery("#'. $this->form_id .'").attr("encoding", "multipart/form-data"); 
  258. }); 
  259. </script>'; 
  260.  
  261. /** 
  262. * Add metaboxes (to 'post' object type) 
  263. */ 
  264. public function add_metaboxes() { 
  265.  
  266. foreach ( $this->_meta_box['pages'] as $page ) { 
  267. if ( apply_filters( 'cmb_show_on', true, $this->_meta_box ) ) 
  268. add_meta_box( $this->_meta_box['id'], $this->_meta_box['title'], array( $this, 'post_metabox' ), $page, $this->_meta_box['context'], $this->_meta_box['priority']) ; 
  269.  
  270. /** 
  271. * Display metaboxes for a post object 
  272. * @since 1.0.0 
  273. */ 
  274. public function post_metabox() { 
  275. if ( ! $this->_meta_box ) 
  276. return; 
  277.  
  278. self::show_form( $this->_meta_box, get_the_ID(), 'post' ); 
  279.  
  280.  
  281. /** 
  282. * Display metaboxes for a user object 
  283. * @since 1.0.0 
  284. */ 
  285. public function user_metabox() { 
  286. if ( ! $this->_meta_box ) 
  287. return; 
  288.  
  289. if ( 'user' != self::set_mb_type( $this->_meta_box ) ) 
  290. return; 
  291.  
  292. if ( ! apply_filters( 'cmb_show_on', true, $this->_meta_box ) ) 
  293. return; 
  294.  
  295. wp_enqueue_script( 'cmb-scripts' ); 
  296.  
  297. // default is to NOT show cmb styles on user profile page 
  298. if ( $this->_meta_box['cmb_styles'] != false ) 
  299. wp_enqueue_style( 'cmb-styles' ); 
  300.  
  301. self::show_form( $this->_meta_box ); 
  302.  
  303.  
  304. /** 
  305. * Loops through and displays fields 
  306. * @since 1.0.0 
  307. * @param array $meta_box Metabox config array 
  308. * @param int $object_id Object ID 
  309. * @param string $object_type Type of object being saved. (e.g., post, user, or comment) 
  310. */ 
  311. public static function show_form( $meta_box, $object_id = 0, $object_type = '' ) { 
  312. $meta_box = self::set_mb_defaults( $meta_box ); 
  313. // Set/get type 
  314. $object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) ); 
  315. // Set/get ID 
  316. $object_id = self::set_object_id( $object_id ? $object_id : self::get_object_id() ); 
  317.  
  318. // Add nonce only once per page. 
  319. if ( ! self::$nonce_added ) { 
  320. wp_nonce_field( self::nonce(), 'wp_meta_box_nonce', false, true ); 
  321. self::$nonce_added = true; 
  322.  
  323. // Use nonce for verification 
  324. echo "\n<!-- Begin CMB Fields -->\n"; 
  325. do_action( 'cmb_before_table', $meta_box, $object_id, $object_type ); 
  326. echo '<table class="form-table cmb_metabox">'; 
  327.  
  328. foreach ( $meta_box['fields'] as $field_args ) { 
  329.  
  330. $field_args['context'] = $meta_box['context']; 
  331.  
  332. if ( 'group' == $field_args['type'] ) { 
  333.  
  334. if ( ! isset( $field_args['show_names'] ) ) { 
  335. $field_args['show_names'] = $meta_box['show_names']; 
  336. self::render_group( $field_args ); 
  337. } else { 
  338.  
  339. $field_args['show_names'] = $meta_box['show_names']; 
  340. // Render default fields 
  341. $field = new cmb_Meta_Box_field( $field_args ); 
  342. $field->render_field(); 
  343. echo '</table>'; 
  344. do_action( 'cmb_after_table', $meta_box, $object_id, $object_type ); 
  345. echo "\n<!-- End CMB Fields -->\n"; 
  346.  
  347.  
  348. /** 
  349. * Render a repeatable group 
  350. */ 
  351. public static function render_group( $args ) { 
  352. if ( ! isset( $args['id'], $args['fields'] ) || ! is_array( $args['fields'] ) ) 
  353. return; 
  354.  
  355. $args['count'] = 0; 
  356. $field_group = new cmb_Meta_Box_field( $args ); 
  357. $desc = $field_group->args( 'description' ); 
  358. $label = $field_group->args( 'name' ); 
  359. $sortable = $field_group->options( 'sortable' ) ? ' sortable' : ''; 
  360. $group_val = (array) $field_group->value(); 
  361. $nrows = count( $group_val ); 
  362. $remove_disabled = $nrows <= 1 ? 'disabled="disabled" ' : ''; 
  363.  
  364. echo '<tr><td colspan="2"><table id="', $field_group->id(), '_repeat" class="repeatable-group'. $sortable .'" style="width:100%;">'; 
  365. if ( $desc || $label ) { 
  366. echo '<tr><th>'; 
  367. if ( $label ) 
  368. echo '<h2 class="cmb-group-name">'. $label .'</h2>'; 
  369. if ( $desc ) 
  370. echo '<p class="cmb_metabox_description">'. $desc .'</p>'; 
  371. echo '</th></tr>'; 
  372.  
  373. if ( ! empty( $group_val ) ) { 
  374.  
  375. foreach ( $group_val as $iterator => $field_id ) { 
  376. self::render_group_row( $field_group, $remove_disabled ); 
  377. } else { 
  378. self::render_group_row( $field_group, $remove_disabled ); 
  379.  
  380. 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>'; 
  381.  
  382. echo '</table></td></tr>'; 
  383.  
  384.  
  385. public static function render_group_row( $field_group, $remove_disabled ) { 
  386.  
  387. echo ' 
  388. <tr class="repeatable-grouping" data-iterator="'. $field_group->count() .'"> 
  389. <td> 
  390. <table class="cmb-nested-table" style="width: 100%;">'; 
  391. if ( $field_group->options( 'group_title' ) ) { 
  392. echo ' 
  393. <tr class="cmb-group-title"> 
  394. <th colspan="2"> 
  395. ', sprintf( '<h4>%1$s</h4>', $field_group->replace_hash( $field_group->options( 'group_title' ) ) ), ' 
  396. <th> 
  397. </tr> 
  398. '; 
  399. // Render repeatable group fields 
  400. foreach ( array_values( $field_group->args( 'fields' ) ) as $field_args ) { 
  401. $field_args['show_names'] = $field_group->args( 'show_names' ); 
  402. $field_args['context'] = $field_group->args( 'context' ); 
  403. $field = new cmb_Meta_Box_field( $field_args, $field_group ); 
  404. $field->render_field(); 
  405. echo ' 
  406. <tr> 
  407. <td class="remove-row" colspan="2"> 
  408. <button '. $remove_disabled .'data-selector="'. $field_group->id() .'_repeat" class="button remove-group-row alignright">'. $field_group->options( 'remove_button' ) .'</button> 
  409. </td> 
  410. </tr> 
  411. </table> 
  412. </td> 
  413. </tr> 
  414. '; 
  415.  
  416. $field_group->args['count']++; 
  417.  
  418. /** 
  419. * Save data from metabox 
  420. */ 
  421. public function save_post( $post_id, $post = false ) { 
  422.  
  423. $post_type = $post ? $post->post_type : get_post_type( $post_id ); 
  424.  
  425. // check permissions 
  426. if ( 
  427. // check nonce 
  428. ! isset( $_POST['wp_meta_box_nonce'] ) 
  429. || ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() ) 
  430. // check if autosave 
  431. || defined('DOING_AUTOSAVE' ) && DOING_AUTOSAVE 
  432. // check user editing permissions 
  433. || ( 'page' == $_POST['post_type'] && ! current_user_can( 'edit_page', $post_id ) ) 
  434. || ! current_user_can( 'edit_post', $post_id ) 
  435. // get the metabox post_types & compare it to this post_type 
  436. || ! in_array( $post_type, $this->_meta_box['pages'] ) 
  437. return $post_id; 
  438.  
  439. self::save_fields( $this->_meta_box, $post_id, 'post' ); 
  440.  
  441. /** 
  442. * Save data from metabox 
  443. */ 
  444. public function save_user( $user_id ) { 
  445.  
  446. // check permissions 
  447. // @todo more hardening? 
  448. if ( 
  449. // check nonce 
  450. ! isset( $_POST['wp_meta_box_nonce'] ) 
  451. || ! wp_verify_nonce( $_POST['wp_meta_box_nonce'], self::nonce() ) 
  452. return $user_id; 
  453.  
  454. self::save_fields( $this->_meta_box, $user_id, 'user' ); 
  455.  
  456. /** 
  457. * Loops through and saves field data 
  458. * @since 1.0.0 
  459. * @param array $meta_box Metabox config array 
  460. * @param int $object_id Object ID 
  461. * @param string $object_type Type of object being saved. (e.g., post, user, or comment) 
  462. */ 
  463. public static function save_fields( $meta_box, $object_id, $object_type = '' ) { 
  464. $meta_box = self::set_mb_defaults( $meta_box ); 
  465.  
  466. $meta_box['show_on'] = empty( $meta_box['show_on'] ) ? array( 'key' => false, 'value' => false ) : $meta_box['show_on']; 
  467.  
  468. self::set_object_id( $object_id ); 
  469. // Set/get type 
  470. $object_type = self::set_object_type( $object_type ? $object_type : self::set_mb_type( $meta_box ) ); 
  471.  
  472. if ( ! apply_filters( 'cmb_show_on', true, $meta_box ) ) 
  473. return; 
  474.  
  475. // save field ids of those that are updated 
  476. self::$updated = array(); 
  477.  
  478. foreach ( $meta_box['fields'] as $field_args ) { 
  479.  
  480. if ( 'group' == $field_args['type'] ) { 
  481. self::save_group( $field_args ); 
  482. } else { 
  483. // Save default fields 
  484. $field = new cmb_Meta_Box_field( $field_args ); 
  485. self::save_field( self::sanitize_field( $field ), $field ); 
  486.  
  487.  
  488. // If options page, save the updated options 
  489. if ( $object_type == 'options-page' ) 
  490. self::save_option( $object_id ); 
  491.  
  492. do_action( "cmb_save_{$object_type}_fields", $object_id, $meta_box['id'], self::$updated, $meta_box ); 
  493.  
  494.  
  495. /** 
  496. * Save a repeatable group 
  497. */ 
  498. public static function save_group( $args ) { 
  499. if ( ! isset( $args['id'], $args['fields'], $_POST[ $args['id'] ] ) || ! is_array( $args['fields'] ) ) 
  500. return; 
  501.  
  502. $field_group = new cmb_Meta_Box_field( $args ); 
  503. $base_id = $field_group->id(); 
  504. $old = $field_group->get_data(); 
  505. $group_vals = $_POST[ $base_id ]; 
  506. $saved = array(); 
  507. $is_updated = false; 
  508. $field_group->index = 0; 
  509.  
  510. // $group_vals[0]['color'] = '333'; 
  511. foreach ( array_values( $field_group->fields() ) as $field_args ) { 
  512. $field = new cmb_Meta_Box_field( $field_args, $field_group ); 
  513. $sub_id = $field->id( true ); 
  514.  
  515. foreach ( (array) $group_vals as $field_group->index => $post_vals ) { 
  516.  
  517. // Get value 
  518. $new_val = isset( $group_vals[ $field_group->index ][ $sub_id ] ) 
  519. ? $group_vals[ $field_group->index ][ $sub_id ] 
  520. : false; 
  521.  
  522. // Sanitize 
  523. $new_val = self::sanitize_field( $field, $new_val, $field_group->index ); 
  524.  
  525. if ( 'file' == $field->type() && is_array( $new_val ) ) { 
  526. // Add image ID to the array stack 
  527. $saved[ $field_group->index ][ $new_val['field_id'] ] = $new_val['attach_id']; 
  528. // Reset var to url string 
  529. $new_val = $new_val['url']; 
  530.  
  531. // Get old value 
  532. $old_val = is_array( $old ) && isset( $old[ $field_group->index ][ $sub_id ] ) 
  533. ? $old[ $field_group->index ][ $sub_id ] 
  534. : false; 
  535.  
  536. $is_updated = ( ! empty( $new_val ) && $new_val != $old_val ); 
  537. $is_removed = ( empty( $new_val ) && ! empty( $old_val ) ); 
  538. // Compare values and add to `$updated` array 
  539. if ( $is_updated || $is_removed ) 
  540. self::$updated[] = $base_id .'::'. $field_group->index .'::'. $sub_id; 
  541.  
  542. // Add to `$saved` array 
  543. $saved[ $field_group->index ][ $sub_id ] = $new_val; 
  544.  
  545. $saved[ $field_group->index ] = array_filter( $saved[ $field_group->index ] ); 
  546. $saved = array_filter( $saved ); 
  547.  
  548. $field_group->update_data( $saved, true ); 
  549.  
  550. public static function sanitize_field( $field, $new_value = null ) { 
  551.  
  552. $new_value = null !== $new_value 
  553. ? $new_value 
  554. : ( isset( $_POST[ $field->id( true ) ] ) ? $_POST[ $field->id( true ) ] : null ); 
  555.  
  556. if ( $field->args( 'repeatable' ) && is_array( $new_value ) ) { 
  557. // Remove empties 
  558. $new_value = array_filter( $new_value ); 
  559.  
  560. // Check if this metabox field has a registered validation callback, or perform default sanitization 
  561. return $field->sanitization_cb( $new_value ); 
  562.  
  563. public static function save_field( $new_value, $field ) { 
  564. $name = $field->id(); 
  565. $old = $field->get_data(); 
  566.  
  567. // if ( $field->args( 'multiple' ) && ! $field->args( 'repeatable' ) && ! $field->group ) { 
  568. // $field->remove_data(); 
  569. // if ( ! empty( $new_value ) ) { 
  570. // foreach ( $new_value as $add_new ) { 
  571. // self::$updated[] = $name; 
  572. // $field->update_data( $add_new, $name, false ); 
  573. // } 
  574. // } 
  575. // } else 
  576. if ( ! empty( $new_value ) && $new_value != $old ) { 
  577. self::$updated[] = $name; 
  578. return $field->update_data( $new_value ); 
  579. } elseif ( empty( $new_value ) ) { 
  580. if ( ! empty( $old ) ) 
  581. self::$updated[] = $name; 
  582. return $field->remove_data(); 
  583.  
  584. /** 
  585. * Get object id from global space if no id is provided 
  586. * @since 1.0.0 
  587. * @param integer $object_id Object ID 
  588. * @return integer $object_id Object ID 
  589. */ 
  590. public static function get_object_id( $object_id = 0 ) { 
  591.  
  592. if ( $object_id ) 
  593. return $object_id; 
  594.  
  595. if ( self::$object_id ) 
  596. return self::$object_id; 
  597.  
  598. // Try to get our object ID from the global space 
  599. switch ( self::get_object_type() ) { 
  600. case 'user': 
  601. $object_id = isset( $GLOBALS['user_ID'] ) ? $GLOBALS['user_ID'] : $object_id; 
  602. $object_id = isset( $_REQUEST['user_id'] ) ? $_REQUEST['user_id'] : $object_id; 
  603. break; 
  604.  
  605. default: 
  606. $object_id = isset( $GLOBALS['post']->ID ) ? $GLOBALS['post']->ID : $object_id; 
  607. $object_id = isset( $_REQUEST['post'] ) ? $_REQUEST['post'] : $object_id; 
  608. break; 
  609.  
  610. // reset to id or 0 
  611. self::set_object_id( $object_id ? $object_id : 0 ); 
  612.  
  613. return self::$object_id; 
  614.  
  615. /** 
  616. * Explicitly Set object id 
  617. * @since 1.0.0 
  618. * @param integer $object_id Object ID 
  619. * @return integer $object_id Object ID 
  620. */ 
  621. public static function set_object_id( $object_id ) { 
  622. return self::$object_id = $object_id; 
  623.  
  624. /** 
  625. * Sets the $object_type based on metabox settings 
  626. * @since 1.0.0 
  627. * @param array|string $meta_box Metabox config array or explicit setting 
  628. * @return string Object type 
  629. */ 
  630. public static function set_mb_type( $meta_box ) { 
  631.  
  632. if ( is_string( $meta_box ) ) { 
  633. self::$mb_object_type = $meta_box; 
  634. return self::get_mb_type(); 
  635.  
  636. if ( ! isset( $meta_box['pages'] ) ) 
  637. return self::get_mb_type(); 
  638.  
  639. $type = false; 
  640. // check if 'pages' is a string 
  641. if ( self::is_options_page_mb( $meta_box ) ) 
  642. $type = 'options-page'; 
  643. // check if 'pages' is a string 
  644. elseif ( is_string( $meta_box['pages'] ) ) 
  645. $type = $meta_box['pages']; 
  646. // if it's an array of one, extract it 
  647. elseif ( is_array( $meta_box['pages'] ) && count( $meta_box['pages'] === 1 ) ) 
  648. $type = is_string( end( $meta_box['pages'] ) ) ? end( $meta_box['pages'] ) : false; 
  649.  
  650. if ( !$type ) 
  651. return self::get_mb_type(); 
  652.  
  653. // Get our object type 
  654. if ( 'user' == $type ) 
  655. self::$mb_object_type = 'user'; 
  656. elseif ( 'comment' == $type ) 
  657. self::$mb_object_type = 'comment'; 
  658. elseif ( 'options-page' == $type ) 
  659. self::$mb_object_type = 'options-page'; 
  660. else 
  661. self::$mb_object_type = 'post'; 
  662.  
  663. return self::get_mb_type(); 
  664.  
  665. /** 
  666. * Determines if metabox is for an options page 
  667. * @since 1.0.1 
  668. * @param array $meta_box Metabox config array 
  669. * @return boolean True/False 
  670. */ 
  671. public static function is_options_page_mb( $meta_box ) { 
  672. return ( isset( $meta_box['show_on']['key'] ) && 'options-page' === $meta_box['show_on']['key'] ); 
  673.  
  674. /** 
  675. * Returns the object type 
  676. * @since 1.0.0 
  677. * @return string Object type 
  678. */ 
  679. public static function get_object_type() { 
  680. if ( self::$object_type ) 
  681. return self::$object_type; 
  682.  
  683. global $pagenow; 
  684.  
  685. if ( 
  686. $pagenow == 'user-edit.php' 
  687. || $pagenow == 'profile.php' 
  688. self::set_object_type( 'user' ); 
  689.  
  690. elseif ( 
  691. $pagenow == 'edit-comments.php' 
  692. || $pagenow == 'comment.php' 
  693. self::set_object_type( 'comment' ); 
  694. else 
  695. self::set_object_type( 'post' ); 
  696.  
  697. return self::$object_type; 
  698.  
  699. /** 
  700. * Sets the object type 
  701. * @since 1.0.0 
  702. * @return string Object type 
  703. */ 
  704. public static function set_object_type( $object_type ) { 
  705. return self::$object_type = $object_type; 
  706.  
  707. /** 
  708. * Returns the object type 
  709. * @since 1.0.0 
  710. * @return string Object type 
  711. */ 
  712. public static function get_mb_type() { 
  713. return self::$mb_object_type; 
  714.  
  715. /** 
  716. * Returns the nonce value for wp_meta_box_nonce 
  717. * @since 1.0.0 
  718. * @return string Nonce value 
  719. */ 
  720. public static function nonce() { 
  721. return basename( __FILE__ ); 
  722.  
  723. /** 
  724. * Defines the url which is used to load local resources. 
  725. * This may need to be filtered for local Window installations. 
  726. * If resources do not load, please check the wiki for details. 
  727. * @since 1.0.1 
  728. * @return string URL to CMB resources 
  729. */ 
  730. public static function get_meta_box_url() { 
  731.  
  732. if ( strtoupper( substr( PHP_OS, 0, 3 ) ) === 'WIN' ) { 
  733. // Windows 
  734. $content_dir = str_replace( '/', DIRECTORY_SEPARATOR, WP_CONTENT_DIR ); 
  735. $content_url = str_replace( $content_dir, WP_CONTENT_URL, dirname(__FILE__) ); 
  736. $cmb_url = str_replace( DIRECTORY_SEPARATOR, '/', $content_url ); 
  737.  
  738. } else { 
  739. $cmb_url = str_replace( 
  740. array(WP_CONTENT_DIR, WP_PLUGIN_DIR),  
  741. array(WP_CONTENT_URL, WP_PLUGIN_URL),  
  742. dirname( __FILE__ ) 
  743. ); 
  744.  
  745. return trailingslashit( apply_filters('cmb_meta_box_url', $cmb_url ) ); 
  746.  
  747. /** 
  748. * Fills in empty metabox parameters with defaults 
  749. * @since 1.0.1 
  750. * @param array $meta_box Metabox config array 
  751. * @return array Modified Metabox config array 
  752. */ 
  753. public static function set_mb_defaults( $meta_box ) { 
  754. return wp_parse_args( $meta_box, self::$mb_defaults ); 
  755.  
  756. /** 
  757. * Removes an option from an option array 
  758. * @since 1.0.1 
  759. * @param string $option_key Option key 
  760. * @param string $field_id Option array field key 
  761. * @return array Modified options 
  762. */ 
  763. public static function remove_option( $option_key, $field_id ) { 
  764.  
  765. self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ]; 
  766.  
  767. if ( isset( self::$options[ $option_key ][ $field_id ] ) ) 
  768. unset( self::$options[ $option_key ][ $field_id ] ); 
  769.  
  770. return self::$options[ $option_key ]; 
  771.  
  772. /** 
  773. * Retrieves an option from an option array 
  774. * @since 1.0.1 
  775. * @param string $option_key Option key 
  776. * @param string $field_id Option array field key 
  777. * @return array Options array or specific field 
  778. */ 
  779. public static function get_option( $option_key, $field_id = '' ) { 
  780.  
  781. self::$options[ $option_key ] = ! isset( self::$options[ $option_key ] ) || empty( self::$options[ $option_key ] ) ? self::_get_option( $option_key ) : self::$options[ $option_key ]; 
  782.  
  783. if ( $field_id ) { 
  784. return isset( self::$options[ $option_key ][ $field_id ] ) ? self::$options[ $option_key ][ $field_id ] : false; 
  785.  
  786. return self::$options[ $option_key ]; 
  787.  
  788. /** 
  789. * Updates Option data 
  790. * @since 1.0.1 
  791. * @param string $option_key Option key 
  792. * @param string $field_id Option array field key 
  793. * @param mixed $value Value to update data with 
  794. * @param bool $single Whether data should be an array 
  795. * @return array Modified options 
  796. */ 
  797. public static function update_option( $option_key, $field_id, $value, $single = true ) { 
  798.  
  799. if ( ! $single ) { 
  800. // If multiple, add to array 
  801. self::$options[ $option_key ][ $field_id ][] = $value; 
  802. } else { 
  803. self::$options[ $option_key ][ $field_id ] = $value; 
  804.  
  805. return self::$options[ $option_key ]; 
  806.  
  807. /** 
  808. * Retrieve option value based on name of option. 
  809. * @uses apply_filters() Calls 'cmb_override_option_get_$option_key' hook to allow 
  810. * overwriting the option value to be retrieved. 
  811. * @since 1.0.1 
  812. * @param string $option Name of option to retrieve. Expected to not be SQL-escaped. 
  813. * @param mixed $default Optional. Default value to return if the option does not exist. 
  814. * @return mixed Value set for the option. 
  815. */ 
  816. public static function _get_option( $option_key, $default = false ) { 
  817.  
  818. $test_get = apply_filters( "cmb_override_option_get_$option_key", 'cmb_no_override_option_get', $default ); 
  819.  
  820. if ( $test_get !== 'cmb_no_override_option_get' ) 
  821. return $test_get; 
  822.  
  823. // If no override, get the option 
  824. return get_option( $option_key, $default ); 
  825.  
  826. /** 
  827. * Saves the option array 
  828. * Needs to be run after finished using remove/update_option 
  829. * @uses apply_filters() Calls 'cmb_override_option_save_$option_key' hook to allow 
  830. * overwriting the option value to be stored. 
  831. * @since 1.0.1 
  832. * @param string $option_key Option key 
  833. * @return boolean Success/Failure 
  834. */ 
  835. public static function save_option( $option_key ) { 
  836.  
  837. $to_save = self::get_option( $option_key ); 
  838.  
  839. $test_save = apply_filters( "cmb_override_option_save_$option_key", 'cmb_no_override_option_save', $to_save ); 
  840.  
  841. if ( $test_save !== 'cmb_no_override_option_save' ) 
  842. return $test_save; 
  843.  
  844. // If no override, update the option 
  845. return update_option( $option_key, $to_save ); 
  846.  
  847. /** 
  848. * Utility method that returns a timezone string representing the default timezone for the site. 
  849. * Roughly copied from WordPress, as get_option('timezone_string') will return 
  850. * and empty string if no value has beens set on the options page. 
  851. * A timezone string is required by the wp_timezone_choice() used by the 
  852. * select_timezone field. 
  853. * @since 1.0.0 
  854. * @return string Timezone string 
  855. */ 
  856. public static function timezone_string() { 
  857. $current_offset = get_option( 'gmt_offset' ); 
  858. $tzstring = get_option( 'timezone_string' ); 
  859.  
  860. if ( empty( $tzstring ) ) { // Create a UTC+- zone if no timezone string exists 
  861. if ( 0 == $current_offset ) 
  862. $tzstring = 'UTC+0'; 
  863. elseif ( $current_offset < 0 ) 
  864. $tzstring = 'UTC' . $current_offset; 
  865. else 
  866. $tzstring = 'UTC+' . $current_offset; 
  867.  
  868. return $tzstring; 
  869.  
  870. /** 
  871. * Utility method that returns time string offset by timezone 
  872. * @since 1.0.0 
  873. * @param string $tzstring Time string 
  874. * @return string Offset time string 
  875. */ 
  876. public static function timezone_offset( $tzstring ) { 
  877. if ( ! empty( $tzstring ) && is_string( $tzstring ) ) { 
  878. if ( substr( $tzstring, 0, 3 ) === 'UTC' ) { 
  879. $tzstring = str_replace( array( ':15', ':30', ':45' ), array( '.25', '.5', '.75' ), $tzstring ); 
  880. return intval( floatval( substr( $tzstring, 3 ) ) * HOUR_IN_SECONDS ); 
  881.  
  882. $date_time_zone_selected = new DateTimeZone( $tzstring ); 
  883. $tz_offset = timezone_offset_get( $date_time_zone_selected, date_create() ); 
  884.  
  885. return $tz_offset; 
  886.  
  887. return 0; 
  888.  
  889. /** 
  890. * Utility method that attempts to get an attachment's ID by it's url 
  891. * @since 1.0.0 
  892. * @param string $img_url Attachment url 
  893. * @return mixed Attachment ID or false 
  894. */ 
  895. public static function image_id_from_url( $img_url ) { 
  896. global $wpdb; 
  897.  
  898. $img_url = esc_url_raw( $img_url ); 
  899. // Get just the file name 
  900. if ( false !== strpos( $img_url, '/' ) ) { 
  901. $explode = explode( '/', $img_url ); 
  902. $img_url = end( $explode ); 
  903.  
  904. // And search for a fuzzy match of the file name 
  905. $attachment = $wpdb->get_col( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE guid LIKE '%%%s%%' LIMIT 1;", $img_url ) ); 
  906.  
  907. // If we found an attachement ID, return it 
  908. if ( !empty( $attachment ) && is_array( $attachment ) ) 
  909. return $attachment[0]; 
  910.  
  911. // No luck 
  912. return false; 
  913.