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 | classes/automation-loop.php +811 -0 5.7.2 → 6.0.3 View file →
@@ -1,0 +1,811 @@
1 +<?php
2 +/**
3 + * Automation Loop
4 + *
5 + * @package AutomatorWP\Classes\Automation_Loop
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 +class AutomatorWP_Automation_Loop extends AutomatorWP_Automation_Type {
13 +
14 + /**
15 + * Type
16 + *
17 + * @since 1.0.0
18 + *
19 + * @var array $args
20 + */
21 + public $args = array(
22 + 'image' => AUTOMATORWP_URL . 'assets/img/automatorwp-logo.svg',
23 + 'label' => '',
24 + 'desc' => '',
25 + 'labels' => array(
26 + 'singular' => '',
27 + 'plural' => '',
28 + ),
29 + 'required_trigger' => '',
30 + );
31 +
32 + /**
33 + * Process the given items IDs to run the automation actions on them
34 + *
35 + * @since 2.2.2
36 + *
37 + * @param array $items_ids The items IDs array.
38 + * @param stdClass $automation The automation object.
39 + * @param stdClass $trigger The trigger object. null if required_trigger is empty
40 + * @param array $trigger_options The trigger options array. An empty array if required_trigger is empty
41 + *
42 + * @return array|false
43 + */
44 + public function process_items( $items_ids, $automation, $trigger, $trigger_options ) {
45 + // Override
46 + }
47 +
48 + /**
49 + * Get the items count
50 + *
51 + * @since 2.2.2
52 + *
53 + * @param stdClass $automation The automation object.
54 + * @param stdClass $trigger The trigger object. null if required_trigger is empty
55 + *
56 + * @return int|false
57 + */
58 + public function get_items_count( $automation, $trigger ) {
59 + // OVERRIDE in case the items count is not from the database
60 +
61 + global $wpdb;
62 +
63 + // Get the posts SQL
64 + $sql = $this->get_items_sql( $automation, $trigger, true );
65 +
66 + if( ! $sql ) {
67 + return false;
68 + }
69 +
70 + return absint( $wpdb->get_var( $sql ) );
71 + }
72 +
73 + /**
74 + * Get the items IDs
75 + *
76 + * @since 2.2.2
77 + *
78 + * @param stdClass $automation The automation object.
79 + * @param stdClass $trigger The trigger object. null if required_trigger is empty
80 + *
81 + * @return array|false
82 + */
83 + public function get_items_ids( $automation, $trigger ) {
84 + // OVERRIDE in case the items count is not from the database
85 +
86 + global $wpdb;
87 +
88 + // Get the posts SQL
89 + $sql = $this->get_items_sql( $automation, $trigger, false );
90 +
91 + if( ! $sql ) {
92 + return false;
93 + }
94 +
95 + return $wpdb->get_col( $sql );
96 + }
97 +
98 + /**
99 + * Get the items SQL (used for count and get ids)
100 + *
101 + * @since 2.2.2
102 + *
103 + * @param stdClass $automation The automation object.
104 + * @param stdClass $trigger The trigger object.
105 + *
106 + * @return string|false
107 + */
108 + public function get_items_sql( $automation, $trigger, $count = false ) {
109 +
110 + global $automatorwp_run_automation_error;
111 +
112 + if( ! is_object( $automation ) ) {
113 + $automatorwp_run_automation_error = __( 'Invalid automation.', 'automatorwp' );
114 + return false;
115 + }
116 +
117 + $loop = 0;
118 + $items_per_loop = 0;
119 +
120 + if( ! $count ) {
121 + $items_per_loop = absint( automatorwp_get_automation_meta( $automation->id, 'items_per_loop', true ) );
122 +
123 + // Bail if users per loop not correctly configured
124 + if( $items_per_loop <= 0 ) {
125 + $automatorwp_run_automation_error = sprintf( __( '%s per loop needs to be higher than 0.', 'automatorwp' ), $this->args['labels']['plural'] );
126 + return false;
127 + }
128 +
129 + // Get the loop stored in options to calculate the offset
130 + $loop = absint( automatorwp_get_automation_meta( $automation->id, 'current_loop', true ) );
131 + }
132 +
133 + $trigger_options = array();
134 +
135 + if( $trigger ) {
136 + // Get the trigger stored options
137 + $trigger_options = automatorwp_get_trigger_stored_options( $trigger->id );
138 + }
139 +
140 + $sql = false;
141 +
142 + /**
143 + * Available filter to override the all users automation SQL (overwritten by the trigger)
144 + *
145 + * @since 2.2.2
146 + *
147 + * @param string $sql The SQL query
148 + * @param stdClass $automation The automation object
149 + * @param stdClass $trigger The trigger object
150 + * @param bool $count True if is looking for the SQL to count the number of users
151 + * @param array $trigger_options The trigger's stored options
152 + * @param int $items_per_loop The automation items per loop option
153 + * @param int $loop The current loop
154 + */
155 + $sql = apply_filters( "automatorwp_get_{$this->type}_automation_sql", $sql, $automation, $trigger, $count, $trigger_options, $items_per_loop, $loop );
156 +
157 + return $sql;
158 +
159 + }
160 +
161 + public function hooks() {
162 +
163 + // Register as loop type
164 + add_filter( 'automatorwp_automation_loop_types', array( $this, 'register_as_automation_loop_type' ), 10, 1 );
165 +
166 + // On insert/update hooks
167 + add_action( 'cmb2_admin_init', array( $this, 'meta_boxes' ), 9 );
168 + add_filter( 'automatorwp_automation_ui_admin_body_class', array( $this, 'automation_ui_admin_body_class' ), 10, 2 );
169 +
170 + add_action( 'ct_insert_object', array( $this, 'on_insert_automation' ), 10, 3 );
171 + add_action( 'ct_insert_object', array( $this, 'on_update_automation' ), 10, 3 );
172 +
173 + add_filter( 'automatorwp_check_automation_required_triggers', array( $this, 'automation_required_triggers' ), 10, 2 );
174 +
175 + // Run automation hooks
176 + add_action('automatorwp_ajax_run_automation', array( $this, 'ajax_run_automation' ) );
177 +
178 + add_filter( 'automatorwp_get_automation_run_details_count', array( $this, 'automation_run_details_count' ), 10, 2 );
179 +
180 + add_filter( 'automatorwp_run_automation_result', array( $this, 'maybe_run_automation' ), 10, 2 );
181 +
182 + parent::hooks();
183 +
184 + }
185 +
186 + /**
187 + * Register the automation loop type
188 + *
189 + * @since 2.2.2
190 + *
191 + * @param array $loop_types The automation loop types.
192 + *
193 + * @return array
194 + */
195 + public function register_as_automation_loop_type( $loop_types ) {
196 +
197 + $loop_types[] = $this->type;
198 +
199 + return $loop_types;
200 +
201 + }
202 +
203 + /**
204 + * Register custom CMB2 meta boxes
205 + *
206 + * @since 1.0.0
207 + */
208 + public function meta_boxes() {
209 +
210 + // Execution Options
211 + $default_datetime = strtotime( date( 'Y-m-d 00:00:00', current_time( 'timestamp' ) ) );
212 +
213 + automatorwp_add_meta_box(
214 + 'automatorwp-automations-execution-options',
215 + __( 'Execution Options', 'automatorwp' ),
216 + 'automatorwp_automations',
217 + array(
218 + 'items_per_loop' => array(
219 + 'type' => 'text',
220 + 'default' => '200',
221 + 'attributes' => array(
222 + 'type' => 'number',
223 + 'min' => '1',
224 + ),
225 + 'before_field' => array( $this, 'items_per_loop_before_field' ),
226 + 'after_field' => array( $this, 'items_per_loop_after_field' ),
227 + ),
228 + 'delay_amount' => array(
229 + 'type' => 'text',
230 + 'default' => '1',
231 + 'attributes' => array(
232 + 'type' => 'number',
233 + 'min' => '1',
234 + ),
235 + 'before_field' => array( $this, 'delay_amount_before_field' ),
236 + ),
237 + 'delay_seconds' => array(
238 + 'type' => 'select',
239 + 'options' => array(
240 + MINUTE_IN_SECONDS => __( 'Minutes', 'automatorwp' ),
241 + HOUR_IN_SECONDS => __( 'Hours', 'automatorwp' ),
242 + DAY_IN_SECONDS => __( 'Days', 'automatorwp' ),
243 + MONTH_IN_SECONDS => __( 'Months', 'automatorwp' ),
244 + YEAR_IN_SECONDS => __( 'Years', 'automatorwp' ),
245 + ),
246 + ),
247 + 'schedule_run' => array(
248 + 'name' => '<div class="dashicons dashicons-calendar-alt"></div>' . __( 'Schedule execution:', 'automatorwp' ),
249 + 'type' => 'checkbox',
250 + 'classes' => 'cmb2-switch',
251 + ),
252 + 'schedule_run_datetime' => array(
253 + 'name' => __( 'Execute this automation on:', 'automatorwp' ),
254 + 'type' => 'text_datetime_timestamp',
255 + 'date_format' => automatorwp_get_date_format( array( 'Y-m-d', 'm/d/Y' ) ),
256 + 'time_format' => automatorwp_get_time_format(),
257 + 'default' => $default_datetime,
258 + ),
259 + 'recurring_run' => array(
260 + 'name' => '<div class="dashicons dashicons-backup"></div>' . __( 'Recurring execution:', 'automatorwp' ),
261 + 'type' => 'checkbox',
262 + 'classes' => 'cmb2-switch',
263 + ),
264 + 'recurring_run_day' => array(
265 + 'name' => __( 'Execute this automation:', 'automatorwp' ),
266 + 'desc' => __( 'of', 'automatorwp' ),
267 + 'type' => 'text',
268 + 'default' => '1',
269 + 'attributes' => array(
270 + 'type' => 'number',
271 + 'min' => '1',
272 + 'max' => '365',
273 + ),
274 + 'before_row' => array( $this, 'recurring_run_day_before_row' ),
275 + 'before_field' => array( $this, 'recurring_run_day_before_field' ),
276 + ),
277 + 'recurring_run_period' => array(
278 + 'name' => __( 'Period:', 'automatorwp' ),
279 + 'type' => 'select',
280 + 'default' => 'day',
281 + 'options' => array(
282 + 'day' => __( 'Every day', 'automatorwp' ),
283 + 'week' => __( 'every week', 'automatorwp' ),
284 + 'month' => __( 'every month', 'automatorwp' ),
285 + 'year' => __( 'every year', 'automatorwp' ),
286 + )
287 + ),
288 + 'recurring_run_time' => array(
289 + 'name' => __( 'at', 'automatorwp' ),
290 + 'type' => 'text_time',
291 + 'time_format' => automatorwp_get_time_format(),
292 + 'default' => date( automatorwp_get_time_format(), $default_datetime ),
293 + 'after_row' => array( $this, 'execute_options_actions' ),
294 + ),
295 + ),
296 + array(
297 + 'priority' => 'default',
298 + 'context' => 'side',
299 + 'show_on_cb' => array( $this, 'execution_options_box_show_cb' ),
300 + )
301 + );
302 +
303 + }
304 +
305 + function get_automation_from_url() {
306 +
307 + global $ct_table;
308 +
309 + if( ! $ct_table ) {
310 + return false;
311 + }
312 +
313 + if( $ct_table->name !== 'automatorwp_automations' ) {
314 + return false;
315 + }
316 +
317 + $primary_key = $ct_table->db->primary_key;
318 + $object_id = isset( $_GET[$primary_key] ) ? absint( $_GET[$primary_key] ) : 0;
319 +
320 + $automation = ct_get_object( $object_id );
321 +
322 + // Bail if automation doesn't exists
323 + if( ! $automation ) {
324 + return false;
325 + }
326 +
327 + return $automation;
328 +
329 + }
330 +
331 + public function items_per_loop_before_field() {
332 + echo '<span class="automatorwp-items-per-loop-label-before">' . automatorwp_dashicon( 'controls-play' ) . __( 'Process', 'automatorwp' ) . '</span>';
333 + }
334 +
335 + public function items_per_loop_after_field() {
336 +
337 + $automation = $this->get_automation_from_url();
338 + $html = '<span class="automatorwp-items-per-loop-label-before">%s</span>';
339 +
340 + // Bail if automation doesn't exists
341 + if( ! $automation ) {
342 + echo sprintf( $html, __( 'items per loop', 'automatorwp' ) );
343 + return;
344 + }
345 +
346 + $automation_types = automatorwp_get_automation_types();
347 +
348 + $label = sprintf( __( '%s per loop', 'automatorwp' ), strtolower( $automation_types[$automation->type]['labels']['plural'] ) );
349 +
350 + echo sprintf( $html, $label );
351 + }
352 +
353 + public function delay_amount_before_field() {
354 + echo '<span class="automatorwp-delay-amount-label-before">' . automatorwp_dashicon( 'filter' ) . __( 'Every', 'automatorwp' ) . '</span>';
355 + }
356 +
357 + /**
358 + * Before recurring run day row
359 + *
360 + * @since 1.0.0
361 + */
362 + public function recurring_run_day_before_row() {
363 + ?><label for="recurring_run_day" class="automatorwp-recurring-run-day-label"><?php _e( 'Execute this automation:', 'automatorwp' ); ?></label><?php
364 + }
365 +
366 + /**
367 + * Before recurring run day field
368 + *
369 + * @since 1.0.0
370 + */
371 + public function recurring_run_day_before_field() {
372 + ?><p class="cmb2-metabox-description"><?php _e( 'The day', 'automatorwp' ); ?></p><?php
373 + }
374 +
375 + /**
376 + * Execute options actions
377 + *
378 + * @since 1.0.0
379 + */
380 + public function execute_options_actions() {
381 +
382 + $automation = $this->get_automation_from_url();
383 +
384 + // Bail if automation doesn't exists
385 + if( ! $automation ) {
386 + return;
387 + }
388 +
389 + // Check if automation has been scheduled to show the next run date
390 + $schedule_run = (bool) automatorwp_get_automation_meta( $automation->id, 'schedule_run', true );
391 + $recurring_run = (bool) automatorwp_get_automation_meta( $automation->id, 'recurring_run', true );
392 + $next_run_date = automatorwp_get_automation_meta( $automation->id, 'next_run_date', true );
393 +
394 + if( ( $schedule_run || $recurring_run ) && ! empty( $next_run_date ) ) :
395 + $date_format = automatorwp_get_date_format();
396 + $time_format = automatorwp_get_time_format(); ?>
397 + <div class="automatorwp-next-run-date">
398 + <span class="dashicons dashicons-controls-play"></span>
399 + <?php _e( 'Next run:', 'automatorwp' ); ?>
400 + <strong><?php echo date( $date_format . ' ' . $time_format, strtotime( $next_run_date ) ); ?></strong>
401 + </div>
402 + <?php endif;
403 +
404 + // Setup vars for an automation in progress
405 + if( $automation->status === 'in-progress' ) {
406 + $original_status = automatorwp_get_automation_meta( $automation->id, 'original_status', true );
407 + $details = automatorwp_get_automation_run_details( $automation );
408 + }
409 +
410 + ?>
411 + <div id="major-publishing-actions">
412 +
413 + <div class="automatorwp-run-automation <?php if( $automation->status === 'in-progress' ) : ?>automatorwp-is-running<?php endif; ?>" <?php if( $automation->status === 'in-progress' ) : ?>data-original-status="<?php echo esc_attr( $original_status ); ?>"<?php endif; ?>>
414 + <button type="button" class="button button-primary button-large" <?php if( $automation->status === 'in-progress' ) : ?>disabled<?php endif; ?>>
415 + <div class="automatorwp-run-automation-run-label" <?php if( $automation->status === 'in-progress' ) : ?>style="display: none;"<?php endif; ?>>
416 + <span class="dashicons dashicons-controls-play"></span> <?php _e( 'Run automation', 'automatorwp' ); ?>
417 + </div>
418 + <div class="automatorwp-run-automation-running-label" <?php if( $automation->status !== 'in-progress' ) : ?>style="display: none;"<?php endif; ?>>
419 + <span class="dashicons dashicons-update"></span> <?php _e( 'Running...', 'automatorwp' ); ?>
420 + </div>
421 + <div class="automatorwp-run-automation-done-label" style="display: none;">
422 + <span class="dashicons dashicons-yes"></span> <?php _e( 'Done!', 'automatorwp' ); ?>
423 + </div>
424 + </button>
425 + </div>
426 +
427 + <div class="automatorwp-cancel-automation-run" <?php if( $automation->status !== 'in-progress' ) : ?>style="display: none;"<?php endif; ?>>
428 + <button type="button" class="button automatorwp-button-danger button-large">
429 + <div class="automatorwp-cancel-automation-run-cancel-label">
430 + <?php _e( 'Cancel', 'automatorwp' ); ?>
431 + </div>
432 + <div class="automatorwp-cancel-automation-run-cancelling-label" style="display: none;">
433 + <?php _e( 'Cancelling...', 'automatorwp' ); ?>
434 + </div>
435 + <div class="automatorwp-cancel-automation-run-done-label" style="display: none;">
436 + <?php _e( 'Cancelled', 'automatorwp' ); ?>
437 + </div>
438 + </button>
439 + </div>
440 +
441 + <div class="clear"></div>
442 +
443 + <div class="automatorwp-run-automation-progress" <?php if( $automation->status !== 'in-progress' ) : ?>style="display: none;"<?php endif; ?>>
444 + <div class="automatorwp-run-automation-progress-bar">
445 + <?php if( $automation->status === 'in-progress' ) : ?>
446 + <div class="automatorwp-run-automation-progress-current-progress" style="width: <?php echo $details['percentage']; ?>%"></div>
447 + <?php else : ?>
448 + <div class="automatorwp-run-automation-progress-current-progress"></div>
449 + <?php endif; ?>
450 + </div>
451 + <?php if( $automation->status === 'in-progress' ) : ?>
452 + <div class="automatorwp-run-automation-progress-text"><?php echo $details['processed'] . '/' . $details['count']; ?></div>
453 + <?php else : ?>
454 + <div class="automatorwp-run-automation-progress-text">0/0</div>
455 + <?php endif; ?>
456 + </div>
457 +
458 + <div class="clear"></div>
459 +
460 + </div>
461 +
462 + <?php
463 + }
464 +
465 + /**
466 + * Execution options box show callback
467 + *
468 + * @since 1.0.0
469 + *
470 + * @param object $cmb CMB2 object
471 + *
472 + * @return bool True/false whether to show the metabox
473 + */
474 + public function execution_options_box_show_cb( $cmb ) {
475 +
476 + global $ct_table;
477 +
478 + if( ! $ct_table ) {
479 + return false;
480 + }
481 +
482 + if( $ct_table->name !== 'automatorwp_automations' ) {
483 + return false;
484 + }
485 +
486 + $object_id = $cmb->object_id();
487 +
488 + $object = ct_get_object( $object_id );
489 +
490 + return ( in_array( $object->type, automatorwp_get_automation_loop_types() ) );
491 +
492 + }
493 +
494 + function automation_ui_admin_body_class( $classes, $automation ) {
495 +
496 + if( in_array( $automation->type, automatorwp_get_automation_loop_types() ) ) {
497 + $classes .= ' is-automatorwp-loop';
498 + }
499 +
500 + return $classes;
501 +
502 + }
503 +
504 + /**
505 + * Handler when a new automation is getting created
506 + *
507 + * @since 1.0.0
508 + *
509 + * @param int $object_id Object ID.
510 + * @param stdClass $object Object.
511 + * @param bool $update Whether this is an existing object being updated or not.
512 + */
513 + public function on_insert_automation( $object_id, $object, $update ) {
514 +
515 + global $ct_table;
516 +
517 + // If not is our custom table, return
518 + if( $ct_table->name !== 'automatorwp_automations' ) {
519 + return;
520 + }
521 +
522 + // Bail if updating
523 + if( $update ) {
524 + return;
525 + }
526 +
527 + // Check if is an loop automation
528 + if( $object->type !== $this->type ) {
529 + return;
530 + }
531 +
532 + /**
533 + * Filter available to define the default items per loop option
534 + *
535 + * @since 1.0.0
536 + *
537 + * @param int $items_per_loop
538 + *
539 + * @return int
540 + */
541 + $items_per_loop = apply_filters( 'automatorwp_default_items_per_loop', 200 );
542 +
543 + // Update the items per loop meta
544 + ct_update_object_meta( $object_id, 'items_per_loop', $items_per_loop );
545 +
546 + }
547 +
548 + /**
549 + * Handler when an automation is getting updated
550 + *
551 + * @since 1.0.0
552 + *
553 + * @param int $object_id Object ID.
554 + * @param stdClass $object Object.
555 + * @param bool $update Whether this is an existing object being updated or not.
556 + */
557 + public function on_update_automation( $object_id, $object, $update ) {
558 +
559 + global $ct_table;
560 +
561 + // If not is our custom table, return
562 + if( $ct_table->name !== 'automatorwp_automations' ) {
563 + return;
564 + }
565 +
566 + // Bail if not updating
567 + if( ! $update ) {
568 + return;
569 + }
570 +
571 + // Check if is an loop automation
572 + if( $object->type !== $this->type ) {
573 + return;
574 + }
575 +
576 + // Calculate the next run date based on settings submitted
577 + automatorwp_update_automation_next_run_date( $object_id, true );
578 + }
579 +
580 + /**
581 + * If required_trigger configure, ensures that the trigger is present when creating the automation
582 + *
583 + * @since 2.2.2
584 + *
585 + * @param array $triggers The automation triggers list.
586 + * @param stdClass $automation The automation object.
587 + *
588 + * @return array
589 + */
590 + public function automation_required_triggers( $triggers, $automation ) {
591 +
592 + if( $automation->type !== $this->type ) {
593 + return $triggers;
594 + }
595 +
596 + if( $this->args['required_trigger'] === '' ) {
597 + return $triggers;
598 + }
599 +
600 + // Creates the required trigger if not exists in the automation
601 +
602 + $create = false;
603 +
604 + // Check if the first action is the action required for anonymous automations
605 + if( ! isset( $triggers[0] ) ) {
606 + $create = true;
607 + }
608 +
609 + if( isset( $triggers[0] ) && $triggers[0]->type !== $this->args['required_trigger'] ) {
610 + $create = true;
611 + }
612 +
613 + if( $create ) {
614 + ct_setup_table( 'automatorwp_triggers' );
615 +
616 + $trigger_args = automatorwp_get_trigger( $this->args['required_trigger'] );
617 +
618 + // Setup the trigger data
619 + $trigger_data = array(
620 + 'automation_id' => $automation->id,
621 + 'title' => $trigger_args['label'],
622 + 'type' => $this->args['required_trigger'],
623 + 'status' => 'active',
624 + 'position' => 0,
625 + 'date' => date( 'Y-m-d H:i:s', current_time( 'timestamp' ) ),
626 + );
627 +
628 + // Insert the new trigger
629 + $trigger_id = ct_insert_object( $trigger_data );
630 +
631 + if( $trigger_id ) {
632 + $trigger_data['id'] = $trigger_id;
633 +
634 + $trigger_data = (object) $trigger_data;
635 +
636 + // Prepend the new trigger at start of the triggers list
637 + array_unshift( $triggers, $trigger_data );
638 + }
639 +
640 + ct_reset_setup_table();
641 + }
642 +
643 +
644 + return $triggers;
645 +
646 + }
647 +
648 + /**
649 + * Handles the ajax run for automation loop
650 + *
651 + * @since 2.2.2
652 + *
653 + * @param stdClass $automation The automation object.
654 + */
655 + public function ajax_run_automation( $automation ) {
656 +
657 + if( $automation->type !== $this->type ) {
658 + return;
659 + }
660 +
661 + $items_per_loop = ( isset( $_POST['items_per_loop'] ) ? absint( $_POST['items_per_loop'] ) : 0 );
662 +
663 + if( $items_per_loop <= 0 ) {
664 + wp_send_json_error( sprintf( __( '%s per loop need to be higher than 0.', 'automatorwp' ), $this->args['labels']['plural'] ) );
665 + }
666 +
667 + // Get the loop before gets updated
668 + $loop = absint( automatorwp_get_automation_meta( $automation->id, 'current_loop', true ) );
669 +
670 + // First loop checks
671 + if( $loop === 0 ) {
672 +
673 + // Update the items per loop
674 + $stored_items_per_loop = absint( automatorwp_get_automation_meta( $automation->id, 'items_per_loop', true ) );
675 +
676 + if( $items_per_loop !== $stored_items_per_loop ) {
677 + automatorwp_update_automation_meta( $automation->id, 'items_per_loop', $items_per_loop );
678 + }
679 +
680 + // Update a flag to meet that is a manual run
681 + automatorwp_update_automation_meta( $automation->id, 'manual_run', '1' );
682 + }
683 + }
684 +
685 + /**
686 + * Updates the automation run details count
687 + *
688 + * @since 2.2.2
689 + *
690 + * @param int $count The run details count.
691 + * @param stdClass $automation The automation object.
692 + *
693 + * @return array
694 + */
695 + public function automation_run_details_count( $count, $automation ) {
696 +
697 + global $automatorwp_run_automation_error;
698 +
699 + if( ! is_object( $automation ) ) {
700 + $automatorwp_run_automation_error = __( 'Invalid automation.', 'automatorwp' );
701 + return $count;
702 + }
703 +
704 + if( $automation->type !== $this->type ) {
705 + return $count;
706 + }
707 +
708 + $trigger = null;
709 +
710 + if( $this->args['required_trigger'] !== '' ) {
711 + $trigger = automatorwp_get_automation_trigger_by_type( $automation->id, $this->args['required_trigger'] );
712 +
713 + // Prevent automations already in progress
714 + if( ! $trigger ) {
715 + $automatorwp_run_automation_error = __( 'Trigger configuration not found.', 'automatorwp' );
716 + return $count;
717 + }
718 + }
719 +
720 + return $this->get_items_count( $automation, $trigger );
721 + }
722 +
723 + /**
724 + * Checks if should run automation
725 + *
726 + * @since 2.2.2
727 + *
728 + * @param array $run_details The automation run details.
729 + * @param stdClass $automation The automation object.
730 + *
731 + * @return array
732 + */
733 + function maybe_run_automation( $result, $automation ) {
734 +
735 + global $automatorwp_run_automation_error;
736 +
737 + if( ! is_object( $automation ) ) {
738 + $automatorwp_run_automation_error = __( 'Invalid automation.', 'automatorwp' );
739 + return false;
740 + }
741 +
742 + if( $automation->type !== $this->type ) {
743 + return $result;
744 + }
745 +
746 + $result = $this->run_automation( $automation );
747 +
748 + return $result;
749 +
750 + }
751 +
752 + /**
753 + * Run this automation
754 + *
755 + * @since 2.2.2
756 + *
757 + * @param stdClass $automation The automation object.
758 + *
759 + * @return bool True on success, false on failure
760 + */
761 + public function run_automation( $automation ) {
762 +
763 + global $automatorwp_run_automation_error;
764 +
765 + // Get the items per loop
766 + $items_per_loop = absint( automatorwp_get_automation_meta( $automation->id, 'items_per_loop', true ) );
767 +
768 + // Bail if items per loop not correctly configured
769 + if( $items_per_loop <= 0 ) {
770 + $automatorwp_run_automation_error = sprintf( __( '%s per loop needs to be higher than 0.', 'automatorwp' ), $this->args['labels']['plural'] );
771 + return false;
772 + }
773 +
774 + $trigger = null;
775 + $trigger_options = array();
776 +
777 + if( $this->args['required_trigger'] !== '' ) {
778 + // Get the required trigger
779 + $trigger = automatorwp_get_automation_trigger_by_type( $automation->id, $this->args['required_trigger'] );
780 +
781 + // Bail if trigger not found
782 + if( ! $trigger ) {
783 + $automatorwp_run_automation_error = __( 'Trigger configuration not found.', 'automatorwp' );
784 + return false;
785 + }
786 +
787 + // Get the trigger stored options
788 + $trigger_options = automatorwp_get_trigger_stored_options( $trigger->id );
789 +
790 + }
791 +
792 + // Update automation status to in progress
793 + if( $automation->status !== 'in-progress' ) {
794 + // Call the automation run started function
795 + automatorwp_run_automation_started( $automation, $trigger, $trigger_options );
796 + }
797 +
798 + // Get the items ids to run the actions
799 + $items_ids = $this->get_items_ids( $automation, $trigger );
800 +
801 + if( $items_ids === false ) {
802 + return false;
803 + }
804 +
805 + $this->process_items( $items_ids, $automation, $trigger, $trigger_options );
806 +
807 + return true;
808 +
809 + }
810 +
811 +}