SuperAPI AI Directory

enable-shopify-cms

Frontend & websites

View repository

Updated 10-16 06:10

About this skill

Enable Shopify CMS

Add Shopify metaobject-based CMS support to the shop template. This replaces the hardcoded homepage content with Shopify-managed content using cms_homepage and cms_page metaobject definitions.

Prerequisites

  • Shopify store with metaobject definitions for cms_homepage and cms_page
  • Storefront API access token configured

Metaobject content model

cms_homepage

Field handle Type Description
title single_line_text Page title
meta_title single_line_text SEO title override
meta_description single_line_text SEO description override
hero_headline single_line_text Hero banner headline
hero_subheadline single_line_text Hero banner subheadline
hero_image file Hero background image
hero_cta_text single_line_text Hero call-to-action label
hero_cta_link single_line_text Hero call-to-action URL
sections json Array of content section definitions

cms_page

Field handle Type Description
slug single_line_text URL slug
title single_line_text Page title
locale single_line_text Locale code (e.g. en-US)
meta_title single_line_text SEO title override
meta_description single_line_text SEO description override
hero_headline single_line_text Hero banner headline
hero_subheadline single_line_text Hero banner subheadline
hero_image file Hero background image
hero_cta_text single_line_text Hero call-to-action label
hero_cta_link single_line_text Hero call-to-action URL
sections json Array of content section definitions

Implementation steps

1. Create lib/shopify/operations/cms.ts

Implement three operations that return domain types from lib/types.ts:

import { defaultLocale } from "@/lib/i18n";
import { assertStorefrontOk } from "@/lib/shopify/errors";
import { storefront } from "@/lib/shopify/storefront";
import type { Homepage, MarketingPage } from "@/lib/types";

export async function getHomepage({
  locale = defaultLocale,
}: {
  locale?: string;
} = {}): Promise<Homepage | null> {
  "use cache";
  cacheLife("max");
  cacheTag("cms:all", "cms:homepage");
  // Query cms_homepage metaobject, transform to Homepage type
}

export async function getMarketingPage({
  slug,
  locale = defaultLocale,
}: {
  slug: string;
  locale?: string;
}): Promise<MarketingPage | null> {
  "use cache";
  cacheLife("max");
  cacheTag("cms:all", "cms:pages", `cms:page:${slug}`);
  // Query cms_page metaobject by slug, transform to MarketingPage type
}

export async function getAllMarketingPageSlugs(): Promise<
  Array<{ slug: string; updatedAt: string }>
> {
  "use cache: remote";
  cacheLife("max");
  cacheTag("cms:all", "cms:pages");
  // Query all cms_page metaobjects, return slugs
}

2. Write GraphQL queries

Use Shopify AI Toolkit's custom-data skill first, then validate the final Storefront GraphQL documents with its Storefront skill. Use metaobjects(type: "cms_homepage") and metaobjects(type: "cms_page") queries with @inContext locale directives.

3. Transform metaobject responses

Create lib/shopify/transforms/cms.ts to convert raw metaobject fields into the domain types:

  • Parse the sections JSON field into ContentSection[]
  • Resolve product references in sections to ProductCard[] using getProductsByIds
  • Map hero fields to HeroSection
  • Map image references to MarketingImage

4. Wire into routes

Update app/page.tsx to use the CMS operation:

import { getHomepage } from "@/lib/shopify/operations/cms";
import { MarketingPageRenderer } from "@/components/cms/page-renderer";

export default async function HomePage() {
  const locale = await getLocale();
  const page = await getHomepage(locale);
  if (!page) return <FallbackHomepage />;
  return (
    <Container>
      <MarketingPageRenderer page={page} />
    </Container>
  );
}

Update app/pages/[slug]/page.tsx to use getMarketingPage and getAllMarketingPageSlugs. To index CMS pages in the sitemap, add a cms-pages-{n} shard type to app/sitemap/[shard]/route.ts and include it in app/sitemap.xml/route.ts.

The homepage and marketing-page reads use plain "use cache" so their stable bodies can be included coherently in prerendered shells. The slug enumeration uses "use cache: remote" because sitemap and discovery reads can run at request time and share results.

5. Use the existing cache invalidation webhook

Keep metaobject invalidation in app/api/webhooks/shopify/route.ts, which already verifies Shopify's signature and maps metaobjects/* topics to cms:all, cms:homepage, cms:pages, and page-specific tags. Extend that mapping if the content model adds another CMS metaobject type; do not create a second unverified CMS webhook endpoint.

Guardrails

  • Return the exact domain types from lib/types.ts — Homepage, MarketingPage, ContentSection.
  • Resolve product references to ProductCard[] — components expect ready-to-render product data.
  • Handle locale fallback gracefully — return default locale content if requested locale is unavailable, never throw.
  • Support the alternates field on MarketingPage — this powers locale-aware URL switching.
  • Keep CMS cache tags aligned with app/api/webhooks/shopify/route.ts.