Full Site Editing sounds simple in the pitch: hand the client a real theme, let them edit everything in the block editor, done. In practice, migrating a bespoke static build into FSE means giving up the freedom of hand-written markup for a system with its own opinions — and those opinions surface as bugs you won't find until you're mid-project. Here are five that come up on almost every migration like this, based on a recent build for a performing arts client's site.
1. The native Navigation block won't match your custom menu
A static build's menu can be any markup you want. The Navigation block can't — you're styling a fixed DOM structure with its own class names and nesting. Budget real time for reverse-engineering that structure before you touch a single style, rather than assuming your existing menu CSS will drop in.
2. Mobile menu animations silently fail with CSS custom properties
If your open/close animation drives a custom property with transition, don't be surprised when it does nothing in some browsers. Transitions on custom-property-driven values are unreliable across engines. Switch to a keyframe animation that reads the same custom property instead — it's a small change with an outsized fix rate:
.menu {
--progress: 0;
animation: menu-slide 280ms ease forwards;
animation-play-state: paused;
}
.menu.is-open {
animation-play-state: running;
}
@keyframes menu-slide {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
3. theme.json's fluid type scale collides with display fonts
Stylised display faces — the kind static sites use freely — often have tighter optical limits than a generic sans. A clamp()-based fluid scale that looks fine on a system font can collide or overflow at specific viewport widths once you swap in something like a heavy mono or condensed display face. Test the actual clamp values against the actual font, not a placeholder, before locking the scale in.
4. ACF/SCF InnerBlocks can duplicate content on save
Two distinct bugs live here, not one shared cause. The first is a genuine ACF issue (and SCF, since it's a direct fork of the ACF codebase): nested InnerBlocks with identical settings render as duplicates on save. ACF appears to cache inner blocks against their settings, so consecutive blocks with the same attribute values hydrate identically instead of independently, and conditional display logic gets ignored. Not a markup problem; check whether your inner blocks share attribute values that ACF might be caching against. The second is the older WordPress global-state footgun, not an ACF hydration issue at all. A WP_Query loop inside a block render template that calls the_post() without a matching wp_reset_postdata() leaves the global $post pointer on whatever the secondary query last touched. ACF's get_field() and the_field() silently fall back to global $post when you don't pass an explicit post ID, so the leaked pointer corrupts field lookups for whatever block renders next, which shows up as a block "remembering" the wrong post. Fix it by checking the render template for a missing wp_reset_postdata() (or $loop->reset_postdata() if there's no global $post) before touching markup.
5. ACF vs. the Block Bindings API for single-post templates
You now have two real options for connecting custom fields to a block template: ACF's established field-to-block workflow, or WordPress core's newer Block Bindings API. ACF is faster to build with today and has the larger ecosystem; Block Bindings is core, dependency-free, and better positioned as FSE tooling keeps maturing. For a client who'll maintain this theme for years, that second point usually wins — but it's worth deciding deliberately rather than defaulting to whichever you've used before.
None of these are exotic edge cases — they're the ordinary cost of moving from markup you fully control to a system with its own structure. Plan for them up front and a static-to-FSE migration is a very good trade for a client who needs to self-serve content. I went through all five of these on a recent migration for Le Marteau qui Chante — the full case study has more detail on how they played out in that build.