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

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant