PATH:
home
/
thebhoeo
/
public_html
/
booksfinders.com
/
pk__db40bc3
/
wp-content
/
plugins
/
cartflows
/
classes
<?php /** * Update Compatibility * * @package CartFlows */ // Exit if accessed directly. if ( ! defined( 'ABSPATH' ) ) { exit; } if ( ! class_exists( 'Cartflows_Update' ) ) : /** * CartFlows Update initial setup * * @since 1.0.0 */ class Cartflows_Update { /** * Class instance. * * @access private * @var Cartflows_Update|null */ private static $instance; /** * Initiator * * @return Cartflows_Update */ public static function get_instance() { if ( ! isset( self::$instance ) ) { self::$instance = new self(); } return self::$instance; } /** * Constructor */ public function __construct() { add_action( 'admin_init', array( $this, 'init' ) ); } /** * Init * * @since 1.0.0 * @return void */ public function init() { do_action( 'cartflows_update_before' ); // Get auto saved version number. $saved_version = get_option( 'cartflows-version', false ); // Update auto saved version number. if ( ! $saved_version ) { update_option( 'cartflows-version', CARTFLOWS_VER ); return; } // If equals then return. if ( version_compare( $saved_version, CARTFLOWS_VER, '=' ) ) { return; } $this->logger_files(); if ( version_compare( $saved_version, '1.1.22', '<' ) ) { update_option( 'wcf_setup_skipped', true ); } if ( version_compare( $saved_version, '1.2.0', '<' ) ) { $this->changed_wp_templates(); } /* Add legacy admin option */ if ( version_compare( $saved_version, '1.6.0', '<' ) ) { update_option( 'cartflows-old-ui-user', true ); update_option( 'cartflows-legacy-admin', true ); update_option( 'cartflows-legacy-meta-show-design-options', true ); } /* Updating meta for global checkout migration & Permalinks */ if ( version_compare( $saved_version, '1.10.0', '<' ) ) { $global_checkout = \Cartflows_Helper::get_common_setting( 'global_checkout' ); if ( $global_checkout ) { $flow_id = wcf()->utils->get_flow_id_from_step_id( $global_checkout ); if ( $flow_id ) { update_option( '_cartflows_store_checkout', $flow_id ); update_option( '_cartflows_old_global_checkout', $global_checkout ); delete_post_meta( $global_checkout, 'wcf-checkout-products' ); } } update_option( 'cartflows_show_weekly_report_email_notice', 'yes' ); $permalink_settings = Cartflows_Helper::get_admin_settings_option( '_cartflows_permalink', false, false ); if ( ! $permalink_settings ) { $default_settings = array( 'permalink' => CARTFLOWS_STEP_POST_TYPE, 'permalink_flow_base' => CARTFLOWS_FLOW_POST_TYPE, 'permalink_structure' => '', ); Cartflows_Helper::update_admin_settings_option( '_cartflows_permalink', $default_settings ); } } // Update required license key to lowercase. Can be removed after 3 major update. if ( version_compare( $saved_version, '1.11.1', '<' ) && _is_cartflows_pro() ) { $api_key = get_option( 'wc_am_client_CartFlows_api_key' ); $api_key_data = get_option( 'wc_am_client_CartFlows' ); // Take backup of options. update_option( 'cartflows_license_backup_data', array( 'wc_am_client_cartflows_api_key' => $api_key, 'wc_am_client_cartflows' => $api_key_data, ) ); delete_option( 'wc_am_client_CartFlows_api_key' ); delete_option( 'wc_am_client_CartFlows' ); // Delete the cached value for old user ( before v1.11.0 and after v1.11.0 ) so WP can add new value. wp_cache_flush(); if ( $api_key_data ) { $new_data = array( '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'], ); update_option( 'wc_am_client_cartflows', $new_data ); } if ( $api_key ) { update_option( 'wc_am_client_cartflows_api_key', $api_key ); } } // Set default page builder to "Other" for those who have set it as "DIVI". if ( version_compare( $saved_version, '2.0.0', '<' ) ) { $common_settings = get_option( '_cartflows_common', array() ); if ( is_array( $common_settings ) && 'divi' === $common_settings['default_page_builder'] ) { $common_settings['default_page_builder'] = 'elementor'; update_option( '_cartflows_common', $common_settings ); } } // Migrate old combined custom script meta to separate JS and CSS meta fields. if ( version_compare( $saved_version, '2.2.2', '<' ) ) { $this->migrate_custom_scripts(); } // 3.0 ships a redesigned admin UI. Existing users (saved_version < 3.0.0) keep the // legacy admin until they opt into the new UI from the in-app notice or the // Advanced-tab toggle. Saved as 'enable' to match the toggle's backComp format // so the field round-trips correctly. Fresh installs short-circuit at the // `! $saved_version` early return above and default to the new UI. if ( is_string( $saved_version ) && version_compare( $saved_version, '3.0.0', '<' ) ) { update_option( 'cartflows-legacy-admin', 'enable' ); } // Update auto saved version number. update_option( 'cartflows-version', CARTFLOWS_VER ); // Update cartflows asset version to regenerate the dynamic css. We are using the time() function to add the random number. update_option( 'cartflows-assets-version', time() ); do_action( 'cartflows_update_after' ); } /** * Loading logger files. * * @since 1.0.0 * @return void */ public function logger_files() { if ( ! defined( 'CARTFLOWS_LOG_DIR' ) ) { $upload_dir = wp_upload_dir( null, false ); define( 'CARTFLOWS_LOG_DIR', $upload_dir['basedir'] . '/cartflows-logs/' ); } wcf()->create_files(); } /** * Set script migration status. * * @param string $status Migration status value. * @since 2.2.2 * @return void */ public function set_script_migration_status( $status ) { update_option( 'cartflows_script_migration_status', $status ); } /** * Determine if the migration notice should be shown. * * Returns false if migration is completed or accepted. * Returns false if status is 'skipped' and 7 days have not yet passed. * Returns false if no old script values exist (auto-sets status to 'completed'). * * @since 2.2.2 * @return bool */ public function should_show_migration_notice() { $status = \CartFlows_Helper::get_script_migration_status(); if ( 'completed' === $status || 'accepted' === $status ) { return false; } if ( 'skipped' === $status ) { $skip_timestamp = (int) get_option( 'cartflows_script_migration_skip_timestamp', 0 ); // Show again only after 7 days have passed since last skip. if ( ( time() - $skip_timestamp ) < WEEK_IN_SECONDS ) { return false; } } // Check cached result first to avoid running the meta query on every page load. $has_old_scripts = get_option( 'cartflows_has_old_custom_scripts', '' ); if ( '' === $has_old_scripts ) { // First time check — run the query once and cache the result. $has_old_scripts = $this->has_old_custom_scripts() ? 'yes' : 'no'; update_option( 'cartflows_has_old_custom_scripts', $has_old_scripts, true ); } // If no old script values exist, auto-complete migration and enable the code editor. if ( 'yes' !== $has_old_scripts ) { $this->set_script_migration_status( 'completed' ); return false; } return true; } /** * Check if any posts have old combined custom script meta values. * * Queries the database for any cartflows_step or cartflows_flow posts * that have non-empty 'wcf-custom-script' or 'wcf-flow-custom-script' meta. * * @since 2.2.3 * @return bool True if old script data exists, false otherwise. */ public function has_old_custom_scripts() { global $wpdb; $result = $wpdb->get_var( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( "SELECT 1 FROM {$wpdb->postmeta} pm INNER JOIN {$wpdb->posts} p ON pm.post_id = p.ID WHERE p.post_type IN (%s, %s) AND pm.meta_key IN (%s, %s) AND pm.meta_value != '' LIMIT 1", 'cartflows_step', 'cartflows_flow', 'wcf-custom-script', 'wcf-flow-custom-script' ) ); return ( null !== $result ); } /** * Get current migration skip count. * * @since 2.2.2 * @return int */ public function get_migration_skip_count() { return (int) get_option( 'cartflows_script_migration_skip_count', 0 ); } /** * Increment migration skip count and record the skip timestamp. * * @since 2.2.2 * @return void */ public function increment_migration_skip_count() { $count = $this->get_migration_skip_count(); update_option( 'cartflows_script_migration_skip_count', $count + 1 ); update_option( 'cartflows_script_migration_skip_timestamp', time() ); } /** * Run on-demand migration of custom scripts triggered by user action. * * Unlike migrate_custom_scripts() which runs during version updates, * this method is called only when the user explicitly clicks "Migrate Data" * in the admin notice. It returns a count of migrated posts and updates * the migration status to 'completed'. * * @since 2.2.2 * @return int Number of posts that had data migrated. */ public function migrate_custom_scripts_on_demand() { $migrated_count = 0; // Migrate step-level custom scripts. $migrated_count += $this->migrate_post_type_scripts_counted( 'cartflows_step', 'wcf-custom-script', 'wcf-step-custom-js', 'wcf-step-custom-css' ); // Migrate flow-level custom scripts. $migrated_count += $this->migrate_post_type_scripts_counted( 'cartflows_flow', 'wcf-flow-custom-script', 'wcf-flow-custom-js', 'wcf-flow-custom-css' ); $this->set_script_migration_status( 'completed' ); return $migrated_count; } /** * Migrate custom scripts for a specific post type and return the count of migrated posts. * * @param string $post_type The post type to query. * @param string $old_meta_key The old combined script meta key. * @param string $new_js_meta_key The new JS-only meta key. * @param string $new_css_meta_key The new CSS-only meta key. * * @since 2.2.2 * @return int Number of posts migrated. */ public function migrate_post_type_scripts_counted( $post_type, $old_meta_key, $new_js_meta_key, $new_css_meta_key ) { global $wpdb; $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( "SELECT p.ID, pm.meta_value FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id WHERE p.post_type = %s AND pm.meta_key = %s AND pm.meta_value != '' LIMIT 500", $post_type, $old_meta_key ) ); if ( empty( $results ) || ! is_array( $results ) ) { return 0; } $migrated = 0; foreach ( $results as $row ) { $post_id = $row->ID; $old_value = $row->meta_value; // Skip if the new meta fields already have values (don't overwrite manual entries). $existing_js = get_post_meta( $post_id, $new_js_meta_key, true ); $existing_css = get_post_meta( $post_id, $new_css_meta_key, true ); if ( ! empty( $existing_js ) || ! empty( $existing_css ) ) { continue; } // Decode HTML entities first since the old value was stored encoded. $decoded = html_entity_decode( $old_value, ENT_QUOTES, 'UTF-8' ); // Extract CSS and JS from the combined script. $parsed = $this->parse_combined_script( $decoded ); $did_migrate = false; if ( ! empty( $parsed['css'] ) ) { update_post_meta( $post_id, $new_css_meta_key, htmlentities( $parsed['css'] ) ); $did_migrate = true; } if ( ! empty( $parsed['js'] ) ) { update_post_meta( $post_id, $new_js_meta_key, htmlentities( $parsed['js'] ) ); $did_migrate = true; } if ( $did_migrate ) { ++$migrated; } } return $migrated; } /** * Migrate old combined custom script meta to separate JS and CSS meta fields. * * Previously, a single textarea accepted both JS and CSS with <script>/<style> tags. * Now we have separate CodeMirror editors for JS and CSS, so we need to split the * old combined value into the new separate meta fields. * * @since 2.2.2 * @return void */ public function migrate_custom_scripts() { // Migrate step-level custom scripts. $this->migrate_post_type_scripts( 'cartflows_step', 'wcf-custom-script', 'wcf-step-custom-js', 'wcf-step-custom-css' ); // Migrate flow-level custom scripts. $this->migrate_post_type_scripts( 'cartflows_flow', 'wcf-flow-custom-script', 'wcf-flow-custom-js', 'wcf-flow-custom-css' ); } /** * Migrate custom scripts for a specific post type from old combined meta to separate JS/CSS meta. * * @param string $post_type The post type to query. * @param string $old_meta_key The old combined script meta key. * @param string $new_js_meta_key The new JS-only meta key. * @param string $new_css_meta_key The new CSS-only meta key. * * @since 2.2.2 * @return void */ public function migrate_post_type_scripts( $post_type, $old_meta_key, $new_js_meta_key, $new_css_meta_key ) { global $wpdb; // Get all posts of this type that have the old custom script meta with a non-empty value. $results = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching $wpdb->prepare( "SELECT p.ID, pm.meta_value FROM {$wpdb->posts} p INNER JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id WHERE p.post_type = %s AND pm.meta_key = %s AND pm.meta_value != '' LIMIT 500", // Limit to 500 posts per batch to avoid memory issues. $post_type, $old_meta_key ) ); if ( empty( $results ) || ! is_array( $results ) ) { return; } foreach ( $results as $row ) { $post_id = $row->ID; $old_value = $row->meta_value; // Skip if the new meta fields already have values (don't overwrite manual entries). $existing_js = get_post_meta( $post_id, $new_js_meta_key, true ); $existing_css = get_post_meta( $post_id, $new_css_meta_key, true ); if ( ! empty( $existing_js ) || ! empty( $existing_css ) ) { continue; } // Decode HTML entities first since the old value was stored encoded. $decoded = html_entity_decode( $old_value, ENT_QUOTES, 'UTF-8' ); // Extract CSS and JS from the combined script. $parsed = $this->parse_combined_script( $decoded ); if ( ! empty( $parsed['css'] ) ) { // Store encoded with htmlentities to match the FILTER_SCRIPT save format. update_post_meta( $post_id, $new_css_meta_key, htmlentities( $parsed['css'] ) ); } if ( ! empty( $parsed['js'] ) ) { // Store encoded with htmlentities to match the FILTER_SCRIPT save format. update_post_meta( $post_id, $new_js_meta_key, htmlentities( $parsed['js'] ) ); } } } /** * Parse a combined script string to extract CSS and JS portions. * * The old custom script field could contain: * - <style>...CSS...</style> blocks * - <script>...JS...</script> blocks * - Bare JS code (no tags, treated as JS) * * @param string $content The combined script content (decoded). * @return array Associative array with 'js' and 'css' keys. * * @since 2.2.2 */ public function parse_combined_script( $content ) { $css = ''; $js = ''; // Extract all <style>...</style> blocks as CSS. if ( preg_match_all( '/<style[^>]*>(.*?)<\/style>/is', $content, $style_matches ) ) { $css = trim( implode( "\n", $style_matches[1] ) ); } // Extract all <script>...</script> blocks as JS. if ( preg_match_all( '/<script[^>]*>(.*?)<\/script>/is', $content, $script_matches ) ) { $js = trim( implode( "\n", $script_matches[1] ) ); } // Remove all <style>...</style> and <script>...</script> blocks from the content. $remaining = preg_replace( '/<style[^>]*>.*?<\/style>/is', '', $content ); if ( null === $remaining ) { $remaining = ''; } $remaining = preg_replace( '/<script[^>]*>.*?<\/script>/is', '', $remaining ); if ( null === $remaining ) { $remaining = ''; } $remaining = trim( $remaining ); // Any remaining content (not inside tags) is treated as JS. if ( ! empty( $remaining ) ) { $js = trim( $js . "\n" . $remaining ); } return array( 'css' => $css, 'js' => $js, ); } /** * Init * * @since 1.0.0 * @return void */ public function changed_wp_templates() { global $wpdb; $query_results = $wpdb->get_results( $wpdb->prepare( "SELECT {$wpdb->posts}.ID FROM {$wpdb->posts} LEFT JOIN {$wpdb->postmeta} ON ( {$wpdb->posts}.ID = {$wpdb->postmeta}.post_id ) where {$wpdb->posts}.post_type = %s AND {$wpdb->postmeta}.meta_key = %s AND {$wpdb->postmeta}.meta_value != %s AND {$wpdb->postmeta}.meta_value != %s", 'cartflows_step', '_wp_page_template', 'cartflows-canvas', 'cartflows-default' ) ); // db call ok; no-cache ok. if ( is_array( $query_results ) && ! empty( $query_results ) ) { require_once CARTFLOWS_DIR . 'classes/importer/batch-process/class-cartflows-change-template-batch.php'; wcf()->logger->log( '(✓) Update Templates BATCH Started!' ); $change_template_batch = new Cartflows_Change_Template_Batch(); foreach ( $query_results as $query_result ) { wcf()->logger->log( '(✓) POST ID ' . $query_result->ID ); $change_template_batch->push_to_queue( $query_result->ID ); } $change_template_batch->save()->dispatch(); } } } /** * Kicking this off by calling 'get_instance()' method */ Cartflows_Update::get_instance(); endif;
[-] class-cartflows-logger.php
[edit]
[+]
logger
[-] class-cartflows-utils.php
[edit]
[-] class-cartflows-functions.php
[edit]
[-] class-cartflows-admin.php
[edit]
[+]
deprecated
[-] class-cartflows-default-meta.php
[edit]
[-] class-cartflows-tracking.php
[edit]
[-] class-cartflows-rollback.php
[edit]
[-] class-cartflows-update.php
[edit]
[-] class-cartflows-frontend.php
[edit]
[-] class-cartflows-flow-frontend.php
[edit]
[+]
..
[-] class-cartflows-loader.php
[edit]
[-] index.php
[edit]
[-] class-cartflows-analytics.php
[edit]
[+]
fields
[-] class-cartflows-admin-notices.php
[edit]
[-] class-cartflows-step-factory.php
[edit]
[-] class-cartflows-dashboard-widget.php
[edit]
[-] class-cartflows-woo-hooks.php
[edit]
[+]
importer
[-] class-cartflows-helper.php
[edit]