Technote

Working with AI Practical

Writing WordPress code with AI: context decides the result

The same question gives wildly different answers, and the variable is usually not the model but what you handed over. Supply your conventions, your version constraints and the surrounding code, and you get code for this project instead of generic WordPress.

Two things become obvious once you start writing WordPress code alongside an AI. The first is that the tedious-to-memorise material — hook names, function signatures, argument order — genuinely gets faster. The second is that there are stretches where no amount of re-prompting stops it returning code that has nothing to do with your project. The cause of the second is rarely the model. It is how much you handed over.

Ask without context and you get the generic answer

Ask “add an admin settings page” and what comes back tends to look like the example in the handbook. Function names carry no prefix, the option key is something like my_plugin_options, and the save handler uses the most widely published approach rather than yours. None of that is wrong. It simply does not fit any particular project, including yours.

The usual reactions are “try a bigger model” or “write a longer prompt”, and both miss the point. The model has never seen your repository. It does not know your prefix convention, the PHP version you have to support, or the helper sitting fifty lines above the insertion point. There is no way to make it guess unknown facts well — only ways to tell it.

Four things to send with the request

Four things to attach to the request — drop one and the output drifts outside the project

Conventions fit in a paragraph: the prefix for functions and option keys, the text domain, where new files go, how output is escaped. Those four lines alone make the returned identifiers look like the rest of the repository, and that similarity removes most of the review time.

Version constraints are the item whose absence is discovered latest. Code that runs locally throws a parse error on the supported PHP version, or calls something recently deprecated, or calls a function your WordPress release does not have yet. One line — “must run on PHP 7.4 and above” — filters out that entire class.

Surrounding code has the largest effect of the four. Paste the region you are editing and the model calls your existing helper instead of writing a second one. Withhold it and you get a duplicate, and duplicates cause trouble later in the specific way that only one of the two ever gets fixed.

How it will be checked turns the request into something verifiable. Write “passing means wp option get acme_settings shows the value after saving” and the output aims at that condition — and you already know what you are about to test.

The same request, two ways

Side by side, the difference is not subtle.

[thin request]
add an admin settings page

[request carrying context]
- plugin acme-core, function prefix acme_, text domain acme
- supports PHP 7.4+ (no enums, no readonly)
- settings live in one option array acme_settings, autoload=no
- save via admin_post + check_admin_referer + current_user_can( 'manage_options' )
- all output goes through esc_html / esc_attr
- goes in includes/class-settings.php (current contents attached)
- passing: after saving, wp option get acme_settings shows the value

Every line of the second request is a condition you can verify in the resulting code. That is the test for good context: if, having read a line, you cannot answer “how would I know whether this was honoured?”, it is still a preference rather than a requirement.

You do not have to retype that list each time. Conventions and constraints are near-constant per project, so they belong in a document in the repository that gets read at the start of every session. That is how we work, and the structure of such a document deserves its own discussion.

What to check first in what comes back

Good context does not remove review. It does decide what you look at first.

Six lines before merging — the top four are checks, the bottom two genuinely recur

Non-existent hook names deserve special mention because they fail silently. add_action() accepts any string, so a callback attached to a mistyped hook never runs and never complains. Whenever you attach a new hook, confirm once that it actually fires.

The short version: what you scale up in AI collaboration is not prompt length but the number of facts you hand over. Conventions, versions, surrounding code, and how it will be checked — four lines that visibly change the output, and that you write once and keep using.

Where and how to attach hooks is covered in the Using hooks and filters properly series, and other ways of folding AI into a workflow live in the AI in practice archive. If the thing that needs work is a running site rather than a file, our optimization program handles upgrades, performance and security as one job.

More on this topic

All technotes

Working with AI Advanced

Security review for AI-written code: four recurring gaps

Generated code usually looks idiomatic. The trouble is that it can look idiomatic while omitting precisely the escaping, the prepared statement, the capability check or the path validation…

Developers 11 min read

Working with AI Advanced

A project context file, so the same mistake is not repeated

Every session starts blank, but a project's decisions and incident history must not. Collect conventions, reasoning, traps already hit and regression checks in one document, and the same…

Developers 9 min read

Working with AI Practical

What AI code review catches, and what it cannot

Missing escaping and missing capability checks are caught reliably. What has to be executed to be known — runtime behaviour, hook ordering across plugins, whether the change matches…

Developers 7 min read

₩270,000 · Join the program