Block bugs cluster in three places: edit/save mismatches, stale attributes after schema changes, and styles that look right in the editor but wrong on the front-end. This tutorial covers the tools and habits that catch them.
Block validation — the yellow warning
When you load a post, WordPress parses the saved HTML and reconstructs blocks. If the reconstruction doesn’t match what your Save function would produce now, you get a “Block validation failed” warning with options to “Attempt block recovery” or “Convert to HTML”.
Causes, in order of frequency:
- You changed the Save function without registering a deprecation
- Save uses different markup than what the parser expects (whitespace, attribute order, missing classes)
- An attribute changed sources (was in comment, now in HTML, or vice versa)
The fix is always one of:
- Register a deprecation for the old version
- Make your Save function output identical HTML to what’s saved
- Force re-save by editing and saving the post
React DevTools
Install the React Developer Tools browser extension. With it:
- Inspect the Edit component tree for any selected block
- See current attribute values in the Props panel
- Trigger re-renders to confirm state updates
- Profile editor performance
WordPress ships React in development mode, so DevTools just works — no config needed.
Unit tests with @wordpress/scripts
@wordpress/scripts includes Jest pre-configured. Write tests for pure functions inside your block — attribute transformers, utility functions, render helpers:
// src/utils.js
export function classNameForType(type) {
return `my-callout-${type}`;
}
// src/utils.test.js
import { classNameForType } from './utils';
test('classNameForType prepends my-callout-', () => {
expect(classNameForType('warning')).toBe('my-callout-warning');
});
End-to-end tests with Playwright
For full block-in-editor flows, @wordpress/e2e-test-utils-playwright provides helpers. These tests run a real WordPress + Chrome:
import { test, expect } from '@wordpress/e2e-test-utils-playwright';
test('Callout block inserts and saves', async ({ admin, editor }) => {
await admin.createNewPost();
await editor.insertBlock({ name: 'my-first-block/callout' });
await editor.setBlockAttribute('title', 'Test title');
await editor.publishPost();
await expect(editor.canvas.getByText('Test title')).toBeVisible();
});
E2E tests are slow but catch the issues unit tests miss — actual editor interactions, attribute persistence, save/load cycles.
Common pitfalls + fixes
| Symptom | Likely cause |
|---|---|
| Yellow “Block validation failed” | Save function changed since content was saved. Add a deprecation. |
| Block disappears after save | Save returned null without render callback set. Either return JSX or wire dynamic render. |
| Styles look right in editor, wrong on front-end | editor.scss styles aren’t loaded on front-end (correct), but you put real styles there. Move to style.scss. |
attributes is undefined | Forgot to declare in block.json. Add it. |
setAttributes is not a function | Typo or trying to call from Save. Save doesn’t have setAttributes. |
| Block doesn’t appear in inserter | Build didn’t run, or stale browser cache. npm run build + hard refresh. |
| Editor crashes when block is selected | React error inside Edit. Open browser console for the stack trace. |
| Edit looks like raw text, not the component | index.js didn’t register the block. Check npm run start output for errors. |
Debugging workflow
When something breaks:
- Open browser DevTools console — most block errors throw there before they affect the UI
- Check
npm run startoutput — webpack errors show up here, not in the browser - Inspect the block in the React DevTools — confirm attributes match what you expect
- Switch to Code editor view (top-right menu) — see the actual saved HTML
- Try with all other plugins deactivated — to rule out conflicts
- Diff the rendered HTML against what Save would output now — for validation issues
What’s next
Part 12 is the finale — publishing your block plugin to wordpress.org so other people can install it.
Get the next one in your inbox. Practical tips, no fluff.
More tutorials
View all- WordPress
How to Prepare Your Plugin or Theme for WordPress 7.0
A step-by-step compatibility process for shipping a WordPress 7.0-ready release — set up a test site, audit your blocks, fix the breaking changes, and ship with confidence.
22 min
- WordPress
WordPress 7.0 for Block Developers: Breaking Changes
WordPress 7.0 enforces the iframed editor, broadens contentOnly mode, and drops PHP 7.3. Here are the breaking changes block and plugin developers must fix before users upgrade.
25 min
- WordPress
WordPress 7.0 AI: Client, Abilities & Connectors
The headline feature of WordPress 7.0 is native AI in Core. Here is what the WP AI Client, the Abilities API, and the Connectors system actually mean for plugin developers.
25 min