$entry ) { $new_key = self::rename( (string) $category ); if ( $new_key !== $category ) { $changed = true; } // A pre-existing entry under the new key takes precedence. if ( ! isset( $migrated[ $new_key ] ) ) { $migrated[ $new_key ] = $entry; } } if ( $changed ) { update_site_option( self::SOURCE_OPTION, $migrated ); } } /** * Rewrite the `category` column on operator-created abilities. * * Uses a direct query because this runs once, touches a plugin-owned * table, and there is no query-layer method for a bulk column rewrite. * Each owned slug is updated individually so the WHERE clause stays an * exact match rather than a LIKE over an unbounded prefix. * * @since 0.0.34 * @return void */ private static function migrate_db_abilities(): void { global $wpdb; if ( ! isset( $wpdb ) || ! is_object( $wpdb ) ) { return; } $table = $wpdb->prefix . 'acrossai_abilities'; // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared foreach ( self::OWNED as $slug ) { $wpdb->query( $wpdb->prepare( "UPDATE `{$table}` SET category = %s WHERE category = %s", self::NEW_PREFIX . $slug, self::OLD_PREFIX . $slug ) ); } // phpcs:enable if ( function_exists( 'wp_cache_flush' ) ) { wp_cache_flush(); } } /** * Map one category slug to its new form, or return it unchanged. * * @since 0.0.34 * @param string $category Stored category slug. * @return string Renamed slug when owned, otherwise the input. */ private static function rename( string $category ): string { foreach ( self::OWNED as $slug ) { if ( self::OLD_PREFIX . $slug === $category ) { return self::NEW_PREFIX . $slug; } } return $category; } }