Skip to content

fix(site): propagate WP_Error from wp_delete_site() to prevent silent redirect on failure#1125

Merged
superdav42 merged 1 commit intomainfrom
fix/t532-site-delete-white-page
May 6, 2026
Merged

fix(site): propagate WP_Error from wp_delete_site() to prevent silent redirect on failure#1125
superdav42 merged 1 commit intomainfrom
fix/t532-site-delete-white-page

Conversation

@superdav42
Copy link
Copy Markdown
Collaborator

@superdav42 superdav42 commented May 6, 2026

Summary

  • Site::delete() was casting wp_delete_site() return to (bool), making any WP_Error truthy — callers received true even when deletion failed
  • handle_model_delete_form() then sent JSON success, wubox JS redirected the user, and the resulting page appeared blank/white because the site was never actually removed
  • Fix: return the WP_Error directly so the delete modal surfaces the real failure instead of silently redirecting

Changes

inc/models/class-site.phpSite::delete() now stores the raw wp_delete_site() return, checks is_wp_error() on it, and propagates any WP_Error to the caller. On success it still returns true; on exception it still returns false.

tests/WP_Ultimo/Models/Site_Test.php — adds test_delete_propagates_wp_error_from_wp_delete_site which creates a blog, pre-deletes it from WordPress, then calls Site::delete() and asserts the returned WP_Error is not coerced to true.

Testing

vendor/bin/phpunit --filter "Site_Test::test_delete_unsaved_site|Site_Test::test_delete_propagates_wp_error_from_wp_delete_site"

Both tests pass. All pre-existing Site_Test / Site_Manager_Test failures are unrelated to this change.

Resolves t532


Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Enhanced site deletion with improved error handling and logging for failed deletion scenarios.
  • Tests

    • Added test coverage for site deletion error propagation when an underlying blog has been previously removed.

… redirect on failure

Site::delete() cast wp_delete_site()'s return to (bool), which made any
WP_Error truthy. handle_model_delete_form() then saw true, sent JSON
success, and the JS redirected the user even though the deletion had
failed — producing a white/blank page or leaving the site intact.

Return the WP_Error directly so callers can surface the real failure in
the delete modal instead of silently redirecting.

Adds regression test confirming WP_Error is propagated (not coerced to
true) when wp_delete_site() refuses to remove the requested blog.

Resolves t532
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 6, 2026

📝 Walkthrough

Walkthrough

The Site::delete() method in WP Ultimo is refactored to wrap calls to WordPress's wp_delete_site() in a try/catch block with explicit error handling. On exceptions, errors are logged and false is returned. If wp_delete_site() returns a WP_Error, it is propagated directly. A regression test validates error propagation when the underlying blog is already deleted.

Changes

Error Handling in Site Deletion

Layer / File(s) Summary
Core Implementation
inc/models/class-site.php
Site::delete() rewritten to wrap wp_delete_site($this->get_id()) in try/catch, returning false on exception, propagating WP_Error if present, or continuing with post-delete hooks on success. Docblock updated to document error paths.
Tests
tests/WP_Ultimo/Models/Site_Test.php
New test test_delete_propagates_wp_error_from_wp_delete_site() creates a blog, deletes it, constructs a Site with that blog_id, and asserts that delete() returns a WP_Error to verify error propagation from wp_delete_site().

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 A Site deletion flows with grace,
Try and catch now guard the place,
Errors whisper, not unseen,
WP_Error keeps it clean!
Tests ensure the path is true,
Robust deletion through and through! ✨

🚥 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 accurately describes the main fix: propagating WP_Error from wp_delete_site() to prevent silent redirects. It directly reflects the core problem and solution in the changeset.
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/t532-site-delete-white-page

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

github-actions Bot commented May 6, 2026

🔨 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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@inc/models/class-site.php`:
- Around line 1777-1783: The catch block in the delete() method currently logs
the throwable and returns false, reintroducing a non-WP_Error failure mode;
change it to return a WP_Error instead by creating a new WP_Error (with a
machine-readable code like 'site_delete_failed'), a translated message including
$e->getMessage(), and any useful data (e.g., 'site_id' => $this->get_id()),
after calling wu_log_add; update the catch block around
wp_delete_site($this->get_id()) so callers can use is_wp_error() uniformly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1dc9c749-d9b7-4296-a7c8-972a297d5a87

📥 Commits

Reviewing files that changed from the base of the PR and between 2f5af0b and 9af3228.

📒 Files selected for processing (2)
  • inc/models/class-site.php
  • tests/WP_Ultimo/Models/Site_Test.php

Comment thread inc/models/class-site.php
Comment on lines 1777 to +1783
try {
$result = (bool) wp_delete_site($this->get_id());
$wp_result = wp_delete_site($this->get_id());
} catch (\Throwable $e) {
$result = false;

wu_log_add('fatal-error', $e->getMessage(), LogLevel::ERROR);

return false;
}
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.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Return a WP_Error from the exception path too.

This branch reintroduces a generic false failure mode, so callers still cannot handle all delete failures uniformly. Wrapping the caught throwable in a translated WP_Error keeps delete() consistent with the new wp_delete_site() error propagation.

💡 Proposed change
 		try {
 			$wp_result = wp_delete_site($this->get_id());
 		} catch (\Throwable $e) {
 			wu_log_add('fatal-error', $e->getMessage(), LogLevel::ERROR);

-			return false;
+			return new \WP_Error(
+				'wu_' . $this->model . '_delete_failed',
+				__('Failed to delete the site.', 'ultimate-multisite')
+			);
 		}

As per coding guidelines: 'Use WP_Error for validation and operation failures, not exceptions. Check is_wp_error() on return values.'

🤖 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/models/class-site.php` around lines 1777 - 1783, The catch block in the
delete() method currently logs the throwable and returns false, reintroducing a
non-WP_Error failure mode; change it to return a WP_Error instead by creating a
new WP_Error (with a machine-readable code like 'site_delete_failed'), a
translated message including $e->getMessage(), and any useful data (e.g.,
'site_id' => $this->get_id()), after calling wu_log_add; update the catch block
around wp_delete_site($this->get_id()) so callers can use is_wp_error()
uniformly.

@superdav42 superdav42 merged commit 22bafcc into main May 6, 2026
11 checks passed
@superdav42
Copy link
Copy Markdown
Collaborator Author

Summary

  • Site::delete() was casting wp_delete_site() return to (bool), making any WP_Error truthy — callers received true even when deletion failed
  • handle_model_delete_form() then sent JSON success, wubox JS redirected the user, and the resulting page appeared blank/white because the site was never actually removed
  • Fix: return the WP_Error directly so the delete modal surfaces the real failure instead of silently redirecting

Changes

inc/models/class-site.phpSite::delete() now stores the raw wp_delete_site() return, checks is_wp_error() on it, and propagates any WP_Error to the caller. On success it still returns true; on exception it still returns false.
tests/WP_Ultimo/Models/Site_Test.php — adds test_delete_propagates_wp_error_from_wp_delete_site which creates a blog, pre-deletes it from WordPress, then calls Site::delete() and asserts the returned WP_Error is not coerced to true.

Testing

vendor/bin/phpunit --filter "Site_Test::test_delete_unsaved_site|Site_Test::test_delete_propagates_wp_error_from_wp_delete_site"

Both tests pass. All pre-existing Site_Test / Site_Manager_Test failures are unrelated to this change.
Resolves t532


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


aidevops.sh v3.14.75 spent 44s on this as a headless bash routine.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented May 6, 2026

Performance Test Results

Performance test results for b781ce0 are in 🛎️!

Note: the numbers in parentheses show the difference to the previous (baseline) test run. Differences below 2% or 0.5 in absolute values are not shown.

URL: /

Run DB Queries Memory Before Template Template WP Total LCP TTFB LCP - TTFB
0 41 37.78 MB 898.00 ms (+27.00 ms / +3% ) 156.50 ms (-3.50 ms / -2% ) 1073.50 ms (-35.50 ms / -3% ) 2036.00 ms 1936.30 ms (-53.30 ms / -3% ) 94.00 ms (+7.80 ms / +8% )
1 56 49.11 MB 940.50 ms 147.00 ms 1090.00 ms 2078.00 ms (-42.00 ms / -2% ) 1997.05 ms (-42.65 ms / -2% ) 82.95 ms

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