PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.3
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.3
6.0.3 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 All 34 releases
← All changes | includes/cmb2.php +732 -0 5.6.1 → 6.0.3 View file →
@@ -1,0 +1,732 @@
1 +<?php
2 +/**
3 + * CMB2
4 + *
5 + * @package AutomatorWP\CMB2
6 + * @author AutomatorWP <[email protected]>, Ruben Garcia <[email protected]>
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 +}