April 28, 2026

Cursor vs Claude Code vs GitHub Copilot for WordPress: A Hands-On Comparison

Most “AI coding tool comparison” articles are useless. They list features from product pages, paste a marketing tagline, and call it analysis. None of them tell you what actually happens when you give the same WordPress task to three different tools and watch them fail in three different ways.

This article does that.

I ran Cursor, Claude Code, and GitHub Copilot through five WordPress development tasks — the kind of work an actual WordPress developer does in a normal week. Building a custom block. Adding a settings page. Auditing a plugin for security issues. Refactoring legacy code. Debugging a hook that’s not firing. Same prompts, same project, same constraints. Then I compared the output.

If you’re trying to decide which tool to invest your time and money in for WordPress work, this is the comparison I wish someone had written for me.

Note on methodology: All tests were run on a local WordPress 6.5 install with a custom plugin and a child theme. Each tool was configured with WordPress-aware rules (a .cursorrules file for Cursor, CLAUDE.md for Claude Code, no rules support for Copilot). I used Claude Sonnet 4.5 in Cursor and Claude Code, and GPT-class models in Copilot’s default configuration. Results are from real sessions; outputs are summarized rather than reproduced verbatim, but the patterns are exactly what I observed.


TL;DR — The verdict

If you only read one section, read this one.

ToolBest forVerdict
CursorDaily editing, small features, in-flow workDefault choice for most WordPress devs
Claude CodeMulti-file refactors, audits, automationWins when the task is bigger than one file
GitHub CopilotInline autocomplete while typingSolid as a typing assistant; weak for reasoning

The simple recommendation: use Cursor as your daily editor, add Claude Code for bigger jobs. If you already have a Copilot subscription, keep it for autocomplete — it doesn’t conflict with the other two. If you don’t have it, you don’t need to add it.

Now the details.


The five tasks I tested

These weren’t synthetic benchmarks. They were real WordPress dev tasks, in roughly increasing order of complexity:

  1. Build a custom Gutenberg block that displays the 5 most recent posts from a selected category, with a category selector in the block sidebar.
  2. Add a settings page to a custom plugin with two options: a text field and a checkbox, properly nonced and sanitized.
  3. Audit a plugin with known security issues (missing escapes, no nonces, deprecated functions) and produce a findings report.
  4. Refactor a procedural plugin to object-oriented PHP with namespaces and PSR-4 autoloading.
  5. Debug a hook that isn’t firing — diagnose why an add_filter callback never runs.

Each task was given to all three tools with the same prompt. I scored on three dimensions: correctness (does it work?), WordPress-correctness (does it follow WP conventions?), and time to working result (how long to a state I’d commit).


Task 1: Build a custom Gutenberg block

The prompt: “Build a custom Gutenberg block called ‘Recent Posts by Category’ that displays the 5 most recent posts from a selected category. Include a category selector in the InspectorControls sidebar. Use server-side rendering for the frontend. The block should be in a plugin called ‘recent-posts-block’.”

Cursor

Time to working result: ~6 minutes.

Cursor generated a complete plugin folder structure: main plugin file with header, block.jsonsrc/edit.js with InspectorControls and a SelectControlsrc/save.js returning null (correct for server-rendered blocks), and a PHP render_callback that runs WP_Query and outputs the post list.

What it got right:

  • Used wp.data.useSelect to fetch categories from the data store
  • Used useBlockProps correctly in edit.js
  • Server-side render properly registered with register_block_type‘s render callback
  • Output was escaped with esc_html() and esc_url() in the PHP callback
  • Block attributes properly typed in block.json

What it missed initially:

  • Forgot to enqueue the build file via register_block_type‘s automatic asset detection (it tried to do it manually, which works but isn’t idiomatic)
  • The categoryId attribute had no default value, causing a PHP warning on first render

Both issues fixed with a single follow-up prompt: “Fix the asset enqueueing to use block.json automatic detection, and add a default value of 0 for categoryId.”

Claude Code

Time to working result: ~12 minutes.

Claude Code asked one clarifying question first: “Should the category selector show all categories, or only categories that have at least one post?” Useful question — most generic implementations don’t filter, which leads to empty dropdown options on a fresh site.

Then it generated the same set of files as Cursor, plus:

  • package.json with @wordpress/scripts as a dev dependency
  • Ran npm install automatically
  • Ran npm run build to produce the production assets
  • Tested the activation by running wp plugin activate recent-posts-block via WP-CLI

The clarifying question, the build step, and the activation test mean it took roughly twice as long, but the result was actually deployable rather than “code that should work.”

What it got right: All of the above plus the toolchain integration.

What it missed: Nothing of substance on this task.

GitHub Copilot

Time to working result: Did not finish.

This isn’t really Copilot’s lane. It’s an autocomplete tool, not a code-generation agent. I tried two approaches:

Approach 1: Open an empty recent-posts-block.php file and start typing the plugin header. Copilot autocompleted the header reasonably. Then I tried to use the inline chat (which Copilot has) to generate the block. The inline chat produced an outline but couldn’t generate the multiple files needed.

Approach 2: Use Copilot’s Workspace mode (the newer agent-style feature). It generated a more complete output, but the result was missing block.json entirely and used the older registerBlockType JavaScript pattern from 2020 instead of the current block.json-driven approach.

Net: Copilot is the wrong tool for “build a multi-file feature from a single prompt.” It’s fine for “autocomplete this function I’m typing.” For anything that requires generating a coordinated set of files with current best practices, it’s behind.

Task 1 winner

Claude Code for the most production-ready output. Cursor for fastest path to a working result. Copilot out of the running.


Task 2: Add a settings page

The prompt: “Add a settings page to a plugin under Settings → My Plugin Settings. Include two options: a text field labeled ‘API Key’ and a checkbox labeled ‘Enable debug mode’. Save them as a single options array. Include proper nonces, sanitization, and capability checks. Use the Settings API.”

This is bread-and-butter WordPress work. Every plugin developer writes one of these eventually.

Cursor

Time to working result: ~4 minutes.

Generated a complete settings class with:

  • add_action('admin_menu') registering the menu item under Settings
  • add_action('admin_init') registering settings, sections, and fields
  • A capability check (current_user_can('manage_options')) before rendering
  • wp_nonce_field() in the form (technically the Settings API handles this via settings_fields(), which Cursor used correctly)
  • Sanitization callback registered with register_setting that sanitized text fields and cast booleans
  • Output escaped with esc_attr() and esc_html()
  • All strings wrapped in __() with a text domain

What it got right: Pretty much everything. This is the kind of task where strong rules in .cursorrules plus a well-trodden API produces near-perfect output.

What it missed: The register_setting() call didn’t include the 'show_in_rest' parameter, which is fine for traditional settings pages but worth adding if you want the settings exposed to the block editor. Minor.

Claude Code

Time to working result: ~7 minutes.

Same output structure as Cursor, but Claude Code also:

  • Created a separate class-settings.php file rather than putting the settings code in the main plugin file
  • Updated the main plugin file to instantiate the settings class on plugins_loaded
  • Added a check that the settings class only loads in admin context
  • Wrote a brief inline comment explaining the sanitization choices

The file separation matters more on larger plugins than on a settings-only example, but it shows Claude Code’s tendency toward proper architecture even on small tasks. Whether that’s a feature or scope creep depends on your preference.

GitHub Copilot

Time to working result: ~15 minutes with significant manual work.

Copilot can autocomplete WordPress Settings API code reasonably well — there’s a lot of it in its training data. Working through the file with Copilot suggesting completions:

  • It correctly autocompleted add_actionadd_menu_page patterns, and basic field rendering
  • It missed nonces entirely on the first pass — generated a form without settings_fields() or any nonce mechanism
  • It used esc_html for attribute output (should be esc_attr)
  • It didn’t wrap any user-facing strings in translation functions

Result: working code, but with security issues that Cursor and Claude Code caught automatically because of their rules-file context.

Task 2 winner

Cursor for speed-to-correct. Claude Code for cleaner architecture. Copilot technically completed the task but produced output a reviewer would reject.


Task 3: Security audit

The prompt: “Review this plugin (path: /wp-content/plugins/legacy-contact-form/) for WordPress security issues. Identify missing output escaping, missing input sanitization, missing nonces, deprecated functions, and any other security concerns. Produce a structured report with severity levels and specific line references. Do not modify files.”

The “plugin” was a deliberately bad legacy contact form plugin I’d written: no escaping on output, no nonces on submission, used mysql_real_escape_string() for “sanitization,” and hardcoded an admin email check that could be spoofed.

Cursor

Time to working result: ~5 minutes.

Cursor’s chat panel handles multi-file analysis tolerably well when files are open. I opened the plugin’s three files, asked the audit prompt, and got back a structured report:

  • Critical: SQL injection risk in form handler — uses string concatenation despite mysql_real_escape_string (which only handles certain escape patterns)
  • Critical: No nonce verification on form submission, allowing CSRF
  • High: Missing current_user_can check before processing admin actions
  • High: Output of submitted data unescaped, allowing stored XSS
  • Medium: Deprecated mysql_* functions used throughout
  • Medium: Email validation done with regex instead of is_email()
  • Low: Strings not internationalized

Each issue had a file and approximate line reference. Cursor missed two real issues: a path traversal in the file upload handler and a timing attack in a token comparison. Caught 7 of 9 actual issues.

Claude Code

Time to working result: ~8 minutes.

This is where Claude Code starts to pull ahead. It read the entire plugin directory autonomously, then ran wp plugin status legacy-contact-form and grep -r "mysql_" . against the plugin to confirm the deprecated function usage was actually present and how widespread.

Findings report had everything Cursor caught, plus:

  • The path traversal in file upload (Cursor missed)
  • The timing attack in token comparison (Cursor missed)
  • A note that the plugin was active on the install — relevant context for prioritizing fixes
  • A suggestion of test queries that would exploit each issue (offered as proof, not as exploitation guide)

Caught 9 of 9 actual issues.

The reason Claude Code did better isn’t model quality — it’s that Claude Code can poke around the codebase autonomously rather than relying on the files I’d opened. Multi-file context wins for this kind of task.

GitHub Copilot

Time to working result: N/A — this task is essentially impossible with Copilot.

Copilot Chat can answer questions about a single file reasonably well, but it doesn’t have a “audit this directory” mode equivalent to what Cursor’s chat or Claude Code provide. I tried by opening each file and asking for security review on each individually. The results were:

  • Found surface-level issues in each file (missing escapes, missing nonces)
  • Missed cross-file issues entirely (the SQL injection risk required understanding how the form handler called the database wrapper)
  • No structured report — just inline commentary
  • No way to combine findings across files into a coherent summary

For codebase-level analysis, this isn’t the right tool.

Task 3 winner

Claude Code by a clear margin. Multi-file audits are exactly where it shines.


Task 4: Refactor procedural to OOP

The prompt: “Refactor this plugin from procedural code to object-oriented PHP with namespaces and PSR-4 autoloading. Preserve all functionality. The plugin file path is /wp-content/plugins/legacy-newsletter/.”

The “plugin” was a 1,200-line procedural newsletter plugin: subscribers, send queue, template system, all in two files with snake_case function names and globals.

Cursor

Time to working result: ~25 minutes, with extensive back-and-forth.

Cursor’s chat handled this in chunks. It proposed a class structure (Subscriber, SendQueue, Template, Newsletter as the main coordinator), generated the namespace/PSR-4 setup, and rewrote each chunk of procedural code into class methods.

Where Cursor struggled:

  • Lost track of context partway through the refactor — at one point it generated a method that called a function that no longer existed because it had been moved to a class earlier in the session
  • Required me to manually update the main plugin file to instantiate classes
  • Generated a composer.json for autoloading but used incorrect namespace mapping the first time

Final code worked but I had to do roughly 30% of the integration work myself.

Claude Code

Time to working result: ~40 minutes, mostly hands-off.

Claude Code’s workflow on this was different. It:

  1. Read all the files in the plugin
  2. Produced a refactoring plan: class structure, file layout, dependencies, migration steps
  3. Asked for confirmation before starting
  4. Created the new directory structure
  5. Wrote the classes one by one, running php -l on each new file to check syntax
  6. Updated the main plugin file to use the new classes
  7. Generated composer.json with correct PSR-4 mapping
  8. Ran composer dump-autoload to verify
  9. Activated the plugin via WP-CLI to test it loaded without errors

The longer time was almost entirely Claude Code working autonomously while I did other things. Active human time was maybe 5 minutes (approve the plan, answer one question about whether to add type hints).

End result was production-ready in a way Cursor’s wasn’t.

GitHub Copilot

Time to working result: Not really feasible.

Copilot can help you type the new OOP structure once you’ve decided what it is, but it can’t plan and execute a refactor across multiple files. I didn’t run this test in full — it would have been Copilot autocompleting code I was writing manually, which isn’t a fair comparison to what the other two tools were doing.

Task 4 winner

Claude Code, decisively. Multi-file refactoring is the task where its terminal-native, agentic approach pays off most.


Task 5: Debug a hook that isn’t firing

The prompt: “I have a filter callback registered with add_filter('the_content', 'my_plugin_modify_content') but it’s not running on single posts. Help me debug why.”

The setup: I deliberately introduced three possible reasons in different test runs to see which the tools could diagnose:

  • Run A: The filter was registered on init, but the function was loaded inside a class constructor that was instantiated on wp_loaded, after the_content had already been hooked.
  • Run B: The function name in the registration didn’t match the actual function name (typo in the registration).
  • Run C: Another plugin was running an add_filter with priority 1 that returned a modified content but stripped certain tags, masking my filter’s changes.

Cursor

Diagnostic approach: Asked questions, suggested checks.

Cursor’s chat suggested debugging steps: var_dump the result of has_filter, check the function name, check the priority, verify the file is loaded. Useful as a checklist but didn’t actually do any of it.

Diagnosed Run A correctly (after I shared the class structure and load timing).

Diagnosed Run B correctly (it suggested I check the function name first, which caught the typo).

For Run C, it suggested checking other plugins but couldn’t identify which one without me providing more context. Reasonable, given Cursor wasn’t running anything to inspect the live system.

Claude Code

Diagnostic approach: Ran actual debug code.

Claude Code’s first move was to run wp eval-file with a script that printed all callbacks registered on the_content, with their priorities and source files. This immediately surfaced the actual hook chain, which was decisive for all three runs:

  • Run A: showed that my_plugin_modify_content wasn’t in the callback list at all, so we knew it was a registration timing issue
  • Run B: showed my_plugin_modify_contentt (with typo) registered but no callable function with that name, leading directly to the fix
  • Run C: showed both my filter and the other plugin’s filter at priorities 10 and 1 respectively, with the other plugin clearly modifying content first

Diagnosis time was about a minute per run after the inspection script ran. The script itself took 30 seconds for Claude Code to write.

This is the kind of thing where being able to execute code in the WordPress runtime, via WP-CLI, transforms the task from “give a chat thread of suggestions” to “diagnose the actual problem.”

GitHub Copilot

Copilot Chat can help you write debugging code, but it can’t run anything. Equivalent to Cursor’s diagnostic approach but slower and less integrated. Caught Run B (the typo) by autocompleting function_exists checks while I was typing them. Couldn’t really help with the other two.

Task 5 winner

Claude Code, by a margin that grows with how complex the problem is.


Aggregating the results

Across the five tasks:

TaskCursorClaude CodeGitHub Copilot
Custom Gutenberg block✓ Fast✓✓ Most complete✗ Wrong tool
Settings page✓✓ Fastest✓ Best architecture⚠ Security issues
Security audit✓ Caught most✓✓ Caught all✗ Can’t really do
OOP refactor⚠ Lost context✓✓ Hands-off✗ Not feasible
Hook debugging⚠ Suggested only✓✓ Diagnosed live⚠ Limited help

The pattern is clear:

  • Cursor wins on speed for in-flow editing tasks. Single file or small feature, you’ll be done before Claude Code has finished planning.
  • Claude Code wins on anything that benefits from running things. Audits, refactors, debugging — all dramatically better when an agent can execute, not just suggest.
  • Copilot wins as autocomplete but not for multi-step tasks. It’s a category-different tool. Comparing it to the other two is slightly unfair, but worth doing because many developers conflate them.

What none of these tools do well (yet)

For balance, here’s where all three fell down on WordPress work:

WooCommerce hook accuracy. All three occasionally invented WooCommerce hooks that don’t exist. Claude Code at least asked “let me verify this hook exists” sometimes; Cursor and Copilot would generate confidently-wrong code. WooCommerce has 300+ hooks and it shows in the error rate.

Plugin compatibility reasoning. None of them have any way to know that, for example, your version of WPML is incompatible with your version of WooCommerce in some specific way. They generate code that should work; whether it works in your specific plugin soup is your problem.

Performance reasoning. All three will happily generate WP_Query calls inside loops or get_posts with posts_per_page = -1 on a million-row table. They can write code, they can audit security, they can refactor — but they don’t reason about performance unless you specifically ask, and even then they’re generic about it.

Modern block editor patterns. The block editor is moving fast. Tools’ training data sometimes lags behind. As of this testing, all three sometimes produced patterns from 2022-2023 that have since been deprecated or changed. Always sanity-check against current @wordpress/scripts documentation.


How I actually use them together

Based on this comparison and several months of real WordPress work, here’s the actual workflow I run now:

Cursor is open all day. It’s my editor. Cmd+K for inline edits, chat panel for “explain this function.” The vast majority of my AI-assisted coding happens here.

Claude Code I open when the task is bigger than a file. Refactoring, auditing, fixing something that requires running code, or doing anything I’d rather walk away from for 30 minutes. The boundary is something like: “if I’d be tempted to delegate this to a junior developer, I delegate it to Claude Code instead.”

Copilot stays installed. I have it from a previous subscription and the autocomplete is genuinely fast. I let it suggest while I type. If I were starting fresh today, I probably wouldn’t pay for it given Cursor’s autocomplete is solid — but it’s not in the way.

The two-tool combination (Cursor + Claude Code) is the productive setup. Adding Copilot doesn’t break it but doesn’t add much either.


Cost comparison

Worth noting since pricing varies:

  • Cursor Pro: $20/month at time of writing
  • Claude Code: Bundled with Claude Pro/Max plans; usage-based via API key for heavy users
  • GitHub Copilot: $10–19/month for individuals, Business and Enterprise tiers higher

For a serious WordPress developer, $20–40/month all-in across these tools is trivial relative to billable hours. The right comparison isn’t “which is cheapest” — it’s “which combination saves you the most time relative to your hourly rate.” For most developers that’s Cursor + Claude Code.


Conclusion

Cursor for everyday work, Claude Code for harder work, Copilot if you happen to have it. The differences aren’t subtle and they aren’t going away — these tools are optimizing for different jobs and the gap between them widens as the work gets more complex.

The bigger point: stop debating which AI coding tool is “best.” They’re complementary. The developers getting the most out of AI tooling in 2026 aren’t the ones who picked the right single tool. They’re the ones who learned which tool fits which task and switched between them fluently.

If you’re starting from scratch: install Cursor first, run it on real WordPress work for a week, then add Claude Code when you hit your first task that’s too big for Cursor’s flow. By the second week, the workflow will feel obvious.