| @@ -37,18 +37,53 @@ | ||
| 37 | 37 | add_action('plugins_loaded', function () use ($app) { |
| 38 | 38 | do_action('fluent_community/portal_loaded', $app); |
| 39 | 39 | |
| 40 | 40 | add_action('init', function () use ($app) { |
| 41 | + /* | |
| 42 | + * Transitional: repair a stale schema on ANY request, not only on the | |
| 43 | + * ones a privileged user makes. | |
| 44 | + * | |
| 45 | + * Both entry points below are gated on a capability, so on an | |
| 46 | + * upgrading site a newly added table does not exist until someone who | |
| 47 | + * can activate plugins loads wp-admin. Cron, REST and ordinary member | |
| 48 | + * requests all reach the plugin before that and read a table that is | |
| 49 | + * not there yet. Multisite is worse: activate_plugins maps to | |
| 50 | + * manage_network_plugins there, so only a super admin, visiting each | |
| 51 | + * subsite in turn, ever migrates it. | |
| 52 | + * | |
| 53 | + * Ahead of on_wp_init deliberately, so the request that performs the | |
| 54 | + * migration is also the first to benefit from it. | |
| 55 | + * | |
| 56 | + * Safe under the concurrency this exposes it to: dbDelta sits behind a | |
| 57 | + * table-exists check, and the preference backfill replays as a no-op | |
| 58 | + * (its INSERT is ON DUPLICATE KEY UPDATE with a self-assignment), so a | |
| 59 | + * burst of traffic straight after an update duplicates work rather | |
| 60 | + * than corrupting anything. | |
| 61 | + * | |
| 62 | + * Remove once 2.9.x is broadly adopted; the capability-gated entry | |
| 63 | + * points are enough on a site that is already current. | |
| 64 | + */ | |
| 65 | + fluent_community_maybe_migrate_db(); | |
| 66 | + | |
| 41 | 67 | do_action('fluent_community/on_wp_init', $app); |
| 42 | 68 | }); |
| 43 | 69 | }); |
| 44 | 70 | |
| 45 | 71 | /* |
| 46 | - * A stale schema is repaired from two places. Portal render catches sites where | |
| 47 | - * an admin browses the community; admin_init catches the plugin-update case, | |
| 48 | - * where the first request after the new code lands is a wp-admin page and a | |
| 49 | - * newly added table would otherwise not exist yet. A missing index only slows | |
| 50 | - * things down, but a missing table is fatal, so the second entry point matters. | |
| 72 | + * A stale schema is repaired from three places. The init hook above is the one | |
| 73 | + * that actually closes the gap, because it needs no privileged user; the two | |
| 74 | + * below predate it and are kept as belt and braces. Portal render catches | |
| 75 | + * sites where an admin browses the community; admin_init catches the | |
| 76 | + * plugin-update case, where the first request after the new code lands is a | |
| 77 | + * wp-admin page. A missing index only slows things down, but a missing table | |
| 78 | + * is fatal, so more than one entry point matters. | |
| 79 | + * | |
| 80 | + * The version option is autoloaded so the check below costs nothing on the | |
| 81 | + * requests where there is nothing to do - which, after the first one, is all | |
| 82 | + * of them. Note that update_option() returns early when the value is | |
| 83 | + * unchanged, so the autoload flag only flips on a site whose version string | |
| 84 | + * actually moves; one already stamped at the current version keeps the old | |
| 85 | + * flag until the next DB version bump. | |
| 51 | 86 | */ |
| 52 | 87 | if (!function_exists('fluent_community_maybe_migrate_db')) { |
| 53 | 88 | function fluent_community_maybe_migrate_db() |
| 54 | 89 | { |
| @@ -63,9 +98,9 @@ | ||
| 63 | 98 | } |
| 64 | 99 | |
| 65 | 100 | set_transient('fluent_community_db_migration_lock', 1, 5 * MINUTE_IN_SECONDS); |
| 66 | 101 | \FluentCommunity\Database\DBMigrator::run(); |
| 67 | - update_option('fluent_community_db_version', FLUENT_COMMUNITY_DB_VERSION, false); | |
| 102 | + update_option('fluent_community_db_version', FLUENT_COMMUNITY_DB_VERSION, true); | |
| 68 | 103 | delete_transient('fluent_community_db_migration_lock'); |
| 69 | 104 | } |
| 70 | 105 | } |
| 71 | 106 | |