Full Site Editing sells itself as the easy handoff: give the client a real theme, let them edit everything in the block editor, done. Then you actually migrate a bespoke static build into FSE — and discover the Navigation block can't match your menu, theme.json breaks your display fonts, and ACF InnerBlocks silently duplicate content on save. Here are five problems that show up on almost every migration like this, and how I fixed each one, 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. 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. Check whether your inner blocks share attribute values that ACF might be caching against. The second is the older WordPress global-state footgun. 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.
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. Once the migration is done, the next step is making sure Google can read the new theme: I run through the WordPress microdata and structured data checklist on every FSE build.