PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 0.9.5
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v0.9.5
1.1.10 1.1.9 1.1.8 1.1.7 1.1.6 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.1 1.0.0 0.9.8 0.9.7 0.9.6 0.9.4 0.9.5 0.9.3 0.9.2 0.9.1 0.9.0 0.8.9 0.8.8 0.8.7 All 34 releases
desktop-mode / includes / migrations.php

migrations.php in OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin 0.9.5, at includes/migrations.php

223 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Desktop Mode — one-time data migrations.
4 *
5 * A tiny, option-versioned migration runner modeled on the lazy schema
6 * installer in `includes/desktop-files/schema.php`: a stored option holds
7 * the highest migration version that has run; on every admin load we
8 * compare it against {@see DESKTOP_MODE_MIGRATION_VERSION} and run any
9 * pending migrations exactly once. Guarded so it is a cheap no-op after
10 * the first successful pass.
11 *
12 * @package WPDesktopMode
13 */
14
15 defined( 'ABSPATH' ) || exit;
16
17 /**
18 * Highest migration version shipped by the plugin.
19 *
20 * Bump this (and add a matching branch in
21 * {@see desktop_mode_run_pending_migrations}) whenever a new one-time
22 * migration is needed.
23 *
24 * - 1: native list windows flipped from opt-out (default ON) to opt-in
25 * Beta (default OFF). Clears the five `native*Enabled` flags from every
26 * user who had them persisted so the whole install reverts to opt-in.
27 * - 2: post & taxonomy-term AI analysis was removed (the copilot now only
28 * analyzes comments for spam, and the assistant finds content via native
29 * WordPress search). Unschedules any queued `desktop_mode_ai_analyze_post`
30 * / `desktop_mode_ai_analyze_term` cron events left over from prior versions.
31 * - 3: the copilot dropped its self-managed AI credentials in favour of
32 * WordPress 7.0 Connectors. Deletes the platform key option and strips the
33 * per-user `apiKey` / `apiKeys` / `provider` / `transport` fields from the
34 * stored OS settings so no provider secret lingers in the database.
35 *
36 * @since 0.9.1
37 */
38 const DESKTOP_MODE_MIGRATION_VERSION = 3;
39
40 /** Option storing the highest migration version that has run. autoload=no. */
41 const DESKTOP_MODE_MIGRATION_OPTION = 'desktop_mode_migration_version';
42
43 /**
44 * Runs any pending migrations, then records the new high-water mark.
45 *
46 * Idempotent: bails immediately when the stored version is already at
47 * or above the shipped version, so it is safe to fire on every request.
48 *
49 * @since 0.9.1
50 *
51 * @return void
52 */
53 function desktop_mode_maybe_run_migrations() {
54 $installed = (int) get_option( DESKTOP_MODE_MIGRATION_OPTION, 0 );
55 if ( $installed >= DESKTOP_MODE_MIGRATION_VERSION ) {
56 return;
57 }
58
59 desktop_mode_run_pending_migrations( $installed );
60
61 update_option( DESKTOP_MODE_MIGRATION_OPTION, DESKTOP_MODE_MIGRATION_VERSION, false );
62 }
63 add_action( 'admin_init', 'desktop_mode_maybe_run_migrations' );
64
65 /**
66 * Dispatches each migration whose version is newer than what has run.
67 *
68 * @since 0.9.1
69 *
70 * @param int $from The highest migration version already applied.
71 * @return void
72 */
73 function desktop_mode_run_pending_migrations( $from ) {
74 $from = (int) $from;
75
76 if ( $from < 1 ) {
77 desktop_mode_migrate_os_settings_optin();
78 }
79
80 if ( $from < 2 ) {
81 desktop_mode_migrate_unschedule_post_term_ai();
82 }
83
84 if ( $from < 3 ) {
85 desktop_mode_migrate_delete_ai_keys();
86 }
87 }
88
89 /**
90 * Migration 1 — reset the native list windows to opt-in.
91 *
92 * The native Posts/Pages/Users/Plugins/Comments windows used to default
93 * ON (opt-out). The shell persists the whole OS-settings object on every
94 * change, so most active users already have these flags stored as `true`
95 * and would keep the native UI even after the default flips. This clears
96 * the five flags from every user who has the meta, leaving the rest of
97 * their settings (wallpaper, accent, dock order, …) untouched. On the
98 * next read the cleared keys fall back to the new `false` default, so the
99 * whole install lands on opt-in and users re-enable each window from
100 * OS Settings → Features → Beta features.
101 *
102 * Only users who actually have the meta are queried — fresh accounts and
103 * users who never touched OS Settings are skipped entirely.
104 *
105 * @since 0.9.1
106 *
107 * @return void
108 */
109 function desktop_mode_migrate_os_settings_optin() {
110 $flags = array(
111 'nativePostsEnabled',
112 'nativePagesEnabled',
113 'nativeUsersEnabled',
114 'nativePluginsEnabled',
115 'nativeCommentsEnabled',
116 );
117
118 $user_ids = get_users(
119 array(
120 'fields' => 'ID',
121 'meta_key' => DESKTOP_MODE_OS_SETTINGS_META_KEY, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- one-time migration; the key is indexed in usermeta and the scan is guarded to run once.
122 'meta_compare' => 'EXISTS',
123 )
124 );
125
126 foreach ( $user_ids as $user_id ) {
127 $raw = get_user_meta( (int) $user_id, DESKTOP_MODE_OS_SETTINGS_META_KEY, true );
128 if ( ! is_array( $raw ) ) {
129 continue;
130 }
131
132 $changed = false;
133 foreach ( $flags as $flag ) {
134 if ( array_key_exists( $flag, $raw ) ) {
135 unset( $raw[ $flag ] );
136 $changed = true;
137 }
138 }
139
140 if ( ! $changed ) {
141 continue;
142 }
143
144 // Re-save through the canonical sanitizer so the cleared flags are
145 // backfilled with the new `false` default and the rest of the
146 // settings array is normalized exactly as a client write would be.
147 desktop_mode_save_os_settings( (int) $user_id, $raw );
148 }
149 }
150
151 /**
152 * Migration 2 — unschedule leftover post/term AI analysis jobs.
153 *
154 * Post and taxonomy-term analysis was removed: the copilot now only
155 * analyzes comments (for the spam score), and the AI assistant finds
156 * content with native WordPress keyword search. Their cron callbacks no
157 * longer exist, so any single-events still queued from a prior version
158 * would simply no-op — but we clear them so the cron array stays tidy and
159 * `wp cron event list` doesn't show orphaned hooks.
160 *
161 * Existing `_desktop_mode_ai_analysis` meta on posts/terms is left in place
162 * (hidden, harmless, and cheap to ignore).
163 *
164 * @since 0.9.1
165 *
166 * @return void
167 */
168 function desktop_mode_migrate_unschedule_post_term_ai() {
169 wp_unschedule_hook( 'desktop_mode_ai_analyze_post' );
170 wp_unschedule_hook( 'desktop_mode_ai_analyze_term' );
171 }
172
173 /**
174 * Migration 3 — delete self-managed AI credentials.
175 *
176 * WordPress 7.0 owns provider credentials (Settings → Connectors), so the
177 * copilot no longer stores keys of its own. Remove the platform key option and
178 * strip the now-unused key / provider / model / transport fields from every
179 * user's stored OS settings so no secret is left behind. The only `ai` field
180 * that remains is `enabled` (the per-user assistant toggle), backfilled from
181 * defaults on next read.
182 *
183 * @since 0.9.4
184 *
185 * @return void
186 */
187 function desktop_mode_migrate_delete_ai_keys() {
188 // Platform-wide key option (formerly `desktop_mode_ai_platform`).
189 delete_option( 'desktop_mode_ai_platform' );
190
191 $user_ids = get_users(
192 array(
193 'fields' => 'ID',
194 'meta_key' => DESKTOP_MODE_OS_SETTINGS_META_KEY, // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- one-time migration; guarded to run once.
195 'meta_compare' => 'EXISTS',
196 )
197 );
198
199 foreach ( $user_ids as $user_id ) {
200 $raw = get_user_meta( (int) $user_id, DESKTOP_MODE_OS_SETTINGS_META_KEY, true );
201 if ( ! is_array( $raw ) || ! isset( $raw['ai'] ) || ! is_array( $raw['ai'] ) ) {
202 continue;
203 }
204
205 // Strip every legacy AI field: the self-managed credentials/transport,
206 // plus the `provider` / `model` preferences — provider + model selection
207 // is now delegated entirely to the Core AI Client.
208 $changed = false;
209 foreach ( array( 'apiKey', 'apiKeys', 'transport', 'provider', 'model' ) as $stale ) {
210 if ( array_key_exists( $stale, $raw['ai'] ) ) {
211 unset( $raw['ai'][ $stale ] );
212 $changed = true;
213 }
214 }
215
216 if ( ! $changed ) {
217 continue;
218 }
219
220 desktop_mode_save_os_settings( (int) $user_id, $raw );
221 }
222 }
223