check(); return; } if ( isset( $assoc['status'] ) ) { $this->print_state( Saddle_Analytics_Migrate::state() ); return; } if ( isset( $assoc['dry-run'] ) ) { $this->dry_run(); return; } if ( isset( $assoc['retry'] ) ) { Saddle_Analytics_Migrate::retry(); } if ( ! Saddle_Analytics_Migrate::queue_if_needed() && 'done' !== ( Saddle_Analytics_Migrate::state()['status'] ?? '' ) ) { WP_CLI::success( 'No Loggle data on this site — nothing to migrate.' ); return; } $state = Saddle_Analytics_Migrate::run( 0.0 ); $this->print_state( $state ); if ( 'done' === ( $state['status'] ?? '' ) ) { WP_CLI::success( 'Loggle data is now in Saddle Analytics.' ); } elseif ( 'failed' === ( $state['status'] ?? '' ) ) { WP_CLI::error( 'Migration failed: ' . ( $state['error'] ?? 'unknown error' ) . ' Your Loggle data is untouched; fix the cause and run with --retry.' ); } else { WP_CLI::warning( 'Another request holds the migration lock. Try again in a moment.' ); } } /** The "no trace" proof: zero rows or a non-zero exit. */ private function check(): void { $left = Saddle_Analytics_Migrate_Cleanup::leftovers(); $file = Saddle_Analytics_Migrate_Cleanup::plugin_file(); if ( $left ) { \WP_CLI\Utils\format_items( 'table', $left, array( 'type', 'name', 'count' ) ); } if ( $file ) { WP_CLI::log( "Note: Loggle's plugin files are still installed ({$file}). Delete Loggle from the Plugins screen; its uninstall no longer touches any data." ); } WP_CLI::log( 'Note: browsers are outside the database — a returning visitor\'s old Loggle cookies are expired on their next visit, and Loggle\'s saved dashboard range in an admin\'s browser on their next admin load.' ); if ( $left ) { WP_CLI::error( count( $left ) . ' Loggle trace(s) left in the database.' ); } WP_CLI::success( 'No Loggle trace left in the database.' ); } private function dry_run(): void { global $wpdb; $old = Saddle_Analytics_Migrate_Tables::old_tables(); if ( ! Saddle_Analytics_Migrate::detect() ) { WP_CLI::log( 'No Loggle data found.' ); return; } $rows = array(); foreach ( $old as $name => $table ) { $rows[] = array( 'table' => $table, 'rows' => (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $table ) ), 'to' => Saddle_Analytics_Install::tables()[ $name ], ); } $ledger = $wpdb->prefix . 'loggle_conversions'; if ( $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $wpdb->esc_like( $ledger ) ) ) ) { $rows[] = array( 'table' => $ledger, 'rows' => (int) $wpdb->get_var( $wpdb->prepare( 'SELECT COUNT(*) FROM %i', $ledger ) ), 'to' => '(dropped — revenue and goals are not in Saddle Analytics)', ); } \WP_CLI\Utils\format_items( 'table', $rows, array( 'table', 'rows', 'to' ) ); WP_CLI::log( 'strategy: ' . ( Saddle_Analytics_Migrate_Tables::is_sqlite() ? 'copy (SQLite cannot rename tables)' : 'rename (falls back to copy if targets exist or RENAME fails)' ) ); $old_settings = get_option( 'loggle_settings', array() ); $mapped = Saddle_Analytics_Migrate::map_settings( is_array( $old_settings ) ? $old_settings : array(), (int) apply_filters( 'loggle_hits_retention', 90 ) ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- Loggle's filter, read for the dry run. WP_CLI::log( 'settings: ' . wp_json_encode( $mapped ) ); WP_CLI::log( 'delete data on uninstall: ' . ( get_option( 'loggle_delete_data_on_uninstall' ) ? 'yes' : 'no' ) ); } private function print_state( array $state ): void { if ( ! $state ) { WP_CLI::log( 'No migration recorded.' ); return; } $counts = (array) ( $state['counts'] ?? array() ); \WP_CLI\Utils\format_items( 'table', array( array( 'status' => $state['status'] ?? '', 'step' => $state['step'] ?? '', 'strategy' => $state['strategy'] ?? '—', 'visitors' => $counts['visitors'] ?? 0, 'hits' => $counts['hits'] ?? 0, 'crawlers' => $counts['crawlers'] ?? 0, 'error' => $state['error'] ?? '', ), ), array( 'status', 'step', 'strategy', 'visitors', 'hits', 'crawlers', 'error' ) ); } }