plugin_data(); $this->maybe_migrate_hpos_data(); } /** * Save Plugin's Data */ public function plugin_data() { $old_version = Helper::get_option( 'bdpg_version', '1.0.0' ); Helper::update_option( 'bdpg_version', BD_PAYMENT_GATEWAYS_VERSION ); $installed_time = Helper::get_option( 'bdpg_installed_datetime', false ); if ( ! $installed_time ) { Helper::update_option( 'bdpg_installed_datetime', current_time( 'timestamp' ) ); // phpcs:ignore } // Trigger migration if version changed. if ( version_compare( $old_version, '4.0.4', '<' ) ) { $this->migrate_hpos_data(); } } /** * Check if HPOS migration is needed and run it. * * @return void */ public function maybe_migrate_hpos_data() { $migration_version = get_option( self::HPOS_MIGRATION_VERSION, '0' ); if ( version_compare( $migration_version, self::CURRENT_HPOS_MIGRATION_VERSION, '<' ) ) { $this->migrate_hpos_data(); update_option( self::HPOS_MIGRATION_VERSION, self::CURRENT_HPOS_MIGRATION_VERSION ); } } /** * Migrate post meta to order meta for HPOS compatibility. * This ensures all existing payment data is copied to HPOS tables. * * @return void */ public function migrate_hpos_data() { // Use Action Scheduler for background migration if available. if ( function_exists( 'as_schedule_single_action' ) ) { $this->schedule_migration(); } else { // Fallback to direct migration if Action Scheduler not available. $this->process_migration_batch(); } } /** * Schedule HPOS migration using Action Scheduler. * * @return void */ public function schedule_migration() { // Check if migration is already scheduled or running. if ( $this->is_migration_scheduled() || $this->is_migration_running() ) { return; } // Initialize migration progress. $this->initialize_migration_progress(); // Schedule the migration to run in the background. as_schedule_single_action( time() + 10, 'bdpg_hpos_migration_batch', array(), 'bdpg_hpos_migration' ); } /** * Initialize migration progress tracking. * * @return void */ private function initialize_migration_progress() { $gateways = array( 'bkash', 'rocket', 'nagad', 'upay' ); $total_orders = 0; // Calculate total orders to process (only count orders with data to migrate). foreach ( $gateways as $gateway ) { $args = array( 'limit' => -1, 'type' => 'shop_order', 'status' => array( 'any' ), 'return' => 'ids', ); $order_ids = wc_get_orders( $args ); foreach ( $order_ids as $order_id ) { $order = wc_get_order( $order_id ); if ( $order && 'woo_' . $gateway === $order->get_payment_method() ) { // Only count if there's data to migrate. $number = get_post_meta( $order_id, 'woo_' . $gateway . '_number', true ); $trans_id = get_post_meta( $order_id, 'woo_' . $gateway . '_trans_id', true ); if ( ! empty( $number ) || ! empty( $trans_id ) ) { ++$total_orders; } } } } // Initialize migration status options. update_option( 'bdpg_hpos_migration_status', 'pending' ); update_option( 'bdpg_hpos_migration_total', $total_orders ); update_option( 'bdpg_hpos_migration_processed', 0 ); update_option( 'bdpg_hpos_migration_gateway', '' ); update_option( 'bdpg_hpos_migration_last_offset', 0 ); update_option( 'bdpg_hpos_migration_start_time', current_time( 'timestamp' ) ); } /** * Process a batch of HPOS migration. * This method is called by Action Scheduler. * * @return void */ public function process_migration_batch() { // Mark migration as running. update_option( 'bdpg_hpos_migration_status', 'running' ); $gateways = array( 'bkash', 'rocket', 'nagad', 'upay' ); $batch_size = 50; $processed_in_batch = 0; $found_gateway_orders = false; // Get current migration state. $current_gateway = get_option( 'bdpg_hpos_migration_gateway', '' ); $last_offset = intval( get_option( 'bdpg_hpos_migration_last_offset', 0 ) ); $total_processed = intval( get_option( 'bdpg_hpos_migration_processed', 0 ) ); // Determine which gateway to process. if ( empty( $current_gateway ) ) { $current_gateway = $gateways[0]; update_option( 'bdpg_hpos_migration_gateway', $current_gateway ); $last_offset = 0; } // Process current gateway. $args = array( 'limit' => $batch_size, 'offset' => $last_offset, 'type' => 'shop_order', 'status' => array( 'any' ), 'return' => 'ids', ); $order_ids = wc_get_orders( $args ); foreach ( $order_ids as $order_id ) { $order = wc_get_order( $order_id ); if ( ! $order ) { continue; } // Check if this order used our gateway. if ( 'woo_' . $current_gateway !== $order->get_payment_method() ) { continue; } // Mark that we found at least one gateway order in this batch. $found_gateway_orders = true; // Get post meta data. $number = get_post_meta( $order_id, 'woo_' . $current_gateway . '_number', true ); $trans_id = get_post_meta( $order_id, 'woo_' . $current_gateway . '_trans_id', true ); // Skip if no data to migrate. if ( empty( $number ) && empty( $trans_id ) ) { continue; } // Migrate to order meta (works for both HPOS and compatibility mode). if ( ! empty( $number ) ) { $order->update_meta_data( 'woo_' . $current_gateway . '_number', $number ); } if ( ! empty( $trans_id ) ) { $order->update_meta_data( 'woo_' . $current_gateway . '_trans_id', $trans_id ); } $order->save_meta_data(); ++$processed_in_batch; ++$total_processed; } // Update progress. $new_offset = $last_offset + $batch_size; update_option( 'bdpg_hpos_migration_last_offset', $new_offset ); update_option( 'bdpg_hpos_migration_processed', $total_processed ); // Check if we need to move to next gateway or continue. // If we found gateway orders in this batch and got a full batch of orders, there might be more. $has_more_orders = $found_gateway_orders && count( $order_ids ) === $batch_size; if ( ! $has_more_orders ) { // Move to next gateway. $gateway_index = array_search( $current_gateway, $gateways, true ); if ( false !== $gateway_index && isset( $gateways[ $gateway_index + 1 ] ) ) { update_option( 'bdpg_hpos_migration_gateway', $gateways[ $gateway_index + 1 ] ); update_option( 'bdpg_hpos_migration_last_offset', 0 ); // Schedule next batch. as_schedule_single_action( time() + 5, 'bdpg_hpos_migration_batch', array(), 'bdpg_hpos_migration' ); } else { // Migration complete. $this->complete_migration(); } } else { // Schedule next batch. as_schedule_single_action( time() + 5, 'bdpg_hpos_migration_batch', array(), 'bdpg_hpos_migration' ); } } /** * Mark migration as complete. * * @return void */ private function complete_migration() { update_option( 'bdpg_hpos_migration_status', 'completed' ); update_option( 'bdpg_hpos_migration_end_time', current_time( 'timestamp' ) ); // Clear Action Scheduler group. if ( function_exists( 'as_unschedule_all_actions' ) ) { as_unschedule_all_actions( 'bdpg_hpos_migration_batch', array(), 'bdpg_hpos_migration' ); } } /** * Check if migration is scheduled. * * @return bool */ public function is_migration_scheduled() { if ( ! function_exists( 'as_has_scheduled_action' ) ) { return false; } return as_has_scheduled_action( 'bdpg_hpos_migration_batch', array(), 'bdpg_hpos_migration' ); } /** * Check if migration is currently running. * * @return bool */ public function is_migration_running() { $status = get_option( 'bdpg_hpos_migration_status', '' ); return 'running' === $status; } /** * Get migration progress data. * * @return array Migration progress data. */ public function get_migration_progress() { $total = intval( get_option( 'bdpg_hpos_migration_total', 0 ) ); $processed = intval( get_option( 'bdpg_hpos_migration_processed', 0 ) ); $status = get_option( 'bdpg_hpos_migration_status', '' ); $current_gateway = get_option( 'bdpg_hpos_migration_gateway', '' ); $start_time = get_option( 'bdpg_hpos_migration_start_time', 0 ); $end_time = get_option( 'bdpg_hpos_migration_end_time', 0 ); $percentage = $total > 0 ? round( ( $processed / $total ) * 100, 2 ) : 0; return array( 'status' => $status, 'total' => $total, 'processed' => $processed, 'percentage' => $percentage, 'current_gateway' => $current_gateway, 'is_scheduled' => $this->is_migration_scheduled(), 'is_running' => $this->is_migration_running(), 'start_time' => $start_time ? date_i18n( 'Y-m-d H:i:s', $start_time ) : '-', 'end_time' => $end_time ? date_i18n( 'Y-m-d H:i:s', $end_time ) : '-', ); } /** * Reset migration data. * * @return void */ public function reset_migration() { delete_option( 'bdpg_hpos_migration_status' ); delete_option( 'bdpg_hpos_migration_total' ); delete_option( 'bdpg_hpos_migration_processed' ); delete_option( 'bdpg_hpos_migration_gateway' ); delete_option( 'bdpg_hpos_migration_last_offset' ); delete_option( 'bdpg_hpos_migration_start_time' ); delete_option( 'bdpg_hpos_migration_end_time' ); // Clear Action Scheduler group. if ( function_exists( 'as_unschedule_all_actions' ) ) { as_unschedule_all_actions( 'bdpg_hpos_migration_batch', array(), 'bdpg_hpos_migration' ); } } /** * Register Action Scheduler hook for migration. * * @return void */ public function register_migration_hook() { add_action( 'bdpg_hpos_migration_batch', array( $this, 'process_migration_batch' ) ); } /** * Activation Redirect */ public function activation_redirect() { if ( get_option( 'bdpg_do_activation_redirect', false ) ) { delete_option( 'bdpg_do_activation_redirect' ); wp_safe_redirect( admin_url( 'admin.php?page=' . BD_PAYMENT_GATEWAYS_MENU_SLUG ) ); exit(); } } }