Skip to content

fix: recover interrupted pending site polling#1415

Merged
superdav42 merged 1 commit into
mainfrom
fix/checkout-pending-site-polling
Jun 13, 2026
Merged

fix: recover interrupted pending site polling#1415
superdav42 merged 1 commit into
mainfrom
fix/checkout-pending-site-polling

Conversation

@superdav42

@superdav42 superdav42 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Recover checkout polling when a raw blog exists but pending-site publish cleanup was interrupted before ownership metadata was written.
  • Keep the thank-you poller active while the page was rendered with a pending site, and cache-bust refresh when polling observes completion.
  • Add regression coverage for the partial-blog/pending-site state.

Verification

  • php -l inc/managers/class-membership-manager.php && php -l tests/WP_Ultimo/Managers/Membership_Manager_Test.php
  • vendor/bin/phpcs inc/managers/class-membership-manager.php tests/WP_Ultimo/Managers/Membership_Manager_Test.php
  • npx eslint assets/js/thank-you.js --ignore-pattern '*.min.js'
  • git diff --check
  • Local WP-CLI simulation of partial publish state: recovery returned ok: true, cleared pending_site, and wrote matching wu_membership_id, wu_customer_id, and wu_type=customer_owned.

Notes

  • vendor/bin/phpunit --filter 'Membership_Manager_Test::test_check_pending_site_created' could not run in this checkout because /tmp/wordpress-tests-lib/includes/functions.php is missing.
  • npm run lint:js -- assets/js/thank-you.js is not suitable here because the npm script ignores the file argument and lints the entire legacy asset tree; direct ESLint was used for the touched file.

aidevops.sh v3.20.57 plugin for OpenCode v1.17.4 with gpt-5.5

Summary by CodeRabbit

  • Bug Fixes
    • Improved site creation reliability when the publishing process is interrupted or incomplete
    • Enhanced detection and recovery of pending sites stuck in intermediate states
    • Better handling to prevent failed deployments from persisting indefinitely

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a recovery mechanism for pending site creation when the underlying blog is created but publish cleanup is interrupted. The backend adds a recover_interrupted_pending_site() helper and integrates it into the polling check, while frontend polling logic is refined to account for pending-site state, and a test validates the recovery path works correctly.

Changes

Pending Site Recovery and Polling

Layer / File(s) Summary
Backend recovery mechanism
inc/managers/class-membership-manager.php
New recover_interrupted_pending_site() finalizes a pending site by linking it to an existing blog (if found), validating metadata matches, updating ownership/type meta in the blog context, deleting the pending-site record, and unscheduling delayed publish work. check_pending_site_created() now calls recovery first and early-returns completed on success; a PHPCS ignore comment is added to the started response echo.
Frontend polling state and redirect logic
assets/js/thank-you.js
has_pending_site is normalized into the Vue component's data. Redirect on publish_status === "completed" now triggers when either the pending-site badge is visible or active publishing was observed. publish_status === "stopped" ready-check now requires both no pending badge and no server-side creating flag; pending-but-not-running cases explicitly fetch the WordPress cron URL before continuing slow-poll.
Recovery test validation
tests/WP_Ultimo/Managers/Membership_Manager_Test.php
Test imports Site model and validates recovery when a multisite blog exists but is missing membership/customer meta. Asserts the pending site is cleaned up and the recovered blog receives correct ownership and type meta.

Sequence Diagram

sequenceDiagram
  participant PollHandler as check_pending_site_created()
  participant Recovery as recover_interrupted_pending_site()
  participant DB as Database/Site Meta
  participant Hook as wu_pending_site_published
  PollHandler->>Recovery: Attempt recovery of interrupted publish
  activate Recovery
  Recovery->>DB: Fetch existing blog by domain/path
  Recovery->>DB: Validate membership/customer meta match
  alt Blog exists and meta valid
    Recovery->>DB: Copy signup options into blog context
    Recovery->>DB: Update site meta (membership, customer, type)
    Recovery->>DB: Delete pending site record
    Recovery->>DB: Unschedule delayed publish action
    Recovery->>Hook: Fire wu_pending_site_published event
    Recovery-->>PollHandler: return true (success)
  else Blog missing or meta mismatch
    Recovery-->>PollHandler: return false (continue normal flow)
  end
  deactivate Recovery
  PollHandler->>PollHandler: Return publish_status = completed if recovered
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • Ultimate-Multisite/ultimate-multisite#797: Both PRs modify check_pending_site_created() control flow around pending-site retry behavior; main adds recovery/early completion path while retrieved removes redundant async enqueue that caused competing retries.
  • Ultimate-Multisite/ultimate-multisite#972: Both directly modify assets/js/thank-you.js polling/redirect logic in completed/stopped branches and repeat-navigation handling.
  • Ultimate-Multisite/ultimate-multisite#1308: Both modify pending-site publish lifecycle; main PR's recovery deletes pending-site record while retrieved PR updates cache invalidation after that deletion.

Suggested labels

bug, origin:worker, review-feedback-scanned

Poem

🐰 A pending site once stuck mid-way,
Blog born but records in dismay,
Now recovery hops in to save the day,
Cleanup complete, the polls hold sway,
Frontend and backend in harmony play!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'fix: recover interrupted pending site polling' accurately summarizes the main objective of the PR, which implements recovery logic for interrupted pending-site polling in checkout flows.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/checkout-pending-site-polling

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

Copy link
Copy Markdown

🔨 Build Complete - Ready for Testing!

📦 Download Build Artifact (Recommended)

Download the zip build, upload to WordPress and test:

🌐 Test in WordPress Playground (Very Experimental)

Click the link below to instantly test this PR in your browser - no installation needed!
Playground support for multisite is very limitied, hopefully it will get better in the future.

🚀 Launch in Playground

Login credentials: admin / password

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
inc/managers/class-membership-manager.php (1)

382-391: 💤 Low value

Use Yoda conditions for the !== comparisons.

The coding guidelines require Yoda conditions in production code. The comparisons on lines 385 and 389 should have the literal/method result on the left side.

Proposed fix
-		if ($existing_membership_id && $existing_membership_id !== (int) $membership->get_id()) {
+		if ($existing_membership_id && (int) $membership->get_id() !== $existing_membership_id) {
 			return false;
 		}

-		if ($existing_customer_id && $existing_customer_id !== (int) $membership->get_customer_id()) {
+		if ($existing_customer_id && (int) $membership->get_customer_id() !== $existing_customer_id) {
 			return false;
 		}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@inc/managers/class-membership-manager.php` around lines 382 - 391, The
comparisons use non-Yoda style; change both !== checks to Yoda conditions by
placing the literal/method result on the left: replace "if
($existing_membership_id && $existing_membership_id !== (int)
$membership->get_id())" with a Yoda-style check using "(int)
$membership->get_id() !== $existing_membership_id", and similarly replace "if
($existing_customer_id && $existing_customer_id !== (int)
$membership->get_customer_id())" with "(int) $membership->get_customer_id() !==
$existing_customer_id"; keep the initial truthiness checks but ensure the casted
method calls are on the left side of the !== comparisons so they follow the
project's Yoda condition guideline.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@inc/managers/class-membership-manager.php`:
- Around line 382-391: The comparisons use non-Yoda style; change both !==
checks to Yoda conditions by placing the literal/method result on the left:
replace "if ($existing_membership_id && $existing_membership_id !== (int)
$membership->get_id())" with a Yoda-style check using "(int)
$membership->get_id() !== $existing_membership_id", and similarly replace "if
($existing_customer_id && $existing_customer_id !== (int)
$membership->get_customer_id())" with "(int) $membership->get_customer_id() !==
$existing_customer_id"; keep the initial truthiness checks but ensure the casted
method calls are on the left side of the !== comparisons so they follow the
project's Yoda condition guideline.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9267e118-c525-4d95-966d-43ef0fec3b83

📥 Commits

Reviewing files that changed from the base of the PR and between bc4d4bb and 2efe1b1.

📒 Files selected for processing (3)
  • assets/js/thank-you.js
  • inc/managers/class-membership-manager.php
  • tests/WP_Ultimo/Managers/Membership_Manager_Test.php

@superdav42 superdav42 merged commit c575595 into main Jun 13, 2026
12 checks passed
@superdav42

Copy link
Copy Markdown
Collaborator Author

Summary

  • Recover checkout polling when a raw blog exists but pending-site publish cleanup was interrupted before ownership metadata was written.
  • Keep the thank-you poller active while the page was rendered with a pending site, and cache-bust refresh when polling observes completion.
  • Add regression coverage for the partial-blog/pending-site state.

Verification

  • php -l inc/managers/class-membership-manager.php && php -l tests/WP_Ultimo/Managers/Membership_Manager_Test.php
  • vendor/bin/phpcs inc/managers/class-membership-manager.php tests/WP_Ultimo/Managers/Membership_Manager_Test.php
  • npx eslint assets/js/thank-you.js --ignore-pattern '*.min.js'
  • git diff --check
  • Local WP-CLI simulation of partial publish state: recovery returned ok: true, cleared pending_site, and wrote matching wu_membership_id, wu_customer_id, and wu_type=customer_owned.

Notes

  • vendor/bin/phpunit --filter 'Membership_Manager_Test::test_check_pending_site_created' could not run in this checkout because /tmp/wordpress-tests-lib/includes/functions.php is missing.
  • npm run lint:js -- assets/js/thank-you.js is not suitable here because the npm script ignores the file argument and lints the entire legacy asset tree; direct ESLint was used for the touched file.

aidevops.sh v3.20.57 plugin for OpenCode v1.17.4 with gpt-5.5


Merged via PR #1415 to main.
Merged by deterministic merge pass (pulse-wrapper.sh).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-feedback-scanned Merged PR already scanned for quality feedback

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant