PluginProbe
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin / 1.1.12
OpenStation: Desktop Windows, Dock & Virtual Desktops for WP Admin v1.1.12
1.1.12 1.1.11 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 All 36 releases
← All changes | includes/migrations.php +161 -2 1.1.5 → 1.1.12 View file →
@@ -55,10 +55,19 @@
55 55 * separate migration from 4.
56 56 * - 6: the Trash stopped registering a desktop icon. Removes the
57 57 * placement the shell had auto-placed for it and closes the hole that
58 58 * leaves in the icon column.
59 + * - 7: seeds a face for every agent that has none.
60 + * - 8: retires automatic AI comment scoring.
61 + * - 9: repairs the Comment Concierge's misspelled ability slug in every
62 + * agent's stored allowlist.
63 + * - 10: the first-run stamps and the shell tour. On a site with prior
64 + * desktop use, records that the site was enabled before the stamps
65 + * existed (`openstation_first_enabled_at` with `at: 0, via: backfill`)
66 + * and marks the `shell-tour` intro seen for every prior user, so an
67 + * update never greets a veteran with a first-boot tour.
59 68 */
60 -const OPENSTATION_MIGRATION_VERSION = 7;
69 +const OPENSTATION_MIGRATION_VERSION = 10;
61 70
62 71 /**
63 72 * Option storing the highest migration version that has run. autoload=no.
64 73 *
@@ -160,11 +169,133 @@
160 169
161 170 if ( $from < 7 ) {
162 171 openstation_migrate_seed_agent_faces();
163 172 }
173 +
174 + if ( $from < 8 ) {
175 + openstation_migrate_remove_comments_ai();
176 + }
177 +
178 + if ( $from < 9 ) {
179 + openstation_migrate_agent_ability_slugs();
180 + }
181 +
182 + if ( $from < 10 ) {
183 + openstation_migrate_first_run_stamps();
184 + }
164 185 }
165 186
166 187 /**
188 + * Migration 9 — repair a misspelled ability slug in stored agent
189 + * allowlists.
190 + *
191 + * The shipped Comment Concierge listed `desktop-mode/search-comments-on-post`,
192 + * an ability that was never registered: the real one is
193 + * `desktop-mode/search-comments-by-post`. The runner drops an unknown
194 + * slug without a word, so every seeded Concierge ran without the one
195 + * tool that reads a post's thread. Fixing the definition only reaches
196 + * sites that seed from now on; this rewrites the slug in place on every
197 + * agent that already stored it, whoever created the agent.
198 + *
199 + * Reads the meta directly rather than through the agents store, because
200 + * that module only loads while the Agents feature is on and an agent
201 + * row outlives the flag being turned off. The key is the frozen
202 + * `_desktop_mode_agent_abilities`; nothing is renamed.
203 + *
204 + * @return void
205 + */
206 +function openstation_migrate_agent_ability_slugs() {
207 + $meta_key = '_desktop_mode_agent_abilities';
208 + $renames = array(
209 + 'desktop-mode/search-comments-on-post' => 'desktop-mode/search-comments-by-post',
210 + );
211 +
212 + $user_ids = get_users(
213 + array(
214 + 'fields' => 'ID',
215 + 'meta_key' => $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.
216 + 'meta_compare' => 'EXISTS',
217 + )
218 + );
219 +
220 + foreach ( $user_ids as $user_id ) {
221 + $raw = get_user_meta( (int) $user_id, $meta_key, true );
222 + $slugs = is_string( $raw ) ? json_decode( $raw, true ) : $raw;
223 + if ( ! is_array( $slugs ) ) {
224 + continue;
225 + }
226 +
227 + $changed = false;
228 + foreach ( $slugs as $i => $slug ) {
229 + if ( is_string( $slug ) && isset( $renames[ $slug ] ) ) {
230 + $slugs[ $i ] = $renames[ $slug ];
231 + $changed = true;
232 + }
233 + }
234 + if ( ! $changed ) {
235 + continue;
236 + }
237 +
238 + // Stored as a JSON string, the shape the agents store writes.
239 + // Slashed because update_user_meta() unslashes its value.
240 + update_user_meta(
241 + (int) $user_id,
242 + $meta_key,
243 + wp_slash( (string) wp_json_encode( array_values( array_unique( $slugs ) ) ) )
244 + );
245 + }
246 +}
247 +
248 +/**
249 + * Migration 10 — the first-run stamps meet an install with a past.
250 + *
251 + * Two facts about a site that already had people in the shell, neither
252 + * of which the stamps can learn on their own:
253 + *
254 + * 1. The site HAS activated. `openstation_first_enabled_at` is written
255 + * the first time a user enables from here on, so without this an
256 + * old, busy install would look like one nobody ever turned on: the
257 + * activation nudge would show to its admins, and the deactivation
258 + * funnel would read "never enabled". The stamp is recorded as
259 + * `at: 0, via: backfill` — a real moment is not known and is not
260 + * invented, and every age computation treats it as unknown.
261 + * 2. Its users have already learned the shell. The tour is for a first
262 + * boot, and the slug it records lives in the seen-intros registry,
263 + * so marking it seen for every prior user is the whole opt-out.
264 + * "Reset what's-new dialogs" brings it back for anyone curious.
265 + *
266 + * On a site with no history both loops are empty, and the runner fires
267 + * at activation, where the activation hook that stamps the real install
268 + * moment runs right after it. The install stamp is deliberately not
269 + * written here: for the in-place update it belongs to the lazy
270 + * `admin_init` backfill, which is honest about being a backfill.
271 + *
272 + * @return void
273 + */
274 +function openstation_migrate_first_run_stamps() {
275 + $prior_users = openstation_users_with_prior_desktop_use();
276 + if ( empty( $prior_users ) ) {
277 + return;
278 + }
279 +
280 + if ( null === openstation_get_first_enabled_stamp() ) {
281 + add_option(
282 + OPENSTATION_FIRST_ENABLED_AT_OPTION,
283 + array(
284 + 'at' => 0,
285 + 'via' => 'backfill',
286 + ),
287 + '',
288 + false
289 + );
290 + }
291 +
292 + foreach ( $prior_users as $user_id ) {
293 + openstation_mark_intro_seen( $user_id, OPENSTATION_SHELL_TOUR_INTRO_SLUG );
294 + }
295 +}
296 +
297 +/**
167 298 * Migration 7 — give the agents that predate faces a seed to grow one
168 299 * from.
169 300 *
170 301 * Agents used to share a single grey robot glyph. They now carry a Mio
@@ -353,9 +484,9 @@
353 484 array_merge(
354 485 get_users(
355 486 array(
356 487 'fields' => 'ID',
357 - 'meta_key' => 'desktop_mode_mode', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- runs once per install; the key is indexed in usermeta and both callers are guarded to a single pass.
488 + 'meta_key' => 'desktop_mode_mode', // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key -- the key is indexed in usermeta; the migration callers run once per install, and the deactivation feedback route once per admin submission.
358 489 'meta_compare' => 'EXISTS',
359 490 )
360 491 ),
361 492 get_users(
@@ -614,8 +745,33 @@
614 745 wp_unschedule_hook( 'desktop_mode_ai_analyze_term' );
615 746 }
616 747
617 748 /**
749 + * Migration 8 — retire the "Score new comments with AI" feature.
750 + *
751 + * Automatic AI scoring of incoming comments was removed: nothing
752 + * schedules `desktop_mode_ai_analyze_comment` any more, and the
753 + * `desktop_mode_comments_ai_moderation` option no longer gates
754 + * anything. Queued single-events would simply no-op, but we clear
755 + * them so the cron array stays tidy and `wp cron event list` doesn't
756 + * show an orphaned hook.
757 + *
758 + * The option row is dropped too — unlike a frozen identifier that
759 + * still has a reader, this one has none left, so leaving it would
760 + * only strand a value no code consults.
761 + *
762 + * Existing `_desktop_mode_ai_analysis` comment meta is left in place
763 + * (hidden, harmless, and still what the on-demand
764 + * `desktop-mode/analyze-comment` ability writes).
765 + *
766 + * @return void
767 + */
768 +function openstation_migrate_remove_comments_ai() {
769 + wp_unschedule_hook( 'desktop_mode_ai_analyze_comment' );
770 + delete_option( 'desktop_mode_comments_ai_moderation' );
771 +}
772 +
773 +/**
618 774 * Migration 3 — delete self-managed AI credentials.
619 775 *
620 776 * WordPress 7.0 owns provider credentials (Settings → Connectors), so the
621 777 * copilot no longer stores keys of its own. Remove the platform key option and
@@ -661,4 +817,7 @@
661 817
662 818 openstation_save_os_settings( (int) $user_id, $raw );
663 819 }
664 820 }
821 +
822 +// Presence owns a verified checkpoint so failures never advance unrelated migrations.
823 +add_action( 'admin_init', 'openstation_presence_migration_tick', 20 );