PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.2
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.2
6.0.2 6.0.1 6.0.0 5.8.6 5.8.5 5.8.4 5.8.3 5.8.2 5.8.1 5.8.0 5.7.9.2 5.7.9.1 5.7.8 5.7.9 5.7.6 5.7.7 5.7.5 5.7.4 5.7.3 5.7.2 5.7.1 trunk 5.6.0 5.6.1 5.6.2 All 33 releases
automatorwp / includes / cmb2.php

cmb2.php in AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI 6.0.2, at includes/cmb2.php

732 lines 19.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * CMB2
4 *
5 * @package AutomatorWP\CMB2
6 * @author AutomatorWP <contact@automatorwp.com>, Ruben Garcia <rubengcdev@gmail.com>
7 * @since 1.0.0
8 */
9 // Exit if accessed directly
10 if( !defined( 'ABSPATH' ) ) exit;
11
12 /**
13 * Tooltip callback for CMB2 fields (used as 'after_field' callback)
14 *
15 * @since 1.0.0
16 */
17 function automatorwp_tooltip_cb() {
18 ?>
19 <div class="automatorwp-tooltip"><span class="dashicons dashicons-editor-help"></span></div>
20 <?php
21 }
22
23 /**
24 * Options callback for select2 fields assigned to posts
25 *
26 * @since 1.0.0
27 *
28 * @param stdClass $field
29 *
30 * @return array
31 */
32 function automatorwp_options_cb_posts( $field ) {
33
34 // Setup vars
35 $value = $field->escaped_value;
36 $none_value = 'any';
37 $none_label = __( 'any post', 'automatorwp' );
38 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
39
40 if( ! empty( $value ) ) {
41 if( ! is_array( $value ) ) {
42 $value = array( $value );
43 }
44
45 foreach( $value as $post_id ) {
46
47 // Skip option none and custom
48 if( isset( $options[$post_id] ) ) {
49 continue;
50 }
51
52 $options[$post_id] = get_post_field( 'post_title', $post_id );
53 }
54 }
55
56 return $options;
57
58 }
59
60 /**
61 * Options callback for select2 fields assigned to terms
62 *
63 * @since 1.0.0
64 *
65 * @param stdClass $field
66 *
67 * @return array
68 */
69 function automatorwp_options_cb_terms( $field ) {
70
71 // Setup vars
72 $value = $field->escaped_value;
73 $taxonomy = $field->args['taxonomy'];
74 $none_value = 'any';
75 $none_label = __( 'any category', 'automatorwp' );
76 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
77
78 if( ! empty( $value ) ) {
79 if( ! is_array( $value ) ) {
80 $value = array( $value );
81 }
82
83 foreach( $value as $term_id ) {
84
85 // Skip option none and custom
86 if( isset( $options[$term_id] ) ) {
87 continue;
88 }
89
90 $term = get_term( $term_id );
91
92 if( $term ) {
93 $options[$term_id] = $term->name;
94 }
95 }
96 }
97
98 return $options;
99
100 }
101
102 /**
103 * Options callback for select2 fields assigned to taxonomies
104 *
105 * @since 1.0.0
106 *
107 * @param stdClass $field
108 *
109 * @return array
110 */
111 function automatorwp_options_cb_taxonomies( $field ) {
112
113 // Setup vars
114 $none_value = 'any';
115 $none_label = __( 'any taxonomy', 'automatorwp' );
116 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
117
118 $post_types = get_post_types( array( 'public' => true ), 'objects' );
119 $taxonomies = get_taxonomies( array( 'public' => true ), 'objects' );
120 $taxonomies_to_exclude = array( 'wp_log_type' );
121
122 foreach( $taxonomies as $taxonomy => $taxonomy_obj ) {
123
124 // Skip some private taxonomies
125 if( in_array( $taxonomy, $taxonomies_to_exclude ) ) {
126 continue;
127 }
128
129 $post_types_label = '';
130 $taxonomy_post_types = array();
131
132 // Loop all taxonomy post types
133 if( is_array( $taxonomy_obj->object_type ) ) {
134
135 foreach( $taxonomy_obj->object_type as $post_type ) {
136
137 if( isset( $post_types[$post_type] ) ) {
138 $post_type_obj = $post_types[$post_type];
139 $taxonomy_post_types[] = $post_type_obj->labels->name;
140 }
141 }
142
143 }
144
145 // Setup the post types labels
146 if( ! empty( $taxonomy_post_types ) ) {
147 $post_types_label = ' (' . implode( ', ', $taxonomy_post_types ) . ')';
148 }
149
150 $options[$taxonomy] = $taxonomy_obj->labels->name . $post_types_label;
151 }
152
153 return $options;
154
155 }
156
157 /**
158 * Options callback for select2 fields assigned to users
159 *
160 * @since 1.0.0
161 *
162 * @param CMB2_Field $field
163 *
164 * @return array
165 */
166 function automatorwp_options_cb_users( $field ) {
167
168 $value = $field->escaped_value;
169 $options = array();
170
171 if( ! empty( $value ) ) {
172 if( ! is_array( $value ) ) {
173 $value = array( $value );
174 }
175
176 foreach( $value as $user_id ) {
177 $user_data = get_userdata( $user_id );
178
179 $options[$user_id] = $user_data->user_login;
180 }
181 }
182
183 return $options;
184
185 }
186
187 /**
188 * Display callback for select2 fields assigned to users
189 *
190 * @since 1.3.0
191 *
192 * @param array $field_args
193 * @param CMB2_Field $field
194 *
195 * @return array
196 */
197 function automatorwp_display_cb_users( $field_args, $field ) {
198
199 $value = $field->escaped_value();
200 $options = array();
201
202 if( ! empty( $value ) ) {
203
204 if( ! is_array( $value ) ) {
205 $value = array( $value );
206 }
207
208 foreach( $value as $user_id ) {
209 $user_data = get_userdata( $user_id );
210
211 $options[$user_id] = $user_data->user_login;
212 }
213
214 $value = implode( ', ', $options );
215 }
216
217 return $value;
218
219 }
220
221 /**
222 * Options callback for post type options
223 *
224 * @since 1.0.0
225 *
226 * @param stdClass $field
227 *
228 * @return array
229 */
230 function automatorwp_options_cb_post_types( $field ) {
231
232 // Setup vars
233 $none_value = 'any';
234 $none_label = __( 'a post of any type', 'automatorwp' );
235 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
236
237 // Get all public post types which means they are visitable
238 $post_types = get_post_types( array(), 'objects' );
239
240 $post_types_excluded = array(
241 'revision',
242 'nav_menu_item',
243 'custom_css',
244 'customize_changeset',
245 'user_request',
246 'oembed_cache',
247 'wp_block',
248 'wp_template',
249 );
250
251 /**
252 * Filter available to extend the post types excluded for the post type selector
253 *
254 * @since 1.0.0
255 *
256 * @param array $post_types_excluded
257 * @param stdClass $field
258 *
259 * @return array
260 */
261 $post_types_excluded = apply_filters( 'automatorwp_options_cb_post_types_excluded', $post_types_excluded, $field );
262
263 // Unset excluded post types
264 foreach( $post_types_excluded as $excluded ) {
265 if( isset( $post_types[$excluded] ) ) {
266 unset( $post_types[$excluded] );
267 }
268 }
269
270 /**
271 * Filter available to extend the post types for the post type selector
272 *
273 * @since 1.0.0
274 *
275 * @param array $post_types
276 * @param stdClass $field
277 *
278 * @return array
279 */
280 $post_types = apply_filters( 'automatorwp_options_cb_post_types', $post_types, $field );
281
282 foreach( $post_types as $post_type => $post_type_object ) {
283 $options[$post_type] = sprintf( __( 'a %s', 'automatorwp' ), strtolower( $post_type_object->labels->singular_name ) );
284 }
285
286 return $options;
287
288 }
289
290 /**
291 * Options callback for post type options
292 *
293 * @since 1.0.0
294 *
295 * @param stdClass $field
296 *
297 * @return array
298 */
299 function automatorwp_options_cb_post_status( $field ) {
300
301 global $wp_post_statuses;
302
303 if ( ! is_array( $wp_post_statuses ) ) {
304 $wp_post_statuses = array();
305 }
306
307 // Setup vars
308 $none_value = 'any';
309 $none_label = __( 'any status', 'automatorwp' );
310 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
311
312 if( count( $wp_post_statuses ) ) {
313
314 // Get statuses from registered post statuses
315 foreach( $wp_post_statuses as $post_status => $args ) {
316 $options[$post_status] = $args->label . ' (' . $post_status . ')';
317 }
318
319 } else {
320 // If post statuses global is empty fallback to get_post_statuses()
321
322 $post_statuses = get_post_statuses();
323
324 foreach( $post_statuses as $post_status => $post_status_label ) {
325 $options[$post_status] = $post_status_label;
326 }
327
328 }
329
330 return $options;
331
332 }
333
334 /**
335 * Options callback for post fields
336 *
337 * @since 1.0.0
338 *
339 * @param stdClass $field
340 *
341 * @return array
342 */
343 function automatorwp_options_cb_post_fields( $field ) {
344
345 // Option none
346 $none_value = 'any';
347 $none_label = __( 'any field', 'automatorwp' );
348 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
349
350 $post_fields = array(
351 'ID' => __( 'ID', 'automatorwp' ),
352 'post_title' => __( 'Title', 'automatorwp' ),
353 'post_name' => __( 'Slug', 'automatorwp' ),
354 'post_type' => __( 'Type', 'automatorwp' ),
355 'post_status' => __( 'Status', 'automatorwp' ),
356 'post_date' => __( 'Date', 'automatorwp' ),
357 'post_date_gmt' => __( 'Date (GMT)', 'automatorwp' ),
358 'post_modified' => __( 'Date Modified', 'automatorwp' ),
359 'post_modified_gmt' => __( 'Date Modified (GMT)', 'automatorwp' ),
360 'post_author' => __( 'Author', 'automatorwp' ),
361 'post_content' => __( 'Content', 'automatorwp' ),
362 'post_excerpt' => __( 'Excerpt', 'automatorwp' ),
363 'post_parent' => __( 'Parent', 'automatorwp' ),
364 'menu_order' => __( 'Order', 'automatorwp' ),
365 'post_password' => __( 'Password', 'automatorwp' ),
366 );
367
368 $post_fields = apply_filters( 'automatorwp_get_post_fields', $post_fields );
369
370 // Excluded roles
371 $field->args['excluded_post_fields'] = ( isset( $field->args['excluded_post_fields'] ) ? $field->args['excluded_post_fields'] : array() );
372
373 // Ensure excluded roles as array
374 if( ! is_array( $field->args['excluded_post_fields'] ) ) {
375 $field->args['excluded_post_fields'] = array( $field->args['excluded_post_fields'] );
376 }
377
378 foreach ( $post_fields as $post_field => $post_field_label ) {
379
380 // Skip excluded roles
381 if( in_array( $post_field, $field->args['excluded_post_fields'] ) ) {
382 continue;
383 }
384
385 $options[$post_field] = $post_field_label;
386
387 }
388
389 return $options;
390
391 }
392
393 /**
394 * Options callback for user fields
395 *
396 * @since 1.0.0
397 *
398 * @param stdClass $field
399 *
400 * @return array
401 */
402 function automatorwp_options_cb_user_fields( $field ) {
403
404 // Option none
405 $none_value = 'any';
406 $none_label = __( 'any field', 'automatorwp' );
407 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
408
409 $user_fields = array(
410 'ID' => __( 'ID', 'automatorwp' ),
411 'user_login' => __( 'Username', 'automatorwp' ),
412 'user_email' => __( 'Email', 'automatorwp' ),
413 'display_name' => __( 'Display name', 'automatorwp' ),
414 'user_nicename' => __( 'Nicename', 'automatorwp' ),
415 'user_url' => __( 'Website', 'automatorwp' ),
416 'user_registered' => __( 'Registration Date', 'automatorwp' ),
417 );
418
419 $user_fields = apply_filters( 'automatorwp_get_user_fields', $user_fields );
420
421 // Excluded roles
422 $field->args['excluded_user_fields'] = ( isset( $field->args['excluded_user_fields'] ) ? $field->args['excluded_user_fields'] : array() );
423
424 // Ensure excluded roles as array
425 if( ! is_array( $field->args['excluded_user_fields'] ) ) {
426 $field->args['excluded_user_fields'] = array( $field->args['excluded_user_fields'] );
427 }
428
429 foreach ( $user_fields as $user_field => $user_field_label ) {
430
431 // Skip excluded roles
432 if( in_array( $user_field, $field->args['excluded_user_fields'] ) ) {
433 continue;
434 }
435
436 $options[$user_field] = $user_field_label;
437
438 }
439
440 return $options;
441
442 }
443
444 /**
445 * Options callback for WordPress roles
446 *
447 * @since 1.0.0
448 *
449 * @param stdClass $field
450 *
451 * @return array
452 */
453 function automatorwp_options_cb_roles( $field ) {
454
455 // Option none
456 $none_value = 'any';
457 $none_label = __( 'any role', 'automatorwp' );
458 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
459
460 $roles = automatorwp_get_editable_roles();
461
462 // Excluded roles
463 $field->args['excluded_roles'] = ( isset( $field->args['excluded_roles'] ) ? $field->args['excluded_roles'] : array() );
464
465 // Ensure excluded roles as array
466 if( ! is_array( $field->args['excluded_roles'] ) ) {
467 $field->args['excluded_roles'] = array( $field->args['excluded_roles'] );
468 }
469
470 foreach ( $roles as $role => $details ) {
471
472 // Skip excluded roles
473 if( in_array( $role, $field->args['excluded_roles'] ) ) {
474 continue;
475 }
476
477 $options[$role] = translate_user_role( $details['name'] );
478
479 }
480
481 return $options;
482
483 }
484
485 /**
486 * Options callback for select2 fields assigned to objects
487 *
488 * @since 1.0.0
489 *
490 * @param stdClass $field
491 *
492 * @return array
493 */
494 function automatorwp_options_cb_objects( $field ) {
495
496 // Setup vars
497 $value = $field->escaped_value;
498 $none_value = '';
499 $none_label = __( 'any item', 'automatorwp' );
500 $options = automatorwp_options_cb_none_option( $field, $none_value, $none_label );
501
502 // Ensure that required attributes are set
503 if( ! isset( $field->args['attributes'] ) ) {
504 return $options;
505 }
506
507 // Ensure that data-table is set
508 if( ! isset( $field->args['attributes']['data-table'] ) ) {
509 return $options;
510 }
511
512 if( ! empty( $value ) ) {
513
514 ct_setup_table( $field->args['attributes']['data-table'] );
515
516 if( ! is_array( $value ) ) {
517 $value = array( $value );
518 }
519
520 foreach( $value as $object_id ) {
521
522 // Skip option none and custom
523 if( isset( $options[$object_id] ) ) {
524 continue;
525 }
526
527 $object = ct_get_object( $object_id );
528
529 $title = ( ! empty( $object->title ) ? $object->title : __( '(No title)', 'automatorwp' ) );
530
531 $options[$object_id] = $title;
532
533 }
534
535 ct_reset_setup_table();
536 }
537
538 return $options;
539
540 }
541
542 /**
543 * Options callback for select2 fields assigned to posts
544 *
545 * @since 1.0.0
546 *
547 * @param stdClass $field
548 *
549 * @return array
550 */
551 function automatorwp_options_cb_filters( $field ) {
552
553 $options = array(
554 'any' => __( 'Choose a filter', 'automatorwp' )
555 );
556
557 foreach( AutomatorWP()->filters as $filter => $args ) {
558
559 // Skip if integration is not registered
560 if( ! isset( AutomatorWP()->integrations[$args['integration']] ) ) {
561 continue;
562 }
563
564 $integration = $args['integration'];
565
566 if( ! isset( $options[$integration] ) ) {
567 $options[$integration] = array();
568 }
569
570 $options[$integration][$filter] = $args['label'];
571 }
572
573 return $options;
574
575 }
576
577 /**
578 * Options callback for select2 fields assigned to posts
579 *
580 * @since 1.0.0
581 *
582 * @param stdClass $field
583 *
584 * @return array
585 */
586 function automatorwp_options_cb_automation_statuses( $field ) {
587
588 $options = automatorwp_get_automation_statuses();
589
590 $object_id = $field->object_id;
591
592 $object = ct_get_object( $object_id );
593
594 if( ! in_array( $object->type, automatorwp_get_automation_loop_types() ) ) {
595 unset( $options['in-progress'] );
596 }
597
598 return apply_filters( 'automatorwp_options_cb_automation_statuses', $options, $field );
599
600 }
601
602 /**
603 * Helper function to handle option none
604 *
605 * @since 1.0.0
606 *
607 * @param stdClass $field
608 * @param string $default_value
609 * @param string $default_label
610 *
611 * @return array
612 */
613 function automatorwp_options_cb_none_option( $field, $default_value = '', $default_label = '' ) {
614
615 $options = array();
616
617 // Setup option custom
618 if( isset( $field->args['option_custom'] ) && $field->args['option_custom'] ) {
619
620 $custom_value = ( isset( $field->args['option_custom_value'] ) ? $field->args['option_custom_value'] : 'custom' );
621 $custom_label = ( isset( $field->args['option_custom_label'] ) ? $field->args['option_custom_label'] : __( 'Use a custom value', 'automatorwp' ) );
622
623 $options[$custom_value] = $custom_label;
624 }
625
626 $none_value = $default_value;
627 $none_label = $default_label;
628
629 // Setup option none
630 if( isset( $field->args['option_none'] ) && $field->args['option_none'] ) {
631
632 $none_value = ( isset( $field->args['option_none_value'] ) ? $field->args['option_none_value'] : $none_value );
633 $none_label = ( isset( $field->args['option_none_label'] ) ? $field->args['option_none_label'] : $none_label );
634
635 $options[$none_value] = $none_label;
636 }
637
638 return $options;
639
640 }
641
642 /**
643 * Handles sanitization for textarea, wysiwyg and oembed fields to allow tags
644 *
645 * @since 1.3.3
646 *
647 * @param mixed $value The unsanitized value from the form.
648 * @param array $field_args Array of field arguments.
649 * @param CMB2_Field $field The field object
650 *
651 * @return mixed Sanitized value to be stored.
652 */
653 function automatorwp_textarea_sanitization_cb( $value, $field_args, $field ) {
654
655 $allowed_protocols = wp_allowed_protocols();
656
657 // Look for tags
658 preg_match_all( "/\{\s*(.*?)\s*\}/", $value, $matches );
659
660 if( is_array( $matches ) && isset( $matches[1] ) ) {
661
662 foreach( $matches[1] as $tag_name ) {
663
664 // Check if is a trigger tag
665 if( strpos( $tag_name, ':' ) !== false) {
666
667 $tag_parts = explode( ':', $tag_name );
668
669 if( isset( $tag_parts[0] ) ) {
670 $trigger_id = $tag_parts[0];
671 $protocol = "{{$trigger_id}";
672
673 if( ! in_array( $protocol, $allowed_protocols ) ) {
674 // Add the "{ID:" as allowed protocol
675 $allowed_protocols[] = $protocol;
676 }
677 }
678
679 }
680 }
681
682 }
683
684 return wp_kses( $value, 'post', $allowed_protocols );
685
686 }
687
688 /**
689 * Helper function to get a field options from the "options" or "options_cb"
690 *
691 * @since 2.0.4
692 *
693 * @param array $field The field configuration
694 *
695 * @return array
696 */
697 function automatorwp_get_field_options( $field ) {
698
699 // Get the field options
700 $field_options = array();
701
702 // Try to get the field options from field args
703 if( isset( $field['options'] ) ) {
704
705 $field_options = $field['options'];
706
707 } else if( isset( $field['options_cb'] ) && is_callable( $field['options_cb'] ) ) {
708
709 $value = ( isset( $field['value'] ) ? $field['value'] : '' );
710
711 $field['value'] = $value;
712 $field['escaped_value'] = $value;
713 $field['args'] = $field;
714
715 $field_options = call_user_func( $field['options_cb'], (object) $field );
716
717 }
718
719 return $field_options;
720
721 }
722
723 /**
724 * Clear callback for CMB2 fields (used as 'after_row' callback)
725 *
726 * @since 1.0.0
727 */
728 function automatorwp_cmb2_div_clear_cb() {
729 ?>
730 <div class="clear"></div>
731 <?php
732 }