v3 path would only matter to beta * testers who ran a pre-release v3 build and then downgraded. * * The constant is named for the current target version rather * than version-generically because the contents are specific to * what a v2 -> v3 upgrade needs to clear. A future v4 will swap * the list rather than amend it. */ private const SWEEP_KEYS = [ // auth artifacts — token cannot satisfy the new scope set Options::GA_TOKEN, Options::GA_AUTH_DATE, Options::GA_AUTH_CODE, // OOB-era leftover; v3 sweeps it just in case // property / account context — UA shapes; GA4 stores // GA_MEASUREMENT_ID + GA_PROPERTY_ID instead. 'fiftyonedegrees_ga_tracking_id', // UA-only Options::* constant removed in v3; literal preserved so the v2 wp_options row still gets swept Options::GA_ACCOUNT_ID, Options::GA_PROPERTIES, // dimensions — UA used a numeric `custom_dimension_index`; // GA4 keys by parameter_name. Map shape is incompatible. Options::GA_CUSTOM_DIMENSIONS_MAP, 'fiftyonedegrees_ga_max_cust_dim_index', // UA-only Options::* constant removed in v3; literal preserved so the v2 wp_options row still gets swept Options::GA_DIMENSIONS, Options::GA_DIMENSIONS_UPDATED, // UA tracking-id-derived JavaScript snippet cache. Options::GA_JS, // UI / error flags tied to the UA tracking-id text input Options::GA_TRACKING_ID_ERROR, Options::GA_ID_UPDATED, Options::GA_CUSTOM_DIMENSIONS_SCREEN, Options::GA_ERROR, ]; /** * Idempotent entry point. Safe to call on every plugins_loaded — * early-returns once the install is marked at the current * VERSION. */ public static function run() { if (get_option(Options::GA_OAUTH_VERSION) === self::VERSION) { return; } $had_state = false; foreach (self::SWEEP_KEYS as $key) { if (delete_option($key)) { $had_state = true; } } // Best-effort sweep + unconditional version stamp. Per-row // delete_option failures are silent and indistinguishable // from "row didn't exist", so we don't gate the stamp on // them — a half-cleaned install lands in a state the admin // diagnoses via the reconnect notice and the GA settings // screen rather than via repeated migration retries. A // total DB outage that breaks update_option below leaves // the version stamp untouched, which DOES retry the // migration on the next request as intended. if ($had_state) { // Surface the reconnect notice only if there was real // state to wipe. Fresh installs (no GA configured yet) // silently bump the version stamp without bothering the // admin. set_transient( self::NOTICE_TRANSIENT, '1', self::NOTICE_TTL_SECONDS ); } update_option(Options::GA_OAUTH_VERSION, self::VERSION); } /** * Uninstall hook contribution — removes the migration version * stamp and any leftover one-shot notice transient. Symmetric * with FiftyOneDegreesOauthState::delete_options. * * Single-blog scope on multisite — same precedent as * cleanup_expired_pending; multisite cleanup deferred. */ public static function delete_options() { delete_option(Options::GA_OAUTH_VERSION); delete_transient(self::NOTICE_TRANSIENT); } }