run_v2_migration(); } // 2. The Duplicate Cleaner (Runs exactly once, regardless of version number) if ( ! get_option( 'ttdvr_duplicates_cleaned' ) ) { $this->clean_existing_duplicates(); update_option( 'ttdvr_duplicates_cleaned', true ); // Set flag so it never runs again } } /** * Phase 2: Scans the database for legacy duplicate Verification IDs and neutralizes them. */ private function clean_existing_duplicates() { global $wpdb; // Find all duplicated verification IDs in the database $duplicates = $wpdb->get_results( " SELECT meta_value, COUNT(post_id) as count FROM {$wpdb->postmeta} WHERE meta_key = '_ttdvr_verification_id' AND meta_value != '' GROUP BY meta_value HAVING count > 1 " ); $total_neutralized = 0; if ( ! empty( $duplicates ) ) { foreach ( $duplicates as $dup ) { $meta_value = $dup->meta_value; // Get all post IDs sharing this exact Verification ID, ordered oldest to newest $posts = $wpdb->get_col( $wpdb->prepare( " SELECT post_id FROM {$wpdb->postmeta} WHERE meta_key = '_ttdvr_verification_id' AND meta_value = %s ORDER BY post_id ASC ", $meta_value ) ); // Remove the first/oldest document from the array (Keep the Original safe) array_shift( $posts ); // Loop through the remaining fakes/duplicates and rename them permanently $counter = 1; foreach ( $posts as $duplicate_post_id ) { // Example output: CERT-123-DUP-4829-1 $neutralized_id = $meta_value . '-DUP-' . wp_rand( 1000, 9999 ) . '-' . $counter; update_post_meta( $duplicate_post_id, '_ttdvr_verification_id', $neutralized_id ); $total_neutralized++; $counter++; } } } // If we actually caught and fixed duplicates, save a message to show the admin! if ( $total_neutralized > 0 ) { set_transient( 'ttdvr_dup_clean_notice', $total_neutralized, 60 ); } } /** * Execute the v2.0.0 data rescue and migration. */ private function run_v2_migration() { global $wpdb; // 1. RESCUE OLD CUSTOM POST TYPES $wpdb->query( " UPDATE {$wpdb->posts} SET post_type = 'ttdvr_document' WHERE post_type IN ('24tt_document', 'tt_document') " ); // 2. RESCUE OLD TAXONOMIES $wpdb->query( " UPDATE {$wpdb->term_taxonomy} SET taxonomy = 'ttdvr_doc_category' WHERE taxonomy IN ('24tt_doc_category', 'tt_doc_category') " ); // 3. RESCUE OLD META KEYS (Data Fields) $wpdb->query( " UPDATE {$wpdb->postmeta} SET meta_key = REPLACE(meta_key, '_24tt_', '_ttdvr_') WHERE meta_key LIKE '_24tt_%' " ); $wpdb->query( " UPDATE {$wpdb->postmeta} SET meta_key = REPLACE(meta_key, '_tt_', '_ttdvr_') WHERE meta_key LIKE '_tt_%' " ); // 4. PREVENT BROKEN FRONTENDS (Configure the Kill Switch) $all_categories = get_terms( array( 'taxonomy' => 'ttdvr_doc_category', 'hide_empty' => false ) ); if ( ! empty( $all_categories ) && ! is_wp_error( $all_categories ) ) { $cat_ids = wp_list_pluck( $all_categories, 'term_id' ); update_option( 'ttdvr_public_categories', $cat_ids ); } if ( false === get_option( 'ttdvr_show_pdf_link' ) ) { update_option( 'ttdvr_show_pdf_link', 'yes' ); } // 5. FINALIZE MIGRATION flush_rewrite_rules(); update_option( 'ttdvr_db_version', TTDVR_VERSION ); set_transient( 'ttdvr_upgrade_complete', true, 60 ); } /** * Show friendly notices after successful background tasks. */ public function display_upgrade_notice() { // v2.0.0 Upgrade Notice if ( get_transient( 'ttdvr_upgrade_complete' ) ) { echo '
🎉 ' . esc_html__( '24TT Document Verifier successfully upgraded to v2.0.0!', '24tt-document-verifier' ) . '
' . esc_html__( 'Your database and existing documents have been safely migrated to the new enterprise architecture. Please visit "Global Settings" to review your new security features.', '24tt-document-verifier' ) . '
🛡️ ' . esc_html__( 'System Integrity Audit Complete', '24tt-document-verifier' ) . '
' . sprintf( esc_html__( 'We successfully scanned your database and neutralized %d legacy duplicate Document IDs. They have been given a "-DUP-" extension to protect your verification system.', '24tt-document-verifier' ), intval( $cleaned_count ) ) . '