PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 5.8.5
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v5.8.5
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
automatorwp / includes / custom-tables / automations.php

automations.php in AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI 5.8.5, at includes/custom-tables/automations.php

1,093 lines 37.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Automations
4 *
5 * @package AutomatorWP\Custom_Tables\Automations
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 * Custom Table Labels
14 *
15 * @since 1.0.0
16 *
17 * @return array
18 */
19 function automatorwp_automations_labels() {
20
21 return array(
22 'singular' => __( 'Automation', 'automatorwp' ),
23 'plural' => __( 'Automations', 'automatorwp' ),
24 'labels' => array(
25 'list_menu_title' => __( 'Automations', 'automatorwp' ),
26 ),
27 );
28
29 }
30 add_filter( 'ct_automatorwp_automations_labels', 'automatorwp_automations_labels' );
31
32 /**
33 * Parse query args for automations
34 *
35 * @since 1.0.0
36 *
37 * @param string $where
38 * @param CT_Query $ct_query
39 *
40 * @return string
41 */
42 function automatorwp_automations_query_where( $where, $ct_query ) {
43
44 global $ct_table;
45
46 if( $ct_table->name !== 'automatorwp_automations' ) {
47 return $where;
48 }
49
50 $table_name = $ct_table->db->table_name;
51
52 // Shorthand
53 $qv = $ct_query->query_vars;
54
55 // Status
56 $where .= automatorwp_custom_table_where( $qv, 'status', 'status', 'string' );
57
58 // Type
59 $where .= automatorwp_custom_table_where( $qv, 'type', 'type', 'string' );
60
61 // User ID
62 $where .= automatorwp_custom_table_where( $qv, 'user_id', 'user_id', 'integer' );
63
64 return $where;
65 }
66 add_filter( 'ct_query_where', 'automatorwp_automations_query_where', 10, 2 );
67
68 /**
69 * Parse query args to be applied on JOIN clause
70 *
71 * @since 2.0.0
72 *
73 * @param string $join
74 * @param CT_Query $ct_query
75 *
76 * @return string
77 */
78 function automatorwp_automations_query_join( $join, $ct_query ) {
79
80 global $ct_table;
81
82 if( $ct_table->name !== 'automatorwp_automations' ) {
83 return $join;
84 }
85
86 $table_name = $ct_table->db->table_name;
87 $meta_table_name = $ct_table->meta->db->table_name;
88
89 // Shorthand
90 $qv = $ct_query->query_vars;
91
92 // Parent post type
93 if( isset( $qv['orderby'] ) && $qv['orderby'] === 'completions' ) {
94 $join .= " LEFT JOIN {$meta_table_name} am ON ( am.id = {$table_name}.id AND am.meta_key = 'completions' )";
95 }
96
97 return $join;
98
99 }
100 add_filter( 'ct_query_join', 'automatorwp_automations_query_join', 10, 2 );
101
102 /**
103 * Parse query args to be applied on ORDER BY clause
104 *
105 * @since 2.0.0
106 *
107 * @param string $orderby
108 * @param CT_Query $ct_query
109 *
110 * @return string
111 */
112 function automatorwp_automations_query_orderby( $orderby, $ct_query ) {
113
114 global $ct_table;
115
116 if( $ct_table->name !== 'automatorwp_automations' ) {
117 return $orderby;
118 }
119
120 // Shorthand
121 $qv = $ct_query->query_vars;
122
123 // Parent post type
124 if( isset( $qv['orderby'] ) && $qv['orderby'] === 'completions' ) {
125 $order = 'DESC';
126
127 if( isset( $qv['order'] ) && $qv['order'] === 'ASC' ) {
128 $order = 'ASC';
129 }
130
131 $orderby = "CAST( am.meta_value AS UNSIGNED ) " . $order;
132 }
133
134 return $orderby;
135
136 }
137 add_filter( 'ct_query_orderby', 'automatorwp_automations_query_orderby', 10, 2 );
138
139 /**
140 * Define the search fields for automations
141 *
142 * @since 1.0.0
143 *
144 * @param array $search_fields
145 *
146 * @return array
147 */
148 function automatorwp_automations_search_fields( $search_fields ) {
149
150 $search_fields[] = 'title';
151
152 return $search_fields;
153
154 }
155 add_filter( 'ct_query_automatorwp_automations_search_fields', 'automatorwp_automations_search_fields' );
156
157 /**
158 * Parse search query args for automations
159 *
160 * @since 1.3.9.7
161 *
162 * @param string $search
163 * @param CT_Query $ct_query
164 *
165 * @return string
166 */
167 function automatorwp_automations_query_search( $search, $ct_query ) {
168
169 global $ct_table, $wpdb;
170
171 if( $ct_table->name !== 'automatorwp_automations' ) {
172 return $search;
173 }
174
175 $table_name = $ct_table->db->table_name;
176
177 // Shorthand
178 $qv = $ct_query->query_vars;
179
180 // Check if is search and query is not filtered by an specific user
181 if( isset( $qv['s'] ) && ! empty( $qv['s'] ) && ! isset( $qv['user_id'] ) ) {
182
183 // Made a user sub-search to retrieve them
184 $users = get_users( array(
185 'search' => sprintf( '*%s*', $qv['s'] ),
186 'search_columns' => array(
187 'user_login',
188 'user_email',
189 'display_name',
190 ),
191 'fields' => 'ID',
192 ) );
193
194 if( ! empty( $users ) ) {
195 $search .= " AND ( {$table_name}.user_id IN (" . implode( ',', array_map( 'absint', $users ) ) . ") )";
196 }
197
198 }
199
200 return $search;
201
202 }
203 add_filter( 'ct_query_search', 'automatorwp_automations_query_search', 10, 2 );
204
205 /**
206 * Define the field for automations views
207 *
208 * @since 1.0.0
209 *
210 * @param string $field_id
211 *
212 * @return string
213 */
214 function automatorwp_automations_views_field( $field_id = '' ) {
215 return 'status';
216 }
217 add_filter( 'ct_list_automatorwp_automations_views_field', 'automatorwp_automations_views_field' );
218
219 /**
220 * Define the field labels for automations views
221 *
222 * @since 1.0.0
223 *
224 * @param array $field_labels
225 *
226 * @return array
227 */
228 function automatorwp_automations_views_field_labels( $field_labels = array() ) {
229 return automatorwp_get_automation_statuses();
230 }
231 add_filter( 'ct_list_automatorwp_automations_views_field_labels', 'automatorwp_automations_views_field_labels' );
232
233 /**
234 * Columns for automations list view
235 *
236 * @since 1.0.0
237 *
238 * @param array $columns
239 *
240 * @return array
241 */
242 function automatorwp_manage_automations_columns( $columns = array() ) {
243
244 $columns['title'] = __( 'Title', 'automatorwp' );
245 $columns['type'] = __( 'Type', 'automatorwp' );
246 $columns['triggers'] = __( 'Triggers', 'automatorwp' );
247 $columns['actions'] = __( 'Actions', 'automatorwp' );
248 $columns['user_id'] = __( 'Author', 'automatorwp' );
249 $columns['completions'] = __( 'Completions', 'automatorwp' );
250 $columns['status'] = __( 'Status', 'automatorwp' );
251 $columns['date'] = __( 'Date', 'automatorwp' );
252
253 return $columns;
254 }
255 add_filter( 'manage_automatorwp_automations_columns', 'automatorwp_manage_automations_columns' );
256
257 /**
258 * Sortable columns for automations list view
259 *
260 * @since 1.0.0
261 *
262 * @param array $sortable_columns
263 *
264 * @return array
265 */
266 function automatorwp_manage_automations_sortable_columns( $sortable_columns ) {
267
268 $sortable_columns['title'] = array( 'title', false );
269 $sortable_columns['type'] = array( 'type', false );
270 $sortable_columns['user_id'] = array( 'user_id', false );
271 $sortable_columns['completions'] = array( 'completions', true );
272 $sortable_columns['status'] = array( 'status', false );
273 $sortable_columns['date'] = array( 'date', true );
274
275 return $sortable_columns;
276
277 }
278 add_filter( 'manage_automatorwp_automations_sortable_columns', 'automatorwp_manage_automations_sortable_columns' );
279
280 /**
281 * Columns rendering for automations list view
282 *
283 * @since 1.0.0
284 *
285 * @param string $column_name
286 * @param integer $object_id
287 */
288 function automatorwp_manage_automations_custom_column( $column_name, $object_id ) {
289
290 // Setup vars
291 $automation = ct_get_object( $object_id );
292
293 if( automatorwp_is_automation_expired( $automation ) ) {
294 automatorwp_deactivate_automation( $automation->id );
295 $automation->status = 'inactive';
296 }
297
298 switch( $column_name ) {
299 case 'title':
300 $title = ! empty( $automation->title ) ? $automation->title : __( '(No title)', 'automatorwp' ); ?>
301 <strong><a href="<?php echo ct_get_edit_link( 'automatorwp_automations', $automation->id ); ?>"><?php echo esc_html( $title ); ?></a></strong>
302 <?php
303
304 break;
305 case 'type':
306 $types = automatorwp_get_automation_types();
307 $type = isset( $types[$automation->type] ) ? $types[$automation->type]['label'] : $automation->type;
308 ?>
309
310 <span class="automatorwp-automation-type automatorwp-automation-type-<?php echo esc_attr( $automation->type ); ?>">
311 <?php if ( isset( $types[$automation->type] ) ) : ?>
312 <div class="automatorwp-integration-icon cmb-tooltip">
313 <img src="<?php echo esc_attr( $types[$automation->type]['image'] ); ?>" alt="<?php echo esc_attr( $types[$automation->type]['label'] ); ?>">
314 <span class="cmb-tooltip-desc cmb-tooltip-top"><?php echo esc_html( $types[$automation->type]['label'] ); ?></span>
315 </div>
316 <?php else : ?>
317 <div class="automatorwp-integration-icon cmb-tooltip">
318 <img src="<?php echo esc_attr( AUTOMATORWP_URL . 'assets/img/integration-missing.svg' ); ?>" alt="<?php echo esc_attr( __( 'Missing plugin', 'automatorwp' ) ); ?>">
319 <span class="cmb-tooltip-desc cmb-tooltip-top"><?php echo esc_html( $automation->type ); ?></span>
320 </div>
321 <?php endif; ?>
322 <?php echo esc_html( $type ); ?>
323 </span>
324
325 <?php
326
327 break;
328 case 'triggers':
329 $triggers = automatorwp_get_automation_triggers( $automation->id );
330
331 foreach( $triggers as $trigger ) {
332
333 $type_args = automatorwp_get_trigger( $trigger->type );
334
335 if( $type_args ) {
336 $integration = automatorwp_get_integration( $type_args['integration'] );
337
338 $integration = apply_filters( 'automatorwp_automations_column_triggers_integration', $integration, $trigger, 'trigger', $automation );
339
340 if( $integration ) : ?>
341
342 <div class="automatorwp-integration-icon cmb-tooltip">
343 <img src="<?php echo esc_attr( $integration['icon'] ); ?>" alt="<?php echo esc_attr( $integration['label'] ); ?>">
344 <span class="cmb-tooltip-desc cmb-tooltip-top"><?php echo esc_html( $integration['label'] ); ?></span>
345 </div>
346
347 <?php endif;
348 } else { ?>
349
350 <div class="automatorwp-integration-icon cmb-tooltip">
351 <img src="<?php echo esc_attr( AUTOMATORWP_URL . 'assets/img/integration-missing.svg' ); ?>" alt="<?php echo esc_attr( __( 'Missing plugin', 'automatorwp' ) ); ?>">
352 <span class="cmb-tooltip-desc cmb-tooltip-top"><?php echo esc_html( $trigger->type ); ?></span>
353 </div>
354
355 <?php }
356
357 echo $trigger->title . '<br>';
358 }
359
360 break;
361 case 'actions':
362 $actions = automatorwp_get_automation_actions( $automation->id );
363
364 foreach( $actions as $action ) {
365
366 $type_args = automatorwp_get_action( $action->type );
367
368 if( $type_args ) {
369 $integration = automatorwp_get_integration( $type_args['integration'] );
370
371 if( $action->type === 'automatorwp_anonymous_user' ) {
372 $integration['icon'] = AUTOMATORWP_URL . 'assets/img/automatorwp-anonymous.svg';
373 }
374
375 if( $integration ) : ?>
376
377 <div class="automatorwp-integration-icon cmb-tooltip">
378 <img src="<?php echo esc_attr( $integration['icon'] ); ?>" alt="<?php echo esc_attr( $integration['label'] ); ?>">
379 <span class="cmb-tooltip-desc cmb-tooltip-top"><?php echo esc_html( $integration['label'] ); ?></span>
380 </div>
381
382 <?php endif;
383
384 } else { ?>
385
386 <div class="automatorwp-integration-icon cmb-tooltip">
387 <img src="<?php echo esc_attr( AUTOMATORWP_URL . 'assets/img/integration-missing.svg' ); ?>" alt="<?php echo esc_attr( __( 'Missing plugin', 'automatorwp' ) ); ?>">
388 <span class="cmb-tooltip-desc cmb-tooltip-top"><?php echo esc_html( $action->type ); ?></span>
389 </div>
390
391 <?php }
392
393 echo $action->title . '<br>';
394 }
395
396 break;
397 case 'user_id':
398 $user = get_userdata( $automation->user_id );
399
400 if( $user ) {
401
402 if( current_user_can( 'edit_users' ) ) {
403 ?>
404
405 <a href="<?php echo get_edit_user_link( $user->ID ); ?>"><?php echo $user->display_name . ' (' . $user->user_login . ')'; ?></a>
406
407 <?php
408 } else {
409 echo $user->display_name;
410 }
411
412 }
413 break;
414 case 'completions':
415 $completions = ct_get_object_meta( $automation->id, 'completions', true );
416
417 if( empty( $completions ) ) {
418 $completions = automatorwp_get_object_completion_times( $automation->id, 'automation' );
419 ct_update_object_meta( $automation->id, 'completions', $completions );
420 }
421
422 $completions = absint( $completions );
423 $times = absint( $automation->times );
424
425 if( $times === 0 ) : ?>
426 <span class="automatorwp-automation-completions"><?php echo $completions; ?></span>
427 <?php else : ?>
428 <span class="automatorwp-automation-completions <?php echo ( $completions >= $times ? 'automatorwp-automation-completions-completed' : '' ) ?>"><?php echo $completions . '/' . $times; ?></span>
429 <?php endif;
430 break;
431 case 'status':
432 $statuses = automatorwp_get_automation_statuses();
433 $status = isset( $statuses[$automation->status] ) ? $statuses[$automation->status] : esc_html( $automation->status );
434 ?>
435
436 <span class="automatorwp-automation-status automatorwp-automation-status-<?php echo esc_attr( $automation->status ); ?>"><?php echo $status; ?></span>
437
438 <?php
439
440 // Expiration
441 $now = current_time( 'timestamp' );
442 $expiration = strtotime( $automation->expiration );
443
444 if( $expiration > 0 ) {
445 $expires_text = $expiration > $now ? __( 'Expires on', 'automatorwp' ) : __( 'Expired on', 'automatorwp' );
446 ?>
447
448 <div class="automatorwp-automation-expiration">
449 <?php echo esc_html( $expires_text ); ?> <abbr title="<?php echo date( 'Y/m/d g:i:s a', $expiration ); ?>"><?php echo date( 'Y/m/d', $expiration ); ?></abbr>
450 </div>
451
452 <?php
453 }
454
455 break;
456 case 'date':
457 $date = strtotime( $automation->date ); ?>
458
459 <abbr title="<?php echo date( 'Y/m/d g:i:s a', $date ); ?>"><?php echo date( 'Y/m/d', $date ); ?></abbr>
460
461 <?php
462 break;
463 }
464 }
465 add_action( 'manage_automatorwp_automations_custom_column', 'automatorwp_manage_automations_custom_column', 10, 2 );
466
467 /**
468 * Filters the array of row action links on the item list table.
469 *
470 * @since 1.4.8
471 *
472 * @param array $actions An array of row action links. Defaults are 'Edit' and 'Delete Permanently'.
473 * @param stdClass $item The item object.
474 *
475 * @return array
476 */
477 function automatorwp_automations_custom_row_actions( $actions, $item ) {
478
479 global $ct_table;
480
481 $primary_key = $ct_table->db->primary_key;
482
483 // List link + object ID + action delete
484 $url = $ct_table->views->list->get_link();
485 $url = add_query_arg( array( $primary_key => $item->$primary_key ), $url );
486
487 $actions['clone'] = sprintf(
488 '<a href="%s" class="automatorwp-clone-automation" aria-label="%s">%s</a>',
489 add_query_arg( array( 'automatorwp-action' => 'clone_automation' ), $url ),
490 esc_attr( __( 'Clone', 'automatorwp' ) ),
491 __( 'Clone', 'automatorwp' )
492 );
493
494 $actions['url_export'] = sprintf(
495 '<a href="%s" class="automatorwp-url-export-automation" aria-label="%s">%s</a>',
496 add_query_arg( array( 'automatorwp-action' => 'url_export_automation' ), $url ),
497 esc_attr( __( 'Export', 'automatorwp' ) ),
498 __( 'Export', 'automatorwp' )
499 );
500
501 if( isset( $actions['delete'] ) ) {
502
503 // Remove the delete action to move it to the end
504 unset( $actions['delete'] );
505
506 // Override the delete action
507 $actions['delete'] = sprintf(
508 '<a href="%s" class="submitdelete" onclick="%s" aria-label="%s">%s</a>',
509 ct_get_delete_link( $ct_table->name, $item->$primary_key ),
510 "return confirm('" .
511 esc_attr( __( "Are you sure you want to delete this automation?\\n\\nClick \\'Cancel\\' to go back, \\'OK\\' to confirm the delete.", 'automatorwp' ) ) .
512 "');",
513 esc_attr( __( 'Delete', 'automatorwp' ) ),
514 __( 'Delete', 'automatorwp' )
515 );
516 }
517
518 return $actions;
519
520 }
521 add_filter( 'automatorwp_automations_row_actions', 'automatorwp_automations_custom_row_actions', 10, 2 );
522
523 /**
524 * Handler for the clone automation action.
525 *
526 * @since 1.4.8
527 *
528 * @param array $request Request parameters
529 */
530 function automatorwp_action_clone_automation( $request ) {
531
532
533 // Bail if automation ID not received
534 if( ! isset( $request['id'] ) ) {
535 return;
536 }
537
538 $automation_id = absint( $request['id'] );
539
540 // Bail if automation ID is not correct received
541 if( $automation_id === 0 ) {
542 return;
543 }
544
545 $ct_table = ct_setup_table( 'automatorwp_automations' );
546
547 $automation = ct_get_object( $automation_id );
548 $edit_capability = $ct_table->cap->edit_item;
549 $url = $ct_table->views->list->get_link();
550
551 ct_reset_setup_table();
552
553 // Check if automation exists and current user can edit it
554 if( ! $automation ) {
555 return;
556 }
557
558 // Check if automation exists and current user can edit it
559 if( ! current_user_can( $edit_capability, $automation->id ) ) {
560 return;
561 }
562
563 ct_reset_setup_table();
564
565 $new_automation_id = automatorwp_clone_automation( $automation_id, get_current_user_id() );
566
567 if( $new_automation_id ) {
568
569 $redirect = ( isset( $request['redirect'] ) ? $request['redirect'] : false );
570
571 if( $redirect ) {
572 $url = $ct_table->views->edit->get_link();
573 $url = add_query_arg( array( 'message' => 'automation_cloned' ), $url );
574 $url = add_query_arg( array( 'id' => $new_automation_id ), $url );
575
576 // Redirect to the new automation
577 wp_redirect( $url );
578 exit;
579 }
580
581 $url = add_query_arg( array( 'message' => 'automation_cloned' ), $url );
582 $url = add_query_arg( array( 'new_id' => $new_automation_id ), $url );
583 } else {
584 $url = add_query_arg( array( 'message' => 'automation_not_cloned' ), $url );
585 }
586
587 wp_redirect( $url );
588 exit;
589
590 }
591 add_action( 'automatorwp_action_clone_automation', 'automatorwp_action_clone_automation' );
592
593 function automatorwp_automations_admin_notices() {
594
595 $messages = array(
596 'automation_cloned' => __( 'Automation cloned successfully.', 'automatorwp' ),
597 'automation_not_cloned' => __( 'Automation could not be cloned.', 'automatorwp' ),
598 );
599
600 // If the new id exists, add a link to edit it directly
601 if( isset( $_GET['new_id'] ) && absint( $_GET['new_id'] ) !== 0 ) {
602 $messages['automation_cloned'] = sprintf(
603 __( 'Automation cloned successfully! <a href="%s">Edit the new automation</a>.', 'automatorwp' ),
604 ct_get_edit_link( 'automatorwp_automations', absint( $_GET['new_id'] ) )
605 );
606 }
607
608 /**
609 * Filters the automations table updated messages.
610 *
611 * @since 1.0.0
612 *
613 * @param array $messages Post updated messages. For defaults @see $messages declarations above.
614 */
615 $messages = apply_filters( 'automatorwp_automations_messages', $messages );
616
617 // Setup screen message
618 if ( isset( $_GET['message'] ) && isset( $messages[$_GET['message']] ) ) {
619 echo '<div id="message" class="updated notice is-dismissible"><p>' . esc_html( $messages[$_GET['message']] ) . '</p></div>';
620 }
621
622 }
623 add_action( 'admin_notices', 'automatorwp_automations_admin_notices' );
624
625 /**
626 * Default data when creating a new item (similar to WP auto draft) see ct_insert_object()
627 *
628 * @since 1.0.0
629 *
630 * @param array $default_data
631 *
632 * @return array
633 */
634 function automatorwp_automations_default_data( $default_data = array() ) {
635
636 // Handle the type during creation
637 $types = automatorwp_get_automation_types();
638 $type = ( isset( $_GET['type'] ) ? sanitize_text_field( $_GET['type'] ) : 'user' );
639
640 if( ! isset( $types[$type] ) ) {
641 $type = 'user';
642 }
643
644 $default_data['type'] = $type;
645 $default_data['user_id'] = get_current_user_id();
646 $default_data['sequential'] = 0;
647 $default_data['times_per_user'] = 1;
648 $default_data['times'] = 0;
649 $default_data['status'] = 'inactive';
650 $default_data['date'] = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
651 $default_data['expiration'] = '';
652 $default_data['title'] = '';
653
654 return $default_data;
655 }
656 add_filter( 'ct_automatorwp_automations_default_data', 'automatorwp_automations_default_data' );
657
658 /**
659 * Turns array of date and time into a valid mysql date on update object data
660 *
661 * @since 1.0.0
662 *
663 * @param array $object_data
664 * @param array $original_object_data
665 *
666 * @return array
667 */
668 function automatorwp_automations_insert_automation_data( $object_data, $original_object_data ) {
669
670 global $ct_table;
671
672 // If not is our custom table, return
673 if( $ct_table->name !== 'automatorwp_automations' ) {
674 return $object_data;
675 }
676
677 // Fix date format
678 if( isset( $object_data['date'] ) && ! empty( $object_data['date'] ) ) {
679 // Covers CMB2 format with array( 'date' => '', 'time' => '' )
680 if( is_array( $object_data['date'] ) ) {
681 $object_data['date'] = implode( ' ', $object_data['date'] );
682 }
683
684 $object_data['date'] = date( 'Y-m-d H:i:s', strtotime( $object_data['date'] ) );
685 }
686
687 // Fix expiration format
688 if( isset( $object_data['expiration'] ) ) {
689 // Covers CMB2 format with array( 'date' => '', 'time' => '' )
690 if( is_array( $object_data['expiration'] ) ) {
691 $object_data['expiration'] = trim( implode( ' ', $object_data['expiration'] ) );
692 }
693
694 if( ! empty( $object_data['expiration'] ) ) {
695 $now = current_time( 'timestamp' );
696 $expiration = strtotime( $object_data['expiration'] );
697
698 if( $object_data['status'] === 'active' && $expiration < $now ) {
699 // Prevent to have an older expiration (which will deactivate constantly the automation)
700 $object_data['expiration'] = '0000-00-00 00:00:00';
701 } else {
702 $object_data['expiration'] = date( 'Y-m-d H:i:s', $expiration );
703 }
704 } else {
705 // Never expires expiration
706 $object_data['expiration'] = '0000-00-00 00:00:00';
707 }
708
709 }
710
711 // Handle sequential saving
712 $object_data['sequential'] = ( isset( $_POST['sequential'] ) ? 1 : 0 );
713
714 return $object_data;
715
716 }
717 add_filter( 'ct_insert_object_data', 'automatorwp_automations_insert_automation_data', 10, 2 );
718
719 /**
720 * Register custom CMB2 meta boxes
721 *
722 * @since 1.0.0
723 */
724 function automatorwp_automations_meta_boxes( ) {
725
726 // Title
727 automatorwp_add_meta_box(
728 'automatorwp-automations-title',
729 __( 'Title', 'automatorwp' ),
730 'automatorwp_automations',
731 array(
732 'title' => array(
733 'name' => __( 'Title', 'automatorwp' ),
734 'type' => 'text',
735 'classes' => 'automatorwp-auto-save',
736 'attributes' => array(
737 'placeholder' => __( 'Enter title here', 'automatorwp' ),
738 )
739 ),
740 ),
741 array(
742 'priority' => 'core',
743 )
744 );
745
746 // Save Changes
747 automatorwp_add_meta_box(
748 'automatorwp-automations-save-changes',
749 __( 'Save Changes', 'automatorwp' ),
750 'automatorwp_automations',
751 array(
752 'type' => array(
753 'name' => __( 'Type', 'automatorwp' ),
754 'type' => 'select',
755 'options' => automatorwp_get_automation_types_labels(),
756 'js_controls' => array(
757 'icon' => 'dashicons-star-filled',
758 'edit_button' => false,
759 'save_button_classes' => 'button button-primary',
760 'cancel_button_classes' => 'button automatorwp-button-danger',
761 ),
762 'before_row' => 'js_controls_before',
763 'after_row' => 'js_controls_after',
764 ),
765 'times_per_user' => array(
766 'name' => __( 'Times per user', 'automatorwp' ),
767 'desc' => __( 'Maximum number of times a user can complete this automation. Set it to 0 for unlimited.', 'automatorwp' ),
768 'type' => 'input',
769 'attributes' => array(
770 'type' => 'number',
771 'min' => '0',
772 ),
773 'classes' => 'automatorwp-has-tooltip',
774 'after_field' => 'automatorwp_tooltip_cb',
775 'js_controls' => array(
776 'icon' => 'dashicons-filter',
777 'save_button' => __( 'Save', 'automatorwp' ),
778 'save_button_classes' => 'button button-primary',
779 'cancel_button_classes' => 'button automatorwp-button-danger',
780 ),
781 'before_row' => 'js_controls_before',
782 'after_row' => 'js_controls_after',
783 ),
784 'times' => array(
785 'name' => __( 'Total times', 'automatorwp' ),
786 'desc' => __( 'Maximum number of times this automation can be completed. Set it to 0 for unlimited.', 'automatorwp' ),
787 'type' => 'input',
788 'attributes' => array(
789 'type' => 'number',
790 'min' => '0',
791 ),
792 'classes' => 'automatorwp-has-tooltip',
793 'after_field' => 'automatorwp_tooltip_cb',
794 'js_controls' => array(
795 'icon' => 'dashicons-admin-site',
796 'save_button' => __( 'Save', 'automatorwp' ),
797 'save_button_classes' => 'button button-primary',
798 'cancel_button_classes' => 'button automatorwp-button-danger',
799 ),
800 'before_row' => 'js_controls_before',
801 'after_row' => 'js_controls_after',
802 ),
803 'user_id' => array(
804 'name' => __( 'Author', 'automatorwp' ),
805 'type' => 'select',
806 'classes' => 'automatorwp-user-selector',
807 'options_cb' => 'automatorwp_options_cb_users',
808 'display_cb' => 'automatorwp_display_cb_users',
809 'js_controls' => array(
810 'icon' => 'dashicons-admin-users',
811 'save_button' => __( 'Save', 'automatorwp' ),
812 'save_button_classes' => 'button button-primary',
813 'cancel_button_classes' => 'button automatorwp-button-danger',
814 ),
815 'before_row' => 'js_controls_before',
816 'after_row' => 'js_controls_after',
817 ),
818 'status' => array(
819 'name' => __( 'Status', 'automatorwp' ),
820 'type' => 'select',
821 'options_cb' => 'automatorwp_options_cb_automation_statuses',
822 'js_controls' => array(
823 'icon' => 'dashicons-post-status',
824 'save_button' => __( 'Save', 'automatorwp' ),
825 'save_button_classes' => 'button button-primary',
826 'cancel_button_classes' => 'button automatorwp-button-danger',
827 ),
828 'before_row' => 'js_controls_before',
829 'after_row' => 'js_controls_after',
830 ),
831 'date' => array(
832 'name' => __( 'Created on', 'automatorwp' ),
833 'desc' => __( 'Automation will take effect based on this date. You can schedule <strong>future</strong> automations by setting this field with a future date.', 'automatorwp' )
834 . '<br>' . __( '<strong>Note:</strong> For future automations, status need to be <strong>active</strong> because setting a future date won\'t update the status automatically.', 'automatorwp' ),
835 'type' => 'text_datetime_timestamp',
836 'date_format' => automatorwp_get_date_format( array( 'm/d/Y', 'd/m/Y' ), 'm/d/Y' ),
837 'time_format' => 'H:i',
838 'escape_cb' => 'automatorwp_automation_date_escape_cb',
839 'display_cb' => 'automatorwp_automation_date_display_cb',
840 'attributes' => array(
841 'autocomplete' => 'off'
842 ),
843 'classes' => 'automatorwp-has-tooltip',
844 'after_field' => 'automatorwp_tooltip_cb',
845 'js_controls' => array(
846 'icon' => 'dashicons-calendar',
847 'save_button' => __( 'Save', 'automatorwp' ),
848 'save_button_classes' => 'button button-primary',
849 'cancel_button_classes' => 'button automatorwp-button-danger',
850 ),
851 'before_row' => 'js_controls_before',
852 'after_row' => 'js_controls_after', // Handled on automatorwp_automations_publishing_actions()
853 ),
854 'expiration' => array(
855 'name' => __( 'Expires on', 'automatorwp' ),
856 'desc' => __( 'Automation will be automatically set to <strong>inactive</strong> after this date. You can schedule the automation deactivation by setting this field with a future date.', 'automatorwp' ),
857 'type' => 'text_datetime_timestamp',
858 'date_format' => automatorwp_get_date_format( array( 'm/d/Y', 'd/m/Y' ), 'm/d/Y' ),
859 'time_format' => 'H:i',
860 'escape_cb' => 'automatorwp_automation_date_escape_cb',
861 'display_cb' => 'automatorwp_automation_date_display_cb',
862 'attributes' => array(
863 'autocomplete' => 'off'
864 ),
865 'classes' => 'automatorwp-has-tooltip',
866 'after_field' => 'automatorwp_tooltip_cb',
867 'js_controls' => array(
868 'icon' => 'dashicons-clock',
869 'save_button' => __( 'Save', 'automatorwp' ),
870 'save_button_classes' => 'button button-primary',
871 'cancel_button_classes' => 'button automatorwp-button-danger',
872 ),
873 'before_row' => 'js_controls_before',
874 //'after_row' => 'js_controls_after', // Handled on automatorwp_automations_publishing_actions()
875 'after_row' => 'automatorwp_automations_publishing_actions',
876
877 ),
878 ),
879 array(
880 'priority' => 'default',
881 'context' => 'side',
882 )
883 );
884
885 }
886 add_action( 'cmb2_admin_init', 'automatorwp_automations_meta_boxes' );
887
888 /**
889 * Expiration escape callback.
890 *
891 * @param string $value Field value.
892 * @param array $field_args Array of field arguments.
893 * @param CMB2_Field $field The field object
894 */
895 function automatorwp_automation_date_escape_cb( $value, $field_args, $field ) {
896
897 if ( $value === '0000-00-00 00:00:00' )
898 $escaped_value = '';
899 else
900 $escaped_value = date( automatorwp_get_date_format( array( 'm/d/Y', 'd/m/Y' ), 'm/d/Y' ) . ' H:i', strtotime( $value ) );
901
902 return $escaped_value;
903
904 }
905
906 /**
907 * Expiration display callback.
908 *
909 * @param array $field_args Array of field arguments.
910 * @param CMB2_Field $field The field object
911 */
912 function automatorwp_automation_date_display_cb( $field_args, $field ) {
913 $value = $field->escaped_value(); ?>
914 <div class="<?php echo $field->row_classes(); ?>" data-fieldtype="text_date_timestamp">
915 <?php echo $value === '' ? __( 'Never Expires', 'automatorwp' ) : $value; ?>
916 </div>
917 <?php
918 }
919
920 /**
921 * Publishing actions
922 *
923 * @since 1.0.0
924 */
925 function automatorwp_automations_publishing_actions( $field_args, $field ) {
926
927 global $ct_table;
928
929 if( ! $ct_table ) {
930 return;
931 }
932
933 if( $ct_table->name !== 'automatorwp_automations' ) {
934 return;
935 }
936
937 // The JS controls after of the date field
938 js_controls_after( $field_args, $field );
939
940 $primary_key = $ct_table->db->primary_key;
941 $object_id = isset( $_GET[$primary_key] ) ? absint( $_GET[$primary_key] ) : 0;
942
943 $automation = ct_get_object( $object_id );
944
945 // Bail if automation doesn't exists
946 if( ! $automation ) {
947 return;
948 }
949
950 $actions = array();
951
952 $url = $ct_table->views->edit->get_link();
953 $url = add_query_arg( array( $primary_key => $object_id ), $url );
954 $url = add_query_arg( array( 'redirect' => true ), $url );
955
956 $actions['clone'] = sprintf(
957 '<a href="%s" class="automatorwp-clone-automation" aria-label="%s">%s</a>',
958 add_query_arg( array( 'automatorwp-action' => 'clone_automation' ), $url ),
959 esc_attr( __( 'Clone', 'automatorwp' ) ),
960 __( 'Clone', 'automatorwp' )
961 );
962
963 $actions['url_export'] = sprintf(
964 '<a href="%s" class="automatorwp-url-export-automation" aria-label="%s">%s</a>',
965 add_query_arg( array( 'automatorwp-action' => 'url_export_automation' ), $url ),
966 esc_attr( __( 'Export', 'automatorwp' ) ),
967 __( 'Export', 'automatorwp' )
968 );
969
970 /**
971 * Filters the array of edit action links on the automation edit page.
972 *
973 * @since 1.4.8
974 *
975 * @param array $actions An array of row action links.
976 * @param stdClass $automation The automation object.
977 *
978 * @return array
979 */
980 $actions = apply_filters( 'automatorwp_automations_edit_actions', $actions, $automation )
981 ?>
982 <div id="major-publishing-actions">
983
984 <div id="automatorwp-automation-actions">
985 <?php foreach( $actions as $action => $action_html ) : ?>
986 <div id="automatorwp-automation-action-<?php echo esc_attr( $action ); ?>" class="automatorwp-automation-action"><?php echo $action_html; ?></div>
987 <?php endforeach; ?>
988 </div>
989
990 <?php if( $automation->status === 'inactive' ) : ?>
991
992 <div class="automatorwp-save-and-activate">
993 <?php submit_button( __( 'Save &amp; Activate', 'automatorwp' ), ' primary large', 'automatorwp-save-and-activate', false ); ?>
994 </div>
995
996 <div id="publishing-action">
997 <?php submit_button( __( 'Save Changes' ), 'large', 'ct-save', false ); ?>
998 </div>
999
1000 <div class="clear"></div>
1001
1002 <?php else : ?>
1003
1004 <div id="publishing-action">
1005 <?php submit_button( __( 'Save Changes' ), 'primary large', 'ct-save', false ); ?>
1006 </div>
1007
1008 <?php endif; ?>
1009
1010 <div id="delete-action">
1011 <?php
1012 printf(
1013 '<a href="%s" class="submitdelete deletion" onclick="%s" aria-label="%s">%s</a>',
1014 ct_get_delete_link( $ct_table->name, $object_id ),
1015 "return confirm('" .
1016 esc_attr( __( "Are you sure you want to delete this automation?\\n\\nClick \\'Cancel\\' to go back, \\'OK\\' to confirm the delete.", 'automatorwp' ) ) .
1017 "');",
1018 esc_attr( __( 'Delete', 'automatorwp' ) ),
1019 __( 'Delete', 'automatorwp' )
1020 );
1021 ?>
1022 </div>
1023
1024 <div class="clear"></div>
1025
1026 </div>
1027
1028 <?php
1029 }
1030
1031 /**
1032 * Remove meta boxes
1033 *
1034 * @since 1.0.0
1035 */
1036 function automatorwp_automations_remove_meta_boxes() {
1037 // Removes submitdiv box
1038 remove_meta_box( 'submitdiv', 'automatorwp_automations', 'side' );
1039 }
1040 add_action( 'add_meta_boxes', 'automatorwp_automations_remove_meta_boxes' );
1041
1042 /**
1043 * On delete an automation
1044 *
1045 * @since 1.0.0
1046 *
1047 * @param int $object_id
1048 */
1049 function automatorwp_automations_delete_object( $object_id ) {
1050
1051 global $wpdb, $ct_table;
1052
1053 if( ! ( $ct_table instanceof CT_Table ) ) {
1054 return;
1055 }
1056
1057 if( $ct_table->name !== 'automatorwp_automations' ) {
1058 return;
1059 }
1060
1061 $logs = AutomatorWP()->db->logs;
1062 $logs_meta = AutomatorWP()->db->logs_meta;
1063
1064 // Delete all logs assigned to this action
1065 $wpdb->query( "DELETE l FROM {$logs} AS l WHERE l.object_id = {$object_id} AND l.type = 'automation'" );
1066
1067 // Delete orphaned log metas
1068 $wpdb->query( "DELETE lm FROM {$logs_meta} lm LEFT JOIN {$logs} l ON l.id = lm.id WHERE l.id IS NULL" );
1069
1070 // Delete all triggers
1071 $triggers = automatorwp_get_automation_triggers( $object_id );
1072
1073 foreach( $triggers as $trigger ) {
1074 ct_setup_table( 'automatorwp_triggers' );
1075
1076 ct_delete_object( $trigger->id );
1077
1078 ct_reset_setup_table();
1079 }
1080
1081 // Delete all actions
1082 $actions = automatorwp_get_automation_actions( $object_id );
1083
1084 foreach( $actions as $action ) {
1085 ct_setup_table( 'automatorwp_actions' );
1086
1087 ct_delete_object( $action->id );
1088
1089 ct_reset_setup_table();
1090 }
1091
1092 }
1093 add_action( 'delete_object', 'automatorwp_automations_delete_object' );