{
"canSharePost": true,
"post": {
"id": "Post Id",
"title": "Sample title",
"content": "<p>Sample content</p>",
"alias": "sample-post-alias",
"tags": [
"sample-tag",
"..."
],
"categoryName": "Sample text",
"categoryAlias": "sample-category",
"publishedAt": "2026-01-01T00:00:00.0000000",
"mediaItem": {
"id": "Media Item Id",
"link": "https://example.com/media/sample.jpg",
"mediaType": "Image"
}
},
"name": "SingleBlog",
"view": "Default",
"section": "SectionA",
"settings": {
"id": "Component Id",
"section": "SectionA",
"type": "NoirSingleBlog",
"name": "SingleBlog",
"configuredInContentApi": true,
"view": "Default",
"displayName": "",
"cssClass": ""
},
"translations": {
"clickToLearnMoreAboutCategory": "Sample text",
"sharePost": "Sample text",
"hours": "Sample text",
"...": "..."
}
}settings.idpostsettings.cssClasspost.categoryName, post.categoryAlias (category link is hidden if missing)post.titlepost.mediaItem.link (hero image is hidden if missing)post.tags[]post.content (rendered as raw HTML)canSharePost (present in the model; the current Liquid template does not use it)translations.*Components/SingleBlog/Default.js exposes a single Alpine object:<section x-data="singleblogdefault">init()pageUrl from window.location.href (used for share links).resize and scroll listeners so header height stays correct.updateHeaderHeight()<header> height and stores it in headerHeight.getReadingTime()#post-wrap.innerText, counts words, and estimates reading time.wps = 3.8 (words per second).time.minutes = -2.time.minutes <= 0 as “< 1 minute”.<header> element height (sticky offset)pageUrl, so they always share the current URL.{{ blog.content }}), so the backend is expected to provide safe HTML./blog/posts/<categoryAlias> when category info exists.top style from headerHeight.time.hours and time.minutes computed in JS.