Skip to content
Ecom

Online Store 2.0: What Sections Everywhere Actually Changes for Shopify Stores

Sections now live on every template, not just the homepage. What this unlocks for merchants, what it means for developers, and the migration quirks we have hit when modernising legacy themes.

By WitsCode10 min read

The shift nobody finishes explaining

Online Store 2.0 arrived in 2021 as a rewrite of how Shopify themes are structured. Five years on, the marketing summary has not changed much. Sections are everywhere, JSON templates replace Liquid templates, apps can ship blocks that drop into any section, and metaobjects give merchants structured content. All of that is accurate, and all of it skips the part that actually matters when you are migrating a store that has been trading for three years with a legacy Vintage theme and a small graveyard of page builder apps.

At WitsCode we have migrated more than two hundred storefronts to OS 2.0 since the architecture stabilised. The gap between the headline story and the reality of a live migration is wide enough to sink a launch. This piece covers what Sections Everywhere actually changes at the template level, where merchant-saved content disappears if you are not careful, how app blocks get abused in ways that quietly break accessibility and Core Web Vitals, and the metaobject-per-landing-page pattern we use to give growth teams a way to ship without a developer in the loop.

From Liquid templates to JSON templates

The foundational change is that page templates are no longer Liquid files rendered by the theme. They are JSON documents that describe an ordered list of sections, the blocks inside each section, and the settings bound to both. A file like templates/product.json is a manifest. The Liquid is pushed down into the section files, which remain the unit of rendering logic. The theme editor writes to that JSON, which means merchants can add, remove, and reorder sections on a product page, a collection page, a blog article, and a customer account page, not only on the homepage.

This sounds like a small shift and it is not. In a Vintage theme, product.liquid was written by the developer, and anything that looked like a merchant-editable layout on a product page was usually a third-party page builder app that stored its configuration in its own database. The theme was a canvas. In OS 2.0, the canvas is the JSON template and the theme editor is the authoring surface. Every decision about what shows above the add-to-cart button, whether the image gallery sits left or right, which trust badges appear, which upsell rail loads below the description, is now a merchant decision by default, bounded by the section library the developer ships.

That reallocation of authority is the entire point of the rewrite. The corollary, which vendors rarely mention, is that the developer now has to think carefully about which sections to expose, how generous the block schema should be, and how to prevent a merchant from assembling a page that fails accessibility or kills LCP on mobile.

What Sections Everywhere actually unlocks

The practical unlocks, once a theme has been migrated properly, fall into four buckets.

The first is template diversity without developer work. In a Vintage theme, a brand that wanted a bespoke landing page for a paid campaign had to ship a new page.campaign.liquid template, ship it through Git or the theme editor, and then hand it to the marketing team who could only change copy through string edits. In OS 2.0, the developer ships one page.landing.json template with a generous section library, and the marketing team composes whatever they need inside the editor. Fifty landing pages without fifty deploys.

The second is section groups, which extended Sections Everywhere into the theme chrome. The header, footer, announcement bar, and any custom aside are now JSON files such as sections/header-group.json, each holding their own sections. A merchant can swap the announcement bar section for a countdown bar during a sale without touching Liquid. An agency can ship a multi-region theme that renders a different footer group based on locale, driven entirely by the editor.

The third is app blocks and app embeds. App blocks are drag-and-drop units that apps register with the theme, so a merchant can add a reviews widget or a loyalty badge into an existing section as a block rather than pasting a Liquid snippet. App embeds are theme-level scripts and pixels that apps register, which merchants toggle on and off from the editor. The developer no longer has to paste vendor snippets into theme.liquid, and uninstalling an app actually removes its surface area.

The fourth, and the most underused, is metaobjects as structured content bound to sections. A section schema can accept a metaobject setting, which lets a section render data that lives outside the template. This is the mechanism behind the landing page pattern we describe below, and it is the closest Shopify has come to a native CMS layer.

The migration gotcha that eats merchant-saved content

The failure mode we see most often on self-led migrations is the loss of merchant-saved content when a developer swaps a Liquid template for a JSON template. The sequence looks innocent. A developer renames product.liquid to product.liquid.old, drops in a new product.json, pushes the theme, and publishes. The storefront renders correctly on the reference product. Two days later the merchant notices that a dozen products that used to carry bespoke trust badges and comparison tables through a page builder app now render without them.

The root cause is that the page builder was storing its per-product layout against the old template path in its own metafields, often keyed by the product ID and the theme ID. When the template changed, the references did not migrate. Shopify does not move third-party metafield content between template formats because it has no way to know which metafields belong to which app. The content is still in the database, but nothing renders it because the new template does not know to read those metafields.

The fix is to inventory every app that writes per-resource layout content before the migration, ask each vendor whether their app has a native OS 2.0 block, and plan the cutover so that either the app block is placed in the new template before the cutover or the stored content is exported and reapplied through the new section. On the stores we migrate, this inventory step routinely adds a week to the project plan and is the single most common reason a do-it-yourself migration regresses.

A related trap is the custom suffix template. In Vintage themes, a developer would ship page.about.liquid to power the About page and Shopify would route to it automatically when the page had the About template selected in Admin. In OS 2.0, the suffix templates must exist as JSON files with the same suffix, so page.about.json. If only page.json is present, the Admin quietly shows the About page as using the default template, and the merchant does not realise they have lost the custom layout until a customer complains. We audit for this on every migration.

App block abuse and the accessibility bill that follows

The freedom to drop app blocks into any section is the single most popular feature of OS 2.0 among merchants, and it is the source of most of the accessibility and performance issues we find during audits.

The pattern we see repeatedly is a merchant inserting a stack of app blocks inside the main product section, between the description and the add-to-cart, because it is the easiest place to put them and the editor makes it a one-click action. The review widget, the upsell bar, the shipping estimator, and the size guide all land inside the <main> landmark with no sub-landmark or heading structure. Each block is typically wrapped in a generic div, not a section or aside, so a screen reader user sees a flat list of unlabelled regions between the product copy and the purchase button. The buy flow technically works and the page passes automated scans, but the real experience is a mess.

The second pattern is the app embed that injects a fixed-position overlay without proper modal semantics. Popup apps and review prompts use app embeds because they are trivial for the merchant to enable. The overlay is often missing aria-modal, has no focus trap, and on mobile covers the primary CTA when it fires on exit intent. The merchant sees conversion uplift on desktop, pushes the app to mobile, and wonders why the product page has gone quiet.

The third pattern, which hits Core Web Vitals rather than accessibility, is the pixel or analytics app that registers a synchronous app embed in the head. We have measured LCP regressions of 400 to 900 milliseconds on mid-tier Android devices when a merchant layers three analytics pixels this way. Each one individually looks benign. Together they push LCP over the threshold and the store loses the green badge in Search Console.

The fix on each of these is the same shape. Treat the app block library as a surface you design, not a free-for-all. Audit each app embed for load strategy. Wrap app block placements in proper landmarks and headings where the app allows it, and ask vendors to fix their markup where they do not. Prefer lazy and deferred variants of scripts. This is ongoing work, not a one-time migration task.

The metaobject-per-landing-page pattern

The pattern that has produced the largest step change for our clients is using metaobjects as the canonical content store for landing pages rather than storing content inside section settings.

The shape is straightforward. Define a landing_page metaobject with the fields your campaign pages actually need, for example a hero headline, a hero media reference, a list of value_prop metaobject references, a testimonial reference, and a richtext FAQ. Build one page.landing.json template whose sections each accept a metaobject setting and render from it. A hero section takes a landing_page reference and renders the hero fields. A value props section takes the same reference and renders the list of value props.

The merchant creates a new campaign page by creating a metaobject entry in Admin, filling in the fields, and creating a Shopify page that uses the page.landing template with the metaobject bound to the section. That is the entire flow. No new sections, no editor gymnastics, no content scattered across a dozen section settings bags. Content lives in one place and can be queried by the Storefront API if the brand later goes headless, translated through Translate and Adapt, or reused on a different template.

The catch, and the reason this pattern is underused, is that the theme editor preview for metaobject-bound sections can feel empty. A merchant opens the editor and sees a section with no visible settings, because the settings are fields on the metaobject, not on the section. Our convention is to ship a small helper section at the top of the landing template that links directly to the metaobject editor, and to document the pattern in the merchant handover so the content team understands where to go. Once the team has used it twice, they stop wanting to edit content inside section settings.

Section groups and the header-injecting app problem

A specific OS 2.0 behaviour that trips up older apps is the migration of the header and footer into section groups. In a Vintage theme, theme.liquid contained {% section 'header' %} and {% section 'footer' %}, and apps that wanted to inject content into the header did so either through app embeds in the head or through merchant-pasted Liquid inside the header section file. When a theme moves to OS 2.0 with section groups, theme.liquid is replaced with {% sections 'header-group' %} and the header section now lives inside a JSON group file.

Apps that monkey-patched the header by string-matching on the old section tag stop working silently. The site renders fine, the app reports a successful install, but the injected markup never appears. Popup apps, cart drawers that extend the header, and currency switchers are the usual casualties. The resolution is to move to the app embed or app block pattern and retire the Liquid injection path. If the app vendor has not shipped that pattern, flag it before the migration rather than after.

What a WitsCode OS 2.0 migration looks like ->

When we migrate a store to OS 2.0, the plan is not a theme swap. It is a content, app, and performance project that happens to produce a new theme at the end.

We start with an inventory of every app that writes per-resource layout or content, every custom template suffix in use, and every piece of merchant-saved content tied to the current theme. We build the new theme on Dawn patterns with a section library designed around the merchant's actual editorial needs, not a generic maximal set. We migrate merchant content into the new JSON templates and into metaobjects where the pattern fits, rather than leaving it stranded in app metafields. We audit app embeds for load strategy and app blocks for accessibility, and we rewrite or replace the ones that regress the baseline. We instrument the storefront so the growth team can A/B test at the section and metaobject level from day one.

The output is a theme that the merchant actually owns, a content model that survives future theme changes, and a storefront the growth team can iterate on without queuing behind a developer. If your store is still running on a Vintage theme in 2026, or if a previous migration left content stranded and app blocks scattered through the main region, that is the project we run. Sections Everywhere is only a feature if the migration lands properly. Otherwise it is just a different shape of the same problem.

Get weekly field notes.

Practical writing on shipping products, straight to your inbox. No spam.

Need help with this?

Shopify Development

We design and build web apps, MVPs, and SaaS products. Talk to us about what you are working on.

Talk to us

Want to discuss ecom for your business?

Start a project and we'll talk through where you are, what's working, and the highest-leverage moves for the next 90 days.