I got a ticket from a client last week. “My team can’t save drafts properly. The button just spins, but nothing happens. No error, nothing.” That is a silent failure, the kind of bug that makes you doubt your own eyes. WordPress error handling does this a lot, and it follows its own frustrating rules.
If you come from a framework like Laravel or Symfony, you expect exceptions and a stack trace when something breaks. WordPress works differently. Its error handling is built around the WP_Error object, and code often fails without a single warning.
How WordPress handles failure
Years ago a developer named Carl Alexander wrote about this on his blog, and honestly not much has changed. WordPress core avoids exceptions and returns a WP_Error object when something goes wrong internally. If the plugin or theme calling that function never checks the result with is_wp_error(), the error just disappears, so the user sees nothing in the interface and nothing in the logs, and the feature simply does not work.
My first move on the client’s site was to enable debugging in wp-config.php and watch the logs. That is always step one, but here it showed nothing. The problem was not a PHP notice or warning. A function was failing silently and returning an error object that the calling code ignored completely, and that code lived in a premium plugin they were running.
Forcing the errors into the open
When a bug is invisible, you cannot guess your way out of it. You have to get WordPress to report what is happening. The debugging constants in wp-config.php are the first thing to reach for. They will not always surface a WP_Error problem, but they do catch the underlying PHP issues that are often the real cause.
// Enable WP_DEBUG mode
define( 'WP_DEBUG', true );
// Enable Debug logging to the /wp-content/debug.log file
define( 'WP_DEBUG_LOG', true );
// Disable display of errors and warnings
define( 'WP_DEBUG_DISPLAY', false );
@ini_set( 'display_errors', 0 );I treat this setup as a baseline for any real debugging. It keeps errors out of the screen output, which can break AJAX requests and leak path information, and writes them to a log file instead. Debugging without it is miserable.
So what’s the takeaway?
The lesson is not a single function to memorize, it is how you approach a break. When something fails in WordPress, work from two assumptions:
- It might be a standard PHP error, which proper logging will reveal.
- It might be a silent
WP_Errorreturn, which requires you to trace the code’s execution path and check the return values of functions you suspect are failing.
For the client, the cause was a third-party API call inside the plugin that was timing out. The plugin developer never checked whether the wp_remote_post() call returned a WP_Error object, so when it failed the rest of the save function stopped running. No log entry, no message on screen, just a spinning button and an annoyed user.
This kind of thing gets complicated fast. If you are tired of debugging someone else’s mess and just want your site to work, drop my team a line. We have probably seen it before.