PluginProbe
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI / 6.0.1
AutomatorWP – No-Code Workflow Automation, Integration & Webhooks Plugin, now with AI v6.0.1
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 / automations.php

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

1,119 lines 33.0 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\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 * Get automation registered statuses
14 *
15 * @since 1.0.0
16 *
17 * @return array
18 */
19 function automatorwp_get_automation_statuses() {
20
21 return apply_filters( 'automatorwp_automation_statuses', array(
22 'active' => __( 'Active', 'automatorwp' ),
23 'in-progress' => __( 'In Progress', 'automatorwp' ),
24 'inactive' => __( 'Inactive', 'automatorwp' ),
25 ) );
26
27 }
28
29 /**
30 * Get automation registered types
31 *
32 * @since 1.3.0
33 *
34 * @return array
35 */
36 function automatorwp_get_automation_types() {
37
38 return apply_filters( 'automatorwp_automation_types', array(
39 'user' => array(
40 'image' => AUTOMATORWP_URL . 'assets/img/automatorwp-logo.svg',
41 'label' => __( 'Logged-in', 'automatorwp' ),
42 'desc' => __( 'Run actions on the user who completes the triggers.', 'automatorwp' ),
43
44 ),
45 'anonymous' => array(
46 'image' => AUTOMATORWP_URL . 'assets/img/automatorwp-anonymous-logo.svg',
47 'label' => __( 'Anonymous', 'automatorwp' ),
48 'desc' => __( 'Run actions based on not logged-in users interactions.', 'automatorwp' ),
49 ),
50 ) );
51
52 }
53
54 /**
55 * Get automation registered types labels
56 *
57 * @since 1.3.0
58 *
59 * @return array
60 */
61 function automatorwp_get_automation_types_labels() {
62
63 $types = automatorwp_get_automation_types();
64 $labels = array();
65
66 foreach( $types as $type => $args ) {
67 $labels[$type] = $args['label'];
68 }
69
70 return $labels;
71
72 }
73
74 /**
75 * Get the automation types that will make a look
76 *
77 * @since 1.3.0
78 *
79 * @return array
80 */
81 function automatorwp_get_automation_loop_types() {
82
83 return apply_filters( 'automatorwp_automation_loop_types', array() );
84
85 }
86
87 /**
88 * Get the automation object data
89 *
90 * @param int $automation_id The automation ID
91 * @param string $output Optional. The required return type. One of OBJECT, ARRAY_A, or ARRAY_N, which correspond to
92 * a object, an associative array, or a numeric array, respectively. Default OBJECT.
93 *
94 * @return array|stdClass|null
95 */
96 function automatorwp_get_automation_object( $automation_id, $output = OBJECT ) {
97
98 ct_setup_table( 'automatorwp_automations' );
99
100 $automation = ct_get_object( $automation_id );
101
102 ct_reset_setup_table();
103
104 return $automation;
105
106 }
107
108 /**
109 * Get the automation metadata
110 *
111 * @param int $automation_id The automation ID
112 * @param string $meta_key Optional. The meta key to retrieve. By default, returns
113 * data for all keys. Default empty.
114 * @param bool $single Optional. Whether to return a single value. Default false.
115 *
116 * @return mixed Will be an array if $single is false. Will be value of meta data field if $single is true.
117 */
118 function automatorwp_get_automation_meta( $automation_id, $meta_key = '', $single = false ) {
119
120 ct_setup_table( 'automatorwp_automations' );
121 $meta_value = ct_get_object_meta( $automation_id, $meta_key, $single );
122 ct_reset_setup_table();
123
124 return $meta_value;
125
126 }
127
128 /**
129 * Update automation metadata
130 *
131 * @param int $automation_id The automation ID.
132 * @param string $meta_key Metadata key.
133 * @param mixed $meta_value Metadata value. Must be serializable if non-scalar.
134 * @param mixed $prev_value Optional. Previous value to check before removing. Default empty.
135 *
136 * @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
137 */
138 function automatorwp_update_automation_meta( $automation_id, $meta_key, $meta_value, $prev_value = '' ) {
139
140 ct_setup_table( 'automatorwp_automations' );
141 $meta_id = ct_update_object_meta( $automation_id, $meta_key, $meta_value, $prev_value );
142 ct_reset_setup_table();
143
144 return $meta_id;
145
146 }
147
148 /**
149 * Get automation triggers
150 *
151 * @since 1.0.0
152 *
153 * @param int $automation_id The automation ID
154 * @param string $output The required return type (OBJECT|ARRAY_A|ARRAY_N)
155 *
156 * @return stdClass|array The automation triggers
157 */
158 function automatorwp_get_automation_triggers( $automation_id, $output = OBJECT ) {
159
160 $cache = automatorwp_get_cache( 'automation_triggers', array(), false );
161
162 if( isset( $cache[$automation_id] ) ) {
163
164 // Use triggers already cached
165 $triggers = $cache[$automation_id];
166
167 } else {
168
169 // Query the triggers for the first time
170 ct_setup_table( 'automatorwp_triggers' );
171
172 $ct_query = new CT_Query( array(
173 'automation_id' => $automation_id,
174 'orderby' => 'position',
175 'order' => 'ASC',
176 'items_per_page' => -1,
177 ) );
178
179 $triggers = $ct_query->get_results();
180
181 ct_reset_setup_table();
182
183 // Cache triggers
184 $cache[$automation_id] = $triggers;
185
186 automatorwp_set_cache( 'automation_triggers', $cache );
187
188 }
189
190 if( $output === ARRAY_N || $output === ARRAY_A ) {
191
192 // Turn array of objects into an array of arrays
193 foreach( $triggers as $i => $trigger ) {
194 $triggers[$i] = (array) $trigger;
195 }
196
197 }
198
199 return $triggers;
200
201 }
202
203 /**
204 * Get automation trigger by type
205 *
206 * @since 1.0.0
207 *
208 * @param int $automation_id The automation ID
209 * @param string $type The trigger type
210 * @param string $output The required return type (OBJECT|ARRAY_A|ARRAY_N)
211 *
212 * @return stdClass|array The automation trigger
213 */
214 function automatorwp_get_automation_trigger_by_type( $automation_id, $type, $output = OBJECT ) {
215
216 $cache = automatorwp_get_cache( 'automation_trigger_by_type', array(), false );
217
218 if( isset( $cache[$automation_id] ) && isset( $cache[$automation_id][$type] ) ) {
219
220 // Use the trigger already cached
221 $trigger = $cache[$automation_id][$type];
222
223 } else {
224
225 $triggers = automatorwp_get_automation_triggers( $automation_id, $output );
226 $trigger = null;
227
228 foreach( $triggers as $item ) {
229
230 if( $output === ARRAY_N || $output === ARRAY_A ) {
231 // Array
232 $item_type = $item['type'];
233 } else {
234 // stdClass
235 $item_type = $item->type;
236 }
237
238 if( $item_type === $type ) {
239 $trigger = $item;
240 break;
241 }
242
243 }
244
245 if( ! isset( $cache[$automation_id] ) ){
246 $cache[$automation_id] = array();
247 }
248
249 // Cache triggers
250 $cache[$automation_id][$type] = $trigger;
251
252 automatorwp_set_cache( 'automation_trigger_by_type', $cache );
253
254 }
255
256 return $trigger;
257
258 }
259
260 /**
261 * Get automation actions
262 *
263 * @since 1.0.0
264 *
265 * @param int $automation_id The automation ID
266 * @param string $output The required return type (OBJECT|ARRAY_A|ARRAY_N)
267 *
268 * @return array Array of automation actions
269 */
270 function automatorwp_get_automation_actions( $automation_id, $output = OBJECT ) {
271
272 $cache = automatorwp_get_cache( 'automation_actions', array(), false );
273
274 if( isset( $cache[$automation_id] ) ) {
275
276 // Use triggers already cached
277 $actions = $cache[$automation_id];
278
279 } else {
280
281 // Query the triggers for the first time
282
283 ct_setup_table( 'automatorwp_actions' );
284
285 $ct_query = new CT_Query( array(
286 'automation_id' => $automation_id,
287 'orderby' => 'position',
288 'order' => 'ASC',
289 'items_per_page' => -1,
290 ) );
291
292 $actions = $ct_query->get_results();
293
294 ct_reset_setup_table();
295
296 // Cache actions
297 $cache[$automation_id] = $actions;
298
299 automatorwp_set_cache( 'automation_actions', $cache );
300
301 }
302
303 if( $output === ARRAY_N || $output === ARRAY_A ) {
304
305 // Turn array of objects into an array of arrays
306 foreach( $actions as $i => $action ) {
307 $actions[$i] = (array) $action;
308 }
309
310 }
311
312 return $actions;
313
314 }
315
316 /**
317 * Get the automation run details
318 *
319 * @since 2.2.2
320 *
321 * @param stdClass $automation The automation object
322 *
323 * @return array|false
324 */
325 function automatorwp_get_automation_run_details( $automation ) {
326
327 global $automatorwp_run_automation_error;
328
329 if( ! is_object( $automation ) ) {
330 $automatorwp_run_automation_error = __( 'Invalid automation.', 'automatorwp' );
331 return false;
332 }
333
334 // Used for automation loop
335 $items_per_loop = absint( automatorwp_get_automation_meta( $automation->id, 'items_per_loop', true ) );
336
337 $count = apply_filters( 'automatorwp_get_automation_run_details_count', 0, $automation );
338
339 $loop = absint( automatorwp_get_automation_meta( $automation->id, 'current_loop', true ) );
340 $processed = ( $loop * $items_per_loop ) + $items_per_loop;
341 $processed = min( $processed, $count );
342 $percentage = ( $count > 0 ? ( $processed / $count ) * 100 : 100 );
343
344 $run_details = array(
345 'loop' => $loop,
346 'items_per_loop' => $items_per_loop,
347 'count' => $count,
348 'processed' => $processed,
349 'percentage' => $percentage,
350 'run_again' => ( $processed < $count ),
351 );
352
353 return apply_filters( 'automatorwp_get_automation_run_details', $run_details, $automation );
354
355 }
356
357 /**
358 * Calculate the next run date for an all users automation
359 *
360 * @since 1.0.0
361 *
362 * @param int $automation_id The automation ID
363 * @param bool $is_saving Flag to meet if the automation is being saved from the edit screen to handle the values from $_POST
364 */
365 function automatorwp_update_automation_next_run_date( $automation_id, $is_saving = false ) {
366
367 // Setup vars
368 $args = automatorwp_setup_automation_next_run_date_args( $automation_id, $is_saving );
369 $current_time = current_time( 'timestamp' );
370 $date_format = automatorwp_get_date_format( array( 'Y-m-d', 'm/d/Y' ) );
371 $time_format = automatorwp_get_time_format();
372 $datetime_format = $date_format . ' ' . $time_format;
373 $timestamp = false;
374
375 if( $args['schedule_run'] === true ) {
376 // Schedule run
377
378 $schedule_run_datetime = $args['schedule_run_datetime'];
379
380 // Check if schedule run datetime is correctly setup (this only when saving)
381 if( is_array( $schedule_run_datetime ) && isset( $schedule_run_datetime['date'] ) && isset( $schedule_run_datetime['time'] ) ) {
382
383 $date = sanitize_text_field( $schedule_run_datetime['date'] );
384 $time = sanitize_text_field( $schedule_run_datetime['time'] );
385
386 $timestamp = automatorwp_get_timestamp_from_value( $date . ' ' . $time, $date_format );
387 } else if( ! empty( $schedule_run_datetime ) ) {
388 // Schedule run datetime is stored as a timestamp
389 $timestamp = $schedule_run_datetime;
390 }
391 } else if( $args['recurring_run'] === true ) {
392 // Recurring run
393
394 $day = $args['recurring_run_day'];
395 $period = $args['recurring_run_period'];
396 $time = $args['recurring_run_time'];
397
398 switch( $period ) {
399 case 'day':
400 $date = date( 'Y-m-d', strtotime(' +1 day', $current_time ) );
401 break;
402 case 'week':
403 $days_of_the_week = array( 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday', 'sunday' );
404 $week_day = $day - 1;
405
406 // Get the current week timestamp
407 $week_timestamp = strtotime( $days_of_the_week[$week_day], strtotime( 'this week', $current_time ) );
408
409 // If lower than today, get the next week
410 if( $week_timestamp <= $current_time ) {
411 $week_timestamp = strtotime( $days_of_the_week[$week_day], strtotime( 'next week', $current_time ) );
412 }
413
414 $date = date( 'Y-m-d', $week_timestamp );
415 break;
416 case 'month':
417 // Get the current month timestamp
418 $month = absint( date('m', $current_time) );
419
420 // Check the max day of this month
421 $max_day = absint( date( 't', $current_time ) );
422 $max_day = min( $day, $max_day );
423
424 $month_timestamp = strtotime( date( "{$max_day}-{$month}-Y", $current_time ) );
425
426 // If lower than today, get the next month
427 if( $month_timestamp <= $current_time ) {
428 $next_month = strtotime( 'next month', $current_time );
429 $month = absint( date('m', $next_month) );
430
431 // Check the max day of next month
432 $max_day = absint( date( 't', $next_month ) );
433 $max_day = min( $day, $max_day );
434
435 $month_timestamp = strtotime( date( "{$max_day}-{$month}-Y", $current_time ) );
436 }
437
438 $date = date( 'Y-m-d', $month_timestamp );
439 break;
440 case 'year':
441 $year = absint( date('Y', $current_time) );
442 $year_day = $day - 1;
443
444 // Check if is a leap year
445 if( $day === 365 && checkdate( 2, 29, $year ) ) {
446 $year_day = 365;
447 }
448
449 // Get the current year timestamp
450
451 $date = DateTime::createFromFormat( 'Y z' , $year . ' ' . $year_day);
452 $year_timestamp = $date->getTimestamp();
453
454 // If lower than today, get the next year
455 if( $year_timestamp <= $current_time ) {
456 // Increase year and restore the day to check if next year is leap
457 $year += 1;
458 $year_day = $day - 1;
459
460 // Check if is a leap year
461 if( $day === 365 && checkdate( 2, 29, $year ) ) {
462 $year_day = 365;
463 }
464
465 $date = DateTime::createFromFormat( 'Y z' , $year . ' ' . $year_day);
466
467 $year_timestamp = $date->getTimestamp();
468 }
469
470 $date = date( 'Y-m-d', $year_timestamp );
471 break;
472 }
473
474 $datetime = $date . ' ' . $time;
475 $timestamp = automatorwp_get_timestamp_from_value( $datetime, $datetime_format );
476
477 }
478
479 // Update the next run date meta
480 if( $timestamp && $timestamp > $current_time ) {
481 automatorwp_update_automation_meta( $automation_id, 'next_run_date', date( 'Y-m-d H:i:s', $timestamp ) );
482 } else {
483 automatorwp_update_automation_meta( $automation_id, 'next_run_date', '' );
484 }
485
486 }
487
488 /**
489 * Setup args for the next run date calculation
490 *
491 * @since 1.0.0
492 *
493 * @param int $automation_id The automation ID
494 * @param bool $is_saving Flag to meet if the automation is being saved from the edit screen to handle the values from $_POST
495 */
496 function automatorwp_setup_automation_next_run_date_args( $automation_id, $is_saving = false ) {
497
498 $args = array();
499
500 // Schedule run
501 if( $is_saving ) {
502 $args['schedule_run'] = ( isset( $_POST['schedule_run'] ) ? true : false );
503 } else {
504 $args['schedule_run'] = (bool) automatorwp_get_automation_meta( $automation_id, 'schedule_run', true );
505 }
506
507 if( $args['schedule_run'] ) {
508
509 // Schedule run datetime
510 if( $is_saving ) {
511 $args['schedule_run_datetime'] = ( isset( $_POST['schedule_run_datetime'] ) ? $_POST['schedule_run_datetime'] : array() );
512 } else {
513 $args['schedule_run_datetime'] = automatorwp_get_automation_meta( $automation_id, 'schedule_run_datetime', true );
514 }
515
516 }
517
518 // Recurring run
519 if( $is_saving ) {
520 $args['recurring_run'] = ( isset( $_POST['recurring_run'] ) ? true : false );
521 } else {
522 $args['recurring_run'] = (bool) automatorwp_get_automation_meta( $automation_id, 'recurring_run', true );
523 }
524
525 if( $args['recurring_run'] ) {
526
527 // Recurring run day
528 if( $is_saving ) {
529 $args['recurring_run_day'] = absint( ( isset( $_POST['recurring_run_day'] ) ? $_POST['recurring_run_day'] : '1' ) );
530 } else {
531 $args['recurring_run_day'] = absint( automatorwp_get_automation_meta( $automation_id, 'recurring_run_day', true ) );
532 }
533
534 // Recurring run period
535 if( $is_saving ) {
536 $args['recurring_run_period'] = ( isset( $_POST['recurring_run_period'] ) ? sanitize_text_field( $_POST['recurring_run_period'] ) : 'day' );
537 } else {
538 $args['recurring_run_period'] = automatorwp_get_automation_meta( $automation_id, 'recurring_run_period', true );
539 }
540
541 // Recurring run time
542 if( $is_saving ) {
543 $args['recurring_run_time'] = ( isset( $_POST['recurring_run_time'] ) ? sanitize_text_field( $_POST['recurring_run_time'] ) : 'day' );
544 } else {
545 $args['recurring_run_time'] = automatorwp_get_automation_meta( $automation_id, 'recurring_run_time', true );
546 }
547
548 }
549
550 return $args;
551
552 }
553
554 /**
555 * Clone automation
556 *
557 * @since 1.0.0
558 *
559 * @param int $automation_id The automation ID
560 * @param int $user_id The user ID to assign to the automation
561 *
562 * @return int|bool Clone result
563 */
564 function automatorwp_clone_automation( $automation_id, $user_id = 0 ) {
565
566 if( $user_id === 0 ) {
567 $user_id = get_current_user_id();
568 }
569
570 ct_setup_table( 'automatorwp_automations' );
571
572 $automation = ct_get_object( $automation_id );
573
574 // Bail if automation does not exists
575 if( ! $automation ) {
576 ct_reset_setup_table();
577 return false;
578 }
579
580 $automation = ( array ) $automation;
581
582 // Set up the new automation info
583 unset( $automation['id'] );
584 $automation['title'] .= ( ! empty( $automation['title'] ) ? ' ' : '' ) . __( '(Cloned)', 'automatorwp' );
585 $automation['user_id'] = $user_id;
586 $automation['status'] = 'inactive';
587 $automation['date'] = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
588
589 // Insert the new automation
590 $new_automation_id = ct_insert_object( $automation );
591
592 if( ! $new_automation_id ) {
593 ct_reset_setup_table();
594 return false;
595 }
596
597 automatorwp_clone_automation_items( $automation_id, $new_automation_id );
598
599 ct_reset_setup_table();
600 return $new_automation_id;
601
602 }
603
604 /**
605 * Clone all automation items to a new one
606 *
607 * @since 1.0.0
608 *
609 * @param int $automation_id The automation ID
610 * @param int $new_automation_id The automation ID to clone all the items
611 */
612 function automatorwp_clone_automation_items( $automation_id, $new_automation_id ) {
613
614 global $wpdb;
615
616 $item_types = array( 'trigger', 'action' );
617 $ids = array();
618 $replacements = array();
619
620 // Migrate all items to the new automation and collect the old and new IDs
621 foreach( $item_types as $item_type ) {
622
623 if( $item_type === 'trigger' ) {
624 $items = automatorwp_get_automation_triggers( $automation_id );
625 } else {
626 $items = automatorwp_get_automation_actions( $automation_id );
627 }
628
629 ct_setup_table( "automatorwp_{$item_type}s" );
630
631 foreach( $items as $item ) {
632
633 $new_item = ( array ) $item;
634
635 unset( $new_item['id'] );
636 $new_item['automation_id'] = $new_automation_id;
637 $new_item['date'] = date( 'Y-m-d H:i:s', current_time( 'timestamp' ) );
638
639 $new_item_id = ct_insert_object( $new_item );
640
641 // Update old ids and replacements to be used on metas
642 if( $new_item_id ) {
643 $ids[$item->id] = $new_item_id;
644
645 if ( $item_type === 'trigger' ) {
646 $replacements['{' . $item->id . ':'] = '{' . $new_item_id . ':';
647 $replacements['{t:' . $item->id . ':'] = '{t:' . $new_item_id . ':';
648 }
649
650 if ( $item_type === 'action' ) {
651 $replacements['{a:' . $item->id . ':'] = '{a:' . $new_item_id . ':';
652 }
653
654 }
655
656 }
657
658 ct_reset_setup_table();
659
660 }
661
662 $tags = array_keys( $replacements );
663
664 // Loop again the items to update their metas
665 foreach( $item_types as $item_type ) {
666
667 // Do not worry about performance, AutomatorWP already caches this functions
668 if( $item_type === 'trigger' ) {
669 $items = automatorwp_get_automation_triggers( $automation_id );
670 } else {
671 $items = automatorwp_get_automation_actions( $automation_id );
672 }
673
674 $ct_table = ct_setup_table( "automatorwp_{$item_type}s" );
675 $metas = array();
676
677 foreach( $items as $item ) {
678
679 // Skip if item not has been cloned
680 if( ! isset( $ids[$item->id] ) ) {
681 continue;
682 }
683
684 // Get all item metas
685 $item_metas = $wpdb->get_results( "SELECT meta_key, meta_value FROM {$ct_table->meta->db->table_name} WHERE id = {$item->id}", ARRAY_A );
686
687 foreach( $item_metas as $i => $item_meta ) {
688
689 $meta_key = $item_metas[$i]['meta_key'];
690
691 /**
692 * Filter to exclude a meta on clone this item
693 * $item_type: trigger | action
694 * $item->type: The trigger or action type
695 * $meta_key: The meta key
696 *
697 * @since 1.0.0
698 *
699 * @param bool $exclude
700 *
701 * @return bool
702 */
703 $exclude = apply_filters( "automatorwp_clone_{$item_type}_{$item->type}_meta_{$meta_key}_excluded", false );
704
705 // Skip if meta gets excluded on clone
706 if( $exclude ) {
707 continue;
708 }
709
710 // Replace metas with old IDs with the new ones
711 $meta_value = str_replace( $tags, $replacements, $item_metas[$i]['meta_value'] );
712
713 // Prepare for the upcoming insert
714 $metas[] = $wpdb->prepare( '%d, %s, %s', array( $ids[$item->id], $meta_key, $meta_value ) );
715 }
716
717 $item_title = str_replace( $tags, $replacements, $item->title );
718
719 /**
720 * Filter to parse the item title
721 * $item_type: trigger | action
722 * $item->type: The trigger or action type
723 *
724 * @since 1.0.0
725 *
726 * @param string $item_title The item title
727 * @param int $old_item_id The old item ID
728 * @param int $new_item_id The new item ID
729 *
730 * @return string
731 */
732 $item_title = apply_filters( "automatorwp_clone_{$item_type}_{$item->type}_title", $item_title, $item->id, $ids[$item->id] );
733
734 // Update the new item title
735 ct_update_object( array(
736 'id' => $ids[$item->id],
737 'title' => $item_title,
738 ) );
739
740 }
741
742 if( count( $metas ) ) {
743 $metas = implode( '), (', $metas );
744
745 // Run a single query to insert all metas instead of insert them one-by-one
746 $wpdb->query( "INSERT INTO {$ct_table->meta->db->table_name} (id, meta_key, meta_value) VALUES ({$metas})" );
747 }
748
749 ct_reset_setup_table();
750
751 }
752
753 }
754
755 /**
756 * Turn an automation into an exportable URL
757 *
758 * @since 1.0.0
759 *
760 * @param int $automation_id The automation ID
761 *
762 * @return string
763 */
764 function automatorwp_get_automation_export_url( $automation_id ) {
765
766 $automation = automatorwp_get_automation_object( $automation_id );
767
768 if( ! $automation ) {
769 return '';
770 }
771
772 $url = 'wp-admin/admin.php?page=automatorwp_import_automation';
773
774 // Setup the automation args
775 // Only include those parameters if they are different from their default value to reduce the URL length
776 if( ! empty( $automation->title ) ) {
777 $url = add_query_arg( 'ti', $automation->title, $url );
778 }
779
780 if( $automation->type !== 'user' ) {
781 $url = add_query_arg( 'ty', $automation->type, $url );
782 }
783
784 if( absint( $automation->sequential ) !== 0 ) {
785 $url = add_query_arg( 's', $automation->sequential, $url );
786 }
787
788 if( absint( $automation->times_per_user ) !== 1 ) {
789 $url = add_query_arg( 'tu', $automation->times_per_user, $url );
790 }
791
792 if( absint( $automation->times ) !== 0 ) {
793 $url = add_query_arg( 'tim', $automation->times, $url );
794 }
795
796 $url .= automatorwp_get_automation_items_export_url( $automation_id );
797
798 return $url;
799
800 }
801
802 /**
803 * Turn automation items into an exportable URL
804 *
805 * @since 1.0.0
806 *
807 * @param int $automation_id The automation ID
808 *
809 * @return string
810 */
811 function automatorwp_get_automation_items_export_url( $automation_id ) {
812
813 $item_types = array( 'trigger', 'action' );
814 $false_url = 'a.php?b=c';
815 $url = $false_url;
816
817 // Loop all automation items
818 foreach( $item_types as $item_type ) {
819
820 // Get the items
821 if( $item_type === 'trigger' ) {
822 $items = automatorwp_get_automation_triggers( $automation_id );
823 } else {
824 $items = automatorwp_get_automation_actions( $automation_id );
825 }
826
827 $url_items = array();
828
829 ct_setup_table( "automatorwp_{$item_type}s" );
830
831 foreach( $items as $item ) {
832
833 // Get the type args
834 if( $item_type === 'trigger' ) {
835 $type_args = automatorwp_get_trigger( $item->type );
836 } else {
837 $type_args = automatorwp_get_action( $item->type );
838 }
839
840 if( ! $type_args ) {
841 continue;
842 }
843
844 // Setup the item options
845 $options = array();
846
847 // Special check for filters
848 if( $item->type === 'filter' ) {
849
850 $filter = ct_get_object_meta( $item->id, 'filter', true );
851
852 $filter_args = automatorwp_get_filter( $filter );
853
854 // If filter args found, append the filter options to the type options
855 if( $filter_args ) {
856 $type_args['options'] = array_merge( $type_args['options'], $filter_args['options'] );
857 }
858
859 }
860
861 foreach( $type_args['options'] as $option => $option_args ) {
862
863 // Skip option if not has fields
864 if( ! isset( $option_args['fields'] ) ) {
865 continue;
866 }
867
868 foreach( $option_args['fields'] as $field_id => $field_args ) {
869
870 /**
871 * Filter to exclude a meta on export this item through URL
872 * $item_type: trigger | action
873 * $item->type: The trigger or action type
874 * $field_id: The meta key
875 *
876 * @since 1.0.0
877 *
878 * @param bool $exclude
879 *
880 * @return bool
881 */
882 $exclude = apply_filters( "automatorwp_export_url_{$item_type}_{$item->type}_meta_{$field_id}_excluded", false );
883
884 // Skip if meta gets excluded on export through URL
885 if( $exclude ) {
886 continue;
887 }
888
889 $field_value = ct_get_object_meta( $item->id, $field_id, true );
890
891 // Skip options with
892 if( isset( $field_args['default'] ) && $field_args['default'] == $field_value ) {
893 continue;
894 }
895
896 // Skip if no value entered
897 if( empty( $field_value ) ) {
898 continue;
899 }
900
901 $options[$field_id] = urlencode( maybe_serialize( $field_value ) );
902
903 }
904
905 }
906
907 $url_items[] = array(
908 'i' => $item->id,
909 't' => $item->type,
910 'o' => $options,
911 );
912
913 }
914
915 ct_reset_setup_table();
916
917 // Add the items to the URL
918 if( $item_type === 'trigger' ) {
919 $prefix = 't';
920 } else {
921 $prefix = 'a';
922 }
923
924 // Pull all url items to reduce the URL length
925 $url = automatorwp_pull_array_for_export_url( $url_items, $url, $prefix );
926
927 }
928
929 // Remove the false URL part
930 $url = str_replace( $false_url, '', $url );
931
932 return $url;
933
934 }
935
936 /**
937 * Helper function to pull array elements to an exportable URL
938 *
939 * @since 1.0.0
940 *
941 * @param array $array
942 * @param string $url
943 * @param string $prefix
944 *
945 * @return string
946 */
947 function automatorwp_pull_array_for_export_url( $array, $url, $prefix = '' ) {
948
949 foreach( $array as $key => $value ) {
950
951 if( is_array( $value ) ) {
952
953 $url = automatorwp_pull_array_for_export_url( $value, $url, "{$prefix}-{$key}" );
954
955 } else {
956 $url = add_query_arg( "{$prefix}-{$key}", $value, $url );
957 }
958
959 }
960
961 return $url;
962
963 }
964
965 /**
966 * Helper function to get array elements from an exportable URL
967 *
968 * @since 1.0.0
969 *
970 * @param array $request
971 * @param string $prefix
972 *
973 * @return array
974 */
975 function automatorwp_get_array_from_export_url( $request, $prefix = '' ) {
976
977 $params = array();
978 $params[$prefix] = array();
979
980 foreach( $request as $key => $value ) {
981
982 // Skip if not starts with the required prefix
983 if( ! automatorwp_starts_with( $key, "{$prefix}-" ) ) {
984 continue;
985 }
986
987 $keys = explode( '-', $key );
988 $length = count( $keys );
989
990 $array = &$params[$prefix];
991
992 foreach ( $keys as $i => $sub_key ) {
993
994 // Skip the first sub key
995 if( $i === 0 ) {
996 continue;
997 }
998
999 // Create the sub key
1000 if( ! isset( $array[$sub_key] ) ) {
1001 $array[$sub_key] = array();
1002 }
1003
1004 // If is the last sub key, assign the original value
1005 if( $i === ( $length - 1 ) ) {
1006 $array[$sub_key] = $value;
1007 }
1008
1009 $array = &$array[$sub_key];
1010
1011 }
1012
1013 }
1014
1015 return $params[$prefix];
1016
1017 }
1018
1019 /**
1020 * Helper function to meet if is a scheduled automation
1021 *
1022 * @param stdClass $automation
1023 *
1024 * @return bool
1025 */
1026 function automatorwp_is_automation_scheduled( $automation ) {
1027
1028 $now = current_time( 'timestamp' );
1029 $date = strtotime( $automation->date );
1030
1031 return ( $date > $now );
1032
1033 }
1034
1035 /**
1036 * Helper function to meet if is an expired automation
1037 *
1038 * @param stdClass $automation
1039 *
1040 * @return bool
1041 */
1042 function automatorwp_is_automation_expired( $automation ) {
1043
1044 // Ensure that automation object is up-to-date
1045 if( ! property_exists( $automation, 'expiration' ) ) return false;
1046 // Bail if automation is not active
1047 if( $automation->status !== 'active' ) return false;
1048
1049 $now = current_time( 'timestamp' );
1050
1051 $expiration = strtotime( $automation->expiration );
1052 $date = strtotime( $automation->date );
1053
1054 // Only check this if automation has been correctly setup
1055 if( $expiration > 0 && $expiration > $date ) {
1056 return ( $expiration < $now );
1057 }
1058
1059 return false;
1060
1061 }
1062
1063 /**
1064 * Helper function to activate an automation
1065 *
1066 * @param int $automation_id
1067 *
1068 * @return bool
1069 */
1070 function automatorwp_activate_automation( $automation_id ) {
1071
1072 ct_setup_table( 'automatorwp_automations' );
1073
1074 $automation = ct_get_object( $automation_id );
1075
1076 // Bail if automation does not exists
1077 if( ! $automation ) {
1078 ct_reset_setup_table();
1079 return false;
1080 }
1081
1082 $automation = ( array ) $automation;
1083 $automation['status'] = 'active';
1084
1085 $result = ct_update_object( $automation );
1086
1087 ct_reset_setup_table();
1088
1089 return true;
1090 }
1091
1092 /**
1093 * Helper function to activate an automation
1094 *
1095 * @param int $automation_id
1096 *
1097 * @return bool
1098 */
1099 function automatorwp_deactivate_automation( $automation_id ) {
1100
1101 ct_setup_table( 'automatorwp_automations' );
1102
1103 $automation = ct_get_object( $automation_id );
1104
1105 // Bail if automation does not exists
1106 if( ! $automation ) {
1107 ct_reset_setup_table();
1108 return false;
1109 }
1110
1111 $automation = ( array ) $automation;
1112 $automation['status'] = 'inactive';
1113
1114 $result = ct_update_object( $automation );
1115
1116 ct_reset_setup_table();
1117
1118 return true;
1119 }