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/custom-tables/automations.php +1100 -0 5.7.3 → 6.0.3 View file →
@@ -1,0 +1,1100 @@
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 + esc_html__( '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 + esc_html__( '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 + esc_html__( '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'] = 0;
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' => automatorwp_js_controls_options( 'star-filled' ),
757 + 'before_row' => 'js_controls_before',
758 + 'after_row' => 'js_controls_after',
759 + ),
760 + 'times_per_user' => array(
761 + 'name' => __( 'Times per user', 'automatorwp' ),
762 + 'desc' => __( 'Maximum number of times a user can complete this automation. Set it to 0 for unlimited.', 'automatorwp' ),
763 + 'type' => 'input',
764 + 'attributes' => array(
765 + 'type' => 'number',
766 + 'min' => '0',
767 + ),
768 + 'classes' => 'automatorwp-has-tooltip',
769 + 'after_field' => 'automatorwp_tooltip_cb',
770 + 'js_controls' => automatorwp_js_controls_options( 'update' ),
771 + 'before_row' => 'js_controls_before',
772 + 'after_row' => 'js_controls_after',
773 + ),
774 + 'times' => array(
775 + 'name' => __( 'Total times', 'automatorwp' ),
776 + 'desc' => __( 'Maximum number of times this automation can be completed. Set it to 0 for unlimited.', 'automatorwp' ),
777 + 'type' => 'input',
778 + 'attributes' => array(
779 + 'type' => 'number',
780 + 'min' => '0',
781 + ),
782 + 'classes' => 'automatorwp-has-tooltip',
783 + 'after_field' => 'automatorwp_tooltip_cb',
784 + 'js_controls' => automatorwp_js_controls_options( 'admin-site' ),
785 + 'before_row' => 'js_controls_before',
786 + 'after_row' => 'js_controls_after',
787 + ),
788 + 'user_id' => array(
789 + 'name' => __( 'Author', 'automatorwp' ),
790 + 'type' => 'select',
791 + 'classes' => 'automatorwp-user-selector',
792 + 'options_cb' => 'automatorwp_options_cb_users',
793 + 'display_cb' => 'automatorwp_display_cb_users',
794 + 'js_controls' => automatorwp_js_controls_options( 'admin-users' ),
795 + 'before_row' => 'js_controls_before',
796 + 'after_row' => 'js_controls_after',
797 + ),
798 + 'status' => array(
799 + 'name' => __( 'Status', 'automatorwp' ),
800 + 'type' => 'select',
801 + 'options_cb' => 'automatorwp_options_cb_automation_statuses',
802 + 'js_controls' => array(
803 + 'icon' => 'dashicons-post-status',
804 + 'save_button' => __( 'Save', 'automatorwp' ),
805 + 'save_button_classes' => 'button button-compact button-primary',
806 + 'cancel_button_classes' => 'button button-compact automatorwp-button-danger',
807 + ),
808 + 'before_row' => 'js_controls_before',
809 + 'after_row' => 'js_controls_after',
810 + ),
811 + 'date' => array(
812 + 'name' => __( 'Created on', 'automatorwp' ),
813 + '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' )
814 + . '<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' ),
815 + 'type' => 'text_datetime_timestamp',
816 + 'date_format' => automatorwp_get_date_format( array( 'm/d/Y', 'd/m/Y' ), 'm/d/Y' ),
817 + 'time_format' => 'H:i',
818 + 'escape_cb' => 'automatorwp_automation_date_escape_cb',
819 + 'display_cb' => 'automatorwp_automation_date_display_cb',
820 + 'attributes' => array(
821 + 'autocomplete' => 'off'
822 + ),
823 + 'classes' => 'automatorwp-has-tooltip',
824 + 'after_field' => 'automatorwp_tooltip_cb',
825 + 'js_controls' => automatorwp_js_controls_options( 'calendar' ),
826 + 'before_row' => 'js_controls_before',
827 + 'after_row' => 'js_controls_after', // Handled on automatorwp_automations_publishing_actions()
828 + ),
829 + 'expiration' => array(
830 + 'name' => __( 'Expires on', 'automatorwp' ),
831 + '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' ),
832 + 'type' => 'text_datetime_timestamp',
833 + 'date_format' => automatorwp_get_date_format( array( 'm/d/Y', 'd/m/Y' ), 'm/d/Y' ),
834 + 'time_format' => 'H:i',
835 + 'escape_cb' => 'automatorwp_automation_date_escape_cb',
836 + 'display_cb' => 'automatorwp_automation_date_display_cb',
837 + 'attributes' => array(
838 + 'autocomplete' => 'off'
839 + ),
840 + 'classes' => 'automatorwp-has-tooltip',
841 + 'after_field' => 'automatorwp_tooltip_cb',
842 + 'js_controls' => automatorwp_js_controls_options( 'clock' ),
843 + 'before_row' => 'js_controls_before',
844 + //'after_row' => 'js_controls_after', // Handled on automatorwp_automations_publishing_actions()
845 + 'after_row' => 'automatorwp_automations_publishing_actions',
846 +
847 + ),
848 + ),
849 + array(
850 + 'priority' => 'default',
851 + 'context' => 'side',
852 + )
853 + );
854 +
855 + // Notes
856 + automatorwp_add_meta_box(
857 + 'automatorwp-automations-notes',
858 + __( 'Notes', 'automatorwp' ) . cmb_tooltip_get_html( __( 'Use this box to add internal notes about this automation.', 'automatorwp' ) ),
859 + 'automatorwp_automations',
860 + array(
861 + 'notes' => array(
862 + 'name' => __( 'Notes', 'automatorwp' ),
863 + 'type' => 'textarea',
864 + 'classes' => 'automatorwp-auto-save',
865 + 'attributes' => array(
866 + 'rows' => 8,
867 + 'placeholder' => __( 'Internal notes here', 'automatorwp' ) . '...',
868 + )
869 + ),
870 + ),
871 + array(
872 + 'priority' => 'default',
873 + 'context' => 'side',
874 + )
875 + );
876 +
877 +}
878 +add_action( 'cmb2_admin_init', 'automatorwp_automations_meta_boxes' );
879 +
880 +/**
881 + * Helper function to reduce code
882 + *
883 + * @param string $icon
884 + * @return array
885 + */
886 +function automatorwp_js_controls_options( $icon = 'automatorwp' ) {
887 + return array(
888 + 'icon' => 'dashicons-' . $icon,
889 + 'save_button' => __( 'Save', 'automatorwp' ),
890 + 'save_button_classes' => 'button button-compact button-primary',
891 + 'cancel_button_classes' => 'button button-compact automatorwp-button-danger',
892 + );
893 +}
894 +
895 +/**
896 + * Expiration escape callback.
897 + *
898 + * @param string $value Field value.
899 + * @param array $field_args Array of field arguments.
900 + * @param CMB2_Field $field The field object
901 + */
902 +function automatorwp_automation_date_escape_cb( $value, $field_args, $field ) {
903 +
904 + if ( $value === '0000-00-00 00:00:00' )
905 + $escaped_value = '';
906 + else
907 + $escaped_value = date( automatorwp_get_date_format( array( 'm/d/Y', 'd/m/Y' ), 'm/d/Y' ) . ' H:i', strtotime( $value ) );
908 +
909 + return $escaped_value;
910 +
911 +}
912 +
913 +/**
914 + * Expiration display callback.
915 + *
916 + * @param array $field_args Array of field arguments.
917 + * @param CMB2_Field $field The field object
918 + */
919 +function automatorwp_automation_date_display_cb( $field_args, $field ) {
920 + $value = $field->escaped_value(); ?>
921 + <div class="<?php echo $field->row_classes(); ?>" data-fieldtype="text_date_timestamp">
922 + <?php echo $value === '' ? __( 'Never Expires', 'automatorwp' ) : $value; ?>
923 + </div>
924 + <?php
925 +}
926 +
927 +/**
928 + * Publishing actions
929 + *
930 + * @since 1.0.0
931 + */
932 +function automatorwp_automations_publishing_actions( $field_args, $field ) {
933 +
934 + global $ct_table;
935 +
936 + if( ! $ct_table ) {
937 + return;
938 + }
939 +
940 + if( $ct_table->name !== 'automatorwp_automations' ) {
941 + return;
942 + }
943 +
944 + // The JS controls after of the date field
945 + js_controls_after( $field_args, $field );
946 +
947 + $primary_key = $ct_table->db->primary_key;
948 + $object_id = isset( $_GET[$primary_key] ) ? absint( $_GET[$primary_key] ) : 0;
949 +
950 + $automation = ct_get_object( $object_id );
951 +
952 + // Bail if automation doesn't exists
953 + if( ! $automation ) {
954 + return;
955 + }
956 +
957 + $actions = array();
958 +
959 + $url = $ct_table->views->edit->get_link();
960 + $url = add_query_arg( array( $primary_key => $object_id ), $url );
961 + $url = add_query_arg( array( 'redirect' => true ), $url );
962 +
963 + $actions['clone'] = sprintf(
964 + '<a href="%s" class="automatorwp-clone-automation" aria-label="%s">%s</a>',
965 + add_query_arg( array( 'automatorwp-action' => 'clone_automation' ), $url ),
966 + esc_attr( __( 'Clone', 'automatorwp' ) ),
967 + automatorwp_dashicon( 'admin-page' ) . esc_html__( 'Clone', 'automatorwp' )
968 + );
969 +
970 + $actions['url_export'] = sprintf(
971 + '<a href="%s" class="automatorwp-url-export-automation" aria-label="%s">%s</a>',
972 + add_query_arg( array( 'automatorwp-action' => 'url_export_automation' ), $url ),
973 + esc_attr( __( 'Export', 'automatorwp' ) ),
974 + automatorwp_dashicon( 'cloud-upload' ) . esc_html__( 'Export', 'automatorwp' )
975 + );
976 +
977 + /**
978 + * Filters the array of edit action links on the automation edit page.
979 + *
980 + * @since 1.4.8
981 + *
982 + * @param array $actions An array of row action links.
983 + * @param stdClass $automation The automation object.
984 + *
985 + * @return array
986 + */
987 + $actions = apply_filters( 'automatorwp_automations_edit_actions', $actions, $automation )
988 + ?>
989 + <div id="major-publishing-actions">
990 +
991 + <?php if( $automation->status === 'inactive' ) : ?>
992 +
993 + <div class="automatorwp-save-and-activate">
994 + <?php submit_button( __( 'Save &amp; Activate', 'automatorwp' ), ' primary large', 'automatorwp-save-and-activate', false ); ?>
995 + </div>
996 +
997 + <div id="publishing-action">
998 + <?php submit_button( __( 'Save Changes' ), 'large', 'ct-save', false ); ?>
999 + </div>
1000 +
1001 + <div class="clear"></div>
1002 +
1003 + <?php else : ?>
1004 +
1005 + <div id="publishing-action">
1006 + <?php submit_button( __( 'Save Changes' ), 'primary large', 'ct-save', false ); ?>
1007 + </div>
1008 +
1009 + <?php endif; ?>
1010 +
1011 + <div id="automatorwp-automation-actions">
1012 + <?php foreach( $actions as $action => $action_html ) : ?>
1013 + <div id="automatorwp-automation-action-<?php echo esc_attr( $action ); ?>" class="automatorwp-automation-action"><?php echo $action_html; ?></div>
1014 + <?php endforeach; ?>
1015 + </div>
1016 +
1017 + <div id="delete-action">
1018 + <?php
1019 + printf(
1020 + '<a href="%s" class="submitdelete deletion" onclick="%s" aria-label="%s">%s</a>',
1021 + ct_get_delete_link( $ct_table->name, $object_id ),
1022 + "return confirm('" .
1023 + esc_attr( __( "Are you sure you want to delete this automation?\\n\\nClick \\'Cancel\\' to go back, \\'OK\\' to confirm the delete.", 'automatorwp' ) ) .
1024 + "');",
1025 + esc_attr( __( 'Delete', 'automatorwp' ) ),
1026 + automatorwp_dashicon( 'trash' ) . esc_html__( 'Delete', 'automatorwp' )
1027 + );
1028 + ?>
1029 + </div>
1030 +
1031 + <div class="clear"></div>
1032 +
1033 + </div>
1034 +
1035 + <?php
1036 +}
1037 +
1038 +/**
1039 + * Remove meta boxes
1040 + *
1041 + * @since 1.0.0
1042 + */
1043 +function automatorwp_automations_remove_meta_boxes() {
1044 + // Removes submitdiv box
1045 + remove_meta_box( 'submitdiv', 'automatorwp_automations', 'side' );
1046 +}
1047 +add_action( 'add_meta_boxes', 'automatorwp_automations_remove_meta_boxes' );
1048 +
1049 +/**
1050 + * On delete an automation
1051 + *
1052 + * @since 1.0.0
1053 + *
1054 + * @param int $object_id
1055 + */
1056 +function automatorwp_automations_delete_object( $object_id ) {
1057 +
1058 + global $wpdb, $ct_table;
1059 +
1060 + if( ! ( $ct_table instanceof CT_Table ) ) {
1061 + return;
1062 + }
1063 +
1064 + if( $ct_table->name !== 'automatorwp_automations' ) {
1065 + return;
1066 + }
1067 +
1068 + $logs = AutomatorWP()->db->logs;
1069 + $logs_meta = AutomatorWP()->db->logs_meta;
1070 +
1071 + // Delete all logs assigned to this action
1072 + $wpdb->query( "DELETE l FROM {$logs} AS l WHERE l.object_id = {$object_id} AND l.type = 'automation'" );
1073 +
1074 + // Delete orphaned log metas
1075 + $wpdb->query( "DELETE lm FROM {$logs_meta} lm LEFT JOIN {$logs} l ON l.id = lm.id WHERE l.id IS NULL" );
1076 +
1077 + // Delete all triggers
1078 + $triggers = automatorwp_get_automation_triggers( $object_id );
1079 +
1080 + foreach( $triggers as $trigger ) {
1081 + ct_setup_table( 'automatorwp_triggers' );
1082 +
1083 + ct_delete_object( $trigger->id );
1084 +
1085 + ct_reset_setup_table();
1086 + }
1087 +
1088 + // Delete all actions
1089 + $actions = automatorwp_get_automation_actions( $object_id );
1090 +
1091 + foreach( $actions as $action ) {
1092 + ct_setup_table( 'automatorwp_actions' );
1093 +
1094 + ct_delete_object( $action->id );
1095 +
1096 + ct_reset_setup_table();
1097 + }
1098 +
1099 +}
1100 +add_action( 'delete_object', 'automatorwp_automations_delete_object' );