Magento 2 CMS Blocks and Widgets Done Right

Magento 2 CMS Blocks and Widgets Done Right

October 17, 2025 · By Magento Company
Magento 2 CMS Blocks and Widgets Done Right

CMS blocks and widgets are how content moves from code to content team in Magento - but teams mix them up constantly, and the result is content that breaks on deploy, drifts between environments, or disables cache on the homepage. Used with a little discipline, they are a clean system. Here is the discipline.

Blocks vs Widgets: The Actual Difference

  • CMS block: a reusable chunk of content - the content itself, managed in admin (Content > Blocks)
  • Widget: a placement of a block (or dynamic component) into a page, container and theme location - the “where”, with optional parameters and scheduling

Simple rule: the block is the content, the widget is the delivery. Merchants editing a promotional message edit a block. Merchants deciding the message shows on the homepage hero for two weeks use a widget pointing at that block.

Admin vs Layout XML

Widgets can be created two ways, and the choice is an architecture decision:

  • Admin-created widget instances: flexible, merchant-controlled, but they live in the database - invisible to git, different between staging and production, and a common source of “it worked on staging” content drift
  • Layout XML widgets: declared in theme/module XML, version-controlled, deployed with code, identical everywhere

Our rule of thumb: structural placements in XML, campaign placements in admin. The homepage hero’s existence is code; which banner occupies it this week is content.

Environment-Safe Content

Blocks travel between environments badly (they are database rows). The mitigations:

  • Keep structural content in code-deployed blocks where feasible (or seed blocks via data patches for content that must exist)
  • For admin-managed blocks, adopt an export/import ritual per release - or accept and document that content is environment-specific
  • Never hardcode store IDs or absolute URLs inside block content; use {{store url=""}} directives so the same block works on staging and production

Caching: The Hidden Trap

A CMS block rendered through layout is cached with the page - fine for most content. The traps:

  • Personalised content in blocks: a block showing customer-specific content must not sit in an FPC-cached page without hole-punching - use dynamic blocks (Adobe Commerce) or customer-data sections
  • Widget TTL settings: some widget types have their own cache lifetime; a “today’s offer” widget with a 24-hour TTL shows yesterday’s offer
  • Cache invalidation after edits: block edits invalidate block_html cache - make sure your deployment and cache-flush habits account for it, or editors report “my change didn’t go live” when it did, to a stale cache

Done right, the split is clean: developers own structure and deployment, merchants own message and timing, and nobody debugs content drift at 6pm on a Friday. That calm is worth the small amount of upfront doctrine.

CMS Development Magento 2