Skip to content

Let every user disable New Stats - #23176

Draft
nbradbury wants to merge 4 commits into
trunkfrom
issue/new-stats-user-opt-out
Draft

Let every user disable New Stats#23176
nbradbury wants to merge 4 commits into
trunkfrom
issue/new-stats-user-opt-out

Conversation

@nbradbury

@nbradbury nbradbury commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

Description

The android_new_stats flag both routed users to New Stats and hid the "Disable new stats" menu item, so anyone on the rollout was stuck there. This adds an opt-out preference that beats the flag and always shows the menu item. The rollout default is unchanged.

Disabling also adds a "Share feedback" dialog, re-used with the "Experimental block editor" toggle.

Testing instructions

  1. My Site → Stats → overflow → "Disable new stats"
  • Feedback dialog appears; "Not now" lands on old Stats with no "try new stats" prompt
  1. Repeat, and rotate while the dialog is up
  • Dialog survives (it didn't previously)
  1. Force-stop, relaunch, open Stats
  • Still opens old Stats
  1. Old Stats → overflow → "Try new stats"
  • New Stats opens with the intro sheet, and sticks across a relaunch
  1. Me → Experimental Features → turn "Experimental block editor" off
  • Share feedback dialog still works (regression check)

The android_new_stats remote flag did two jobs: it routed users to New Stats,
and it hid the "Disable new stats" overflow item whenever it was on. Users on
the rollout had no way back.

Add an explicit NEW_STATS_USER_OPTED_OUT preference that beats the flag, so
routing becomes !optedOut && (flagEnabled || optedIn), and always show the
overflow item. The rollout default is unchanged; only the escape hatch is new.

Extract the routing decision into NewStatsRouting, which the My Site menu and
the Stats widgets now share instead of duplicating the condition. Opting back
in clears the opt-out, and the "try new stats" suggestion no longer nags users
who deliberately left.

Also reuse the experimental-features feedback dialog when New Stats is
disabled. FeedbackDialog moves to ui/compose/components with a message
parameter, and navigation is deferred until the dialog is answered since
finishing the activity would otherwise tear it down.
optOut() reset NEW_STATS_INTRO_SHOWN, and NewStatsActivity.onCreate re-reads
that flag on every recreation. Rotating after tapping "Disable new stats" left
shouldShowIntro true, so the intro bottom sheet mounted on top of the feedback
dialog and looked like the dialog had vanished.

This was unreachable until navigation was deferred for the dialog, since the
activity used to finish on the same frame.

Reset the flag in optIn() instead. Same outcome for the user - the intro shows
when they return to New Stats - but it is set from StatsFragment while New Stats
is off screen, so it can no longer re-arm under a live NewStatsActivity.
@nbradbury nbradbury added the Stats label Aug 4, 2026
@dangermattic

Copy link
Copy Markdown
Collaborator
1 Message
📖 This PR is still a Draft: some checks will be skipped.

Generated by 🚫 Danger

@wpmobilebot

wpmobilebot commented Aug 4, 2026

Copy link
Copy Markdown
Contributor

🤖 Build Failure Analysis

This build has failures. Claude has analyzed them - check the build annotations for details.

Three fixes from review:

leaveNewStats() bailed out when there was no selected site, after optOut() had
already persisted. The dialog closed, no navigation happened and finish() never
ran, leaving the user on a screen nothing else routes them to. Only the old
Stats launch needs a site, so guard just that and always finish.

NEW_STATS_USER_OPTED_OUT was a DeletablePrefKey, which AppPrefs.reset() wipes on
sign-out. Since it is the only thing that can override the android_new_stats
rollout flag, signing out silently pushed the user back into New Stats. Move it
to UndeletablePrefKey, alongside the other "user said no" flags.

NewStatsRouting's docstring claimed to be the single source of truth, but
shortcuts, deep links, notifications and the activity log all route straight to
old Stats. Say so instead.
isNewStatsEnabled() only forwarded to NewStatsRouting. Both call sites now use
the injected router directly, removing the indirection the router was added to
get rid of.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants