Syncing frontend and backend code in one repo

The WordPress ecosystem has settled into treating the frontend and the backend as two separate projects that talk through one narrow, fragile pipe. The cost of that is what I call the fragmentation tax. After 14 years of it, I still do not accept that syncing frontend and backend code should feel like a negotiation every time you want to add a toggle to a WooCommerce checkout.

I have burned plenty of hours working out why a React-based Gutenberg block was getting a 400 Bad Request, only to find that I had refactored a PHP hook on the server and left the JavaScript fetch call pointing at the old shape. Tools help a little. What actually fixed it for me was an architectural change: stop spreading one project across several repositories.

Why a monorepo helps here

Separate repos for your React frontend and your WordPress backend make life harder for you and for your AI agents. Roots Bedrock is where this landed for me. With the logic and the UI in one codebase, the development environment treats them as one thing, and version control stays in step instead of drifting.

In a monorepo your coding agent, whether that is Claude Code or Cursor, can read the PHP function producing the data and not just the CSS styling it. That context is usually what separates a patch that breaks in a week from a real refactor. My guide on maximizing Claude Code effectiveness covers how I set up those sessions.

When the cache outlives the hook

The assumption that trips people up is that the data will be there by the time the JavaScript asks for it. One client’s checkout failed intermittently because the frontend kept getting a cached REST API response that the backend hook had not cleared yet. Here is the way most devs write a custom endpoint:

<?php
// The Naive Approach: Manual sync
add_action( 'rest_api_init', function () {
    register_rest_route( 'bbioon/v1', '/update-user/', array(
        'methods' => 'POST',
        'callback' => 'bbioon_update_user_data',
    ) );
} );

function bbioon_update_user_data( $request ) {
    // We hope the frontend sends 'user_meta'...
    $meta = $request->get_param( 'user_meta' );
    update_user_meta( get_current_user_id(), 'bbioon_custom_field', $meta );
    return new WP_REST_Response( array( 'status' => 'success' ), 200 );
}

Change that payload key to custom_meta, whether it is the frontend dev doing it or you three months later, and the backend fails without saying a word. So I work schema-first now, or keep a documentation file like AGENTS.md that both sides have to agree with.

Keeping an AGENTS.md in the project root

I keep an AGENTS.md file at the root of the project, written for the LLM rather than for a person. It holds a map of the endpoints and the payload each one expects. When I ask the agent to add a feature, it reads that map first, which saves me from re-checking the register_rest_route params every few minutes.

If you are stuck across several repos, Cursor Workspaces lets you point the agent at both of them at once. It fakes enough of a monorepo to give the AI the context it needs. A workaround, but it does the job.

If this kind of frontend and backend wiring is eating your dev hours, I take it on. I have been wrestling with WordPress since the 4.x days.

Build with the whole stack in view

The more distance you put between your logic and your UI, the more places a bug has to sit unnoticed. A monorepo plus a context file for the agent takes most of the guesswork out of it. The WordPress REST API handbook is the reference I go back to when the endpoint contract itself is the thing in question.

author avatar
Ahmad Wael
I'm a WordPress and WooCommerce developer with 15+ years of experience building custom e-commerce solutions and plugins. I specialize in PHP development, following WordPress coding standards to deliver clean, maintainable code. Currently, I'm exploring AI and e-commerce by building multi-agent systems and SaaS products that integrate technologies like Google Gemini API with WordPress platforms, approaching every project with a commitment to performance, security, and exceptional user experience.