ion process_step() { // Since this hooks on an action, don't let it run if we're not in a cron. if ( ! edd_doing_cron() ) { return; } global $wpdb; $meta_rows = $wpdb->get_results( "SELECT meta_id, edd_order_id, meta_value FROM {$this->get_meta_table_name()} WHERE meta_key = '_edd_complete_actions_run' ORDER BY edd_order_id DESC LIMIT 500" ); edd_debug_log( 'Found records to migrate (max 500): ' . count( $meta_rows ) ); // If we don't have anymore items to process, mark it as complete. if ( empty( $meta_rows ) ) { $this->mark_complete(); return; } // Iterate through the meta rows and update the order. $migrated_meta_ids = array(); $migrated_note_ids = array(); // We don't need to schedule a recalculation here. add_filter( 'edd_recalculate_bypass_cron', '__return_true' ); foreach ( $meta_rows as $row ) { // Convert the timestamp to a DateTime object. $date = new Date(); $date->setTimestamp( $row->meta_value )->setTimezone( new \DateTimeZone( 'UTC' ) ); // Update the order. $updated = edd_update_order( $row->edd_order_id, array( 'date_actions_run' => $date->format( 'mysql' ) ) ); if ( $updated ) { // Store the meta ids we can remove. $migrated_meta_ids[] = $row->meta_id; // Store the note ids we can remove. $note_content = __( 'After payment actions processed.', 'easy-digital-downloads' ); $note_id = $wpdb->get_var( "SELECT id FROM {$this->get_notes_table_name()} WHERE object_id = {$row->edd_order_id} AND object_type = 'order' AND content = '{$note_content}'" ); if ( $note_id ) { $migrated_note_ids[] = $note_id; } } } // Remove our filter for bypassing the cron. remove_filter( 'edd_recalculate_bypass_cron', '__return_true' ); $migrated_meta_ids = array_filter( $migrated_meta_ids ); // If we have any migrated meta IDs, delete them. if ( ! empty( $migrated_meta_ids ) ) { // Delete the meta rows we just migrated. $wpdb->query( "DELETE FROM {$this->get_meta_table_name()} WHERE meta_id IN (" . implode( ',', $migrated_meta_ids ) . ')' ); } $migrated_note_ids = array_filter( $migrated_note_ids ); // If we found notes to delete, delete them. if ( ! empty( $migrated_note_ids ) ) { $wpdb->query( "DELETE FROM {$this->get_notes_table_name()} WHERE id IN (" . implode( ',', $migrated_note_ids ) . ')' ); } $this->add_or_update_initial_notification(); $percent_complete = $this->get_percentage_complete(); edd_debug_log( 'Processed step of order actions date migration. Percentage Complete: ' . $percent_complete . '%' ); // ...And schedule another single event so we can process the next batch. wp_schedule_single_event( time() + MINUTE_IN_SECONDS, 'edd_migrate_order_actions_date' ); } /** * Marks the migration as complete. * * @since 3.2.0 * * @param bool $add_notification If we should add a notification that the migration is complete. * * @return void */ private function mark_complete( $add_notification = true ) { // Set the upgrade as complete. edd_set_upgrade_complete( 'migrate_order_actions_date' ); // Delete the total count option. It may not exist, but we should delete it anyway. delete_option( $this->total_count_option ); if ( false === $add_notification ) { return; } $initial_notification = $this->get_initial_notification(); if ( ! empty( $initial_notification ) ) { EDD()->notifications->update( $initial_notification->id, array( 'dismissed' => 1 ) ); } EDD()->notifications->maybe_add_local_notification( array( 'remote_id' => $this->complete_remote_id, 'buttons' => '', 'conditions' => '', 'type' => 'success', 'title' => __( 'Order Table Optimization Complete!', 'easy-digital-downloads' ), 'content' => __( 'Easy Digital Downloads has finished updating your orders database! Thank you for your patience.', 'easy-digital-downloads' ), ) ); } /** * Gets the initial notification about the migration. * * @since 3.2.0 * * @return object */ private function get_initial_notification() { return EDD()->notifications->get_item_by( 'remote_id', $this->in_progress_remote_id ); } /** * Adds or updates the initial notification about the migration. * * @since 3.2.0 * * @return void */ private function add_or_update_initial_notification() { $initial_notification = $this->get_initial_notification(); $percent_complete = $this->get_percentage_complete(); // translators: %s is the % complete. $notification_title = sprintf( __( 'Optimizing Orders Table ( %d%% )', 'easy-digital-downloads' ), $percent_complete ); if ( ! empty( $initial_notification ) ) { $date = new Date(); $date->setTimestamp( time() )->setTimezone( new \DateTimeZone( 'UTC' ) ); // Update the notification. EDD()->notifications->update( $initial_notification->id, array( 'title' => $notification_title, 'date_created' => $date->format( 'mysql' ), ) ); } else { // Add the notification. EDD()->notifications->maybe_add_local_notification( array( 'remote_id' => $this->in_progress_remote_id, 'buttons' => '', 'conditions' => '', 'type' => 'info', 'title' => $notification_title, 'content' => __( 'Easy Digital Downloads is updating the Orders and Order Meta table in the background. This process may take a while to complete depending on the number of orders you have. We\'ll let you know when the process is complete.', 'easy-digital-downloads' ), ) ); } } /** * Gets the name of the order meta table. * * @since 3.2.0 * * @return string */ private function get_meta_table_name() { $order_meta_table = new \EDD\Database\Tables\Order_Meta(); return $order_meta_table->table_name; } /** * Gets the name of the notes table. * * @since 3.2.0 * * @return string */ private function get_notes_table_name() { $notes_table = new \EDD\Database\Tables\Notes(); return $notes_table->table_name; } /** * Gets the percentage complete. * * @since 3.2.0 * * @return int */ private function get_percentage_complete() { static $percent_complete; if ( ! is_null( $percent_complete ) ) { return $percent_complete; } global $wpdb; // Get the total amount of rows remaining. $total_rows_remaining = $wpdb->get_var( "SELECT COUNT(*) FROM {$this->get_meta_table_name()} WHERE meta_key = '_edd_complete_actions_run'" ); // Get the total we started with. $total_rows_start = get_option( $this->total_count_option ); // Format a % complete without decimals. $percent_complete = number_format( ( ( $total_rows_start - $total_rows_remaining ) / $total_rows_start ) * 100, 0 ); // Just in case we end up over 100%, somehow...make it 100%; if ( $percent_complete > 100 ) { $percent_complete = 100; } return $percent_complete; } }