| @@ -37,12 +37,80 @@ | ||
| 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 | |
| 71 | + /* | |
| 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. | |
| 86 | + */ | |
| 87 | + if (!function_exists('fluent_community_maybe_migrate_db')) { | |
| 88 | + function fluent_community_maybe_migrate_db() | |
| 89 | + { | |
| 90 | + $currentDBVersion = get_option('fluent_community_db_version'); | |
| 91 | + | |
| 92 | + if ($currentDBVersion && version_compare($currentDBVersion, FLUENT_COMMUNITY_DB_VERSION, '>=')) { | |
| 93 | + return; | |
| 94 | + } | |
| 95 | + | |
| 96 | + if (get_transient('fluent_community_db_migration_lock')) { | |
| 97 | + return; | |
| 98 | + } | |
| 99 | + | |
| 100 | + set_transient('fluent_community_db_migration_lock', 1, 5 * MINUTE_IN_SECONDS); | |
| 101 | + \FluentCommunity\Database\DBMigrator::run(); | |
| 102 | + update_option('fluent_community_db_version', FLUENT_COMMUNITY_DB_VERSION, true); | |
| 103 | + delete_transient('fluent_community_db_migration_lock'); | |
| 104 | + } | |
| 105 | + } | |
| 106 | + | |
| 107 | + add_action('admin_init', function () { | |
| 108 | + if (current_user_can('activate_plugins')) { | |
| 109 | + fluent_community_maybe_migrate_db(); | |
| 110 | + } | |
| 111 | + }); | |
| 112 | + | |
| 45 | 113 | add_action('fluent_community/portal_render_for_user', function () { |
| 46 | 114 | if (!\FluentCommunity\App\Services\Helper::isSiteAdmin()) { |
| 47 | 115 | return; |
| 48 | 116 | } |
| @@ -56,13 +124,9 @@ | ||
| 56 | 124 | } |
| 57 | 125 | /* |
| 58 | 126 | * We will remove this after final release |
| 59 | 127 | */ |
| 60 | - $currentDBVersion = get_option('fluent_community_db_version'); | |
| 61 | - if (!$currentDBVersion || version_compare($currentDBVersion, FLUENT_COMMUNITY_DB_VERSION, '<')) { | |
| 62 | - update_option('fluent_community_db_version', FLUENT_COMMUNITY_DB_VERSION, 'no'); | |
| 63 | - \FluentCommunity\Database\DBMigrator::run(); | |
| 64 | - } | |
| 128 | + fluent_community_maybe_migrate_db(); | |
| 65 | 129 | |
| 66 | 130 | |
| 67 | 131 | if (defined('FLUENT_COMMUNITY_PRO_VERSION')) { |
| 68 | 132 | add_filter('fluent_community/portal_notices', function ($notices) { |