How to Build a WordPress Plugin With ChatGPT in One Day
Build a WordPress plugin with ChatGPT in a day, and review it properly. The four security checks AI code omits by default, prompts that fix them, and where to stop.
Quick answer
You can build a working WordPress plugin with ChatGPT in a day, and the code it produces will almost certainly be insecure unless you ask for specific things. AI models reliably generate correct plugin structure and hooks, and just as reliably omit nonce verification, capability checks, input sanitisation and output escaping. Treat the model as a fast typist with no security instincts: specify the four safeguards explicitly, then review the output against them before the plugin touches a live site.
The genre of post this belongs to usually reads as a diary: I asked ChatGPT for a plugin, here is what it said, it worked, isn’t that remarkable. It was remarkable in 2023. It is now Tuesday.
What is worth writing down is the part those posts leave out. WordPress plugins run with full access to your site’s database and file system. The failure mode of AI-written plugin code is not that it does not work, which would be obvious and harmless. It is that it works perfectly while leaving an admin endpoint callable by anonymous visitors.
This is the workflow that produces a plugin you can actually deploy: the structure, the prompts that get secure code rather than merely working code, the four things to check every time, and the boundary where you should stop and hire a developer.
What a WordPress plugin minimally is
A folder in wp-content/plugins/ containing a PHP file with a header comment. That is the entire requirement. Everything else is convention.
wp-content/plugins/tc-reading-time/
├── tc-reading-time.php <- header comment lives here
├── includes/
├── admin/
└── readme.txt
<?php
/**
* Plugin Name: TC Reading Time
* Description: Adds an estimated reading time above post content.
* Version: 1.0.0
* Author: Your Name
* License: GPL-2.0-or-later
* Text Domain: tc-reading-time
*/
// Refuse to run if loaded directly rather than through WordPress.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
That ABSPATH guard is the first thing AI-generated plugins routinely omit, and it is the cheapest line of defence you will ever write. Without it, the file can be requested directly over HTTP, outside WordPress, with none of the security context loaded.
The four things AI code gets wrong
These are not exotic edge cases. They are the four checks that appear in every WordPress security guideline, and in practice a model will skip them unless you name them.
| Safeguard | What it stops | The function | Typical omission |
|---|---|---|---|
| Capability check | A subscriber performing an admin action | current_user_can() | Form handler with no check at all |
| Nonce verification | Cross-site request forgery | wp_verify_nonce() / check_admin_referer() | Nonce is created in the form and never verified on submit |
| Input sanitisation | Malicious data entering the database | sanitize_text_field() and siblings | Raw $_POST written straight to options |
| Output escaping | Stored XSS when the value is displayed | esc_html(), esc_attr(), esc_url() | Value echoed directly back into the page |
The nonce-and-capability pair is the one people get half right. A nonce proves the request came from your form; it does not prove the person is allowed to do the thing. A capability check proves they are allowed; it does not prove they meant to. You need both.
Watch out
Ask an AI model for an AJAX handler and you will usually get wp_ajax_ and wp_ajax_nopriv_ registered together, because that is the pattern that appears most often in training data. The nopriv variant makes the endpoint callable by logged-out visitors. If the handler writes to the database, you have just published an unauthenticated write endpoint. Register nopriv only when you genuinely intend anonymous access.
A settings handler, written correctly
This is the pattern to compare AI output against. It is deliberately ordinary: a form that saves one option. Every one of the four safeguards appears.
function tc_handle_settings_save() {
// 1. Capability: is this user allowed to do this at all?
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( esc_html__( 'Insufficient permissions.', 'tc-reading-time' ) );
}
// 2. Nonce: did this request come from our form?
check_admin_referer( 'tc_save_settings', 'tc_nonce' );
// 3. Sanitise every value on the way in.
$label = isset( $_POST['tc_label'] )
? sanitize_text_field( wp_unslash( $_POST['tc_label'] ) )
: '';
$wpm = isset( $_POST['tc_wpm'] )
? absint( $_POST['tc_wpm'] )
: 200;
// Validate ranges, do not just trust the type.
if ( $wpm < 50 || $wpm > 1000 ) {
$wpm = 200;
}
update_option( 'tc_reading_label', $label );
update_option( 'tc_reading_wpm', $wpm );
wp_safe_redirect( admin_url( 'options-general.php?page=tc-reading-time&updated=1' ) );
exit;
}
add_action( 'admin_post_tc_save_settings', 'tc_handle_settings_save' );
Then escape on the way out, every time, without exception:
<input type="text"
name="tc_label"
value="<?php echo esc_attr( get_option( 'tc_reading_label', '' ) ); ?>" />
The rule is escape late, at the point of output, rather than trusting that a value was clean when it went in. A value sanitised in 2024 and displayed by code written in 2026 in a different context needs escaping appropriate to that context.
Prompts that produce usable code
The difference between a plugin you can ship and one you cannot is almost entirely in what you asked for. Four techniques, in order of impact.
- Name the safeguards in the prompt. Not “make it secure”, which produces a comment saying the code is secure. Say: verify a nonce with check_admin_referer, check current_user_can(‘manage_options’), sanitise all input with the appropriate sanitize_ function, and escape all output with esc_html or esc_attr.
- Ask for the WordPress way, not the PHP way. Models will happily write raw SQL, use
file_get_contentsfor remote requests, and echo HTML directly. Specify$wpdb->prepare,wp_remote_get, the Settings API, andwp_enqueue_script. - Build one function at a time. Asking for an entire plugin in one prompt produces something plausible and hard to review. Asking for one function gives you code you can actually read, and each subsequent request keeps the context tight.
- Give it the version you are targeting. Say WordPress 6.x and PHP 8.2. Otherwise you get deprecated patterns from older training data, and
create_functionor pre-namespace idioms that no longer run.
Pro tip
After the model produces a file, start a fresh conversation, paste the code in, and ask it to find security problems in this WordPress plugin as a reviewer. Models are noticeably better at critiquing code than at writing it defensively, and a clean context removes the pull toward defending its own earlier output. It is the cheapest review pass available.
The day, realistically
| Stage | Rough time | What actually happens |
|---|---|---|
| Define the scope in one sentence | 15 min | The hardest part. Vague scope produces vague code |
| Scaffold: header, guard, activation hook | 30 min | Fast and usually correct |
| Core functionality | 2 to 3 hours | Iterative. Works around the third attempt |
| Admin settings screen | 1 to 2 hours | Where the security omissions cluster |
| Security review against the four checks | 1 hour | The step people skip. Do not |
| Testing on a staging site | 1 hour | Fatal errors, conflicts, PHP notices |
Test on a local install or a staging site, never on production. A fatal error in a plugin you just activated takes the site down, and although WordPress has fatal error protection, relying on it as your testing strategy is not a strategy.
Turn on WP_DEBUG while you develop. AI-generated code frequently produces undefined index notices and deprecation warnings that are invisible with debugging off and become fatal on the next PHP version.
When to stop and hire someone
AI-assisted development is genuinely good for small, self-contained plugins that solve one problem on one site. The boundaries are reasonably clear.
- Anything handling payments. Regulatory and liability exposure that no amount of prompting substitutes for expertise.
- Anything storing personal data. Data protection obligations attach to the design, not just the code.
- Anything you intend to distribute. A vulnerability in your own site is your problem. A vulnerability in a plugin a thousand sites installed is everyone’s.
- File uploads. The classic path to remote code execution, and the area where generated code is weakest because the correct approach involves several non-obvious WordPress functions.
- Anything you cannot read. If you cannot follow what the code does, you cannot review it, and shipping code you do not understand is the actual risk here regardless of who wrote it.
That last point is the honest summary. AI lowers the cost of writing a plugin; it does not lower the cost of being wrong. The review step is the whole job, and it is the step that a day-long build tends to eat.
If a plugin you built this way breaks the site, the recovery routes are in our guide to fixing a WordPress site after a plugin failure. If you are weighing building against commissioning, what WordPress development actually costs sets out the realistic numbers.
Frequently asked questions
Can ChatGPT really build a working WordPress plugin?
Yes, for small single-purpose plugins. It reliably produces correct plugin structure, header comments, hooks and filters, and it iterates quickly when something does not work. The limitation is not capability but defaults: the code works while routinely omitting nonce verification, capability checks, sanitisation and escaping unless you request them by name.
Is AI-generated WordPress plugin code safe to use?
Not without review. The characteristic failure is code that functions perfectly while leaving an admin action callable by anyone, because the model wrote a handler with no capability check. Verify four things in every handler: current_user_can, nonce verification, input sanitisation and output escaping. If all four are present and correct, the code is usually fine.
What should I include in a prompt to get secure plugin code?
Name the safeguards explicitly rather than asking for secure code. Request nonce verification with check_admin_referer, a current_user_can capability check, sanitisation with the appropriate sanitize_ function, and escaping with esc_html or esc_attr on output. Also state your WordPress and PHP versions, or you will get deprecated patterns from older training data.
Why is wp_ajax_nopriv dangerous in generated code?
Registering wp_ajax_nopriv alongside wp_ajax makes the endpoint callable by logged-out visitors. AI models pair them by default because that combination is common in training data. If the handler writes to the database or changes settings, you have created an unauthenticated write endpoint. Register the nopriv variant only when anonymous access is genuinely intended.
How long does it take to build a WordPress plugin with AI?
A small single-purpose plugin is a realistic day: about half an hour to scaffold, two to three hours on core functionality, one to two on an admin screen, then an hour each for security review and testing. Anything involving payments, personal data or file uploads is not a one-day project regardless of tooling.
Should I put AI-generated code in functions.php or a plugin?
A plugin, nearly always. Code in an active parent theme’s functions.php is deleted by the next theme update, and it stops working if you switch themes. A plugin survives both, and crucially it can be deactivated from the dashboard or by renaming its folder if it causes a fatal error, which theme code cannot.
What is the difference between sanitising and escaping?
Sanitising cleans data on the way in, before it is stored, using functions such as sanitize_text_field or absint. Escaping makes data safe on the way out, at the moment it is printed, using esc_html, esc_attr or esc_url. You need both, because the context a value is displayed in may differ from the context it was collected in.
When should I hire a developer instead of using AI?
Anything handling payments, storing personal data, accepting file uploads, or intended for public distribution. Those carry liability that prompting does not address, and file uploads in particular are where generated code is weakest. The simplest test is whether you can read and follow the code. If you cannot review it, you should not ship it.