Build WordPress plugins from scratch: actions and filters, shortcodes, settings pages, custom post types, meta boxes, AJAX, REST endpoints, custom tables, cron and blocks.
Lessons
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.
// 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.
<?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.
Install the free Query Monitor plugin. It adds a panel to the admin bar showing, for the current request:
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.
0 from admin-ajax.php means no callback was registered for that action — check the wp_ajax_ hook name.-1 means the nonce check failed.rest_no_route error means the route is not registered — check it was added on rest_api_init.debug.log and the browser console first — the answer is often already there.error_log() probes to narrow down where the expected and actual behaviour diverge.debug.log is empty.0 response.In accordance with Section 6 & Section 7 of the DPDP Act 2023, third-party analytics and marketing trackers are strictly gated behind your affirmative consent. You may withdraw consent at any time under Section 6(4).
Essential for session authentication (ci_session), Cross-Site Request Forgery security (csrf_cookie_name), and Cloudflare DDoS/bot prevention. Cannot be disabled.
Gated under DPDP Section 7. Allows Google Analytics 4 (Google Consent Mode v2) to measure aggregate, anonymized tool usage.
Enables browser local storage to preserve your theme selection (dark/light mode) and code editor layout between visits.
Used to display developer sponsorships and native tool partner notices.