Skip to content
ThemesCraft.

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.

SafeguardWhat it stopsThe functionTypical omission
Capability checkA subscriber performing an admin actioncurrent_user_can()Form handler with no check at all
Nonce verificationCross-site request forgerywp_verify_nonce() / check_admin_referer()Nonce is created in the form and never verified on submit
Input sanitisationMalicious data entering the databasesanitize_text_field() and siblingsRaw $_POST written straight to options
Output escapingStored XSS when the value is displayedesc_html(), esc_attr(), esc_url()Value echoed directly back into the page
The four checks to verify in every AI-generated handler. Two of them, nonce and capability, must both be present. Either alone is insufficient.

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.

  1. 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.
  2. Ask for the WordPress way, not the PHP way. Models will happily write raw SQL, use file_get_contents for remote requests, and echo HTML directly. Specify $wpdb->prepare, wp_remote_get, the Settings API, and wp_enqueue_script.
  3. 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.
  4. 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_function or 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

StageRough timeWhat actually happens
Define the scope in one sentence15 minThe hardest part. Vague scope produces vague code
Scaffold: header, guard, activation hook30 minFast and usually correct
Core functionality2 to 3 hoursIterative. Works around the third attempt
Admin settings screen1 to 2 hoursWhere the security omissions cluster
Security review against the four checks1 hourThe step people skip. Do not
Testing on a staging site1 hourFatal errors, conflicts, PHP notices
A realistic day for a small single-purpose plugin. Anything touching payments, user data or file uploads is not a one-day project.

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.

Leave a response

Your email address will not be published. Required fields are marked *