My AI-Powered Workflow for Building WordPress Websites

Quick Summary

  • Each stage of an AI-assisted WordPress build should end with a repeatable check, since the agent can be wrong with confidence.
  • Checks include diffs of ACF JSON field groups, byte-for-byte code comparisons, PHP lint, WP_DEBUG renders and headless-Chrome screenshots against the design.
  • Back up before running idempotent migration scripts, confirm each check can actually fail, and test on the environment and plugin stack you launch with.

Every stage of my WordPress workflow now ends the same way: with a check I can run again and get the same answer. That rule matters more than which AI tool writes the code.

For the heavy lifting I use Claude Code, an AI coding agent that works in the terminal on your codebase: it reads files, edits them and runs commands. It handles volume well. It is also wrong with enough confidence that “the agent says it’s done” can’t be the finish line. (If you’re choosing between tools, I compare Claude Code, Cursor and ChatGPT by the kind of job each suits.)

So the workflow is a series of handoffs, and each one closes with something checkable. It’s the process I used to rebuild this site in September 2026. For each stage: what I do, what the AI does, and what I check.

1. Spec: a design to diff against, and a content model

What I do: finish the design before any theme code exists, then decide the content model. For every section: is it edited per page, shared across pages, or a post type?

What the AI does: on my site, the design itself came from AI. Claude Design produced a static HTML/CSS/JS prototype of 13 pages, plus a README handoff that mapped each section to a future template part and listed what still needed real data. A working prototype is better input for an agent than a flat mockup, because it has real markup, real breakpoints and real motion to compare against.

What I check: the shared-versus-per-page split, because it’s the most expensive thing to change later. Services, process, pricing, FAQ and the testimonials heading appear on several pages, so they became shared content, edited in one place. Everything on the “needs real data” list gets an owner, even if the answer comes later.

A content model is a promise to whoever edits the site. I’d rather make it on purpose than discover it in a template.

2. Scaffold: the theme and its field groups, as files

What I do: fix the architecture. A classic theme whose functions.php only loads files from inc/, one file per responsibility, pages built from ACF Flexible Content sections with one layout per design section. The reasoning behind that layout is in how I structure a scalable WordPress project.

What the AI does: generates the skeleton and the field groups. ACF’s local JSON setting writes every field group into the theme’s acf-json folder, so the whole content model, including all 24 section layouts on my site, exists as files.

What I check: the JSON diff. Reviewing a content model in version control is faster and more honest than clicking through admin screens, and it means the agent and I are reading the same source. I go deeper on this pattern in ACF + WordPress.

3. Templates: one design section, one file

What I do: set the rules before the agent writes a line. The design’s CSS and JS stay exactly as delivered; anything WordPress needs goes in a separate, small stylesheet. Layout names map to file names, so hero_home becomes template-parts/sections/hero-home.php.

What the AI does: converts each static section into a template part, with escaping and field lookups, one section at a time. It also wires page scripts to load only where their section is used. Deciding that is cheap: ACF stores the list of a page’s Flexible Content layouts in post meta, so the theme can ask whether a page uses hero_home without loading any field values.

What I check: each section against the prototype. Keeping the design’s CSS untouched pays off here, because any visual difference is a template bug, not a styling debate.

4. Content: scripts that are safe to run twice

What I do: decide what must survive the move, and set two rules for every script that writes to the database. Take a backup first. Make the script idempotent, so running it twice gives the same result as running it once.

What the AI does: writes those scripts. Sometimes, though, the best migration is none: the old portfolio post type kept its internal names (projects and project-category), so its 45 projects kept their data, categories and ordering untouched. Only the public URL base changed, from /projects/ to /project/, with 301 redirects from every old URL. A version constant in the theme flushes the rewrite rules once when a slug changes, and the SEO plugin’s cached URLs were reset so canonicals and the sitemap followed.

What I check: that what went in is what came out. Where scripts saved post content, every code block was compared byte for byte after saving. That caught a real bug on 4 posts: wp_update_post() strips backslashes from its input, and the fix was wrapping the data in wp_slash().

5. Verification: the AI WordPress workflow runs on checks, not impressions

What I do: define “done” as a list of commands that pass. Then I read the failures myself, and look at the screenshots myself.

What the AI does: writes and runs the checks. The first is the cheapest: PHP lint on every file in the theme.

Shell
# Run from the theme folder. Prints only the files that fail, then a verdict.
status=0
while IFS= read -r -d '' file; do
  if ! result=$(php -l "$file" 2>&1); then
    echo "$result"
    status=1
  fi
done < <(find . -name '*.php' -not -path './vendor/*' -print0)
[ "$status" -eq 0 ] && echo "PHP lint: all files OK" || echo "PHP lint: FAILED"

Lint only proves the files parse. The next check renders every page with WP_DEBUG on, so notices and warnings that a browser would never show end up in debug.log. With WP_DEBUG and WP_DEBUG_LOG set to true and WP_DEBUG_DISPLAY set to false in wp-config.php, a script along these lines does the job through WP-CLI:

PHP
<?php
// render-check.php: run with  wp eval-file render-check.php
// Requests every published page, post and project; reports non-200 responses
// and anything new in debug.log.
$log    = WP_CONTENT_DIR . '/debug.log';
$before = file_exists( $log ) ? filesize( $log ) : 0;

$post_ids = get_posts( [
	'post_type'      => [ 'page', 'post', 'projects' ],
	'post_status'    => 'publish',
	'posts_per_page' => -1,
	'fields'         => 'ids',
] );

foreach ( $post_ids as $post_id ) {
	$url      = get_permalink( $post_id );
	$response = wp_remote_get( $url, [ 'timeout' => 20 ] );
	$code     = wp_remote_retrieve_response_code( $response );
	if ( 200 !== $code ) {
		WP_CLI::warning( "{$code} {$url}" );
	}
}

clearstatcache();
$after = file_exists( $log ) ? filesize( $log ) : 0;
if ( $after > $before ) {
	WP_CLI::warning( 'New entries in debug.log:' );
	echo file_get_contents( $log, false, null, $before );
} else {
	WP_CLI::success( count( $post_ids ) . ' URLs rendered, no new notices.' );
}

After that come the checks that need a real browser: headless-Chrome screenshots at desktop and phone widths, compared against the static design, and scripted interaction tests for the parts that move. On my site that meant the portfolio filter with “load more”, the live blog search, the Copy buttons on code blocks, and the redirects.

What I check: that each check can fail. A test that has never been seen failing hasn’t proved much yet. The byte-for-byte comparison from stage 4 earned its place precisely because it did fail.

6. Clean-up and launch: fewer plugins, fewer surprises

What I do: go through the plugin list and ask one question of each: does the site still need this, now that the theme exists? On my site several answers were no. The Google Analytics tag moved out of a code-snippets plugin into a few lines of theme code. Code highlighting moved from SyntaxHighlighter to self-hosted Prism.js with a Copy button, line numbers and wrapped long lines. An extra file-types plugin that only existed to allow SVG uploads went, and so did a consent API plugin that had no consent banner to talk to.

What the AI does: writes the small replacements, the redirect map, and a list of dead URLs to answer with 410 Gone. The site has no store, so the old WooCommerce pages (shop, cart, checkout, my account) now say exactly that.

What I check: status codes (301 where something moved, 410 where it’s gone) and the front end with the real plugin stack active, not a clean install. Caching and optimization plugins change what the browser receives, so the last screenshots are taken on the environment that will actually go live.

What I don’t hand over in my AI WordPress workflow

The agent does most of the typing in this workflow. It doesn’t make the calls: what the content model promises, what survives the migration, which plugin stays, and whether a fix treats the cause or the symptom. The long version of how this played out is in I built a WordPress theme with AI, and the wider picture beyond WordPress, including where the time AI saves actually goes, is in how I use AI to build websites faster without cutting corners.

The short version:

  • Write the spec before the prompt: a finished design and an explicit content model.
  • Keep the content model in files, where it can be diffed.
  • Give the agent units small enough to compare against the design one at a time.
  • End every stage with a check that can be run again, and make sure it can fail.
  • Test on the environment you’ll launch on.
Share on X (opens in a new tab) Share on LinkedIn (opens in a new tab) Share on Facebook (opens in a new tab)

ChatGPT (opens in a new tab) Claude (opens in a new tab) Gemini (opens in a new tab) Perplexity (opens in a new tab) Grok (opens in a new tab)

More Insights

See More