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/events.php +2085 -0 5.7.9.2 → 6.0.3 View file →
@@ -1,0 +1,2085 @@
1 +<?php
2 +/**
3 + * Events
4 + *
5 + * @package AutomatorWP\Events
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 + * Handles an event trigger
14 + *
15 + * @since 1.0.0
16 + *
17 + * @param array $event Event information
18 + *
19 + * @return array|false An array of triggered triggers or false if event is not correctly triggered
20 + */
21 +function automatorwp_trigger_event( $event ) {
22 +
23 + global $automatorwp_completed_triggers, $automatorwp_event;
24 +
25 + $automatorwp_event = false;
26 +
27 + // Check the event received
28 + if( ! automatorwp_is_event_correct( $event ) ) {
29 + return false;
30 + }
31 +
32 + $automatorwp_event = $event;
33 +
34 + // Initialize completed triggers count
35 + if( ! is_array( $automatorwp_completed_triggers ) ) {
36 + $automatorwp_completed_triggers = array();
37 + }
38 +
39 + // Get triggered triggers
40 + $triggers = automatorwp_get_event_triggered_triggers( $event['trigger'] );
41 +
42 + foreach( $triggers as $trigger ) {
43 +
44 + if( automatorwp_maybe_completed_trigger( $trigger, $event ) ) {
45 + $automatorwp_completed_triggers[] = $trigger;
46 + }
47 +
48 + }
49 +
50 + return ( count( $automatorwp_completed_triggers ) ? $automatorwp_completed_triggers : false );
51 +
52 +}
53 +
54 +/**
55 + * Checks if event contains the required attributes (by default, user_id and trigger)
56 + *
57 + * @since 1.0.0
58 + *
59 + * @param array $event Event information
60 + *
61 + * @return bool
62 + */
63 +function automatorwp_is_event_correct( $event = array() ) {
64 +
65 + // Check trigger
66 + if( ! isset( $event['trigger'] ) ) {
67 + return false;
68 + }
69 +
70 + if( ! isset( AutomatorWP()->triggers[$event['trigger']] ) ) {
71 + return false;
72 + }
73 +
74 + $trigger = AutomatorWP()->triggers[$event['trigger']];
75 +
76 + // Check the user ID if trigger is not anonymous
77 + if( ! $trigger['anonymous'] ) {
78 +
79 + // Check user
80 + if( ! isset( $event['user_id'] ) ) {
81 + return false;
82 + }
83 +
84 + $event['user_id'] = absint( $event['user_id'] );
85 +
86 + if( $event['user_id'] === 0 ) {
87 + return false;
88 + }
89 +
90 + }
91 +
92 + /**
93 + * Filter to add custom checks to event checking
94 + *
95 + * @since 1.0.0
96 + *
97 + * @param bool $is_correct If event is correct or not
98 + * @param array $event Event information
99 + *
100 + * @return bool
101 + */
102 + return apply_filters( 'automatorwp_is_event_correct', true, $event );
103 +
104 +}
105 +
106 +/**
107 + * Get triggers by type commonly triggered by automatorwp_trigger_event() function
108 + *
109 + * @since 1.0.0
110 + *
111 + * @param string $trigger_type The trigger type triggered in event
112 + *
113 + * @return array
114 + */
115 +function automatorwp_get_event_triggered_triggers( $trigger_type ) {
116 +
117 + ct_setup_table( 'automatorwp_triggers' );
118 +
119 + $ct_query = new CT_Query( array(
120 + 'type' => $trigger_type,
121 + 'orderby' => 'position',
122 + 'order' => 'ASC',
123 + 'items_per_page' => -1,
124 + ) );
125 +
126 + $triggers = $ct_query->get_results();
127 +
128 + ct_reset_setup_table();
129 +
130 + if( is_array( $triggers ) ) {
131 + return $triggers;
132 + } else {
133 + return array();
134 + }
135 +
136 +}
137 +
138 +/**
139 + * Check if trigger can be marked as completed
140 + *
141 + * @since 1.0.0
142 + *
143 + * @param stdClass $trigger The trigger object
144 + * @param array $event Event information
145 + *
146 + * @return bool
147 + */
148 +function automatorwp_maybe_completed_trigger( $trigger, $event = array() ) {
149 +
150 + // Check if trigger is correct
151 + if( ! is_object( $trigger ) ) {
152 + return false;
153 + }
154 +
155 + // Check if automation is correct
156 + $automation = automatorwp_get_trigger_automation( $trigger->id );
157 +
158 + if( ! is_object( $automation ) ) {
159 + return false;
160 + }
161 +
162 + // Check if automation is expired to deactivate it
163 + if( automatorwp_is_automation_expired( $automation ) ) {
164 + automatorwp_deactivate_automation( $automation->id );
165 +
166 + // The automation has expired so bail here
167 + return false;
168 + }
169 +
170 + $trigger_args = automatorwp_get_trigger( $trigger->type );
171 +
172 + if( $automation->type === 'anonymous' ) {
173 + // Anonymous automation
174 +
175 + // Bail if user trigger is used on an anonymous automation
176 + if( ! $trigger_args['anonymous'] ) {
177 + return false;
178 + }
179 +
180 + return automatorwp_maybe_anonymous_completed_trigger( $trigger, $event );
181 +
182 + } else {
183 + // User automation
184 +
185 + // Bail if anonymous trigger is used on a user automation
186 + if( $trigger_args['anonymous'] ) {
187 + return false;
188 + }
189 +
190 + // Args has been checked on automatorwp_is_event_correct() function
191 + $user_id = $event['user_id'];
192 +
193 + return automatorwp_maybe_user_completed_trigger( $trigger, $user_id, $event );
194 +
195 + }
196 +
197 +}
198 +
199 +// -------------------------------------------
200 +// Guest event
201 +// -------------------------------------------
202 +
203 +/**
204 + * Check if anonymous has completed a trigger
205 + *
206 + * @since 1.3.0
207 + *
208 + * @param stdClass $trigger The trigger object
209 + * @param array $event Event information
210 + *
211 + * @return bool
212 + */
213 +function automatorwp_maybe_anonymous_completed_trigger( $trigger, $event = array() ) {
214 +
215 + // Check if trigger is correct
216 + if( ! is_object( $trigger ) ) {
217 + return false;
218 + }
219 +
220 + // Check if automation is correct
221 + $automation = automatorwp_get_trigger_automation( $trigger->id );
222 +
223 + if( ! is_object( $automation ) ) {
224 + return false;
225 + }
226 +
227 + // Get the trigger stored options
228 + $trigger_options = automatorwp_get_trigger_stored_options( $trigger->id );
229 +
230 + foreach( $trigger_options as $option => $value ) {
231 + // Replace all tags by their replacements
232 + $trigger_options[$option] = automatorwp_parse_automation_tags( $automation->id, 0, $value );
233 + }
234 +
235 + // Check if anonymous has access to the trigger
236 + if( ! automatorwp_anonymous_has_access_to_trigger( $trigger, $event, $trigger_options, $automation ) ) {
237 + return false;
238 + }
239 +
240 + // Check if anonymous deserves the trigger
241 + if( ! automatorwp_anonymous_deserves_trigger( $trigger, $event, $trigger_options, $automation ) ) {
242 + return false;
243 + }
244 +
245 + // Mark trigger as completed
246 + $trigger_completed = automatorwp_anonymous_completed_trigger( $trigger, $event, $trigger_options, $automation );
247 +
248 + if( ! $trigger_completed ) {
249 + return false;
250 + }
251 +
252 + $user_id = automatorwp_get_anonymous_automation_user_id( $automation, $event );
253 +
254 + // Bail if user can't be created
255 + if( ! $user_id ) {
256 + return false;
257 + }
258 +
259 + // Update anonymous log user ID
260 + automatorwp_update_anonymous_completed_trigger_log_user_id( $user_id );
261 +
262 + automatorwp_maybe_user_completed_automation( $automation, $user_id, $event );
263 +
264 + return true;
265 +
266 +}
267 +
268 +/**
269 + * Check if anonymous has access to trigger
270 + *
271 + * @since 1.3.0
272 + *
273 + * @param stdClass $trigger The trigger object
274 + * @param array $event Event information
275 + * @param array $trigger_options The trigger's stored options
276 + * @param stdClass $automation The trigger's automation object
277 + *
278 + * @return bool True if anonymous has access, false otherwise
279 + */
280 +function automatorwp_anonymous_has_access_to_trigger( $trigger = null, $event = array(), $trigger_options = array(), $automation = null ) {
281 +
282 + // Check if trigger is correct
283 + if( ! is_object( $trigger ) ) {
284 + return false;
285 + }
286 +
287 + // Check if automation is correct
288 + if( $automation === null ) {
289 + $automation = automatorwp_get_trigger_automation( $trigger->id );
290 +
291 + if( ! is_object( $automation ) ) {
292 + return false;
293 + }
294 + }
295 +
296 + $has_access = true;
297 +
298 + // Bail if automation is not active
299 + if( $automation->status !== 'active' ) {
300 + $has_access = false;
301 + }
302 +
303 + // Bail if is a future automation
304 + if( $has_access && automatorwp_is_automation_scheduled( $automation ) ) {
305 + $has_access = false;
306 + }
307 +
308 + // Bail if expired automation
309 + if( $has_access && automatorwp_is_automation_expired( $automation ) ) {
310 + $has_access = false;
311 + }
312 +
313 + // Check if exceeded automation completion times
314 + $times = absint( $automation->times );
315 +
316 + if( $has_access && $times > 0 ) {
317 + $completion_times = automatorwp_get_object_completion_times( $automation->id, 'automation' );
318 +
319 + if( $completion_times >= $times ) {
320 + $has_access = false;
321 + }
322 + }
323 +
324 + /**
325 + * Filter to override the has access check.
326 + * This filter is to check the automation configuration.
327 + * Triggers should use the 'automatorwp_anonymous_deserves_trigger' filter instead.
328 + *
329 + * @since 1.3.0
330 + *
331 + * @param bool $has_access True if anonymous has access, false otherwise
332 + * @param stdClass $trigger The trigger object
333 + * @param array $event Event information
334 + * @param array $trigger_options The trigger's stored options
335 + * @param stdClass $automation The trigger's automation object
336 + *
337 + * @return bool True if anonymous has access, false otherwise
338 + */
339 + return apply_filters( 'automatorwp_anonymous_has_access_to_trigger', $has_access, $trigger, $event, $trigger_options, $automation );
340 +
341 +}
342 +
343 +/**
344 + * Check if anonymous deserves trigger
345 + *
346 + * @since 1.3.0
347 + *
348 + * @param stdClass $trigger The trigger object
349 + * @param array $event Event information
350 + * @param array $trigger_options The trigger's stored options
351 + * @param stdClass $automation The trigger's automation object
352 + *
353 + * @return bool True if anonymous deserves trigger, false otherwise
354 + */
355 +function automatorwp_anonymous_deserves_trigger( $trigger = null, $event = array(), $trigger_options = array(), $automation = null ) {
356 +
357 + // Check if trigger is correct
358 + if( ! is_object( $trigger ) ) {
359 + return false;
360 + }
361 +
362 + // Check if automation is correct
363 + if( $automation === null ) {
364 + $automation = automatorwp_get_trigger_automation( $trigger->id );
365 +
366 + if( ! is_object( $automation ) ) {
367 + return false;
368 + }
369 + }
370 +
371 + $deserves_trigger = true;
372 +
373 + /**
374 + * Filter to override the anonymous deserves trigger check.
375 + * This filter is to check the trigger configuration.
376 + * Triggers should use this filter.
377 + *
378 + * @since 1.3.0
379 + *
380 + * @param bool $deserves_trigger True if anonymous deserves trigger, false otherwise
381 + * @param stdClass $trigger The trigger object
382 + * @param array $event Event information
383 + * @param array $trigger_options The trigger's stored options
384 + * @param stdClass $automation The trigger's automation object
385 + *
386 + * @return bool True if anonymous deserves trigger, false otherwise
387 + * @return bool True if anonymous deserves trigger, false otherwise
388 + */
389 + return apply_filters( 'automatorwp_anonymous_deserves_trigger', $deserves_trigger, $trigger, $event, $trigger_options, $automation );
390 +
391 +}
392 +
393 +/**
394 + * Registers the trigger completion
395 + *
396 + * @since 1.3.0
397 + *
398 + * @param stdClass $trigger The trigger object
399 + * @param array $event Event information
400 + * @param array $trigger_options The trigger's stored options
401 + * @param stdClass $automation The trigger's automation object
402 + *
403 + * @return bool
404 + */
405 +function automatorwp_anonymous_completed_trigger( $trigger = null, $event = array(), $trigger_options = array(), $automation = null ) {
406 +
407 + global $automatorwp_last_anonymous_trigger_log_id;
408 +
409 + // Initialize last anonymous trigger log ID
410 + $automatorwp_last_anonymous_trigger_log_id = 0;
411 +
412 + // Check if trigger is correct
413 + if( ! is_object( $trigger ) ) {
414 + return false;
415 + }
416 +
417 + // Check if automation is correct
418 + if( $automation === null ) {
419 + $automation = automatorwp_get_trigger_automation( $trigger->id );
420 +
421 + if( ! is_object( $automation ) ) {
422 + return false;
423 + }
424 + }
425 +
426 + // Get the trigger completion times
427 + $log_meta = array(
428 + 'times' => 1
429 + );
430 +
431 + if( isset( $event['comment_id'] ) ) {
432 + $log_meta['comment_id'] = $event['comment_id'];
433 + }
434 +
435 + /**
436 + * Filter to add custom log meta to meet that user has completed this trigger
437 + *
438 + * @since 1.3.0
439 + *
440 + * @param array $log_meta Log meta data
441 + * @param stdClass $trigger The trigger object
442 + * @param array $event Event information
443 + * @param array $trigger_options The trigger's stored options
444 + * @param stdClass $automation The trigger's automation object
445 + *
446 + * @return array
447 + */
448 + $log_meta = apply_filters( 'automatorwp_anonymous_completed_trigger_log_meta', $log_meta, $trigger, $event, $trigger_options, $automation );
449 +
450 + /**
451 + * Backward compatibility filter!
452 + *
453 + * Filter to add custom log meta to meet that user has completed this trigger
454 + *
455 + * @since 1.0.0
456 + *
457 + * @param array $log_meta Log meta data
458 + * @param stdClass $trigger The trigger object
459 + * @param int $user_id The user ID (here will be 0, since user hasn't been created yet)
460 + * @param array $event Event information
461 + * @param array $trigger_options The trigger's stored options
462 + * @param stdClass $automation The trigger's automation object
463 + *
464 + * @return array
465 + */
466 + $log_meta = apply_filters( 'automatorwp_user_completed_trigger_log_meta', $log_meta, $trigger, 0, $event, $trigger_options, $automation );
467 +
468 + // Insert a new log entry to register the trigger completion
469 + $automatorwp_last_anonymous_trigger_log_id = automatorwp_insert_log( array(
470 + 'title' => automatorwp_parse_automation_item_log_label( $trigger, 'trigger', 'view' ),
471 + 'type' => 'trigger',
472 + 'object_id' => $trigger->id,
473 + 'user_id' => 0,
474 + 'post_id' => ( isset( $event['post_id'] ) ? $event['post_id'] : 0 ),
475 + 'date' => automatorwp_get_event_log_date(),
476 + ), $log_meta );
477 +
478 + if( is_wp_error( $automatorwp_last_anonymous_trigger_log_id ) ) {
479 + $automatorwp_last_anonymous_trigger_log_id = 0;
480 + }
481 +
482 + /**
483 + * Available action to hook on a trigger completion
484 + *
485 + * @since 1.3.0
486 + *
487 + * @param stdClass $trigger The trigger object
488 + * @param array $event Event information
489 + * @param array $trigger_options The trigger's stored options
490 + * @param stdClass $automation The trigger's automation object
491 + */
492 + do_action( 'automatorwp_anonymous_completed_trigger', $trigger, $event, $trigger_options, $automation );
493 +
494 + return true;
495 +
496 +}
497 +
498 +/**
499 + * Get the anonymous automation user ID
500 + *
501 + * @since 1.3.0
502 + *
503 + * @param stdClass $automation The automation object
504 + * @param array $event Event information
505 + *
506 + * @return int|false The user ID, false otherwise
507 + */
508 +function automatorwp_get_anonymous_automation_user_id( $automation = null, $event = array() ) {
509 +
510 + if( ! is_object( $automation ) ) {
511 + return false;
512 + }
513 +
514 + $actions = automatorwp_get_automation_actions( $automation->id );
515 +
516 + // Check if isset the first action
517 + if( ! isset( $actions[0] ) ) {
518 + return false;
519 + }
520 +
521 + // Check if anonymous user action exists
522 + if( isset( $actions[0] ) && $actions[0]->type !== 'automatorwp_anonymous_user' ) {
523 + return false;
524 + }
525 +
526 + $action = $actions[0];
527 +
528 + // Get all action options to parse all replacements
529 + $action_options = automatorwp_get_action_stored_options( $action->id );
530 +
531 + foreach( $action_options as $option => $value ) {
532 + // Replace all tags by their replacements
533 + $action_options[$option] = automatorwp_parse_automation_tags( $automation->id, 0, $value );
534 + }
535 +
536 + // Execute the anonymous user action to decide the user to assign the logs
537 + $user_id = false;
538 +
539 + /**
540 + * Filter to decide to which user ID will be assigned to the automation
541 + *
542 + * @since 1.0.0
543 + *
544 + * @param int $user_id The user ID
545 + * @param stdClass $action The action object
546 + * @param array $action_options The action's stored options (with tags already passed)
547 + * @param stdClass $automation The action's automation object
548 + *
549 + * @return int|false The user ID, false otherwise
550 + */
551 + return apply_filters( 'automatorwp_get_anonymous_automation_user_id', $user_id, $action, $action_options, $automation );
552 +
553 +}
554 +
555 +/**
556 + * Update the trigger log user ID for anonymous events
557 + *
558 + * @since 1.3.0
559 + *
560 + * @param int $user_id The user ID
561 + */
562 +function automatorwp_update_anonymous_completed_trigger_log_user_id( $user_id ) {
563 +
564 + global $automatorwp_last_anonymous_trigger_log_id;
565 +
566 + // Bail if not ID found
567 + if( absint( $automatorwp_last_anonymous_trigger_log_id ) === 0 ) {
568 + return;
569 + }
570 +
571 + ct_setup_table( 'automatorwp_logs' );
572 +
573 + // Update the log user ID
574 + ct_update_object( array(
575 + 'id' => $automatorwp_last_anonymous_trigger_log_id,
576 + 'user_id' => $user_id,
577 + ) );
578 +
579 + ct_reset_setup_table();
580 +
581 +}
582 +
583 +// -------------------------------------------
584 +// User event
585 +// -------------------------------------------
586 +
587 +/**
588 + * Check if user has completed a trigger
589 + *
590 + * @since 1.0.0
591 + *
592 + * @param stdClass $trigger The trigger object
593 + * @param int $user_id The user ID
594 + * @param array $event Event information
595 + *
596 + * @return bool
597 + */
598 +function automatorwp_maybe_user_completed_trigger( $trigger, $user_id = 0, $event = array() ) {
599 +
600 + // Check if trigger is correct
601 + if( ! is_object( $trigger ) ) {
602 + return false;
603 + }
604 +
605 + // Check the user ID
606 + if( $user_id === 0 ) {
607 + return false;
608 + }
609 +
610 + // Check if automation is correct
611 + $automation = automatorwp_get_trigger_automation( $trigger->id );
612 +
613 + if( ! is_object( $automation ) ) {
614 + return false;
615 + }
616 +
617 + // Get the trigger stored options
618 + $trigger_options = automatorwp_get_trigger_stored_options( $trigger->id );
619 +
620 + foreach( $trigger_options as $option => $value ) {
621 + // Replace all tags by their replacements
622 + $trigger_options[$option] = automatorwp_parse_automation_tags( $automation->id, $user_id, $value );
623 + }
624 +
625 + // Check if user has access to the trigger
626 + if( ! automatorwp_user_has_access_to_trigger( $trigger, $user_id, $event, $trigger_options, $automation ) ) {
627 + return false;
628 + }
629 +
630 + // Check if user deserves the trigger
631 + if( ! automatorwp_user_deserves_trigger( $trigger, $user_id, $event, $trigger_options, $automation ) ) {
632 + return false;
633 + }
634 +
635 + // Check if user deserves the trigger filters
636 + if( ! automatorwp_user_deserves_trigger_filters( $trigger, $user_id, $event, $trigger_options, $automation ) ) {
637 + return false;
638 + }
639 +
640 + // Mark trigger as completed
641 + return automatorwp_user_completed_trigger( $trigger, $user_id, $event, $trigger_options, $automation );
642 +
643 +}
644 +
645 +/**
646 + * Check if user has access to trigger
647 + *
648 + * @since 1.0.0
649 + *
650 + * @param stdClass $trigger The trigger object
651 + * @param int $user_id The user ID
652 + * @param array $event Event information
653 + * @param array $trigger_options The trigger's stored options
654 + * @param stdClass $automation The trigger's automation object
655 + *
656 + * @return bool True if user has access, false otherwise
657 + */
658 +function automatorwp_user_has_access_to_trigger( $trigger = null, $user_id = 0, $event = array(), $trigger_options = array(), $automation = null ) {
659 +
660 + // Check if trigger is correct
661 + if( ! is_object( $trigger ) ) {
662 + return false;
663 + }
664 +
665 + // Check the user ID
666 + if( $user_id === 0 ) {
667 + return false;
668 + }
669 +
670 + // Check if automation is correct
671 + if( $automation === null ) {
672 + $automation = automatorwp_get_trigger_automation( $trigger->id );
673 +
674 + if( ! is_object( $automation ) ) {
675 + return false;
676 + }
677 + }
678 +
679 + $has_access = true;
680 +
681 + // Bail if automation is not active
682 + if( $automation->status !== 'active' ) {
683 + $has_access = false;
684 + }
685 +
686 + // Bail if is a future automation
687 + if( $has_access && automatorwp_is_automation_scheduled( $automation ) ) {
688 + $has_access = false;
689 + }
690 +
691 + // Bail if expired automation
692 + if( $has_access && automatorwp_is_automation_expired( $automation ) ) {
693 + $has_access = false;
694 + }
695 +
696 + // Check if user exceeded completion times
697 + $times_per_user = absint( $automation->times_per_user );
698 +
699 + if( $has_access && $times_per_user > 0 ) {
700 + $user_completion_times = automatorwp_get_user_completion_times( $automation->id, $user_id, 'automation' );
701 +
702 + if( $user_completion_times >= $times_per_user ) {
703 + $has_access = false;
704 + }
705 + }
706 +
707 + // Check if exceeded automation completion times
708 + $times = absint( $automation->times );
709 +
710 + if( $has_access && $times > 0 ) {
711 + $completion_times = automatorwp_get_object_completion_times( $automation->id, 'automation' );
712 +
713 + if( $completion_times >= $times ) {
714 + $has_access = false;
715 + }
716 + }
717 +
718 + // Check if automation is sequential
719 + if( $has_access && $automation->sequential ) {
720 +
721 + $automation_triggers = automatorwp_get_automation_triggers( $automation->id );
722 +
723 + // Loop all automation triggers to check if all previous triggers has been completed
724 + foreach( $automation_triggers as $automation_trigger ) {
725 +
726 + // If both triggers has the same position, then we have reached our current trigger
727 + if( $automation_trigger->position === $trigger->position ) {
728 + break;
729 + }
730 +
731 + // If user has not completed a previous trigger, set access to false
732 + if( ! automatorwp_has_user_completed_trigger( $automation_trigger->id, $user_id ) ) {
733 + $has_access = false;
734 + break;
735 + }
736 +
737 + }
738 +
739 + }
740 +
741 + /**
742 + * Filter to override the has access check.
743 + * This filter is to check the automation configuration.
744 + * Triggers should use the 'automatorwp_user_deserves_trigger' filter instead.
745 + *
746 + * @since 1.0.0
747 + *
748 + * @param bool $has_access True if user has access, false otherwise
749 + * @param stdClass $trigger The trigger object
750 + * @param int $user_id The user ID
751 + * @param array $event Event information
752 + * @param array $trigger_options The trigger's stored options
753 + * @param stdClass $automation The trigger's automation object
754 + *
755 + * @return bool True if user has access, false otherwise
756 + */
757 + return apply_filters( 'automatorwp_user_has_access_to_trigger', $has_access, $trigger, $user_id, $event, $trigger_options, $automation );
758 +
759 +}
760 +
761 +/**
762 + * Check if user deserves trigger
763 + *
764 + * @since 1.0.0
765 + *
766 + * @param stdClass $trigger The trigger object
767 + * @param int $user_id The user ID
768 + * @param array $event Event information
769 + * @param array $trigger_options The trigger's stored options
770 + * @param stdClass $automation The trigger's automation object
771 + *
772 + * @return bool True if user deserves trigger, false otherwise
773 + */
774 +function automatorwp_user_deserves_trigger( $trigger = null, $user_id = 0, $event = array(), $trigger_options = array(), $automation = null ) {
775 +
776 + // Check if trigger is correct
777 + if( ! is_object( $trigger ) ) {
778 + return false;
779 + }
780 +
781 + // Check the user ID
782 + if( $user_id === 0 ) {
783 + return false;
784 + }
785 +
786 + // Check if automation is correct
787 + if( $automation === null ) {
788 + $automation = automatorwp_get_trigger_automation( $trigger->id );
789 +
790 + if( ! is_object( $automation ) ) {
791 + return false;
792 + }
793 + }
794 +
795 + if( automatorwp_has_user_completed_trigger( $trigger->id, $user_id ) ) {
796 +
797 + $automation_triggers = automatorwp_get_automation_triggers( $automation->id );
798 +
799 + // Only pass this check if automation has more than 1 trigger
800 + if( count( $automation_triggers ) > 1 ) {
801 + return false;
802 + }
803 + }
804 +
805 + $deserves_trigger = true;
806 +
807 + /**
808 + * Filter to override the user deserves trigger check.
809 + * This filter is to check the trigger configuration.
810 + * Triggers should use this filter.
811 + *
812 + * @since 1.0.0
813 + *
814 + * @param bool $deserves_trigger True if user deserves trigger, false otherwise
815 + * @param stdClass $trigger The trigger object
816 + * @param int $user_id The user ID
817 + * @param array $event Event information
818 + * @param array $trigger_options The trigger's stored options
819 + * @param stdClass $automation The trigger's automation object
820 + *
821 + * @return bool True if user deserves trigger, false otherwise
822 + */
823 + return apply_filters( 'automatorwp_user_deserves_trigger', $deserves_trigger, $trigger, $user_id, $event, $trigger_options, $automation );
824 +
825 +}
826 +
827 +/**
828 + * Check if user deserves trigger filters
829 + *
830 + * @since 1.0.0
831 + *
832 + * @param stdClass $trigger The trigger object
833 + * @param int $user_id The user ID
834 + * @param array $event Event information
835 + * @param array $trigger_options The trigger's stored options
836 + * @param stdClass $automation The trigger's automation object
837 + *
838 + * @return bool True if user deserves trigger, false otherwise
839 + */
840 +function automatorwp_user_deserves_trigger_filters( $trigger = null, $user_id = 0, $event = array(), $trigger_options = array(), $automation = null ) {
841 +
842 + global $automatorwp_completed_trigger_filters;
843 +
844 + // Check if trigger is correct
845 + if( ! is_object( $trigger ) ) {
846 + return false;
847 + }
848 +
849 + // Check the user ID
850 + if( $user_id === 0 ) {
851 + return false;
852 + }
853 +
854 + // Check if automation is correct
855 + if( $automation === null ) {
856 + $automation = automatorwp_get_trigger_automation( $trigger->id );
857 +
858 + if( ! is_object( $automation ) ) {
859 + return false;
860 + }
861 + }
862 +
863 + if( automatorwp_has_user_completed_trigger( $trigger->id, $user_id ) ) {
864 + $automation_triggers = automatorwp_get_automation_triggers( $automation->id );
865 +
866 + // Only pass this check if automation has more than 1 trigger
867 + if( count( $automation_triggers ) > 1 ) {
868 + return false;
869 + }
870 + }
871 +
872 + $deserves_trigger_filters = true;
873 +
874 + // Bail if is a filter
875 + if( $trigger->type === 'filter' ) {
876 + return $deserves_trigger_filters;
877 + }
878 +
879 + // Initialize completed filters
880 + $automatorwp_completed_trigger_filters = array();
881 +
882 + $filters = automatorwp_get_trigger_filters( $trigger );
883 +
884 + foreach( $filters as $i => $filter ) {
885 +
886 + $deserves_filter = true;
887 +
888 + // Get the trigger stored options
889 + $filter_options = automatorwp_get_filter_stored_options( $filter->id, 'trigger' );
890 +
891 + foreach( $filter_options as $option => $value ) {
892 + // Replace all tags by their replacements
893 + $filter_options[$option] = automatorwp_parse_automation_tags( $automation->id, $user_id, $value );
894 + }
895 +
896 + /**
897 + * Filter to override the user deserves filter check.
898 + * This filter is to check the filter configuration.
899 + * Filters should use this filter.
900 + *
901 + * @since 1.0.0
902 + *
903 + * @param bool $deserves_filter True if user deserves filter, false otherwise
904 + * @param stdClass $filter The filter object
905 + * @param int $user_id The user ID
906 + * @param array $event Event information
907 + * @param array $filter_options The filter's stored options
908 + * @param stdClass $automation The filter's automation object
909 + *
910 + * @return bool True if user deserves filter, false otherwise
911 + */
912 + $deserves_filter = apply_filters( 'automatorwp_user_deserves_trigger_filter', $deserves_filter, $filter, $user_id, $event, $filter_options, $automation );
913 +
914 + if( $i === 0 ) {
915 + // On first filter there is no need to apply the operator
916 + $deserves_trigger_filters = $deserves_filter;
917 + } else {
918 + // Apply the operator
919 + if( $filter_options['operator'] === 'and' ) {
920 + $deserves_trigger_filters = $deserves_trigger_filters && $deserves_filter;
921 + } else {
922 + $deserves_trigger_filters = $deserves_trigger_filters || $deserves_filter;
923 + }
924 + }
925 +
926 + // Store completed filters
927 + if( $deserves_filter ) {
928 + $automatorwp_completed_trigger_filters[] = $filter;
929 + }
930 +
931 + // Break this loop if the trigger filters are not passed
932 + if( ! $deserves_trigger_filters ) {
933 +
934 + // For OR operators, prevent to bail until check all of them
935 + if( $i < count( $filters ) && $filter_options['operator'] === 'or' ) {
936 + continue;
937 + }
938 +
939 + // Register why user has not completed this filter
940 + $log_meta = array(
941 + 'item_type' => 'trigger'
942 + );
943 +
944 + /**
945 + * Filter to add custom log meta to meet that user has completed this trigger
946 + *
947 + * @since 1.0.0
948 + *
949 + * @param array $log_meta Log meta data
950 + * @param stdClass $filter The filter object
951 + * @param int $user_id The user ID
952 + * @param array $event Event information
953 + * @param array $filter_options The filter's stored options
954 + * @param stdClass $automation The filter's automation object
955 + *
956 + * @return array
957 + */
958 + $log_meta = apply_filters( 'automatorwp_user_not_passed_filter_log_meta', $log_meta, $filter, $user_id, $event, $filter_options, $automation );
959 +
960 + // Insert a new log entry to register why user not passed the trigger filter
961 + automatorwp_insert_log( array(
962 + 'title' => automatorwp_parse_automation_item_log_label( $filter, 'trigger', 'view' ),
963 + 'type' => 'filter',
964 + 'object_id' => $filter->id,
965 + 'user_id' => $user_id,
966 + 'post_id' => ( isset( $event['post_id'] ) ? $event['post_id'] : 0 ),
967 + 'date' => automatorwp_get_event_log_date(),
968 + ), $log_meta );
969 +
970 + // Force to clear the cache for this filter
971 + automatorwp_clear_user_last_completion_cache( $filter, $user_id, 'filter' );
972 +
973 + break;
974 + }
975 +
976 + }
977 +
978 + /**
979 + * Filter to override the user deserves trigger filters check.
980 + *
981 + * @since 1.0.0
982 + *
983 + * @param bool $deserves_trigger_filters True if user deserves the trigger filters, false otherwise
984 + * @param stdClass $trigger The trigger object
985 + * @param int $user_id The user ID
986 + * @param array $event Event information
987 + * @param array $trigger_options The trigger's stored options
988 + * @param stdClass $automation The trigger's automation object
989 + *
990 + * @return bool True if user deserves trigger, false otherwise
991 + */
992 + return apply_filters( 'automatorwp_user_deserves_trigger_filters', $deserves_trigger_filters, $trigger, $user_id, $event, $trigger_options, $automation );
993 +
994 +}
995 +
996 +/**
997 + * Registers the trigger completion
998 + *
999 + * @since 1.0.0
1000 + *
1001 + * @param stdClass $trigger The trigger object
1002 + * @param int $user_id The user ID
1003 + * @param array $event Event information
1004 + * @param array $trigger_options The trigger's stored options
1005 + * @param stdClass $automation The trigger's automation object
1006 + *
1007 + * @return bool
1008 + */
1009 +function automatorwp_user_completed_trigger( $trigger = null, $user_id = 0, $event = array(), $trigger_options = array(), $automation = null ) {
1010 +
1011 + global $automatorwp_completed_trigger_filters;
1012 +
1013 + if( ! is_array( $automatorwp_completed_trigger_filters ) ) {
1014 + $automatorwp_completed_trigger_filters = array();
1015 + }
1016 +
1017 + // Check if trigger is correct
1018 + if( ! is_object( $trigger ) ) {
1019 + return false;
1020 + }
1021 +
1022 + // Check the user ID
1023 + if( $user_id === 0 ) {
1024 + return false;
1025 + }
1026 +
1027 + // Check if automation is correct
1028 + if( $automation === null ) {
1029 + $automation = automatorwp_get_trigger_automation( $trigger->id );
1030 +
1031 + if( ! is_object( $automation ) ) {
1032 + return false;
1033 + }
1034 + }
1035 +
1036 + // Get the trigger completion times
1037 + $completion_times = automatorwp_get_user_trigger_completion_times( $trigger->id, $user_id );
1038 +
1039 + $log_meta = array(
1040 + 'times' => ( $completion_times + 1 )
1041 + );
1042 +
1043 + if( isset( $event['comment_id'] ) ) {
1044 + $log_meta['comment_id'] = $event['comment_id'];
1045 + }
1046 +
1047 + /**
1048 + * Filter to add custom log meta to meet that user has completed this trigger
1049 + *
1050 + * @since 1.0.0
1051 + *
1052 + * @param array $log_meta Log meta data
1053 + * @param stdClass $trigger The trigger object
1054 + * @param int $user_id The user ID
1055 + * @param array $event Event information
1056 + * @param array $trigger_options The trigger's stored options
1057 + * @param stdClass $automation The trigger's automation object
1058 + *
1059 + * @return array
1060 + */
1061 + $log_meta = apply_filters( 'automatorwp_user_completed_trigger_log_meta', $log_meta, $trigger, $user_id, $event, $trigger_options, $automation );
1062 +
1063 + // Insert a new log entry to register the trigger completion
1064 + automatorwp_insert_log( array(
1065 + 'title' => automatorwp_parse_automation_item_log_label( $trigger, 'trigger', 'view' ),
1066 + 'type' => 'trigger',
1067 + 'object_id' => $trigger->id,
1068 + 'user_id' => $user_id,
1069 + 'post_id' => ( isset( $event['post_id'] ) ? $event['post_id'] : 0 ),
1070 + 'date' => automatorwp_get_event_log_date(),
1071 + ), $log_meta );
1072 +
1073 + /**
1074 + * Available action to hook on a trigger completion
1075 + *
1076 + * @since 1.0.0
1077 + *
1078 + * @param stdClass $trigger The trigger object
1079 + * @param int $user_id The user ID
1080 + * @param array $event Event information
1081 + * @param array $trigger_options The trigger's stored options
1082 + * @param stdClass $automation The trigger's automation object
1083 + */
1084 + do_action( 'automatorwp_user_completed_trigger', $trigger, $user_id, $event, $trigger_options, $automation );
1085 +
1086 + if( $trigger->type !== 'filter' ) {
1087 +
1088 + // Mark all completed filters
1089 + foreach( $automatorwp_completed_trigger_filters as $filter ) {
1090 +
1091 + // Get the trigger stored options
1092 + $filter_options = automatorwp_get_filter_stored_options( $filter->id, 'trigger' );
1093 +
1094 + // Registers the passed filter (as a trigger entry)
1095 + automatorwp_user_completed_trigger( $filter, $user_id, $event, $filter_options, $automation );
1096 +
1097 + }
1098 +
1099 + // Check if user has completed the automation
1100 + automatorwp_maybe_user_completed_automation( $automation, $user_id, $event );
1101 +
1102 + }
1103 +
1104 + return true;
1105 +
1106 +}
1107 +
1108 +/**
1109 + * Registers the automation completion
1110 + *
1111 + * @since 1.0.0
1112 + *
1113 + * @param stdClass $automation The automation object
1114 + * @param int $user_id The user ID
1115 + * @param array $event Event information
1116 + *
1117 + * @return bool
1118 + */
1119 +function automatorwp_maybe_user_completed_automation( $automation = null, $user_id = 0, $event = array() ) {
1120 +
1121 + // Check if automation is correct
1122 + if( ! is_object( $automation ) ) {
1123 + return false;
1124 + }
1125 +
1126 + // Check the user ID
1127 + if( $user_id === 0 ) {
1128 + return false;
1129 + }
1130 +
1131 + $triggers = automatorwp_get_automation_triggers( $automation->id );
1132 +
1133 + $all_completed = true;
1134 +
1135 + // Check if user has completed all automation trigger
1136 + foreach( $triggers as $trigger ) {
1137 +
1138 + if( $trigger->type === 'filter' ) {
1139 + continue;
1140 + }
1141 +
1142 + // If user has not completed this trigger the number of times required then break to finish this function
1143 + if( ! automatorwp_has_user_completed_trigger( $trigger->id, $user_id ) ) {
1144 + $all_completed = false;
1145 + break;
1146 + }
1147 +
1148 + }
1149 +
1150 + // Bail if user has not completed all automation triggers
1151 + if( ! $all_completed ) {
1152 + return false;
1153 + }
1154 +
1155 + // Mark trigger as completed
1156 + return automatorwp_user_completed_automation( $automation, $user_id, $event );
1157 +
1158 +}
1159 +
1160 +/**
1161 + * Registers the automation completion
1162 + *
1163 + * @since 1.0.0
1164 + *
1165 + * @param stdClass $automation The automation object
1166 + * @param int $user_id The user ID
1167 + * @param array $event Event information
1168 + *
1169 + * @return bool
1170 + */
1171 +function automatorwp_user_completed_automation( $automation = null, $user_id = 0, $event = array() ) {
1172 +
1173 + // Check if automation is correct
1174 + if( ! is_object( $automation ) ) {
1175 + return false;
1176 + }
1177 +
1178 + // Check the user ID
1179 + if( $user_id === 0 ) {
1180 + return false;
1181 + }
1182 +
1183 + // Execute all automation actions
1184 + automatorwp_execute_all_automation_actions( $automation, $user_id, $event );
1185 +
1186 + /**
1187 + * Available filter to determine if user has completed an automation
1188 + *
1189 + * @since 1.2.4
1190 + *
1191 + * @param bool $complete Determines if the automation should be marked as completed, by default true
1192 + * @param stdClass $automation The automation object
1193 + * @param int $user_id The user ID
1194 + * @param array $event Event information
1195 + *
1196 + * @return bool
1197 + */
1198 + $complete = apply_filters( 'automatorwp_can_user_complete_automation', true, $automation, $user_id, $event );
1199 +
1200 + if( ! $complete ) {
1201 + return false;
1202 + }
1203 +
1204 + // Insert a new log entry to register the automation completion
1205 + automatorwp_insert_log( array(
1206 + 'title' => $automation->title,
1207 + 'type' => 'automation',
1208 + 'object_id' => $automation->id,
1209 + 'user_id' => $user_id,
1210 + 'post_id' => ( isset( $event['post_id'] ) ? $event['post_id'] : 0 ),
1211 + 'date' => automatorwp_get_event_log_date(),
1212 + ) );
1213 +
1214 + // Increment the completions
1215 + $completions = absint( automatorwp_get_automation_meta( $automation->id, 'completions', true ) );
1216 + automatorwp_update_automation_meta( $automation->id, 'completions', $completions + 1 );
1217 +
1218 + /**
1219 + * Available action to hook on an automation completion
1220 + *
1221 + * @since 1.0.0
1222 + *
1223 + * @param stdClass $automation The automation object
1224 + * @param int $user_id The user ID
1225 + * @param array $event Event information
1226 + */
1227 + do_action( 'automatorwp_user_completed_automation', $automation, $user_id, $event );
1228 +
1229 + return true;
1230 +
1231 +}
1232 +
1233 +/**
1234 + * Execute all automation actions
1235 + *
1236 + * @since 1.0.0
1237 + *
1238 + * @param stdClass $automation The automation object
1239 + * @param int $user_id The user ID
1240 + * @param array $event Event information
1241 + *
1242 + * @return bool
1243 + */
1244 +function automatorwp_execute_all_automation_actions( $automation = null, $user_id = 0, $event = array() ) {
1245 +
1246 + // Check if automation is correct
1247 + if( ! is_object( $automation ) ) {
1248 + return false;
1249 + }
1250 +
1251 + // Check the user ID
1252 + if( $user_id === 0 ) {
1253 + return false;
1254 + }
1255 +
1256 + // Get all automation action to execute them
1257 + $actions = automatorwp_get_automation_actions( $automation->id );
1258 +
1259 + foreach( $actions as $action ) {
1260 + automatorwp_execute_action( $action, $user_id, $event );
1261 + }
1262 +
1263 + return true;
1264 +
1265 +}
1266 +
1267 +/**
1268 + * Execute an action
1269 + *
1270 + * @since 1.0.0
1271 + *
1272 + * @param stdClass $action The action object
1273 + * @param int $user_id The user ID
1274 + * @param array $event Event information
1275 + *
1276 + * @return bool
1277 + */
1278 +function automatorwp_execute_action( $action = null, $user_id = 0, $event = array() ) {
1279 +
1280 + // Check if action is correct
1281 + if( ! is_object( $action ) ) {
1282 + return false;
1283 + }
1284 +
1285 + // Check the user ID
1286 + if( $user_id === 0 ) {
1287 + return false;
1288 + }
1289 +
1290 + // Setup the automation assigned to this action
1291 + $automation = automatorwp_get_automation_object( $action->automation_id );
1292 +
1293 + // Check if automation is correct
1294 + if( ! is_object( $automation ) ) {
1295 + return false;
1296 + }
1297 +
1298 + // Get all action options to parse all replacements
1299 + $action_options = automatorwp_get_action_stored_options( $action->id );
1300 +
1301 + foreach( $action_options as $option => $value ) {
1302 + // Replace all tags by their replacements
1303 + $action_options[$option] = automatorwp_parse_automation_tags( $automation->id, $user_id, $value );
1304 + }
1305 +
1306 + // Bail if action can not be executed
1307 + if( ! automatorwp_can_execute_action( $action, $user_id, $event, $action_options, $automation ) ) {
1308 + return false;
1309 + }
1310 +
1311 + // Check if user deserves the action filters
1312 + if( ! automatorwp_user_deserves_action_filters( $action, $user_id, $event, $action_options, $automation ) ) {
1313 + return false;
1314 + }
1315 +
1316 + /**
1317 + * Available action to hook for execute an action function
1318 + *
1319 + * @since 1.0.0
1320 + *
1321 + * @param stdClass $action The action object
1322 + * @param int $user_id The user ID
1323 + * @param array $event Event information
1324 + * @param array $action_options The action's stored options (with tags already passed)
1325 + * @param stdClass $automation The action's automation object
1326 + */
1327 + do_action( 'automatorwp_execute_action', $action, $user_id, $event, $action_options, $automation );
1328 + // Run hook based on action type
1329 + do_action( "automatorwp_execute_action_{$action->type}", $action, $user_id, $event, $action_options, $automation );
1330 +
1331 + $log_meta = array();
1332 +
1333 + /**
1334 + * Filter to add custom log meta to meet that and action has been executed to a specific user
1335 + *
1336 + * @since 1.0.0
1337 + *
1338 + * @param array $log_meta Log meta data
1339 + * @param stdClass $action The action object
1340 + * @param int $user_id The user ID
1341 + * @param array $action_options The action's stored options (with tags already passed)
1342 + * @param stdClass $automation The action's automation object
1343 + *
1344 + * @return array
1345 + */
1346 + $log_meta = apply_filters( 'automatorwp_user_completed_action_log_meta', $log_meta, $action, $user_id, $action_options, $automation );
1347 +
1348 + /**
1349 + * Filter to assign a custom post ID to this action
1350 + *
1351 + * @since 1.0.0
1352 + *
1353 + * @param int $post_id The post ID, by default 0
1354 + * @param stdClass $action The action object
1355 + * @param int $user_id The user ID
1356 + * @param array $event Event information
1357 + * @param array $action_options The action's stored options (with tags already passed)
1358 + * @param stdClass $automation The action's automation object
1359 + *
1360 + * @return int
1361 + */
1362 + $post_id = apply_filters( 'automatorwp_user_completed_action_post_id', 0, $action, $user_id, $event, $action_options, $automation );
1363 +
1364 + // Parse the log label (including the automation tags)
1365 + $log_title = automatorwp_parse_automation_item_log_label( $action, 'action', 'view' );
1366 + $log_title = automatorwp_parse_automation_tags( $automation->id, $user_id, $log_title );
1367 +
1368 + // Insert a new log entry to register the trigger completion
1369 + automatorwp_insert_log( array(
1370 + 'title' => $log_title,
1371 + 'type' => 'action',
1372 + 'object_id' => $action->id,
1373 + 'user_id' => $user_id,
1374 + 'post_id' => $post_id,
1375 + 'date' => automatorwp_get_event_log_date(),
1376 + ), $log_meta );
1377 +
1378 + /**
1379 + * Available action to hook on an action completion
1380 + *
1381 + * @since 1.0.0
1382 + *
1383 + * @param stdClass $action The action object
1384 + * @param int $user_id The user ID
1385 + * @param array $event Event information
1386 + * @param array $action_options The action's stored options (with tags already passed)
1387 + * @param stdClass $automation The action's automation object
1388 + */
1389 + do_action( 'automatorwp_user_completed_action', $action, $user_id, $event, $action_options, $automation );
1390 +
1391 + return true;
1392 +
1393 +}
1394 +
1395 +/**
1396 + * Checks if an action should be executed or not
1397 + *
1398 + * @since 1.2.4
1399 + *
1400 + * @param stdClass $action The action object
1401 + * @param int $user_id The user ID
1402 + * @param array $event Event information
1403 + * @param array $action_options The action's stored options (with tags already passed)
1404 + * @param stdClass $automation The action's automation object
1405 + *
1406 + * @return bool
1407 + */
1408 +function automatorwp_can_execute_action( $action = null, $user_id = 0, $event = array(), $action_options = array(), $automation = null ) {
1409 +
1410 + // Check if action is correct
1411 + if( ! is_object( $action ) ) {
1412 + return false;
1413 + }
1414 +
1415 + // Check the user ID
1416 + if( $user_id === 0 ) {
1417 + return false;
1418 + }
1419 +
1420 + // Check if automation is correct
1421 + if( $automation === null ) {
1422 + $automation = automatorwp_get_action_automation( $action->id );
1423 +
1424 + if( ! is_object( $automation ) ) {
1425 + return false;
1426 + }
1427 + }
1428 +
1429 + $execute = true;
1430 +
1431 + /**
1432 + * Available filter to determine if an action should be executed or not
1433 + *
1434 + * @since 1.2.4
1435 + *
1436 + * @param bool $execute Determines if the action should be executed, by default true
1437 + * @param stdClass $action The action object
1438 + * @param int $user_id The user ID
1439 + * @param array $event Event information
1440 + * @param array $action_options The action's stored options (with tags already passed)
1441 + * @param stdClass $automation The action's automation object
1442 + *
1443 + * @return bool
1444 + */
1445 + return apply_filters( 'automatorwp_can_execute_action', $execute, $action, $user_id, $event, $action_options, $automation );
1446 +
1447 +}
1448 +
1449 +/**
1450 + * Check if user deserves action filters
1451 + *
1452 + * @since 1.0.0
1453 + *
1454 + * @param stdClass $action The action object
1455 + * @param int $user_id The user ID
1456 + * @param array $event Event information
1457 + * @param array $action_options The action's stored options
1458 + * @param stdClass $automation The action's automation object
1459 + *
1460 + * @return bool True if user deserves action, false otherwise
1461 + */
1462 +function automatorwp_user_deserves_action_filters( $action = null, $user_id = 0, $event = array(), $action_options = array(), $automation = null ) {
1463 +
1464 + global $automatorwp_completed_action_filters, $automatorwp_last_action_passed_all_filters;
1465 +
1466 + // Check if action is correct
1467 + if( ! is_object( $action ) ) {
1468 + return false;
1469 + }
1470 +
1471 + // Check the user ID
1472 + if( $user_id === 0 ) {
1473 + return false;
1474 + }
1475 +
1476 + // Check if automation is correct
1477 + if( $automation === null ) {
1478 + $automation = automatorwp_get_action_automation( $action->id );
1479 +
1480 + if( ! is_object( $automation ) ) {
1481 + return false;
1482 + }
1483 + }
1484 +
1485 + $deserves_action_filters = true;
1486 +
1487 + // Bail if is a filter
1488 + if( $action->type === 'filter' ) {
1489 +
1490 + if( ! is_array( $automatorwp_completed_action_filters ) ) {
1491 + return false;
1492 + }
1493 +
1494 + if( ! $automatorwp_last_action_passed_all_filters ) {
1495 + return false;
1496 + }
1497 +
1498 + $found = false;
1499 +
1500 + foreach ( $automatorwp_completed_action_filters as $filter ) {
1501 + if( absint( $filter->id ) === absint( $action->id ) ) {
1502 + $found = true;
1503 + }
1504 + }
1505 +
1506 + // If filter has not been passed, prevent its execution
1507 + if( ! $found ) {
1508 + return false;
1509 + }
1510 +
1511 + return $deserves_action_filters;
1512 + }
1513 +
1514 + // Initialize completed actions
1515 + $automatorwp_completed_action_filters = array();
1516 + $automatorwp_last_action_passed_all_filters = false;
1517 +
1518 + $filters = automatorwp_get_action_filters( $action );
1519 +
1520 + foreach( $filters as $i => $filter ) {
1521 +
1522 + $deserves_filter = true;
1523 +
1524 + // Get the action stored options
1525 + $filter_options = automatorwp_get_filter_stored_options( $filter->id, 'action' );
1526 +
1527 + foreach( $filter_options as $option => $value ) {
1528 + // Replace all tags by their replacements
1529 + $filter_options[$option] = automatorwp_parse_automation_tags( $automation->id, $user_id, $value );
1530 + }
1531 +
1532 + /**
1533 + * Filter to override the user deserves filter check.
1534 + * This filter is to check the filter configuration.
1535 + * Filters should use this filter.
1536 + *
1537 + * @since 1.0.0
1538 + *
1539 + * @param bool $deserves_filter True if user deserves filter, false otherwise
1540 + * @param stdClass $filter The filter object
1541 + * @param int $user_id The user ID
1542 + * @param array $event Event information
1543 + * @param array $filter_options The filter's stored options
1544 + * @param stdClass $automation The filter's automation object
1545 + *
1546 + * @return bool True if user deserves filter, false otherwise
1547 + */
1548 + $deserves_filter = apply_filters( 'automatorwp_user_deserves_action_filter', $deserves_filter, $filter, $user_id, $event, $filter_options, $automation );
1549 +
1550 + if( $i === 0 ) {
1551 + // On first filter there is no need to apply the operator
1552 + $deserves_action_filters = $deserves_filter;
1553 + } else {
1554 + // Apply the operator
1555 + if( $filter_options['operator'] === 'and' ) {
1556 + $deserves_action_filters = $deserves_action_filters && $deserves_filter;
1557 + } else {
1558 + $deserves_action_filters = $deserves_action_filters || $deserves_filter;
1559 + }
1560 + }
1561 +
1562 + // Store completed filters
1563 + if( $deserves_filter ) {
1564 + $automatorwp_completed_action_filters[] = $filter;
1565 + }
1566 +
1567 + // Break this loop if the action filters are not passed
1568 + if( ! $deserves_action_filters ) {
1569 +
1570 + // For OR operators, prevent to bail until check all of them
1571 + if( $i < count( $filters ) && $filter_options['operator'] === 'or' ) {
1572 + continue;
1573 + }
1574 +
1575 + // Register why user has not completed this filter
1576 + $log_meta = array(
1577 + 'item_type' => 'action'
1578 + );
1579 +
1580 + /**
1581 + * Filter to add custom log meta to meet that user has completed this action
1582 + *
1583 + * @since 1.0.0
1584 + *
1585 + * @param array $log_meta Log meta data
1586 + * @param stdClass $filter The filter object
1587 + * @param int $user_id The user ID
1588 + * @param array $event Event information
1589 + * @param array $filter_options The filter's stored options
1590 + * @param stdClass $automation The filter's automation object
1591 + *
1592 + * @return array
1593 + */
1594 + $log_meta = apply_filters( 'automatorwp_user_not_passed_filter_log_meta', $log_meta, $filter, $user_id, $event, $filter_options, $automation );
1595 +
1596 + // Parse the log label (including the automation tags)
1597 + $log_title = automatorwp_parse_automation_item_log_label( $filter, 'action', 'view' );
1598 + $log_title = automatorwp_parse_automation_tags( $automation->id, $user_id, $log_title );
1599 +
1600 + // Insert a new log entry to register why user not passed the action filter
1601 + automatorwp_insert_log( array(
1602 + 'title' => $log_title,
1603 + 'type' => 'filter',
1604 + 'object_id' => $filter->id,
1605 + 'user_id' => $user_id,
1606 + 'post_id' => ( isset( $event['post_id'] ) ? $event['post_id'] : 0 ),
1607 + 'date' => automatorwp_get_event_log_date(),
1608 + ), $log_meta );
1609 +
1610 + // Force to clear the cache for this filter
1611 + automatorwp_clear_user_last_completion_cache( $filter, $user_id, 'filter' );
1612 +
1613 + break;
1614 + }
1615 +
1616 + }
1617 +
1618 + /**
1619 + * Filter to override the user deserves action filters check.
1620 + *
1621 + * @since 1.0.0
1622 + *
1623 + * @param bool $deserves_action_filters True if user deserves the action filters, false otherwise
1624 + * @param stdClass $action The action object
1625 + * @param int $user_id The user ID
1626 + * @param array $event Event information
1627 + * @param array $action_options The action's stored options
1628 + * @param stdClass $automation The action's automation object
1629 + *
1630 + * @return bool True if user deserves action, false otherwise
1631 + */
1632 + $deserves_action_filters = apply_filters( 'automatorwp_user_deserves_action_filters', $deserves_action_filters, $action, $user_id, $event, $action_options, $automation );
1633 +
1634 + // Used to meet if should register the rest of filter actions
1635 + $automatorwp_last_action_passed_all_filters = $deserves_action_filters;
1636 +
1637 + return $deserves_action_filters;
1638 +}
1639 +
1640 +// -------------------------------------------
1641 +// Automation execution
1642 +// -------------------------------------------
1643 +
1644 +/**
1645 + * Run an automation
1646 + *
1647 + * @since 2.2.2
1648 + *
1649 + * @param int $automation_id The automation ID
1650 + *
1651 + * @return bool
1652 + */
1653 +function automatorwp_run_automation( $automation_id ) {
1654 +
1655 + global $automatorwp_run_automation_error;
1656 +
1657 + // Initialize error
1658 + $automatorwp_run_automation_error = '';
1659 +
1660 + // Sanitization
1661 + $automation_id = absint( $automation_id );
1662 +
1663 + // Bail if automation id not provided
1664 + if( $automation_id === 0 ) {
1665 + $automatorwp_run_automation_error = __( 'Invalid automation ID.', 'automatorwp' );
1666 + return false;
1667 + }
1668 +
1669 + // Get the automation
1670 + $automation = automatorwp_get_automation_object( $automation_id );
1671 +
1672 + // Bail if automation not found
1673 + if( ! $automation ) {
1674 + $automatorwp_run_automation_error = sprintf( __( 'Automation with ID %d not found.', 'automatorwp' ), $automation_id );
1675 + return false;
1676 + }
1677 +
1678 + // Only loop automations can be run here
1679 + if( ! in_array( $automation->type, automatorwp_get_automation_loop_types() ) ) {
1680 + $automatorwp_run_automation_error = __( 'Invalid automation type.', 'automatorwp' );
1681 + return false;
1682 + }
1683 +
1684 + // Check if exceeded automation completion times
1685 + $times = absint( $automation->times );
1686 +
1687 + if( $times > 0 ) {
1688 + $completion_times = automatorwp_get_object_completion_times( $automation->id, 'automation' );
1689 +
1690 + if( $completion_times >= $times ) {
1691 + $automatorwp_run_automation_error = __( 'Automation has been run the number of times allowed. Change the "Total times" setting for this automation to allow run it again.', 'automatorwp' );
1692 + return false;
1693 + }
1694 + }
1695 +
1696 + $result = apply_filters( 'automatorwp_run_automation_result', false, $automation );
1697 +
1698 + // Bail if automation has not run correctly
1699 + if( ! $result ) {
1700 + return false;
1701 + }
1702 +
1703 + // Check if run finished
1704 + if( automatorwp_maybe_run_automation_finished( $automation ) ) {
1705 + // Call the automation run finished function
1706 + automatorwp_run_automation_finished( $automation );
1707 + } else {
1708 + // Increase loop
1709 + $loop = absint( automatorwp_get_automation_meta( $automation->id, 'current_loop', true ) );
1710 + automatorwp_update_automation_meta( $automation->id, 'current_loop', $loop + 1 );
1711 +
1712 + // Check if is a manual run
1713 + $manual_run = (bool) automatorwp_get_automation_meta( $automation->id, 'manual_run', true );
1714 +
1715 + if( ! $manual_run ) {
1716 +
1717 + // Get the delay amount and seconds from the automation
1718 + $delay_amount = absint( automatorwp_get_automation_meta( $automation->id, 'delay_amount', true ) );
1719 + $delay_seconds = absint( automatorwp_get_automation_meta( $automation->id, 'delay_seconds', true ) );
1720 +
1721 + $delay = $delay_amount * $delay_seconds;
1722 +
1723 + if( $delay <= 0 ) {
1724 + $delay = 60;
1725 + }
1726 +
1727 + /**
1728 + * Available filter to override the delay between runs
1729 + *
1730 + * @since 1.0.0
1731 + *
1732 + * @param int $delay By default, 60 (1 minute)
1733 + * @param stdClass $automation The automation object
1734 + *
1735 + * @return int
1736 + */
1737 + $delay = apply_filters( 'automatorwp_run_automation_delay_between_runs', $delay, $automation );
1738 +
1739 + // if not is a manual run, schedule this function after a delay
1740 + if( function_exists( 'as_schedule_single_action' ) ) {
1741 + as_schedule_single_action( current_time( 'timestamp' ) + $delay, 'automatorwp_continue_automation_run', array( $automation->id ) );
1742 + } else {
1743 + wp_schedule_single_event( current_time( 'timestamp' ) + $delay, 'automatorwp_continue_automation_run', array( $automation->id ) );
1744 + }
1745 + }
1746 + }
1747 +
1748 + return $result;
1749 +
1750 +}
1751 +add_action( 'automatorwp_run_automation', 'automatorwp_run_automation' );
1752 +
1753 +/**
1754 + * Continue an all users automation run (used to check if automation run has been cancelled)
1755 + * Note: This function is only called by the single action/event schedule function
1756 + *
1757 + * @since 2.2.2
1758 + *
1759 + * @param int $automation_id The automation ID
1760 + *
1761 + * @return bool
1762 + */
1763 +function automatorwp_continue_automation_run( $automation_id ) {
1764 +
1765 + global $automatorwp_run_automation_error;
1766 +
1767 + // Initialize error
1768 + $automatorwp_run_automation_error = '';
1769 +
1770 + // Sanitization
1771 + $automation_id = absint( $automation_id );
1772 +
1773 + // Bail if automation id not provided
1774 + if( $automation_id === 0 ) {
1775 + $automatorwp_run_automation_error = __( 'Invalid automation ID.', 'automatorwp' );
1776 + return false;
1777 + }
1778 +
1779 + // Get the automation
1780 + $automation = automatorwp_get_automation_object( $automation_id );
1781 +
1782 + // Bail if automation not found
1783 + if( ! $automation ) {
1784 + $automatorwp_run_automation_error = sprintf( __( 'Automation with ID %d not found.', 'automatorwp' ), $automation_id );
1785 + return false;
1786 + }
1787 +
1788 + if( $automation->status !== 'in-progress' ) {
1789 + $automatorwp_run_automation_error = __( 'Automation run has been cancelled.', 'automatorwp' );
1790 + return false;
1791 + }
1792 +
1793 + // Continue running the automation
1794 + automatorwp_run_automation( $automation->id );
1795 +
1796 +}
1797 +add_action( 'automatorwp_continue_automation_run', 'automatorwp_continue_automation_run' );
1798 +
1799 +/**
1800 + * Automation run started
1801 + *
1802 + * @since 2.2.2
1803 + *
1804 + * @param stdClass $automation The automation object
1805 + * @param stdClass $trigger The trigger object
1806 + * @param array $trigger_options The trigger stored option
1807 + */
1808 +function automatorwp_run_automation_started( $automation, $trigger, $trigger_options ) {
1809 +
1810 + global $automatorwp_completed_triggers;
1811 +
1812 + // Initialize completed triggers count
1813 + if( ! is_array( $automatorwp_completed_triggers ) ) {
1814 + $automatorwp_completed_triggers = array();
1815 + }
1816 +
1817 + if( ! is_object( $automation ) ) {
1818 + return;
1819 + }
1820 +
1821 + // Store the original status
1822 + automatorwp_update_automation_meta( $automation->id, 'original_status', $automation->status );
1823 +
1824 + $ct_table = ct_setup_table( 'automatorwp_automations' );
1825 +
1826 + // Update the automation status
1827 + $ct_table->db->update(
1828 + array( 'status' => 'in-progress' ),
1829 + array( 'id' => $automation->id )
1830 + );
1831 +
1832 + ct_reset_setup_table();
1833 +
1834 + // Get the trigger completion times
1835 + $completion_times = automatorwp_get_object_completion_times( $trigger->id, 'trigger' );
1836 +
1837 + $log_meta = array(
1838 + 'times' => ( $completion_times + 1 )
1839 + );
1840 +
1841 + /**
1842 + * Filter to add custom log meta to meet that user has completed this trigger
1843 + *
1844 + * @since 1.0.0
1845 + *
1846 + * @param array $log_meta Log meta data
1847 + * @param stdClass $trigger The trigger object
1848 + * @param int $user_id The user ID
1849 + * @param array $event Event information
1850 + * @param array $trigger_options The trigger's stored options
1851 + * @param stdClass $automation The trigger's automation object
1852 + *
1853 + * @return array
1854 + */
1855 + $log_meta = apply_filters( 'automatorwp_user_completed_trigger_log_meta', $log_meta, $trigger, 0, array(), $trigger_options, $automation );
1856 +
1857 + // Insert a new log entry to register the trigger completion
1858 + automatorwp_insert_log( array(
1859 + 'title' => automatorwp_parse_automation_item_log_label( $trigger, 'trigger', 'view' ),
1860 + 'type' => 'trigger',
1861 + 'object_id' => $trigger->id,
1862 + 'user_id' => 0,
1863 + 'post_id' => 0,
1864 + 'date' => automatorwp_get_event_log_date(),
1865 + ), $log_meta );
1866 +
1867 + $automatorwp_completed_triggers[] = $trigger;
1868 +
1869 +}
1870 +
1871 +/**
1872 + * Check if automation run has been finished
1873 + *
1874 + * @since 2.2.2
1875 + *
1876 + * @param stdClass $automation The automation object
1877 + *
1878 + * @return bool
1879 + */
1880 +function automatorwp_maybe_run_automation_finished( $automation ) {
1881 +
1882 + global $automatorwp_run_automation_error;
1883 +
1884 + if( ! is_object( $automation ) ) {
1885 + $automatorwp_run_automation_error = __( 'Invalid automation.', 'automatorwp' );
1886 + return false;
1887 + }
1888 +
1889 + $details = automatorwp_get_automation_run_details( $automation );
1890 +
1891 + if( ! $details ) {
1892 + $automatorwp_run_automation_error = __( 'Can not retrieve run details.', 'automatorwp' );
1893 + return false;
1894 + }
1895 +
1896 + // Check if finished
1897 + if( $details['processed'] >= $details['count'] ) {
1898 + return true;
1899 + }
1900 +
1901 + return false;
1902 +
1903 +}
1904 +
1905 +/**
1906 + * Automation run finished
1907 + *
1908 + * @since 2.2.2
1909 + *
1910 + * @param stdClass $automation The automation object
1911 + */
1912 +function automatorwp_run_automation_finished( $automation ) {
1913 +
1914 + global $automatorwp_run_automation_error;
1915 +
1916 + if( ! is_object( $automation ) ) {
1917 + $automatorwp_run_automation_error = __( 'Invalid automation.', 'automatorwp' );
1918 + return;
1919 + }
1920 +
1921 + // Restore automation status
1922 + $original_status = automatorwp_get_automation_meta( $automation->id, 'original_status', true );
1923 +
1924 + if( empty( $original_status ) ) {
1925 + $original_status = 'active';
1926 + }
1927 +
1928 + $ct_table = ct_setup_table( 'automatorwp_automations' );
1929 +
1930 + // Update the automation status
1931 + $ct_table->db->update(
1932 + array( 'status' => $original_status ),
1933 + array( 'id' => $automation->id )
1934 + );
1935 +
1936 + ct_reset_setup_table();
1937 +
1938 + // Insert a new log entry to register the automation completion
1939 + automatorwp_insert_log( array(
1940 + 'title' => $automation->title,
1941 + 'type' => 'automation',
1942 + 'object_id' => $automation->id,
1943 + 'user_id' => 0,
1944 + 'post_id' => 0,
1945 + 'date' => automatorwp_get_event_log_date(),
1946 + ) );
1947 +
1948 + // Increment the completions
1949 + $completions = absint( automatorwp_get_automation_meta( $automation->id, 'completions', true ) );
1950 + automatorwp_update_automation_meta( $automation->id, 'completions', $completions + 1 );
1951 +
1952 + // Restore loop
1953 + automatorwp_update_automation_meta( $automation->id, 'current_loop', 0 );
1954 +
1955 + // Restore manual run flag
1956 + automatorwp_update_automation_meta( $automation->id, 'manual_run', '' );
1957 +
1958 + // Get the automation maximum completion times
1959 + $times = absint( $automation->times );
1960 +
1961 + // Prevent to update the next run date if automation already reached the total times allowed
1962 + if( $times > 0 ) {
1963 + if( $completions >= $times ) {
1964 + return;
1965 + }
1966 + }
1967 +
1968 + // Update the next run date
1969 + automatorwp_update_automation_next_run_date( $automation->id );
1970 +
1971 +}
1972 +
1973 +/**
1974 + * Cancel an all users automation rum
1975 + *
1976 + * @since 2.2.2
1977 + *
1978 + * @param int $automation_id The automation ID
1979 + *
1980 + * @return bool
1981 + */
1982 +function automatorwp_cancel_automation_run( $automation_id ) {
1983 +
1984 + global $automatorwp_run_automation_error;
1985 +
1986 + // Initialize error
1987 + $automatorwp_run_automation_error = '';
1988 +
1989 + // Sanitization
1990 + $automation_id = absint( $automation_id );
1991 +
1992 + // Bail if automation id not provided
1993 + if( $automation_id === 0 ) {
1994 + $automatorwp_run_automation_error = __( 'Invalid automation ID.', 'automatorwp' );
1995 + return false;
1996 + }
1997 +
1998 + // Get the automation
1999 + $automation = automatorwp_get_automation_object( $automation_id );
2000 +
2001 + // Bail if automation not found
2002 + if( ! $automation ) {
2003 + $automatorwp_run_automation_error = sprintf( __( 'Automation with ID %d not found.', 'automatorwp' ), $automation_id );
2004 + return false;
2005 + }
2006 +
2007 + if( $automation->status !== 'in-progress' ) {
2008 + $automatorwp_run_automation_error = __( 'Can not cancel automation run because is not running.', 'automatorwp' );
2009 + return false;
2010 + }
2011 +
2012 + // Restore automation status
2013 + $original_status = automatorwp_get_automation_meta( $automation->id, 'original_status', true );
2014 +
2015 + if( empty( $original_status ) ) {
2016 + $original_status = 'active';
2017 + }
2018 +
2019 + $ct_table = ct_setup_table( 'automatorwp_automations' );
2020 +
2021 + // Update the automation status
2022 + $ct_table->db->update(
2023 + array( 'status' => $original_status ),
2024 + array( 'id' => $automation->id )
2025 + );
2026 +
2027 + ct_reset_setup_table();
2028 +
2029 + // Insert a new log entry to register the automation completion
2030 + automatorwp_insert_log( array(
2031 + 'title' => sprintf( __( '%s run cancelled by the user', 'automatorwp' ), $automation->title ),
2032 + 'type' => 'automation',
2033 + 'object_id' => $automation->id,
2034 + 'user_id' => get_current_user_id(),
2035 + 'post_id' => 0,
2036 + 'date' => automatorwp_get_event_log_date(),
2037 + ) );
2038 +
2039 + // Restore loop
2040 + automatorwp_update_automation_meta( $automation->id, 'current_loop', 0 );
2041 +
2042 + // Restore manual run flag
2043 + automatorwp_update_automation_meta( $automation->id, 'manual_run', '' );
2044 +
2045 + // Update the next run date
2046 + automatorwp_update_automation_next_run_date( $automation->id );
2047 +
2048 + return true;
2049 +
2050 +}
2051 +
2052 +/**
2053 + * Helper function to get the last error happened in the run automation function
2054 + *
2055 + * @since 2.2.2
2056 + *
2057 + * @return string|null
2058 + */
2059 +function automatorwp_get_run_automation_error() {
2060 +
2061 + global $automatorwp_run_automation_error;
2062 +
2063 + return $automatorwp_run_automation_error;
2064 +}
2065 +
2066 +/**
2067 + * Helper function to get the current log date on the events engine
2068 + *
2069 + * @since 1.0.0
2070 + *
2071 + * @return string
2072 + */
2073 +function automatorwp_get_event_log_date() {
2074 +
2075 + global $automatorwp_completed_triggers;
2076 +
2077 + // The global $automatorwp_completed_triggers is used to increase log time by the number of loops perform
2078 + // This prevents unlimited completions when multiple triggers has been triggered
2079 + if( ! is_array( $automatorwp_completed_triggers ) ) {
2080 + $automatorwp_completed_triggers = array();
2081 + }
2082 +
2083 + return date( 'Y-m-d H:i:s', current_time( 'timestamp' ) + count( $automatorwp_completed_triggers ) );
2084 +
2085 +}