PluginProbe
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce / 3.3.0
CartFlows – Funnel Builder & Checkout Plugin for WooCommerce v3.3.0
3.3.0 3.2.1 3.2.0 3.1.4 3.1.3 3.1.2 3.1.1 3.1.0 3.0.1 trunk 1.0.4 1.1.0 1.1.0.1 1.1.1 1.1.10 1.1.11 1.1.12 1.1.13 1.1.14 1.1.15 1.1.16 1.1.17 1.1.18 1.1.19 1.1.2 All 162 releases
← All changes | classes/class-cartflows-update.php +579 -4 1.1.0.1 → 3.3.0 View file →
@@ -4,8 +4,12 @@
4 4 *
5 5 * @package CartFlows
6 6 */
7 7
8 +// Exit if accessed directly.
9 +if ( ! defined( 'ABSPATH' ) ) {
10 + exit;
11 +}
8 12 if ( ! class_exists( 'Cartflows_Update' ) ) :
9 13
10 14 /**
11 15 * CartFlows Update initial setup
@@ -17,14 +21,16 @@
17 21 /**
18 22 * Class instance.
19 23 *
20 24 * @access private
21 - * @var $instance Class instance.
25 + * @var Cartflows_Update|null
22 26 */
23 27 private static $instance;
24 28
25 29 /**
26 30 * Initiator
31 + *
32 + * @return Cartflows_Update
27 33 */
28 34 public static function get_instance() {
29 35 if ( ! isset( self::$instance ) ) {
30 36 self::$instance = new self();
@@ -35,9 +41,9 @@
35 41 /**
36 42 * Constructor
37 43 */
38 44 public function __construct() {
39 - add_action( 'admin_init', __CLASS__ . '::init' );
45 + add_action( 'admin_init', array( $this, 'init' ) );
40 46 }
41 47
42 48 /**
43 49 * Init
@@ -44,9 +50,9 @@
44 50 *
45 51 * @since 1.0.0
46 52 * @return void
47 53 */
48 - static public function init() {
54 + public function init() {
49 55
50 56 do_action( 'cartflows_update_before' );
51 57
52 58 // Get auto saved version number.
@@ -54,8 +60,9 @@
54 60
55 61 // Update auto saved version number.
56 62 if ( ! $saved_version ) {
57 63 update_option( 'cartflows-version', CARTFLOWS_VER );
64 + return;
58 65 }
59 66
60 67 // If equals then return.
61 68 if ( version_compare( $saved_version, CARTFLOWS_VER, '=' ) ) {
@@ -61,15 +68,583 @@
61 68 if ( version_compare( $saved_version, CARTFLOWS_VER, '=' ) ) {
62 69 return;
63 70 }
64 71
72 + $this->logger_files();
73 +
74 + if ( version_compare( $saved_version, '1.1.22', '<' ) ) {
75 + update_option( 'wcf_setup_skipped', true );
76 + }
77 +
78 + if ( version_compare( $saved_version, '1.2.0', '<' ) ) {
79 +
80 + $this->changed_wp_templates();
81 + }
82 +
83 + /* Add legacy admin option */
84 + if ( version_compare( $saved_version, '1.6.0', '<' ) ) {
85 + update_option( 'cartflows-old-ui-user', true );
86 + update_option( 'cartflows-legacy-admin', true );
87 + update_option( 'cartflows-legacy-meta-show-design-options', true );
88 + }
89 +
90 + /* Updating meta for global checkout migration & Permalinks */
91 + if ( version_compare( $saved_version, '1.10.0', '<' ) ) {
92 +
93 + $global_checkout = \Cartflows_Helper::get_common_setting( 'global_checkout' );
94 +
95 + if ( $global_checkout ) {
96 + $flow_id = wcf()->utils->get_flow_id_from_step_id( $global_checkout );
97 + if ( $flow_id ) {
98 + update_option( '_cartflows_store_checkout', $flow_id );
99 + update_option( '_cartflows_old_global_checkout', $global_checkout );
100 + delete_post_meta( $global_checkout, 'wcf-checkout-products' );
101 + }
102 + }
103 +
104 + update_option( 'cartflows_show_weekly_report_email_notice', 'yes' );
105 +
106 + $permalink_settings = Cartflows_Helper::get_admin_settings_option( '_cartflows_permalink', false, false );
107 +
108 + if ( ! $permalink_settings ) {
109 +
110 + $default_settings = array(
111 + 'permalink' => CARTFLOWS_STEP_POST_TYPE,
112 + 'permalink_flow_base' => CARTFLOWS_FLOW_POST_TYPE,
113 + 'permalink_structure' => '',
114 +
115 + );
116 +
117 + Cartflows_Helper::update_admin_settings_option( '_cartflows_permalink', $default_settings );
118 +
119 + }
120 + }
121 + // Update required license key to lowercase. Can be removed after 3 major update.
122 + if ( version_compare( $saved_version, '1.11.1', '<' ) && _is_cartflows_pro() ) {
123 +
124 + $api_key = get_option( 'wc_am_client_CartFlows_api_key' );
125 + $api_key_data = get_option( 'wc_am_client_CartFlows' );
126 +
127 + // Take backup of options.
128 + update_option(
129 + 'cartflows_license_backup_data',
130 + array(
131 + 'wc_am_client_cartflows_api_key' => $api_key,
132 + 'wc_am_client_cartflows' => $api_key_data,
133 + )
134 + );
135 +
136 + delete_option( 'wc_am_client_CartFlows_api_key' );
137 + delete_option( 'wc_am_client_CartFlows' );
138 +
139 + // Delete the cached value for old user ( before v1.11.0 and after v1.11.0 ) so WP can add new value.
140 + wp_cache_flush();
141 +
142 + if ( $api_key_data ) {
143 +
144 + $new_data = array(
145 + 'wc_am_client_cartflows_api_key' => isset( $api_key_data['wc_am_client_CartFlows_api_key'] ) ? $api_key_data['wc_am_client_CartFlows_api_key'] : $api_key_data['wc_am_client_cartflows_api_key'],
146 + );
147 +
148 + update_option( 'wc_am_client_cartflows', $new_data );
149 + }
150 +
151 + if ( $api_key ) {
152 + update_option( 'wc_am_client_cartflows_api_key', $api_key );
153 + }
154 + }
155 +
156 + // Set default page builder to "Other" for those who have set it as "DIVI".
157 + if ( version_compare( $saved_version, '2.0.0', '<' ) ) {
158 + $common_settings = get_option( '_cartflows_common', array() );
159 +
160 + if ( is_array( $common_settings ) && 'divi' === $common_settings['default_page_builder'] ) {
161 +
162 + $common_settings['default_page_builder'] = 'elementor';
163 + update_option( '_cartflows_common', $common_settings );
164 + }
165 + }
166 +
167 + // Migrate old combined custom script meta to separate JS and CSS meta fields.
168 + if ( version_compare( $saved_version, '2.2.2', '<' ) ) {
169 + $this->migrate_custom_scripts();
170 + }
171 +
172 + // 3.0 ships a redesigned admin UI. Existing users (saved_version < 3.0.0) keep the
173 + // legacy admin until they opt into the new UI from the in-app notice or the
174 + // Advanced-tab toggle. Saved as 'enable' to match the toggle's backComp format
175 + // so the field round-trips correctly. Fresh installs short-circuit at the
176 + // `! $saved_version` early return above and default to the new UI.
177 + if ( is_string( $saved_version ) && version_compare( $saved_version, '3.0.0', '<' ) ) {
178 + update_option( 'cartflows-legacy-admin', 'enable' );
179 + }
180 +
181 + // Knowledge Base docs were stored autoloaded, adding hundreds of KB to every request.
182 + if ( is_string( $saved_version ) && version_compare( $saved_version, '3.2.1', '<' ) ) {
183 + $this->migrate_knowledge_base_docs_storage();
184 + }
185 +
65 186 // Update auto saved version number.
66 187 update_option( 'cartflows-version', CARTFLOWS_VER );
67 188
189 + // Update cartflows asset version to regenerate the dynamic css. We are using the time() function to add the random number.
190 + update_option( 'cartflows-assets-version', time() );
191 +
68 192 do_action( 'cartflows_update_after' );
69 193 }
194 +
195 + /**
196 + * Loading logger files.
197 + *
198 + * @since 1.0.0
199 + * @return void
200 + */
201 + public function logger_files() {
202 +
203 + if ( ! defined( 'CARTFLOWS_LOG_DIR' ) ) {
204 +
205 + $upload_dir = wp_upload_dir( null, false );
206 +
207 + define( 'CARTFLOWS_LOG_DIR', $upload_dir['basedir'] . '/cartflows-logs/' );
208 + }
209 +
210 + wcf()->create_files();
211 + }
212 +
213 + /**
214 + * Set script migration status.
215 + *
216 + * @param string $status Migration status value.
217 + * @since 2.2.2
218 + * @return void
219 + */
220 + public function set_script_migration_status( $status ) {
221 + update_option( 'cartflows_script_migration_status', $status );
222 + }
223 +
224 + /**
225 + * Determine if the migration notice should be shown.
226 + *
227 + * Returns false if migration is completed or accepted.
228 + * Returns false if status is 'skipped' and 7 days have not yet passed.
229 + * Returns false if no old script values exist (auto-sets status to 'completed').
230 + *
231 + * @since 2.2.2
232 + * @return bool
233 + */
234 + public function should_show_migration_notice() {
235 + $status = \CartFlows_Helper::get_script_migration_status();
236 +
237 + if ( 'completed' === $status || 'accepted' === $status ) {
238 + return false;
239 + }
240 +
241 + if ( 'skipped' === $status ) {
242 + $skip_timestamp = (int) get_option( 'cartflows_script_migration_skip_timestamp', 0 );
243 +
244 + // Show again only after 7 days have passed since last skip.
245 + if ( ( time() - $skip_timestamp ) < WEEK_IN_SECONDS ) {
246 + return false;
247 + }
248 + }
249 +
250 + // Check cached result first to avoid running the meta query on every page load.
251 + $has_old_scripts = get_option( 'cartflows_has_old_custom_scripts', '' );
252 +
253 + if ( '' === $has_old_scripts ) {
254 + // First time check — run the query once and cache the result.
255 + $has_old_scripts = $this->has_old_custom_scripts() ? 'yes' : 'no';
256 + update_option( 'cartflows_has_old_custom_scripts', $has_old_scripts, true );
257 + }
258 +
259 + // If no old script values exist, auto-complete migration and enable the code editor.
260 + if ( 'yes' !== $has_old_scripts ) {
261 + $this->set_script_migration_status( 'completed' );
262 + return false;
263 + }
264 +
265 + return true;
266 + }
267 +
268 + /**
269 + * Check if any posts have old combined custom script meta values.
270 + *
271 + * Queries the database for any cartflows_step or cartflows_flow posts
272 + * that have non-empty 'wcf-custom-script' or 'wcf-flow-custom-script' meta.
273 + *
274 + * @since 2.2.3
275 + * @return bool True if old script data exists, false otherwise.
276 + */
277 + public function has_old_custom_scripts() {
278 +
279 + global $wpdb;
280 +
281 + $result = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
282 + $wpdb->prepare(
283 + "SELECT 1 FROM {$wpdb->postmeta} pm
284 + INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID
285 + WHERE p.post_type IN (%s, %s)
286 + AND pm.meta_key IN (%s, %s)
287 + AND pm.meta_value != ''
288 + LIMIT 1",
289 + 'cartflows_step',
290 + 'cartflows_flow',
291 + 'wcf-custom-script',
292 + 'wcf-flow-custom-script'
293 + )
294 + );
295 +
296 + return ( null !== $result );
297 + }
298 +
299 + /**
300 + * Get current migration skip count.
301 + *
302 + * @since 2.2.2
303 + * @return int
304 + */
305 + public function get_migration_skip_count() {
306 + return (int) get_option( 'cartflows_script_migration_skip_count', 0 );
307 + }
308 +
309 + /**
310 + * Increment migration skip count and record the skip timestamp.
311 + *
312 + * @since 2.2.2
313 + * @return void
314 + */
315 + public function increment_migration_skip_count() {
316 + $count = $this->get_migration_skip_count();
317 + update_option( 'cartflows_script_migration_skip_count', $count + 1 );
318 + update_option( 'cartflows_script_migration_skip_timestamp', time() );
319 + }
320 +
321 + /**
322 + * Run on-demand migration of custom scripts triggered by user action.
323 + *
324 + * Unlike migrate_custom_scripts() which runs during version updates,
325 + * this method is called only when the user explicitly clicks "Migrate Data"
326 + * in the admin notice. It returns a count of migrated posts and updates
327 + * the migration status to 'completed'.
328 + *
329 + * @since 2.2.2
330 + * @return int Number of posts that had data migrated.
331 + */
332 + public function migrate_custom_scripts_on_demand() {
333 +
334 + $migrated_count = 0;
335 +
336 + // Migrate step-level custom scripts.
337 + $migrated_count += $this->migrate_post_type_scripts_counted(
338 + 'cartflows_step',
339 + 'wcf-custom-script',
340 + 'wcf-step-custom-js',
341 + 'wcf-step-custom-css'
342 + );
343 +
344 + // Migrate flow-level custom scripts.
345 + $migrated_count += $this->migrate_post_type_scripts_counted(
346 + 'cartflows_flow',
347 + 'wcf-flow-custom-script',
348 + 'wcf-flow-custom-js',
349 + 'wcf-flow-custom-css'
350 + );
351 +
352 + $this->set_script_migration_status( 'completed' );
353 +
354 + return $migrated_count;
355 + }
356 +
357 + /**
358 + * Migrate custom scripts for a specific post type and return the count of migrated posts.
359 + *
360 + * @param string $post_type The post type to query.
361 + * @param string $old_meta_key The old combined script meta key.
362 + * @param string $new_js_meta_key The new JS-only meta key.
363 + * @param string $new_css_meta_key The new CSS-only meta key.
364 + *
365 + * @since 2.2.2
366 + * @return int Number of posts migrated.
367 + */
368 + public function migrate_post_type_scripts_counted( $post_type, $old_meta_key, $new_js_meta_key, $new_css_meta_key ) {
369 +
370 + global $wpdb;
371 +
372 + $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
373 + $wpdb->prepare(
374 + "SELECT p.ID, pm.meta_value FROM {$wpdb->posts} p
375 + INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
376 + WHERE p.post_type = %s AND pm.meta_key = %s AND pm.meta_value != ''
377 + LIMIT 500",
378 + $post_type,
379 + $old_meta_key
380 + )
381 + );
382 +
383 + if ( empty( $results ) || ! is_array( $results ) ) {
384 + return 0;
385 + }
386 +
387 + $migrated = 0;
388 +
389 + foreach ( $results as $row ) {
390 + $post_id = $row->ID;
391 + $old_value = $row->meta_value;
392 +
393 + // Skip if the new meta fields already have values (don't overwrite manual entries).
394 + $existing_js = get_post_meta( $post_id, $new_js_meta_key, true );
395 + $existing_css = get_post_meta( $post_id, $new_css_meta_key, true );
396 +
397 + if ( ! empty( $existing_js ) || ! empty( $existing_css ) ) {
398 + continue;
399 + }
400 +
401 + // Decode HTML entities first since the old value was stored encoded.
402 + $decoded = html_entity_decode( $old_value, ENT_QUOTES, 'UTF-8' );
403 +
404 + // Extract CSS and JS from the combined script.
405 + $parsed = $this->parse_combined_script( $decoded );
406 +
407 + $did_migrate = false;
408 +
409 + if ( ! empty( $parsed['css'] ) ) {
410 + update_post_meta( $post_id, $new_css_meta_key, htmlentities( $parsed['css'] ) );
411 + $did_migrate = true;
412 + }
413 +
414 + if ( ! empty( $parsed['js'] ) ) {
415 + update_post_meta( $post_id, $new_js_meta_key, htmlentities( $parsed['js'] ) );
416 + $did_migrate = true;
417 + }
418 +
419 + if ( $did_migrate ) {
420 + ++$migrated;
421 + }
422 + }
423 +
424 + return $migrated;
425 + }
426 +
427 + /**
428 + * Stop the Knowledge Base docs option from being autoloaded on every request.
429 + * Only the legacy admin renders the screen that reads it, so the new UI drops it entirely.
430 + *
431 + * @since x.x.x
432 + * @return void
433 + */
434 + public function migrate_knowledge_base_docs_storage() {
435 +
436 + // Earlier blocks in init() rewrite this option, so CARTFLOWS_LEGACY_ADMIN is stale here — see class-cartflows-loader.php:158 for the allowlist.
437 + $legacy_admin_saved = get_option( 'cartflows-legacy-admin', false );
438 + $is_legacy_admin = in_array( $legacy_admin_saved, array( true, 1, '1', 'enable', 'yes' ), true );
439 +
440 + if ( ! $is_legacy_admin ) {
441 + delete_option( 'cartflows_docs_data' );
442 +
443 + if ( function_exists( 'as_unschedule_all_actions' ) ) {
444 + as_unschedule_all_actions( 'cartflows_update_knowledge_base_data' );
445 + }
446 +
447 + return;
448 + }
449 +
450 + if ( false === get_option( 'cartflows_docs_data', false ) ) {
451 + return;
452 + }
453 +
454 + // wp_set_option_autoload() landed in WP 6.4 and we still support 5.8.
455 + if ( function_exists( 'wp_set_option_autoload' ) ) {
456 + wp_set_option_autoload( 'cartflows_docs_data', false );
457 + return;
458 + }
459 +
460 + $docs_data = get_option( 'cartflows_docs_data' );
461 +
462 + delete_option( 'cartflows_docs_data' );
463 + add_option( 'cartflows_docs_data', $docs_data, '', false );
464 + }
465 +
466 + /**
467 + * Migrate old combined custom script meta to separate JS and CSS meta fields.
468 + *
469 + * Previously, a single textarea accepted both JS and CSS with <script>/<style> tags.
470 + * Now we have separate CodeMirror editors for JS and CSS, so we need to split the
471 + * old combined value into the new separate meta fields.
472 + *
473 + * @since 2.2.2
474 + * @return void
475 + */
476 + public function migrate_custom_scripts() {
477 +
478 + // Migrate step-level custom scripts.
479 + $this->migrate_post_type_scripts(
480 + 'cartflows_step',
481 + 'wcf-custom-script',
482 + 'wcf-step-custom-js',
483 + 'wcf-step-custom-css'
484 + );
485 +
486 + // Migrate flow-level custom scripts.
487 + $this->migrate_post_type_scripts(
488 + 'cartflows_flow',
489 + 'wcf-flow-custom-script',
490 + 'wcf-flow-custom-js',
491 + 'wcf-flow-custom-css'
492 + );
493 + }
494 +
495 + /**
496 + * Migrate custom scripts for a specific post type from old combined meta to separate JS/CSS meta.
497 + *
498 + * @param string $post_type The post type to query.
499 + * @param string $old_meta_key The old combined script meta key.
500 + * @param string $new_js_meta_key The new JS-only meta key.
501 + * @param string $new_css_meta_key The new CSS-only meta key.
502 + *
503 + * @since 2.2.2
504 + * @return void
505 + */
506 + public function migrate_post_type_scripts( $post_type, $old_meta_key, $new_js_meta_key, $new_css_meta_key ) {
507 +
508 + global $wpdb;
509 +
510 + // Get all posts of this type that have the old custom script meta with a non-empty value.
511 + $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
512 + $wpdb->prepare(
513 + "SELECT p.ID, pm.meta_value FROM {$wpdb->posts} p
514 + INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id
515 + WHERE p.post_type = %s AND pm.meta_key = %s AND pm.meta_value != ''
516 + LIMIT 500", // Limit to 500 posts per batch to avoid memory issues.
517 + $post_type,
518 + $old_meta_key
519 + )
520 + );
521 +
522 + if ( empty( $results ) || ! is_array( $results ) ) {
523 + return;
524 + }
525 +
526 + foreach ( $results as $row ) {
527 + $post_id = $row->ID;
528 + $old_value = $row->meta_value;
529 +
530 + // Skip if the new meta fields already have values (don't overwrite manual entries).
531 + $existing_js = get_post_meta( $post_id, $new_js_meta_key, true );
532 + $existing_css = get_post_meta( $post_id, $new_css_meta_key, true );
533 +
534 + if ( ! empty( $existing_js ) || ! empty( $existing_css ) ) {
535 + continue;
536 + }
537 +
538 + // Decode HTML entities first since the old value was stored encoded.
539 + $decoded = html_entity_decode( $old_value, ENT_QUOTES, 'UTF-8' );
540 +
541 + // Extract CSS and JS from the combined script.
542 + $parsed = $this->parse_combined_script( $decoded );
543 +
544 + if ( ! empty( $parsed['css'] ) ) {
545 + // Store encoded with htmlentities to match the FILTER_SCRIPT save format.
546 + update_post_meta( $post_id, $new_css_meta_key, htmlentities( $parsed['css'] ) );
547 + }
548 +
549 + if ( ! empty( $parsed['js'] ) ) {
550 + // Store encoded with htmlentities to match the FILTER_SCRIPT save format.
551 + update_post_meta( $post_id, $new_js_meta_key, htmlentities( $parsed['js'] ) );
552 + }
553 + }
554 + }
555 +
556 + /**
557 + * Parse a combined script string to extract CSS and JS portions.
558 + *
559 + * The old custom script field could contain:
560 + * - <style>...CSS...</style> blocks
561 + * - <script>...JS...</script> blocks
562 + * - Bare JS code (no tags, treated as JS)
563 + *
564 + * @param string $content The combined script content (decoded).
565 + * @return array Associative array with 'js' and 'css' keys.
566 + *
567 + * @since 2.2.2
568 + */
569 + public function parse_combined_script( $content ) {
570 +
571 + $css = '';
572 + $js = '';
573 +
574 + // Extract all <style>...</style> blocks as CSS.
575 + if ( preg_match_all( '/<style[^>]*>(.*?)<\/style>/is', $content, $style_matches ) ) {
576 + $css = trim( implode( "\n", $style_matches[1] ) );
577 + }
578 +
579 + // Extract all <script>...</script> blocks as JS.
580 + if ( preg_match_all( '/<script[^>]*>(.*?)<\/script>/is', $content, $script_matches ) ) {
581 + $js = trim( implode( "\n", $script_matches[1] ) );
582 + }
583 +
584 + // Remove all <style>...</style> and <script>...</script> blocks from the content.
585 + $remaining = preg_replace( '/<style[^>]*>.*?<\/style>/is', '', $content );
586 + if ( null === $remaining ) {
587 + $remaining = '';
588 + }
589 +
590 + $remaining = preg_replace( '/<script[^>]*>.*?<\/script>/is', '', $remaining );
591 + if ( null === $remaining ) {
592 + $remaining = '';
593 + }
594 +
595 + $remaining = trim( $remaining );
596 +
597 + // Any remaining content (not inside tags) is treated as JS.
598 + if ( ! empty( $remaining ) ) {
599 + $js = trim( $js . "\n" . $remaining );
600 + }
601 +
602 + return array(
603 + 'css' => $css,
604 + 'js' => $js,
605 + );
606 + }
607 +
608 + /**
609 + * Init
610 + *
611 + * @since 1.0.0
612 + * @return void
613 + */
614 + public function changed_wp_templates() {
615 +
616 + global $wpdb;
617 +
618 + $query_results = $wpdb->get_results(
619 + $wpdb->prepare(
620 + "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} LEFT JOIN {$wpdb->postmeta} ON ( {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id )
621 + where {$wpdb->posts}.post_type = %s AND {$wpdb->postmeta}.meta_key = %s AND {$wpdb->postmeta}.meta_value != %s AND {$wpdb->postmeta}.meta_value != %s",
622 + 'cartflows_step',
623 + '_wp_page_template',
624 + 'cartflows-canvas',
625 + 'cartflows-default'
626 + )
627 + ); // db call ok; no-cache ok.
628 +
629 + if ( is_array( $query_results ) && ! empty( $query_results ) ) {
630 +
631 + require_once CARTFLOWS_DIR . 'classes/importer/batch-process/class-cartflows-change-template-batch.php';
632 +
633 + wcf()->logger->log( '(✓) Update Templates BATCH Started!' );
634 +
635 + $change_template_batch = new Cartflows_Change_Template_Batch();
636 +
637 + foreach ( $query_results as $query_result ) {
638 +
639 + wcf()->logger->log( '(✓) POST ID ' . $query_result->ID );
640 + $change_template_batch->push_to_queue( $query_result->ID );
641 + }
642 +
643 + $change_template_batch->save()->dispatch();
644 + }
645 + }
70 646 }
71 -
72 647 /**
73 648 * Kicking this off by calling 'get_instance()' method
74 649 */
75 650 Cartflows_Update::get_instance();