SponsoredHosinger Special Offer

WP+ WordPress Plugin Development

Build WordPress plugins from scratch: actions and filters, shortcodes, settings pages, custom post types, meta boxes, AJAX, REST endpoints, custom tables, cron and blocks.

Debugging Plugins

WordPress Plugin Development Lesson 26 of 27 ~3 min read

Overview

Debugging a WordPress plugin starts with making errors visible — WP_DEBUG logging, Query Monitor, targeted error_log() calls — and then narrowing the problem down one step at a time.

The debug constants

// wp-config.php — development only.
define( 'WP_DEBUG', true );           // Report every error, warning and notice.
define( 'WP_DEBUG_LOG', true );       // Write them to wp-content/debug.log.
define( 'WP_DEBUG_DISPLAY', false );  // Do not print them into pages.
define( 'SCRIPT_DEBUG', true );       // Load unminified core JS and CSS.
define( 'SAVEQUERIES', true );        // Record every database query (slow — dev only).

A healthy plugin produces zero notices. Treat every line in debug.log as a bug: deprecated-function notices become fatal errors in a future WordPress or PHP version.

Logging values

<?php
// A quick, temporary probe.
error_log( 'gdc-books: saving post ' . $post_id );

// Arrays and objects need print_r with the "return" flag.
error_log( 'gdc-books settings: ' . print_r( get_option( 'gdc_books_settings' ), true ) );

// Which hook am I in, and how did I get here?
error_log( current_action() . ' via ' . wp_debug_backtrace_summary() );

Prefix every log line with your plugin slug so you can filter the log. Then follow it live from a terminal with tail -f wp-content/debug.log.

Query Monitor

Install the free Query Monitor plugin. It adds a panel to the admin bar showing, for the current request:

  • PHP errors, with the plugin and line that caused them.
  • Every database query, its time, and which plugin ran it — duplicates and slow queries highlighted.
  • Every hook that fired and every callback attached to it, with priorities.
  • HTTP API calls to external services, and how long they took.
  • REST and AJAX requests, shown in the response headers.
Tip: When a hook callback "does nothing", open Query Monitor's Hooks & Actions panel and search for the hook name. If your callback is not listed, it was never added — usually a typo in the hook name or a file that never loaded.

Debugging AJAX and REST

  • Open the browser DevTools Network tab and click the request: the Response tab shows PHP errors that broke your JSON.
  • A response of 0 from admin-ajax.php means no callback was registered for that action — check the wp_ajax_ hook name.
  • A response of -1 means the nonce check failed.
  • A REST rest_no_route error means the route is not registered — check it was added on rest_api_init.

A methodical process

  1. Reproduce the bug reliably, with exact steps.
  2. Read debug.log and the browser console first — the answer is often already there.
  3. Switch to a default theme and deactivate other plugins. If the bug disappears, re-enable them one by one to find the conflict. The Health Check & Troubleshooting plugin does this for your session only, without affecting visitors.
  4. Add error_log() probes to narrow down where the expected and actual behaviour diverge.
  5. Fix, then remove every probe before committing.

Practice

  • Enable all the debug constants and browse your plugin's screens until debug.log is empty.
  • Use Query Monitor to find how many queries your shortcode runs, and reduce them.
  • Break the AJAX action name on purpose and recognise the 0 response.
Create a free account to save which lessons you've finished. Save my progress