What AI Agents Get Wrong in WordPress, and How to Catch It
A green wp-scripts build is not a correctness signal. The agent tested its own fake WordPress functions and reported success. Here is what catches it.
Devon Parker · @dparker
APIs and integrations
- Topic
- WP
- Section
- WordPress Internals
- Published
- 16 OCT 2026
- Reading time
- 8 MIN
- Words
- 1764W
The plugin worked. That is what makes this worth writing about. A single prompt produced a
14-file Gutenberg block plugin, it activated cleanly in real WordPress 7.1.3, the block
registered, the agent's own WP-CLI command returned the correct row, and the front end
rendered correctly over HTTP. Escaping held against a deliberately hostile attribute set: a
CSS injection attempt was rejected, a <script> tag was stripped, and
<strong> survived.
Along the way, the agent reported several green results that meant nothing at all. One of them is the difference between shipping working code and shipping a white screen, and no tool in the default WordPress workflow would have told you which one you had. These are the failure modes, in the order they will bite you.
A green build never checked that the API exists
The first failure is structural and it is the one that should change how you read build output.
@wordpress/scripts runs webpack, and webpack is configured to treat every
@wordpress/* package as an external. In the generated bundle,
import { PanelColorSettings } from '@wordpress/block-editor' becomes a lookup on
window.wp.blockEditor. Nothing resolves that import at build time. The contract
between your code and WordPress is written into the generated index.asset.php
file, which lists dependencies such as wp-block-editor and
wp-components, and that file is what wires your script to the page. The build
itself only checks that your JavaScript is syntactically valid and that the things you imported
from your own files exist.
In that run the imported component was still a real export of
@wordpress/block-editor 18.1.0, and the string was present in WordPress 7.1.3's
core bundle. That is luck, not verification. If the component had been removed in a WordPress
release, the build would have passed exactly as it did, and the block editor would have failed
at runtime for every user.
This is not a WordPress-specific quirk so much as a consequence of how WordPress ships JavaScript. The dependency is a global at runtime, so a bundler has nothing to check against. Which means the only valid question about a generated block is not "did it build" but "did it render in an editor".
What a green build does tell you
That your syntax parses, that your local imports resolve, and that SCSS compiles. Those
are real signals, and they are all it has. Treat a passing
npm run build the way you would treat php -l: proof the file can be
read, not proof the code is right.
The agent verified itself against its own beliefs
The second failure is worse, because the agent looked thorough while doing it. Asked to
verify its work, the agent wrote a test harness containing hand-rolled implementations of
wp_kses_post(), get_block_wrapper_attributes() and
esc_attr__(). It ran that harness, reported that hostile input was stripped and
valid input preserved, and deleted the harness afterwards.
An independent check against real WordPress 7.1.3 reproduced every one of those results. The stubs happened to be faithful. That does not rescue the method. What the harness tested was whether the code does what the model believes WordPress does. If the model's belief is wrong, the harness confirms the wrong belief and reports green, and it does so with the same confidence it shows when it is right. A stub cannot detect a misconception, because the stub was generated from the same misconception.
The agent stated the limitation itself, in its own summary: it could not run the WP-CLI command it had written because no WordPress was present. It knew what it was missing and it filled the hole with an invention. That is the behaviour to watch for, and it is the most persuasive failure in this whole area, because the transcript reads like diligence.
The only fix is a real install
Verification has to happen somewhere the agent cannot author. A Playground instance, a
wp-env environment or a local install with WP-CLI gives the agent something to
be wrong against. WordPress published an official wp-playground agent skill on
30 January 2026 for exactly this reason: it starts WordPress, works out whether the
repository holds a plugin or a theme, mounts the code, and lets the agent check its own work
over HTTP. Building that loop is the subject of the second module of the course on
WordPress development with AI agents.
WordPress's own scaffolder hands you a classic theme
The third failure is inherited rather than generated, and it catches people who do the sensible thing and scaffold first.
Running wp scaffold _s produces a classic PHP template theme: around 20 files,
including header.php, footer.php, single.php,
page.php, archive.php, sidebar.php and
template-parts/content.php. There is no theme.json. The
style.css header still declares "Tested up to: 5.4" and "Requires PHP: 5.6".
So a workflow that reads "scaffold a theme with WP-CLI, then ask the agent to modernise it"
starts with a theme designed for the classic editor and asks the agent to convert it. That is a
harder task than generating a block theme from nothing, and it is harder to review because the
diff is spread across every template file. wp scaffold plugin does not have this
problem and remains a fine modern baseline, producing a main plugin file,
readme.txt, composer.json, .distignore and
.gitignore. The theme command is the one to avoid.
Two related environment traps are worth knowing before you blame the agent. Both
wp scaffold plugin and wp scaffold _s refuse to run until WordPress is
installed, so "scaffold now, install later" does not work. And wp-config.php needs
its require_once ABSPATH . 'wp-settings.php'; line or WP-CLI reports a strange
wp-config.php file and stops. Neither is the agent's fault, and both cost time if
you meet them mid-task.
Nothing in the toolchain cross-checks the small inconsistencies
The fourth failure class is cosmetic individually and expensive in aggregate: locally plausible details that are globally wrong, none of which any gate flags.
In the generated plugin, the header declared Requires at least: 6.4 and
phpcs.xml.dist set minimum_supported_wp_version to 6.4, while
readme.txt said "Tested up to: 6.7". WordPress was at 7.1.3. Nothing in the
toolchain objects to a compatibility line that no human would have typed in 2026, and a plugin
reviewer would notice it immediately.
The same class of defect shows up in hooks. A wrong hook name is a valid string. A callback
that declares three required parameters on a filter that passes two is valid PHP until the
filter fires on a path nobody tested. A capability name with a typo is a valid string, and
WordPress resolves it at runtime against a list built from roles, quietly returning false. PHP
has no opinion about any of this, which is why php -l reported "No syntax errors"
on every generated file including the two *.asset.php files, and was silent about
everything that mattered.
| Failure | What reports it | Caught by default |
|---|---|---|
| Syntax error in PHP | php -l | Yes |
| JavaScript that will not parse | wp-scripts build | Yes |
| Imported core component no longer exists | A running editor | No |
| Wrong capability name | A user hitting the screen | No |
| Filter arity mismatch | The hook firing on a real request | No |
| Output escaping that looks right | Hostile input against real WordPress | No |
readme.txt version drift | A human reviewer | No |
| Hallucinated hook or function | WPCS, PHPStan or a fatal | No |
The right-hand column is the whole argument. The automated signals you get for free cover syntax and nothing else, and the failures that reach customers are all in the bottom five rows.
WordPress already wrote the rejection criteria
On 1 February 2026 the WordPress project published official AI contribution guidelines, and they name these failures in the project's own voice. Contributions require disclosure of meaningful AI assistance. They must remain GPLv2-or-later compatible, which rules out tools whose terms restrict how their output may be redistributed. And the guideline on quality over volume lists the rejectable patterns: generic pull request descriptions that do not reflect real testing, large unreviewed code dumps, over-architected code where a simple solution would do, and hallucinated references to APIs, hooks, functions or links that do not exist.
The stated consequence is blunt. Maintainers may close or reject contributions that appear to be AI slop. An FAQ names Copilot, Claude Code, Codex and ChatGPT as the common tools.
Those guidelines govern contributions to WordPress itself. The reason to read them anyway is that their failure list is accurate for client work, and it is written by the organisation that sees more contributed WordPress code than anyone else. The mental model it prescribes is the useful part: treat AI output like code from an unknown external contributor. Review it, run it, and validate it before it goes anywhere.
There is no benchmark that tells you which agent is safe
The last thing to know is what you cannot look up. Aider's polyglot benchmark, the most widely cited language-by-language agent benchmark in the ecosystem, covers C++, Go, Java, JavaScript, Python and Rust. It does not contain PHP. Aider also has not shipped a release since August 2025. No other vendor publishes a benchmark claim that survives contact with its own documentation.
So there is no number that ranks agents by WordPress competence, and anyone quoting one is either reading a vendor badge or inventing. The one published WordPress run is a single session, one model, one plugin, demonstrated once. It is genuinely encouraging and it is not a benchmark. I would rather hold both of those ideas at the same time than pretend the second one away, because the correct response to a single success is not to generalise it. It is to install WPCS and PHPStan, wire them into the loop, give the agent a real WordPress to test against, and read the diff.
What to do on Monday
- Add
WPCSandPHPStanas Composer dev dependencies and run them on every generated change. They are the only gates in this stack that catch a wrong hook or a bad capability name, and they are opt-in. - Give the agent a running WordPress. Playground or
wp-envturns every claim the agent makes about its own work into something you can check in a browser. - Ask what the agent did not test. The summary in that run volunteered it could not execute its own CLI command, which is the single most useful sentence in the transcript.
- Read
readme.txt, the plugin header andphpcs.xml.disttogether every time. Version drift between those three files is the cheapest defect to catch and the easiest to ship. - Keep
wp scaffold pluginand dropwp scaffold _sfrom your prompts. A classic theme is not a starting point for a block theme.
Devon Parker · @dparker
APIs and integrations
Works through REST contract design, webhook reliability, idempotency keys, retry policy and the unglamorous edge cases that appear when two systems disagree about what happened.
Continue