Closes #8702: Story 4 — Fresh-install Pro detection & resolution - #8754
Conversation
…ption and manual retry logic
…se only PSR-4 only
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Complexity | 0 |
🟢 Coverage 61.54% diff coverage · +0.06% coverage variation
Metric Results Coverage variation ✅ +0.06% coverage variation (-0.10%) Diff coverage ✅ 61.54% diff coverage (50.00%) Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (91a0742) 47853 22625 47.28% Head commit (d32de6a) 47929 (+76) 22689 (+64) 47.34% (+0.06%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#8754) 78 48 61.54% Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.
…ous auto detection
…k/8702-story-4-fresh-install-pro-detection-resolution
…sk/8702-story-4-fresh-install-pro-detection-resolution
…sk/8702-story-4-fresh-install-pro-detection-resolution
hellofromahmed
left a comment
There was a problem hiding this comment.
Approving with minor requests.
Notes for @wp-media/qa-team
- This currently applies to free and paid subscriptions.
- We have two attempts and then fail with the notice that @jeawhanlee mentioned here.
- This PR will introduce more calls to user details endpoint because we remove the transient with each attempt.
|
Note Generated by the AI delivery pipeline (lead-reviewer · Claude Sonnet 5). Review: ❌ CHANGES REQUESTED Blockers:
Nice-to-haves:
Verified, no new issue found: retry/backoff arithmetic ( Test coverage: PASS with the gaps noted above — integration tests cover |
|
Note Generated by the AI delivery pipeline (qa-engineer · Claude Sonnet 5). Code-level pass only — Strategy C (test suite + source analysis), no live environment or browser this run. QA:
Blockers:
|
Co-authored-by: Ahmed Saeed <146129302+hellofromahmed@users.noreply.github.com>
…n' of github.com:wp-media/wp-rocket into task/8702-story-4-fresh-install-pro-detection-resolution
…uine CRITICAL: APIClient::get_remote_subscription_data()'s error/fallback path (network failure, non-200, empty body, decode failure) returns a hardcoded plan_type => 'free' default - indistinguishable from a real free-tier response by the existing empty($value['plan_type']) check. A transient RocketCDN API outage could therefore spuriously persist/ activate cdn_state and trigger a full cache clear. Predates the "activate from nothing" change (it could already spuriously downgrade an already-paid customer during an outage); that change just widened the blast radius. Now requires status_code === 200 before trusting plan_type, matching the same conclusive-result pattern PR #8754 uses. Also adds a current_user_can('rocket_manage_options') check as defense-in-depth - not currently exploitable (every caller of get_subscription_data() is already capability-gated) but the write path had no boundary of its own. Test class switched from AdminTestCase to the RocketCDN TestCase base (which explicitly sets an admin screen) instead of depending on ambient screen state from whichever test ran previously, and a new test proves the is_admin() guard is a genuine no-op on the front end.
… to frontend subscriber and restor subscriber registration
…sk/8702-story-4-fresh-install-pro-detection-resolution
…sk/8702-story-4-fresh-install-pro-detection-resolution
…sk/8702-story-4-fresh-install-pro-detection-resolution
|
@jeawhanlee @hellofromahmed Thanks for the PR, Please check possible risks raised by AI and confirm we are good or need further change /followup GH 🙏
|
|
@DahmaniAdame I believe we'll need the correct text for this new notice: |
|
@Mai-Saad I believe we are good here. |
…ub.com:wp-media/wp-rocket into enhancement/8693-rocketcdn-free-tiers-refactor
…k/8702-story-4-fresh-install-pro-detection-resolution


Description
Fixes #8702
On fresh install, RocketCDN's Pro/Free status is unknown until the license API responds. This PR adds a background retry loop that resolves it automatically, with a manual retry option if all attempts fail, so users are not left in an indeterminate CDN state.
Type of change
Detailed scenario
What was tested
Automated (PHPUnit integration/unit tests):
SubscriptionController::auto_detect_pro_subscription()— the synchronous first-install check, schedules the retry job only when the subscription API doesn't return a conclusive result.SubscriptionController::scheduled_auto_detect_pro_subscription()— retries on an inconclusive API response, cancels/clears state on a conclusive one, and sets a failure transient once attempts are exhausted.DataManagerSubscriber::handle_manual_retry_pro_detection(), fired viaadmin_post_rocket_retry_pro_detection— nonce check, capability check, transient clear, and a synchronous one-shot detection check (no job scheduling).Render\Controller::add_rocketcdn_paid_section()/add_rocketcdn_free_section()— updated to branch on live subscription data.How to test
rocket_cdn_auto_detectis scheduled via Action Scheduler and runs even outside wp-admin (e.g. a plain WP-Cron request).pre_http_request) and confirm the RocketCDN paid/free section rendered reflects the resolved plan.rocket_cdn_pro_detection_failedtransient is set and the admin notice appears on the WP Rocket settings page.Affected Features & Quality Assurance Scope
RocketCDN: fresh-install activation flow, the WP Rocket settings page admin notices, the CDN driver sections (paid/free), and plugin uninstall (added transient cleanup).
Technical description
Documentation
SubscriptionController::auto_detect_pro_subscription()runs synchronously onwp_rocket_first_install; if the subscription API doesn't give a conclusive answer (HTTP 200) right away, it schedules therocket_cdn_auto_detectAction Scheduler job viaQueue::schedule_pro_detection_job().Queue::schedule_pro_detection_job()cancels any already-pending detection job before scheduling a new one, avoiding duplicate pending actions across retries/re-triggers;cancel_pro_detection_job()now matches regardless of theattemptarg the job was scheduled with.SubscriptionController::scheduled_auto_detect_pro_subscription( $attempt )is the Action Scheduler callback: a conclusive result clears the failure transient and cancels any further pending job; an inconclusive one reschedules with$attempt - 1until it hits 0, at which pointrocket_cdn_pro_detection_failedis set.DataManagerSubscriber(which owns these hooks) is now registered as a common subscriber instead of an admin-only one, so its Action Scheduler callbacks are also registered on genuine WP-Cron requests, not just wp-admin/AJAX ones — fixes "no callbacks are registered" failures when Action Scheduler's async loopback isn't available.Render\Controller::add_rocketcdn_paid_section()/add_rocketcdn_free_section()now branch onSubscriptionController::is_paid()(live/cached subscription data) instead of the DB-persistedContext::get_driver()state.NoticesSubscriber::display_pro_detection_failure()shows the failure as an admin notice with a retry link toadmin_post_rocket_retry_pro_detection, handled byDataManagerSubscriber::handle_manual_retry_pro_detection()(nonce + capability checked, then clears the failure transient and re-runs the subscription check synchronously — a one-shot check outside the automatic backoff chain, it does not reschedule the Action Scheduler job).composer install:mobiledetect/mobiledetectlib3.74 declares both a PSR-4 and a classmap autoloader; Mozart's classmap mover failed to match the nested classmap path and deleted the vendor copy before the target existed. Addedoverride_autoloadincomposer.jsonso Mozart treats the package as PSR-4-only, matching how it's already vendored ininc/Dependencies/Detection/MobileDetect.php.New dependencies
None.
Risks
Low. The detection job only reads subscription status and never modifies the CDN configuration a user has already set; retries are capped, deduplicated, and end in a visible, dismissible-by-action notice rather than a silent failure.
Mandatory Checklist
Code validation
Code style
Unticked items justification
N/A — all mandatory items apply and are checked.
Additional Checks