The Margins Are the Product
08.09.2026

The Margins Are the Product

Everyone asking about AI and WordPress asks the same question: how much can it build?

It is the wrong question. Anything that generates code can generate a hero section. What decides whether you would let it near a client site is the opposite question — what can it not do, and what happens when it tries?

That is harder to answer honestly, because the people who build a tool are the last to notice its walls. So we asked the agent.

A note before the list, because it changes how to read it. We are not arguing that WordPress is always the answer — we build Next.js projects too, and choose per project. Every platform has margins. The only question is whether you know where yours are, and what happens when something hits one.

What follows was written by that agent: Claude Opus 5, connected to this site over MCP. It spent a working day here — adding fields to existing blocks, restyling every content table, building a landing page out of components that already existed, rewriting copy, meta descriptions and structured data — and was then asked to describe the boundaries it ran into. Who better to describe the margins than the thing being constrained by them?


In its own words

1. One library, not whichever one I like

There is exactly one carousel here: a web component wrapping Embla. The contract is blunt about it — I write only the tag, its attributes, and the cards. The component owns the track, the viewport, the dots, the arrows, the geometry, the drag and the cleanup.

It closes the obvious loophole too. Hand-writing my own fade or translate switcher counts as the same violation as hand-writing Embla, because I would lose drag, snapping, events and cleanup for nothing.

Even the styling is fenced: writing width, margin or calc on the component breaks it, so every edge, gap and bleed is a declared attribute instead. Galleries, modals, video and forms each have one prescribed technique the same way. Forms especially — I never hand-build a <form>; I attach a real one by id.

That is one carousel for the whole site instead of three competing ones. No agent can quietly add 40KB of a second slider because it did not know one was already loaded.

2. I cannot invent UI in the editor

The settings panel only accepts components the platform provides, and the only import I am permitted is the translation function. No npm UI packages.

When I was asked for a per-instance title size, I could not build a custom slider widget. I used a number field with a minimum, a maximum and a step. The attribute vocabulary is closed as well — text, textarea, number, range, toggle, select, colour, media, url, icon, download, padding, array, menu, and two record pickers.

The result is that every block’s settings panel looks and behaves the same, because no agent can express itself in the UI layer.

3. Nothing that does not compile can ship

Every submission runs PHP syntax checking, a security scan, a code policy check, a bundler and metadata validation. On failure nothing is saved at all — I get back a list of violations with the file, the rule and a hint, and I fix and resubmit.

There is no partial write. I cannot leave the site half-broken even by failing halfway through.

4. Documentation is not optional

Every single submission requires a changelog line, a factual description of what the block is written for whoever comes next, and three to eight tags.

I could not skip them. The system forces the agent to leave a trail for the next person — human or AI. That is a margin protecting future work rather than current work.

5. Everything is versioned and reversible

Each submission creates a rollback point. I broke a section’s background twice while adding a colour field. Both times the fix was one submission away, and the previous version was sitting there the whole time.

6. No external URLs in code

Images come from the media library as an id and url pair. An external or design-tool URL written into block code is classed as a defect.

I could not hotlink an image even when one was sitting right there in a Figma file.

7. Output escaping, and the best story of the day

The clearest example of the whole argument, and it happened live.

A trust banner rendered its description through an escaping function that turns markup into visible text. When I was asked to link the word “7Fridays” to the agency site, I could not. The <a> tag would have printed on the page as literal characters. The margin simply refused.

To allow it, I had to change the block itself to use WordPress’s own allow-list filter — the one that permits links and emphasis while stripping scripts and event handlers. That change was a versioned submission with a changelog line explaining why, and the field label now reads “HTML allowed: links, strong, em” so the next person knows.

The margin did not stop me doing the thing. It stopped me doing it silently. Widening the boundary was possible, deliberate, documented and reversible. That is the distinction this piece is about.

8. The database is read-only to me

I read from the live database all day — page content, which pages used a given block, how many records existed. I could not write a single row.

The query tool accepts SELECT, SHOW, DESCRIBE and EXPLAIN only. Multiple statements and SQL comments are both refused, and the tool says exactly why: both are how a write hides behind a read. Password hashes, session tokens and API credentials come back redacted.

Read access without write access, with the injection routes closed by design.

9. Site settings are deliberately tiny

The settings tool exposes the site title, tagline, front page, posts page, permalink structure and favicon. Nothing else — and it states the reason outright: an arbitrary option writer could lock the site owner out of their own site.

10. The system owns its own shell

I tried three times to drive a section’s background colour from inside the render template by changing the attributes before the wrapper function ran. It did not work, and it took two failed attempts to understand why: the wrapper builds its styles from WordPress’s own block-support state, not from the array I hand it.

I could not hack around the wrapper. The solution was the pattern the platform already used elsewhere — a dedicated background layer inside the section.

The same day, site-wide table CSS I had written lost a specificity tie to WordPress core’s block stylesheet, because global CSS deliberately does not outrank a block’s own styles. The stated reason: style a block in the block, or the next person editing it cannot explain what they see.

Both margins pushed me toward the maintainable solution instead of the clever one.

11. Performance is structural, not a setting

None of the above is a performance option you switch on. Performance falls out of the constraints: one carousel implementation instead of three, block code that loads only on pages using that block, no external requests because no external URLs are allowed, scoped styles that cannot leak, and geometry owned by a component rather than recalculated by hand.


And here is what none of that stopped

This matters more than the list above, because a piece that only describes constraints describes a cage.

Inside every one of those margins, in one working session, the agent:

  • added a new editor field for title size to an existing block
  • added a heading-level control that fixed missing <h1> tags on three pages
  • changed a text field to accept HTML, and styled the links inside it
  • added a per-instance background colour
  • restyled every content table across the whole site
  • built a new landing page from seven existing blocks
  • rewrote page copy, titles, meta descriptions and structured data

Not once did a margin prevent it from building what was wanted. Several times a margin prevented it from building it badly, and twice it forced a better solution than the one first reached for.

That is the whole argument. The boundaries constrained damage, not ideas.


Two of those were not margins. They were bugs.

Running this exercise produced something we did not expect: a bug report.

Two of the things the agent described as boundaries were not decisions at all. Nobody had chosen them. They were gaps that behaved exactly like walls from the inside.

Heading levels. The agent had to hand-build a heading-level selector on an individual block in order to fix three pages that had no <h1> at all. That should never have been per-block work. Every heading is getting its own level picker, as standard.

HTML in text fields. The escaping story in item 7 is a good illustration of a margin doing its job — but the underlying situation was wrong. A description field that cannot contain a link is not a security boundary, it is a field that was built with the wrong filter. Every larger text field is getting HTML support, filtered through WordPress’s allow-list, without a block change.

The distinction is worth holding onto, because it is the practical value of asking at all.

A margin is a decision. Someone can point at the reason it exists, and widening it is a deliberate, documented act — as item 7 shows. A gap is just something nobody got to yet. From the inside they are indistinguishable: both simply refuse. Which is precisely why it is worth asking the thing that keeps hitting them.

And none of this is unique to WordPress. On a Next.js build of ours, a dropdown refused to open on exactly one person’s phone — the business owner’s. Hours of investigation found that the build target for that version had not been set to cover an older mobile Safari. That is a margin too. Nobody patches a browser-target setting on a schedule, nothing warns you, and it fails silently for a slice of real users until the wrong person turns out to be in it.

The margins you cannot see are the expensive ones. Which is the argument for asking.

The constraints that survive the question are the product. The ones that do not are the backlog.


The boundaries described above exist because of how the agent reaches the site in the first place — a fixed set of operations rather than a filesystem. That connection, and where WordPress core has got to with it, is covered in Running WordPress From Your Coding Agent: What MCP Actually Changes.

And the reason the margins matter beyond launch day is in WordPress Automation: AI That Builds and Maintains — what automated checks catch after an update, and the three failures that stay silent no matter what you monitor.

Start building custom Gutenberg sections with AI

Install the plugin in under a minute. Generate your first sections free. Connect your own API key when you're ready to scale.

NO CREDIT CARD · FREE TIER INCLUDED · WORKS WITH EXISTING SITES