Vibe Coding WordPress: Where AI-Written Code Breaks
A vibe-coded WordPress plugin can pass every click test and still leave your site open. The settings page saves, the shortcode renders and the REST endpoint returns clean JSON. Then a subscriber account, or a visitor who never logged in, calls that same endpoint and downloads every form entry the site has ever collected.
Vibe coding WordPress plugins fails this way because the AI handles the part you can see and skips the part WordPress leaves to the developer. These are the questions it most often never asks:
- who is allowed to run this code
- what the input actually contains
- when the hook fires
- what every other active plugin is doing on the same request
My position is simple. Let the AI write the code, and keep the engineering with a person who understands WordPress, because on WordPress the engineering is mostly the part a demo never shows. Below are the places AI-written WordPress code breaks most often, the fixed code for each and the review checklist I’d run before any of it reaches a live site.
The Vibe Coding Debate on X
Developers have been arguing about vibe coding on X all week. The post that set it off was a spot-the-bug challenge from @dark_coderz on October 8, which has crossed 475,000 views: “If you’re a developer and can’t spot the bug, you’re probably a vibe coder.” The screenshot is a tiny JavaScript function:
function getUser() {
const user = {
name: "Ash",
age: 20
};
return
user;
}
console.log(getUser()); // undefinedJavaScript inserts a semicolon after the bare return, so the function returns undefined and the object below it never leaves. Nothing throws, nothing warns and the code looks fine at a glance.
I read people replying that the challenge was pointless because an AI can spot that bug too, and one developer said exactly that under the original post. He has a point about that snippet. The expensive bugs in WordPress sit somewhere else, though. A missing capability check is just as quiet as that return, and no linter turns it red, because to PHP and to the AI it is perfectly valid code.
Bryan Helmkamp put the distinction well: prompting agents without “durable, human-provided authoritative intent is vibe coding not software engineering,” and the disappointing results on brownfield codebases in 2026 reflect that. A WordPress site running a few dozen plugins is about as brownfield as code gets.
Where I Stand
Before going into the code, I want to make sure my position is clear, because most of the arguing on X happens between two extremes.
There are broadly three ways WordPress developers are handling AI right now.
The first is full vibe coding, the way Andrej Karpathy described it in February 2025: give in to the vibes and “forget that the code even exists.” For a throwaway prototype on a local site, that is fine. Nobody gets hurt when a local experiment has an open endpoint.
The second is refusing AI altogether. I think that is a mistake. Current models write valid PHP almost every time, they know the WordPress APIs well and they save hours on the repetitive parts, for example:
- settings pages
- block scaffolds
- WP-CLI commands
- tests
Avoiding them makes the work slower, and the code comes out no safer for it.
The third is the one I recommend. The AI writes, and a person who understands WordPress owns every line that touches permissions, input, output, the database and the request lifecycle. It is wise to treat AI output the way you’d treat a pull request from a fast, well-read junior developer who has never run a production WordPress site. You read it first and merge it after.
Being extreme in either direction isn’t a good idea at all. The first camp ships open endpoints, and the second writes every settings page by hand.
Why WordPress Code Breaks Differently
WordPress is a shared runtime. Your plugin’s code runs in the same PHP process as core, the theme and every other active plugin, on every request, with full access to the database, the filesystem and the current user’s capabilities. There is no sandbox between your functions.php snippet and the wp_users table.

That design is why WordPress is so easy to extend, and it is also why AI-written code fails here in its own way. When an AI-built standalone app is wrong, the build often breaks or the page throws an error, and somebody notices. A WordPress plugin written by AI usually fails silently, because WordPress fills the gaps with defaults that suit a working demo:
- A REST route without a real permission check is still a working route.
- An AJAX handler with a nonce check but no capability check still saves the settings.
- An option saved without an autoload decision still saves, and then loads on every page.
- A string concatenated into SQL still returns the right rows for normal input.
- A filter at the default priority still runs, in whatever order the plugins happened to load.
Brad Williams made a related point about vibe-coded websites in September: most of those things WordPress does out of the box, and it’s easy to forget important features when your CMS has been handling them for you. Plugin code is the reverse case. WordPress gives you the tools, and it doesn’t force you to use them.
Vibe Coding Security in Numbers
The current data points to AI code that is fluent and insecure at the same time, which is a worse combination for WordPress than code that simply fails. These are the figures that matter for plugin work:
- Veracode’s 2026 GenAI Code Security Report found that roughly 44% of AI code generation tasks introduced a known security vulnerability. The average security pass rate across models was 56%, barely changed from 55% in its first report, even though syntax is now correct nearly 100% of the time.
- The same report breaks it down by vulnerability type. Models passed SQL injection tasks 83% of the time but cross-site scripting tasks only 15% of the time.
- Patchstack’s State of WordPress Security in 2026 counted 11,334 new vulnerabilities in the WordPress ecosystem in 2025, up 42% from 2024. Plugins accounted for 91% of them, and core had only 6, all low priority.
- Patchstack’s 2026 vulnerability statistics put cross-site scripting first at about 31% of disclosed issues, broken access control at about 20% and SQL injection at about 8%.
- The same Patchstack report names broken access control as the most exploited vulnerability class of 2025.
Put the two sources side by side and the pattern is clear. AI models have learned $wpdb->prepare() well, and they are weakest at escaping output, which is exactly the class that tops the WordPress vulnerability list. Patchstack’s report also says, in plain words, that “vibe coding is here to stay, and it’s rapidly merging with WordPress,” with agencies generating new plugins on demand.
The WordPress.org Plugins Team is seeing the same wave. Its June 2026 update reported a record of around 700 new plugin submissions a week in May, 2.7 times the 2025 figure and 5 times the 2024 figure. Back in January, a Plugins Team member wrote on r/WordPress that most of a record day’s submissions were written with AI tools, that the team has no policy against AI-generated plugins and that “AI coding tools frequently fail to implement the changes we require.” The same post adds that if your AI can’t keep up with the requirements, the plugin won’t be approved, and the same goes for a human developer. That last line is the fairest summary of this whole debate I have read.
Where AI-Written WordPress Code Breaks
These are the failure points I’d check first in any AI-written plugin or snippet. Before going into each one, I want to ensure the pattern is clear: in almost every case, the AI writes code that does the job and skips the part that decides who is allowed to do the job, or what happens when the job runs next to something else.
Nonces and Capability Checks
A nonce proves the request came from a form your site generated for this user. It does not prove the user is allowed to do the thing. AI-written AJAX and admin-post.php handlers often check the nonce and stop there.
// What AI usually writes: a nonce check and nothing else.
add_action( 'wp_ajax_gt_save_settings', 'gt_save_settings' );
function gt_save_settings() {
check_ajax_referer( 'gt_settings', 'nonce' );
update_option( 'gt_settings', $_POST['settings'] );
wp_send_json_success();
}wp_ajax_ hooks fire for every logged-in user, subscribers included. If that nonce is ever printed on a screen a subscriber can open, a subscriber can rewrite your settings. Even without that, the handler saves raw $_POST data straight into an option.
function gt_save_settings() {
check_ajax_referer( 'gt_settings', 'nonce' );
if ( ! current_user_can( 'manage_options' ) ) {
wp_send_json_error( array( 'message' => __( 'You are not allowed to do this.', 'gt-plugin' ) ), 403 );
}
$raw = isset( $_POST['settings'] ) ? wp_unslash( $_POST['settings'] ) : array();
$clean = array(
'title' => isset( $raw['title'] ) ? sanitize_text_field( $raw['title'] ) : '',
'enabled' => ! empty( $raw['enabled'] ),
);
update_option( 'gt_settings', $clean, false );
wp_send_json_success();
}The fixed version answers 3 questions the first one ignored:
- Did this request come from our form? (
check_ajax_referer()) - Is this user allowed to change settings? (
current_user_can()) - What exactly are we storing? (an allowlist of keys, each sanitized for its type)
David Perez of the Plugins Team put “REST, AJAX or admin-post endpoints without a capability check (a nonce alone is not authorization)” first among the patterns that push a release’s security score up, in a comment on the automated security review announcement. He also wrote that most of what the team sees isn’t malicious code. It’s “an endpoint that was written for an admin screen and ended up reachable by anyone.” That sentence describes vibe-coded WordPress code better than any thread on X.
REST API Permission Callbacks
Since WordPress 5.5, registering a REST route without a permission_callback triggers a _doing_it_wrong notice, because the REST API treats routes without one as public. The core team added the notice after missing callbacks had exposed endpoints “multiple times in the wild.”
AI models learned that lesson in the most literal way. They almost always include a permission_callback now, and often it is __return_true, because that’s the documented value that makes the notice go away.
// Public to the entire internet.
register_rest_route( 'gt/v1', '/export', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'gt_export_entries',
'permission_callback' => '__return_true',
) );__return_true is correct for data you would happily print on the homepage. For anything else, the callback should ask a real question:
add_action( 'rest_api_init', function () {
register_rest_route( 'gt/v1', '/export', array(
'methods' => WP_REST_Server::READABLE,
'callback' => 'gt_export_entries',
'permission_callback' => function () {
return current_user_can( 'manage_options' );
},
) );
} );For routes that act on one object, the check should be about that object, for example current_user_can( 'edit_post', $id ), so an Editor can’t touch something they couldn’t edit in the admin. You can find every public route on a site by searching the codebase for __return_true. It is a quick check and I’d run it on every AI-written plugin before activating it.
Sanitization and Escaping
The WordPress rule is to sanitize on input, validate what you can and escape on output, as late as possible. AI-written code tends to do one of the three, usually sanitizing the input and then trusting it forever.
// Unescaped output. $title and $url came from the database, so they "feel" safe.
echo '<a href="' . $url . '">' . $title . '</a>';printf(
'<a href="%1$s">%2$s</a>',
esc_url( $url ),
esc_html( $title )
);The escaping functions are not interchangeable, and the AI mixes them up often enough that it is worth knowing which one goes where:
esc_html()for text between tagsesc_attr()for values inside HTML attributesesc_url()for anything inhreforsrcwp_kses_post()when you genuinely need to allow post-style HTMLwp_json_encode()when passing data to scripts, andesc_js()only for the rare inline handler
Remember the 15% cross-site scripting pass rate from Veracode. On WordPress, data stored in a post, an option or user meta is user input that happens to be sitting in the database. Escaping it at output is the only point where you know the context.
Database Queries
AI models know $wpdb->prepare() exists, and Veracode’s 83% SQL injection pass rate shows it. The failures are subtler than a missing call:
- interpolating a variable into the query string and then wrapping the already-built string in
prepare() - building a
LIKEclause without escaping the wildcards - putting a table or column name in a placeholder that only works for values
// Classic SQL injection. Works perfectly for every normal email address.
$rows = $wpdb->get_results(
"SELECT * FROM {$wpdb->prefix}gt_entries WHERE email = '" . $_GET['email'] . "'"
);$email = isset( $_GET['email'] ) ? sanitize_email( wp_unslash( $_GET['email'] ) ) : '';
$search = isset( $_GET['s'] ) ? sanitize_text_field( wp_unslash( $_GET['s'] ) ) : '';
$rows = $wpdb->get_results(
$wpdb->prepare(
'SELECT id, email, created_at FROM %i WHERE email = %s AND message LIKE %s LIMIT %d',
$wpdb->prefix . 'gt_entries',
$email,
'%' . $wpdb->esc_like( $search ) . '%',
50
)
);%i is the identifier placeholder for table and column names, added in WordPress 6.2. esc_like() escapes % and _ in the user’s search term before you add your own wildcards. And before writing any direct query, it’s worth asking whether WP_Query, get_posts() or the meta APIs already do the job, because those come with caching and the AI reaches for raw SQL far more often than it needs to.
Hooks, Priorities and Load Order
This is where AI-written code breaks in ways that only show up on some sites. WordPress loads plugins, then fires plugins_loaded, init, wp_loaded and so on, and a lot of functions simply aren’t ready before a certain point.
// Runs the moment the plugin file is included.
if ( current_user_can( 'manage_options' ) ) {
add_action( 'admin_menu', 'gt_add_settings_page' );
}current_user_can() depends on pluggable functions that load after plugins, so calling it at file load is a fatal error waiting for the right request. The fix is to let the hook ask the question at the right time. add_options_page() already takes a capability argument:
add_action( 'admin_menu', function () {
add_options_page(
__( 'GT Settings', 'gt-plugin' ),
__( 'GT Settings', 'gt-plugin' ),
'manage_options',
'gt-settings',
'gt_render_settings_page'
);
} );Priorities are the other half. The default priority is 10, and two callbacks on the same hook at the same priority run in the order they were added, which depends on plugin load order. AI code almost never chooses a priority on purpose. If your the_content filter needs to run after another plugin’s filter, say so with a number and a comment explaining why, and test it with that other plugin active. Query Monitor’s hooks panel shows exactly which callbacks are attached to a hook and at what priority. My WordPress developer cheat sheet has the common hooks in the order they fire.
Transients and Caching
A transient is a cached value with an expiry date. AI writes transients that technically work and then misses the details that make them safe on a real host:
- A transient set without an expiration is autoloaded, so it loads on every request and never cleans itself up.
- With a persistent object cache like Redis, transients live in the object cache. AI-written cleanup code that runs
DELETE FROM wp_options WHERE option_name LIKE '_transient_%'does nothing there. - Caching per-user data under one shared key leaks one user’s data to the next user.
get_transient()returnsfalseon a miss, so storingfalseas a real value turns every request into a miss.
$stats = get_transient( 'gt_dashboard_stats' );
if ( false === $stats ) {
$stats = gt_build_dashboard_stats(); // The slow part: queries, remote calls.
set_transient( 'gt_dashboard_stats', $stats, 12 * HOUR_IN_SECONDS );
}Transients should be used when the work is expensive and the answer can go a few hours stale. They should be skipped when the value is cheap to compute or must be fresh on every request, because then you’re paying for a cache write you never needed.
Autoloaded Options and Performance
Every option with autoload turned on is loaded on every single page request, front end and admin. WordPress 6.6 changed the Options API so the $autoload parameter defaults to null, which lets WordPress decide, and options over 150,000 bytes are no longer autoloaded unless you pass true explicitly.
AI-written plugins undo that protection in 2 ways. They pass true or 'yes' out of habit, and they store things in options that were never meant to be options:
- logs
- API responses
- import queues
- lists that grow with every form submission
The result is bloat, causing slow admin load and a heavier first query on every page. A setting that only one admin screen reads should be saved with false. Data that grows over time belongs in its own table or a custom post type. You can check what a plugin added with:
wp option list --autoload=on --search="gt_*" --format=tableIf autoload bloat is already slowing a site down, my notes on WordPress speed optimization cover the cleanup.
Multisite
AI models are trained mostly on single-site code, and multisite breaks most of its assumptions. The usual mistakes are:
$wpdb->prefixand$wpdb->base_prefixused interchangeably. The first is the current site’s prefix, the second is the network’s.get_option()used for settings that should be network-wide, whereget_site_option()belongs.- Custom tables created only on activation, so a network-activated plugin has no table on sites created later. New sites need the
wp_initialize_sitehook. switch_to_blog()without a matchingrestore_current_blog(), which leaves the rest of the request running on the wrong site.- Capabilities like
manage_optionschecked where the action should be limited to super admins.
If the plugin will ever run on a network, multisite has to be in the prompt and in the test plan. Otherwise, the Network: header should stay out of the plugin.
Internationalization
AI code usually wraps strings in __(), which looks like translation support. Then it breaks the rules the translation tools depend on:
// Translation tools can't extract any of these.
__( $message, 'gt-plugin' );
__( 'Saved ' . $count . ' entries', 'gt-plugin' );
__( 'Settings saved', $this->text_domain );/* translators: %d: number of saved entries. */
$text = sprintf( _n( 'Saved %d entry', 'Saved %d entries', $count, 'gt-plugin' ), $count );The text domain has to be a literal string matching the plugin slug, the string has to be literal too and plurals need _n(). Load timing matters as well. Since WordPress 6.7, core shows a _load_textdomain_just_in_time notice when a plugin triggers translation loading before init, which is exactly what happens when an AI puts translated strings in a class constructor that runs on plugin load. For plugins hosted on WordPress.org, the manual load_plugin_textdomain() call the AI likes to add isn’t needed at all.
Block Editor Dependencies
Block code is where AI output ages fastest, because the editor’s APIs change more often than PHP’s. These are the failures I’d look for:
- Hardcoded script dependencies like
array( 'wp-blocks', 'wp-element' )while the JavaScript imports from@wordpress/componentsor@wordpress/data, so the editor throws on a screen where those scripts weren’t loaded. - A changed
save()function with no deprecation, so every existing block in every post shows “This block contains unexpected or invalid content.” - Blocks registered in JavaScript only, skipping
block.json, which loses server-side registration and asset handling.
The fix for the first one is to let @wordpress/scripts generate the dependency list and use it:
$asset = include plugin_dir_path( __FILE__ ) . 'build/index.asset.php';
wp_enqueue_script(
'gt-sidebar',
plugins_url( 'build/index.js', __FILE__ ),
$asset['dependencies'],
$asset['version'],
true
);For blocks, register_block_type( __DIR__ . '/build/my-block' ) reads block.json and handles the rest. Any change to saved markup needs a deprecated entry, and an AI won’t add one unless you tell it that existing content matters.
PHP Version Compatibility
WordPress 7.0 raised the minimum PHP version to 7.4, and it is fully compatible with PHP 7.4 through 8.5. Modern models write modern PHP by default, and every one of these is a parse error on PHP 7.4:
- constructor property promotion
matchexpressions- the nullsafe operator
?-> - enums
- readonly properties
The plugin should either be written for its real minimum or say so in the Requires PHP: header, which WordPress checks before activation and before updates. Without the header, a parse error on an older host shows up at activation, or worse, after an automatic update on a plugin that was already active. I’d decide the minimum PHP version before the first prompt and put it in the agent’s rules file, because “write PHP 7.4-compatible code” is much easier to follow than “undo the PHP 8.2 syntax you just used everywhere.”
Plugin Conflicts
AI code is written as if it’s the only code on the site. On WordPress it never is. These are the conflicts I’d check for:
- Unprefixed function, class and constant names like
save_settings()orSettings, which fatal the moment another plugin declares the same name. - Bundled Composer libraries such as an HTTP client or a PDF library loaded globally. If 2 plugins ship different versions, whichever loads first wins, and the other plugin gets an API it wasn’t written for. Tools like PHP-Scoper or Strauss move your copy into your own namespace.
- Global
wp_enqueue_script()calls on every admin page, where the script should load only on the plugin’s own screen. - Output buffering,
remove_all_filters()and other global changes that quietly break someone else’s plugin.
A namespace or a short unique prefix on everything is the cheapest insurance in WordPress development, and it costs one line in the prompt.
Security Disclosures and Maintenance
This is the part vibe coding has no answer for, because a published plugin has to be fixed every time someone finds a hole in it.
Patchstack’s 2026 report found that 46% of vulnerabilities in 2025 had no patch by the time they were publicly disclosed, and that the median time to mass exploitation for heavily exploited vulnerabilities was 5 hours. The same report notes that under the EU’s Cyber Resilience Act, every commercial WordPress plugin will need a vulnerability disclosure program to be sold to European users.
WordPress.org is closing part of the gap from its side. Since June 5, every plugin and theme release goes through a 6-hour cooldown during which several AI models and Jetpack Scan review the changes, and high-risk releases are blocked automatically. On July 28 that review caught a backdoor committed to a plugin with around 20,000 active installations before the release was distributed. It is a good system, and it is also a sign of how much AI-assisted code is now flowing into the directory.
None of that replaces you. When a researcher emails you a report about your plugin’s REST endpoint, you need to understand the endpoint well enough to fix it the same day. If the code was vibe-coded and never read, you’ll be asking an AI to fix code you don’t understand, based on a report you can’t verify, under a public deadline. Whoever plans to maintain a folder full of vibe-coded plugins that way must be having a lot of free weekends.
AI-Written WordPress Code Review Checklist
These are the steps I’d run on any AI-written plugin, snippet or theme feature before it reaches a live site:
- Search the code for
wp_ajax_,admin_post_,register_rest_routeand__return_true. Every handler needs a capability check that matches the action, and every REST route needs a real permission callback. - Search for
$_GET,$_POST,$_REQUESTand$_COOKIE. Each one should be unslashed, sanitized for its type and validated against what you expect. - Search for
echo,printandprintf. Every variable printed into HTML should pass through the right escaping function for its context. - Search for
$wpdb->. Every query with a variable should useprepare()with the right placeholders, including%ifor identifiers. - Run PHPCS with the
WordPress-Extraruleset. ItsWordPress.Securitysniffs (EscapeOutput, ValidatedSanitizedInput and NonceVerification) catch a large share of the patterns above. - Run Plugin Check locally or in CI with
wordpress/plugin-check-action. It covers security, translation, performance and directory requirements. - Run PHPStan with
szepeviktor/phpstan-wordpress, or Semgrep with WordPress rules, to follow user input across files. - Activate the plugin on a staging site with Query Monitor,
WP_DEBUGandWP_DEBUG_LOGon. Fix every notice, including_doing_it_wrongnotices. - Test it as a subscriber and as a logged-out visitor. Try every endpoint and form directly.
- Test it on the lowest PHP version in
Requires PHP:, on multisite if you support it, and next to the plugins your users are most likely to run. - Read the diff yourself. If you can’t explain a block of code, you shouldn’t ship it.
Steps 5 to 7 come almost directly from David Perez’s list of tools that catch what the WordPress.org security review flags. His last line is the one I’d put on the wall: “A short security-focused review step before tagging a release catches more than any scanner will.”
Using Claude Code and Cursor on WordPress Code
I compared both tools recently in Cursor vs Claude Code, and my pick is Claude Code. For this topic, the choice of tool matters less than what you tell it. Both read a rules file at the start of every session, and that file is where your WordPress engineering should live so you don’t have to repeat it in every prompt.
A rules file for WordPress plugin work can be short. Something like this works as a CLAUDE.md for Claude Code, or as a project rule in Cursor (my Cursor rules guide covers where those files go):
# WordPress plugin rules
- Minimum PHP 7.4, minimum WordPress 6.6. No PHP 8.0+ syntax.
- Prefix every function, class, constant, option, hook and handle with `gt_` or the `GT\Plugin` namespace.
- Every AJAX, admin-post and REST handler checks a capability. A nonce is not authorization.
- Never use `__return_true` as a permission_callback unless the data is public. Say why in a comment.
- Sanitize input with the type-specific function. Escape late with esc_html, esc_attr, esc_url or wp_kses_post.
- Every query with a variable uses $wpdb->prepare() with %s, %d, %f or %i.
- Pass autoload false to add_option and update_option unless the value is needed on every request.
- All user-facing strings use literal text and the `gt-plugin` text domain. No translated strings before init.
- Script dependencies come from the generated .asset.php file.
- Any change to a block's saved markup needs a deprecation.
- Run phpcs --standard=WordPress-Extra and Plugin Check before saying a task is done.Specific prompts help as much as the rules file. Chris Eggleston shared a good example of this: ask for a hook that runs after a Gravity Forms submission and sends entry data to a webhook URL stored in wp_options, instead of asking the AI to “build a plugin.” The narrower the job, the easier the output is to review.
The WordPress-specific agents are getting better at the feedback loop too. Automattic’s Studio Code, still in beta, is an agent built into the Studio desktop app and CLI. It works on local WordPress sites, runs WP-CLI commands and edits theme and plugin files there. That makes it a good place to vibe, because nothing touches production until you publish. It doesn’t make the output reviewed.
If you connect an agent to a live site through MCP, the same rule applies one level up. My WordPress MCP setup guide compares the main options, including Site Agent, which is my own plugin. Whichever you pick, write access to a production site should sit behind your approval.
FAQs on Vibe Coding WordPress Plugins
It is safe when someone who understands WordPress security reviews the code before it runs on a live site. The AI is good at the APIs and weak at deciding who may call them, so capability checks, escaping and database queries need a human read every time.
Not for being AI-generated. The Plugins Team has said it has no policy against AI-generated plugins. The plugin still has to meet every guideline, and the team has said AI tools often fail to make the changes reviewers ask for. If the code can’t be fixed to meet the requirements, it isn’t approved.
It catches a lot of them. Since June 2026, releases go through a 6-hour cooldown with an automated review by several AI models and Jetpack Scan, and high-risk releases are blocked. It only covers plugins distributed through WordPress.org, though, and custom plugins on client sites never go through it.
Missing or weak authorization is the one I’d check first, because an open endpoint leaks data without anyone on the site doing anything wrong. Unescaped output is the most common vulnerability class overall in Patchstack’s 2026 statistics, and models pass cross-site scripting tasks only 15% of the time in Veracode’s tests.
For learning and local experiments, yes. It’s a fast way to see how hooks and APIs fit together. For a plugin on a site with real users, a beginner should treat every AI answer as a lesson to understand before shipping it.
Final Remarks
The vibe coding debate on X keeps asking whether developers who can’t spot a bug are real developers. For WordPress, I’d ask a narrower question. Can the person shipping this plugin say who is allowed to call each endpoint, what each input contains and what the code does next to every other plugin on the site? If yes, use AI as much as you like. If not, the AI has written a plugin that nobody owns, and on a live site somebody has to.
If you’d rather have the plugin built to that standard from the start, that’s what my custom WordPress plugin development service is for.
Tell Google you want more of this.
Add Gaurav Tiwari as a preferred sourceOne tap, and this site shows up more often in your own Top Stories, AI Overviews and AI Mode. Remove it any time.