Skip to content

CMS Bundle (Blocks & Pages)

A headless storefront needs your CMS blocks (header strips, promos, footers) and pages (about, policies, landing pages) — but fetching them one-by-one over the standard GraphQL is slow and leaves {{media}} directives unresolved. CMS Bundle returns all of them in a single call, with directives already resolved to absolute (or CDN) URLs, HTML sanitised, a deduplicated list of every referenced image, and a version hash so the storefront knows when to re-fetch.

CMS Block Bundle in the admin

Magento

Open Source 2.4.9 GA (and later 2.4.x).

PHP

Tested on 8.4 and 8.5.

Multi-store

Every query is store-scoped — each store view gets its own bundle.

Safe

Unpublished pages/blocks are never returned to anonymous callers.
{ cmsBlockBundle {
version count image_count
blocks { identifier title content is_active update_time }
images { url referenced_by } } }

Every active block for the store, content fully resolved + sanitised.

  1. Resolves directives{{media url=...}}, {{store url=...}} and nested {{block id=...}} become absolute URLs (a missing/broken directive falls back to raw content with a log, never crashing the bundle).

  2. Sanitises HTML (when enabled) — strips inline styles/classes/IDs and Word/MSO junk, and rewrites CMS block-embed directives to <div data-cms-block-id="…"> placeholders your storefront renders.

  3. Rewrites media to your CDN (when configured) — every /pub/media/ URL points at your storefront’s image CDN instead of Magento.

  4. Extracts every image into a deduplicated list with which blocks/pages reference each one — so your storefront can pre-fetch and rehost them, and a missing image is traceable.

  5. Stamps a version hash — timestamp + sha1 of all content, so the storefront re-fetches only when something actually changed.

Why a bundle instead of the standard cmsBlocks query?

Speed and completeness. One store-scoped DB round-trip returns every block with directives already resolved, versus the standard resolver querying scope per identifier and leaving {{media}} placeholders for you to resolve. Your storefront pre-warms a content cache once and serves CMS chrome instantly.

How does my storefront know when to refresh?

Compare the version hash. It changes only when block/page content or timestamps change, so the storefront re-fetches the bundle just when needed — and cmsBlockSingle / cmsPageSingle let a webhook patch a single item without a full refresh.

Can each store view have different CMS content?

Yes — every query is store-scoped (store_id, defaulting to the request’s store), so a UK and a DE store view each get their own correctly-scoped block and page set.

Is the HTML safe to render?

When the sanitiser is enabled, content is run through an allow-list that strips inline styles/classes and editor junk and normalises embed directives — so what reaches your storefront is clean, predictable HTML. Verified clean on PHP 8.4 and 8.5.