CMS Content Models: Structure and Implementation
These are the types returned by the Content Management API, as defined in its GraphQL schema. Fields used only internally, such as A/B test bookkeeping, are left out.
Page
type Page {
id: ID!
revisionId: ID
title: String!
handle: String!
description: String
status: String!
sections(after: String, before: String, first: Int, last: Int): SectionConnection!
sectionOverrides: JSON
sectionsWithUnpublishedOverrides: [ID!]!
hasUnpublishedChanges: Boolean!
seo: SEO!
template: Template
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Page History
Returned by the pageHistory query.
type PageRevisionConnection {
edges: [PageRevisionEdge!]!
nodes: [PageRevision!]!
pageInfo: PageInfo!
totalCount: Int
}
type PageRevisionEdge {
cursor: String!
node: PageRevision!
}
Page Revision
type PageRevision {
id: ID!
pageId: String!
title: String!
handle: String!
description: String
status: String!
sections: [Section]
sectionOrder: [ID]
seo: SEO!
user: User
storeId: String!
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
createdAt: DateTime
sectionOverrides: JSON
}
Page Info
Pagination info on connections. Content release lists use ContentReleasePageInfo, whose cursors can be null.
type PageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String!
endCursor: String!
}
Blog
type Blog {
id: ID!
title: String!
handle: String!
description: String
status: String!
articles(after: String, before: String, first: Int, last: Int): ArticleConnection!
sections(after: String, before: String, first: Int, last: Int): SectionConnection!
sectionOverrides: JSON
hasUnpublishedChanges: Boolean!
seo: SEO!
template: Template
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Article
type Article {
id: ID!
title: String!
handle: String!
status: String!
blogId: ID
blog: Blog
template: Template
description: String
author: String
category: String
tags: [String]
excerpt: String
bodyHtml: String
sections(after: String, before: String, first: Int, last: Int): SectionConnection!
sectionOverrides: JSON
hasUnpublishedChanges: Boolean!
seo: SEO!
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Product Page
type ProductPage {
id: ID!
title: String!
handle: String!
description: String
status: String!
sections(after: String, before: String, first: Int, last: Int): SectionConnection!
sectionOverrides: JSON
hasUnpublishedChanges: Boolean!
seo: SEO!
template: Template
sourceProduct: Product // null when the page has no linked or synced Shopify product
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Product Page History
Returned by the productPageHistory query.
type ProductPageRevisionConnection {
edges: [ProductPageEdge!]!
nodes: [ProductPageRevision!]!
pageInfo: PageInfo!
totalCount: Int
}
Product Page Revision
type ProductPageRevision {
id: ID!
productId: String!
title: String!
handle: String!
description: String
status: String!
sections: [Section]
sectionOrder: [ID]
seo: SEO!
user: User
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
storeId: String!
createdAt: DateTime
sectionOverrides: JSON
}
Product Status
The status of a Shopify product, returned on sourceProduct.data.status.
enum ProductStatus {
ACTIVE
ARCHIVED
DRAFT
UNLISTED // active, but only reachable by direct link
}
Collection
type CollectionPage {
id: ID!
title: String!
handle: String!
description: String
status: String!
sections(after: String, before: String, first: Int, last: Int): SectionConnection!
sectionOverrides: JSON
hasUnpublishedChanges: Boolean!
seo: SEO!
template: Template
sourceCollection: ShopifyCollection // null when the page has no linked or synced Shopify collection
publishedAt: DateTime
firstPublishedAt: DateTime
firstPublishedAtTimezone: String
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Section
A section's data holds its field values. Its shape comes from the section's schema; see the Section Schema API.
type SectionConnection {
edges: [SectionEdge!]!
nodes: [Section!]!
pageInfo: PageInfo!
totalCount: Int
}
type SectionEdge {
cursor: String!
node: Section!
}
type Section {
id: ID!
revisionId: ID
parentContentType: ContentType
title: String!
status: String!
data: JSON // the section's field values, shaped by its section schema
dataSource: JSON
styles: JSON
hasReferences: Boolean
referencesCount: Int
publishedAt: DateTime
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Template
type Template {
id: ID!
title: String!
type: String!
isDefault: Boolean!
status: String!
sections(after: String, before: String, first: Int, last: Int): SectionConnection!
publishedAt: DateTime
storeId: String!
createdAt: DateTime
updatedAt: DateTime
disjunctive: Boolean
rules: [TemplateRule]
locale: Locale
}
type TemplateRule {
id: ID!
templateId: String!
attribute: String!
operator: String!
value: String!
createdAt: DateTime
updatedAt: DateTime
}
Site Settings
type SiteSettings {
id: ID!
revisionId: ID
status: String!
settings: JSON
seo: SEO!
favicon: String
publishedAt: DateTime
createdAt: DateTime
updatedAt: DateTime
locale: Locale
}
Schedule
type Schedule {
id: ID!
title: String!
description: String
executeAt: DateTime
timezone: String
state: ScheduleState!
totalContentCount: Int!
content: [Content!]
createdAt: DateTime
updatedAt: DateTime
}
enum ScheduleState {
created
succeeded
scheduled
queued
running
failed
}
Content Release
type ContentRelease {
id: ID!
name: String!
handle: String!
status: ContentReleaseStatus!
description: String
publishedAt: DateTime
archivedAt: DateTime
createdAt: DateTime
updatedAt: DateTime
scheduledPublishAt: DateTime
scheduleTimezone: String
scheduleOverwriteConflicts: Boolean
drafts: [ContentReleaseDraftEntry!]!
conflicts: [ContentReleaseConflict!]!
}
enum ContentReleaseStatus {
open
publishing
published
archived
}
enum ContentReleaseDraftType {
page
article
blog
product
collection
siteSettings
section
template
}
type ContentReleaseDraftEntry {
contentType: ContentReleaseDraftType!
contentId: ID!
draftId: ID!
baseVersion: Int
title: String
handle: String
contentHandle: String
updatedAt: DateTime
updatedByUserName: String
hasContentChanges: Boolean! // false when publishing leaves this content unchanged
affectedLocations: [ContentReleaseAffectedLocation!]!
affectedLocationsTruncated: Boolean!
}
type ContentReleaseAffectedLocation {
contentType: ContentReleaseDraftType!
contentId: ID!
title: String
handle: String
locale: Locale // null when the content has no locale
}
type ContentReleaseConflict {
contentType: String!
contentId: ID!
baseVersion: Int!
currentVersion: Int!
currentUpdatedAt: DateTime
currentUpdatedByUserName: String
changes: [ContentReleaseConflictChange!]! // computed only when requested
}
type ContentReleaseConflictChange {
field: String!
path: String!
changeType: String!
valueType: String!
liveValue: JSON
draftValue: JSON
baseValue: JSON // the value the draft's edit was recorded against; site settings drafts only, otherwise null
conflicting: Boolean // true when publishing overwrites a live edit here; null wherever baseValue is always null
}
type ContentReleaseConnection {
edges: [ContentReleaseEdge!]!
nodes: [ContentRelease!]!
pageInfo: ContentReleasePageInfo!
totalCount: Int!
}
type ContentReleaseEdge {
cursor: String!
node: ContentRelease!
}
type ContentReleasePageInfo {
hasNextPage: Boolean!
hasPreviousPage: Boolean!
startCursor: String
endCursor: String
}
Event
An entry in the store's change journal, returned by the events query.
type Event {
id: ID!
storeId: ID!
contentEnvironmentId: ID
releaseId: ID
type: String! // <subject>.<action>, e.g. content.page.published
subjectType: String!
subjectId: ID!
actorUserId: ID
occurredAt: DateTime!
data: JSON
}
Content Environment
type ContentEnvironment {
id: ID!
name: String!
handle: String!
storeId: String!
createdAt: DateTime!
}
Locale
A storefront locale. Localized content carries its locale; see Localization.
type Locale {
id: ID!
languageCode: String!
countryCode: String
isPrimary: Boolean
active: Boolean
createdAt: DateTime
updatedAt: DateTime
fallbackLocale: FallbackLocale
isFallbackLocale: Boolean
}
type FallbackLocale {
id: ID!
languageCode: String!
countryCode: String
}
User
type User {
id: String!
first_name: String
last_name: String
email: String!
avatar_url: String
}
SEO
type SEO {
title: String
description: String
image: String
keywords: [String!]
noIndex: Boolean
noFollow: Boolean
}