| @@ -1,0 +1,430 @@ | ||
| 1 | +<?php | |
| 2 | +/** | |
| 3 | + * Compatibility with CMB2 | |
| 4 | + * | |
| 5 | + * @since 1.0.0 | |
| 6 | + */ | |
| 7 | +// Exit if accessed directly | |
| 8 | +defined( 'ABSPATH' ) || exit; | |
| 9 | + | |
| 10 | +/** | |
| 11 | + * Check if should override on admin init action | |
| 12 | + * | |
| 13 | + * @since 1.0.0 | |
| 14 | + * | |
| 15 | + * @param $ct_table_name | |
| 16 | + * @param $object | |
| 17 | + */ | |
| 18 | +function ct_cmb2_admin_init() { | |
| 19 | + | |
| 20 | + global $ct_registered_tables, $ct_table, $ct_cmb2_override, $pagenow; | |
| 21 | + | |
| 22 | + // Setup a custom global to meet that we need to override it | |
| 23 | + $ct_cmb2_override = false; | |
| 24 | + | |
| 25 | + // Check if is on admin.php | |
| 26 | + if( $pagenow !== 'admin.php' ) { | |
| 27 | + return; | |
| 28 | + } | |
| 29 | + | |
| 30 | + // Check if isset page query parameter | |
| 31 | + if( ! isset( $_GET['page'] ) ) { | |
| 32 | + return; | |
| 33 | + } | |
| 34 | + | |
| 35 | + foreach( $ct_registered_tables as $ct_registered_table ) { | |
| 36 | + | |
| 37 | + // Check if is a list page slug (to allow work in the add form) | |
| 38 | + if( $_GET['page'] === $ct_registered_table->views->list->get_slug() | |
| 39 | + && $ct_registered_table->views->list->add_form ) { | |
| 40 | + // Let know to this compatibility module it needs to operate | |
| 41 | + $ct_cmb2_override = true; | |
| 42 | + } | |
| 43 | + | |
| 44 | + // Check if is edit page slug | |
| 45 | + if( $_GET['page'] === $ct_registered_table->views->edit->get_slug() ) { | |
| 46 | + // Let know to this compatibility module it needs to operate | |
| 47 | + $ct_cmb2_override = true; | |
| 48 | + } | |
| 49 | + } | |
| 50 | + | |
| 51 | +} | |
| 52 | +add_action( 'admin_init', 'ct_cmb2_admin_init', 1 ); | |
| 53 | + | |
| 54 | +/** | |
| 55 | + * Check if should override on add meta boxes action | |
| 56 | + * | |
| 57 | + * @since 1.0.0 | |
| 58 | + * | |
| 59 | + * @param $ct_table_name | |
| 60 | + * @param $object | |
| 61 | + */ | |
| 62 | +function ct_cmb2_add_meta_boxes( $ct_table_name, $object ) { | |
| 63 | + | |
| 64 | + global $ct_registered_tables, $ct_table, $ct_cmb2_override; | |
| 65 | + | |
| 66 | + // If not is a registered table, return | |
| 67 | + if( ! isset( $ct_registered_tables[$ct_table_name] ) ) { | |
| 68 | + return; | |
| 69 | + } | |
| 70 | + | |
| 71 | + // If not object given, return | |
| 72 | + if( ! $object ) { | |
| 73 | + return; | |
| 74 | + } | |
| 75 | + | |
| 76 | + $primary_key = $ct_table->db->primary_key; | |
| 77 | + | |
| 78 | + // Setup a false post var to allow CMB2 trigger cmb2_override_meta_value hook | |
| 79 | + $_REQUEST['post'] = $object->$primary_key; | |
| 80 | + | |
| 81 | + // Let know to this compatibility module it needs to operate | |
| 82 | + $ct_cmb2_override = true; | |
| 83 | + | |
| 84 | + // Fix: CMB2 stop enqueuing their assets so need to add it again | |
| 85 | + CMB2_Hookup::enqueue_cmb_css(); | |
| 86 | + CMB2_Hookup::enqueue_cmb_js(); | |
| 87 | + | |
| 88 | +} | |
| 89 | +add_action( 'add_meta_boxes', 'ct_cmb2_add_meta_boxes', 10, 2 ); | |
| 90 | + | |
| 91 | +/** | |
| 92 | + * On save an object, let it know to CMB2 | |
| 93 | + * | |
| 94 | + * @since 1.0.0 | |
| 95 | + * | |
| 96 | + * @param $object_id | |
| 97 | + * @param $object | |
| 98 | + */ | |
| 99 | +function ct_cmb2_save_object( $object_id, $object ) { | |
| 100 | + | |
| 101 | + global $ct_registered_tables, $ct_table, $ct_cmb2_override; | |
| 102 | + | |
| 103 | + // Return if CMB2 not exists | |
| 104 | + if( ! class_exists( 'CMB2' ) ) { | |
| 105 | + return; | |
| 106 | + } | |
| 107 | + | |
| 108 | + // Return if user is not allowed | |
| 109 | + if ( $object_id !== 0 && ! current_user_can( $ct_table->cap->edit_item, $object_id ) ) { | |
| 110 | + return; | |
| 111 | + } | |
| 112 | + | |
| 113 | + if ( $object_id === 0 && ! current_user_can( $ct_table->cap->edit_items ) ) { | |
| 114 | + return; | |
| 115 | + } | |
| 116 | + | |
| 117 | + // Setup a custom global to meet that we need to override it | |
| 118 | + $ct_cmb2_override = true; | |
| 119 | + | |
| 120 | + // Loop all registered boxes | |
| 121 | + foreach( CMB2_Boxes::get_all() as $cmb ) { | |
| 122 | + | |
| 123 | + // Skip meta boxes that do not support this CT_Table | |
| 124 | + if( ! in_array( $ct_table->name, $cmb->meta_box['object_types'] ) ) { | |
| 125 | + continue; | |
| 126 | + } | |
| 127 | + | |
| 128 | + // Take a trip to reading railroad – if you pass go collect $200 | |
| 129 | + $cmb->save_fields( $object_id, 'post', $_POST ); | |
| 130 | + } | |
| 131 | + | |
| 132 | +} | |
| 133 | +add_action( 'ct_save_object', 'ct_cmb2_save_object', 10, 2 ); | |
| 134 | + | |
| 135 | +/** | |
| 136 | + * Override the CMB2 field value | |
| 137 | + * | |
| 138 | + * @since 1.0.0 | |
| 139 | + * | |
| 140 | + * @param $value | |
| 141 | + * @param $object_id | |
| 142 | + * @param $args | |
| 143 | + * @param $field | |
| 144 | + * | |
| 145 | + * @return mixed|string | |
| 146 | + */ | |
| 147 | +function ct_cmb2_override_meta_value( $value, $object_id, $args, $field ) { | |
| 148 | + | |
| 149 | + global $ct_registered_tables, $ct_table, $ct_cmb2_override; | |
| 150 | + | |
| 151 | + if( ! is_a( $ct_table, 'CT_Table' ) ) { | |
| 152 | + return $value; | |
| 153 | + } | |
| 154 | + | |
| 155 | + if( $ct_cmb2_override !== true ) { | |
| 156 | + return $value; | |
| 157 | + } | |
| 158 | + | |
| 159 | + $object = (array) ct_get_object( $object_id ); | |
| 160 | + | |
| 161 | + // Check if is a main field | |
| 162 | + if( isset( $object[$args['field_id']] ) ) { | |
| 163 | + return $object[$args['field_id']]; | |
| 164 | + } | |
| 165 | + | |
| 166 | + // If not is a main field and CT_Table supports meta data, then try to get its value from meta table | |
| 167 | + if( in_array( 'meta', $ct_table->supports ) ) { | |
| 168 | + return ct_get_object_meta( $object_id, $args['field_id'], ( $args['single'] || $args['repeat'] ) ); | |
| 169 | + } | |
| 170 | + | |
| 171 | + return ''; | |
| 172 | +} | |
| 173 | +add_filter( 'cmb2_override_meta_value', 'ct_cmb2_override_meta_value', 10, 4 ); | |
| 174 | + | |
| 175 | +/** | |
| 176 | + * Override the CMB2 field value save | |
| 177 | + * | |
| 178 | + * @since 1.0.0 | |
| 179 | + * | |
| 180 | + * @param $check | |
| 181 | + * @param $args | |
| 182 | + * @param $field_args | |
| 183 | + * @param $field | |
| 184 | + * | |
| 185 | + * @return bool|false|int | |
| 186 | + */ | |
| 187 | +function ct_cmb2_override_meta_save( $check, $args, $field_args, $field ) { | |
| 188 | + | |
| 189 | + global $ct_registered_tables, $ct_table, $ct_cmb2_override; | |
| 190 | + | |
| 191 | + if( $ct_cmb2_override !== true ) { | |
| 192 | + return $check; | |
| 193 | + } | |
| 194 | + | |
| 195 | + $object = (array) ct_get_object( $args['id'] ); | |
| 196 | + | |
| 197 | + // If not is a main field and CT_Table supports meta data, then try to save the given value to the meta table | |
| 198 | + // Note: Main fields are automatically stored by the save method on the CT_Edit_View edit screen | |
| 199 | + if( ! isset( $object[$args['field_id']] ) && in_array( 'meta', $ct_table->supports ) ) { | |
| 200 | + | |
| 201 | + // Add metadata if not single | |
| 202 | + if ( ! $args['single'] ) { | |
| 203 | + return ct_add_object_meta( $args['id'], $args['field_id'], $args['value'], false ); | |
| 204 | + } | |
| 205 | + | |
| 206 | + // Delete meta if we have an empty array | |
| 207 | + if ( is_array( $args['value'] ) && empty( $args['value'] ) ) { | |
| 208 | + return ct_delete_object_meta( $args['id'], $args['field_id'], $field->value ); | |
| 209 | + } | |
| 210 | + | |
| 211 | + // Update metadata | |
| 212 | + return ct_update_object_meta( $args['id'], $args['field_id'], $args['value'] ); | |
| 213 | + | |
| 214 | + } | |
| 215 | + | |
| 216 | + return $check; | |
| 217 | + | |
| 218 | +} | |
| 219 | +add_filter( 'cmb2_override_meta_save', 'ct_cmb2_override_meta_save', 10, 4 ); | |
| 220 | + | |
| 221 | +/** | |
| 222 | + * Override the CMB2 field value remove | |
| 223 | + * | |
| 224 | + * @since 1.0.0 | |
| 225 | + * | |
| 226 | + * @param $check | |
| 227 | + * @param $args | |
| 228 | + * @param $field_args | |
| 229 | + * @param $field | |
| 230 | + * | |
| 231 | + * @return bool|false|int | |
| 232 | + */ | |
| 233 | +function ct_cmb2_override_meta_remove( $check, $args, $field_args, $field ) { | |
| 234 | + | |
| 235 | + global $ct_registered_tables, $ct_table, $ct_cmb2_override, $wpdb; | |
| 236 | + | |
| 237 | + if( $ct_cmb2_override !== true ) { | |
| 238 | + return $check; | |
| 239 | + } | |
| 240 | + | |
| 241 | + $object = (array) ct_get_object( $args['id'] ); | |
| 242 | + | |
| 243 | + // If not is a main field and CT_Table supports meta data, then try to remove the given value to the meta table | |
| 244 | + // Note: Main fields are automatically managed by the save method on the CT_Edit_View edit screen | |
| 245 | + if( ! isset( $object[$args['field_id']] ) && in_array( 'meta', $ct_table->supports ) ) { | |
| 246 | + | |
| 247 | + if( $field_args['multiple'] && ! $field_args['repeatable'] ) { | |
| 248 | + // Delete multiple entries | |
| 249 | + $meta_table_name = $ct_table->meta->db->table_name; | |
| 250 | + $primary_key = $ct_table->db->primary_key; | |
| 251 | + | |
| 252 | + $where = array( | |
| 253 | + 'meta_key' => $args['field_id'] | |
| 254 | + ); | |
| 255 | + | |
| 256 | + $where[$primary_key] = $args['id']; | |
| 257 | + | |
| 258 | + return $wpdb->delete( $meta_table_name, $where ); | |
| 259 | + | |
| 260 | + } else { | |
| 261 | + // Delete single entry | |
| 262 | + return ct_delete_object_meta( $args['id'], $args['field_id'], $field->value ); | |
| 263 | + } | |
| 264 | + | |
| 265 | + } | |
| 266 | + | |
| 267 | + return $check; | |
| 268 | + | |
| 269 | +} | |
| 270 | +add_filter( 'cmb2_override_meta_remove', 'ct_cmb2_override_meta_remove', 10, 4 ); | |
| 271 | + | |
| 272 | +function ct_cmb_get_new_field( $field_args, $field_group = null ) { | |
| 273 | + | |
| 274 | + if ( $field_group ) { | |
| 275 | + $args = array( | |
| 276 | + 'field_args' => $field_args, | |
| 277 | + 'group_field' => $field_group, | |
| 278 | + ); | |
| 279 | + } else { | |
| 280 | + $args = array( | |
| 281 | + 'field_args' => $field_args, | |
| 282 | +// 'object_type' => $this->object_type(), | |
| 283 | +// 'object_id' => $this->object_id(), | |
| 284 | +// 'cmb_id' => $this->cmb_id, | |
| 285 | + ); | |
| 286 | + } | |
| 287 | + | |
| 288 | + return new CMB2_Field( $args ); | |
| 289 | +} | |
| 290 | + | |
| 291 | +/** | |
| 292 | + * Helper function to sanitize data when inserting objects | |
| 293 | + * | |
| 294 | + * @param CMB2 $cmb CMB2 object | |
| 295 | + * @param array $data Data to sanitize | |
| 296 | + * | |
| 297 | + * @return array Sanitized data | |
| 298 | + */ | |
| 299 | +function ct_cmb_get_sanitized_data( $cmb, $data ) { | |
| 300 | + | |
| 301 | + $sanitized_data = array(); | |
| 302 | + | |
| 303 | + foreach ( $cmb->prop( 'fields' ) as $field_args ) { | |
| 304 | + | |
| 305 | + switch ( $field_args['type'] ) { | |
| 306 | + | |
| 307 | + case 'group': | |
| 308 | + if ( ! isset( $field_args['id'], $field_args['fields'] ) || ! is_array( $field_args['fields'] ) ) { | |
| 309 | + break; | |
| 310 | + } | |
| 311 | + | |
| 312 | + $field_group = ct_cmb_get_new_field( $field_args ); | |
| 313 | + | |
| 314 | + $sanitized_data[$field_group->id( true )] = ct_cmb_get_group_sanitized_data( $cmb, $field_group, $data ); | |
| 315 | + | |
| 316 | + break; | |
| 317 | + | |
| 318 | + case 'title': | |
| 319 | + // Don't process title fields. | |
| 320 | + break; | |
| 321 | + | |
| 322 | + default: | |
| 323 | + $field = ct_cmb_get_new_field( $field_args ); | |
| 324 | + | |
| 325 | + $value = isset( $data[ $field->id( true ) ] ) | |
| 326 | + ? $data[ $field->id( true ) ] | |
| 327 | + : null; | |
| 328 | + | |
| 329 | + $sanitized_data[$field->id( true )] = $field->sanitization_cb( $value ); | |
| 330 | + | |
| 331 | + break; | |
| 332 | + } | |
| 333 | + | |
| 334 | + } | |
| 335 | + | |
| 336 | + return apply_filters( 'ct_cmb2_get_sanitized_data', $sanitized_data, $data, $cmb ); | |
| 337 | + | |
| 338 | +} | |
| 339 | + | |
| 340 | +/** | |
| 341 | + * Helper function to sanitize data from a group field | |
| 342 | + * | |
| 343 | + * @param CMB2 $cmb CMB2 object | |
| 344 | + * @param CMB2_Field $field_group Field group object | |
| 345 | + * @param array $data Data to sanitize | |
| 346 | + * | |
| 347 | + * @return array Sanitized data | |
| 348 | + */ | |
| 349 | +function ct_cmb_get_group_sanitized_data( $cmb, $field_group, $data ) { | |
| 350 | + | |
| 351 | + $base_id = $field_group->id(); | |
| 352 | + | |
| 353 | + if ( ! isset( $data[ $base_id ] ) ) { | |
| 354 | + return array(); | |
| 355 | + } | |
| 356 | + | |
| 357 | + $old = $field_group->get_data(); | |
| 358 | + // Check if group field has sanitization_cb. | |
| 359 | + $group_vals = $field_group->sanitization_cb( $data[ $base_id ] ); | |
| 360 | + $saved = array(); | |
| 361 | + | |
| 362 | + $field_group->index = 0; | |
| 363 | + $field_group->data_to_save = $data; | |
| 364 | + | |
| 365 | + foreach ( array_values( $field_group->fields() ) as $field_args ) { | |
| 366 | + if ( 'title' === $field_args['type'] ) { | |
| 367 | + // Don't process title fields. | |
| 368 | + continue; | |
| 369 | + } | |
| 370 | + | |
| 371 | + $field = ct_cmb_get_new_field( $field_args, $field_group ); | |
| 372 | + $sub_id = $field->id( true ); | |
| 373 | + if ( empty( $saved[ $field_group->index ] ) ) { | |
| 374 | + $saved[ $field_group->index ] = array(); | |
| 375 | + } | |
| 376 | + | |
| 377 | + foreach ( (array) $group_vals as $field_group->index => $post_vals ) { | |
| 378 | + | |
| 379 | + // Get value. | |
| 380 | + $new_val = isset( $group_vals[ $field_group->index ][ $sub_id ] ) | |
| 381 | + ? $group_vals[ $field_group->index ][ $sub_id ] | |
| 382 | + : false; | |
| 383 | + | |
| 384 | + // Sanitize. | |
| 385 | + $new_val = $field->sanitization_cb( $new_val ); | |
| 386 | + | |
| 387 | + if ( is_array( $new_val ) && $field->args( 'has_supporting_data' ) ) { | |
| 388 | + if ( $field->args( 'repeatable' ) ) { | |
| 389 | + $_new_val = array(); | |
| 390 | + foreach ( $new_val as $group_index => $grouped_data ) { | |
| 391 | + // Add the supporting data to the $saved array stack. | |
| 392 | + $saved[ $field_group->index ][ $grouped_data['supporting_field_id'] ][] = $grouped_data['supporting_field_value']; | |
| 393 | + // Reset var to the actual value. | |
| 394 | + $_new_val[ $group_index ] = $grouped_data['value']; | |
| 395 | + } | |
| 396 | + $new_val = $_new_val; | |
| 397 | + } else { | |
| 398 | + // Add the supporting data to the $saved array stack. | |
| 399 | + $saved[ $field_group->index ][ $new_val['supporting_field_id'] ] = $new_val['supporting_field_value']; | |
| 400 | + // Reset var to the actual value. | |
| 401 | + $new_val = $new_val['value']; | |
| 402 | + } | |
| 403 | + } | |
| 404 | + | |
| 405 | + // Get old value. | |
| 406 | + $old_val = is_array( $old ) && isset( $old[ $field_group->index ][ $sub_id ] ) | |
| 407 | + ? $old[ $field_group->index ][ $sub_id ] | |
| 408 | + : false; | |
| 409 | + | |
| 410 | + $is_updated = ( ! CMB2_Utils::isempty( $new_val ) && $new_val !== $old_val ); | |
| 411 | + $is_removed = ( CMB2_Utils::isempty( $new_val ) && ! CMB2_Utils::isempty( $old_val ) ); | |
| 412 | + | |
| 413 | + // Compare values and add to `$updated` array. | |
| 414 | + if ( $is_updated || $is_removed ) { | |
| 415 | + //$cmb->updated[] = $base_id . '::' . $field_group->index . '::' . $sub_id; | |
| 416 | + } | |
| 417 | + | |
| 418 | + // Add to `$saved` array. | |
| 419 | + $saved[ $field_group->index ][ $sub_id ] = $new_val; | |
| 420 | + | |
| 421 | + }// End foreach. | |
| 422 | + | |
| 423 | + $saved[ $field_group->index ] = CMB2_Utils::filter_empty( $saved[ $field_group->index ] ); | |
| 424 | + }// End foreach. | |
| 425 | + | |
| 426 | + $saved = CMB2_Utils::filter_empty( $saved ); | |
| 427 | + | |
| 428 | + return $saved; | |
| 429 | + | |
| 430 | +} | |