Content Fragments
Activity: Create Queries
Query to get list of all Press Releases:
query allReleases {
pressReleaseList{
items{
_id
_path
title
}
}
}
Query to get specific press release by path:
query releaseByPath($path: String!) {
pressReleaseByPath(_path: $path) {
item {
_path
_id
_variation
title
slug
date
content {
plaintext
}
}
}
}
Activity: Dedicated Content Fragment Block
Block JSON
{
"definitions": [
{
"title": "Content Fragment",
"id": "content-fragment",
"plugins": {
"xwalk": {
"page": {
"resourceType": "core/franklin/components/block/v1/block",
"template": {
"name": "Content Fragment",
"model": "content-fragment"
}
}
}
}
}
],
"models": [
{
"id": "content-fragment",
"fields": [
{
"component": "aem-content-fragment",
"name": "path",
"value": "",
"label": "Content Fragment path",
"variationName": "contentFragmentVariation",
"validation": {
"rootPath": "/content/dam/www-site"
}
}
]
}
],
"filters": []
}
Block JS
function showEmpty(block) {
const emptyMessage = 'No content fragment selected. Use the Universal Editor to select a content fragment.';
block.innerHTML = `<div class="content-fragment-empty">${emptyMessage}</div>`;
}
function showError(block, message) {
block.innerHTML = `<div class="content-fragment-error">Error: ${message}</div>`;
}
function getAEMHost() {
let host;
if (window.location.hostname.endsWith('adobeaemcloud.com')) {
host = 'https://author-p219104-e2263158.adobeaemcloud.com';
} else {
host = 'https://publish-p219104-e2263158.adobeaemcloud.com';
// or actual public facing domain
}
// Remove trailing slash if present
if (host.endsWith('/')) {
host = host.slice(0, -1);
}
return host;
}
function createDisplay(contentfragment) {
const cfDiv = document.createElement('div');
const prHeading = document.createElement('h1');
prHeading.innerHTML = contentfragment.data.pressReleaseByPath.item.title;
const prDate = document.createElement('p');
prDate.innerHTML = contentfragment.data.pressReleaseByPath.item.date;
const prContent = document.createElement('div');
prContent.innerHTML = contentfragment.data.pressReleaseByPath.item.content.plaintext;
cfDiv.appendChild(prHeading);
cfDiv.appendChild(prDate);
cfDiv.appendChild(prContent);
return cfDiv;
}
export default async function decorate(block) {
// Get the content fragment path from the UE generated content in the DOM
const cfPath = block.querySelector('a')?.textContent;
if (!cfPath) {
showEmpty(block);
return;
}
try {
const gqlUrl = `${getAEMHost()}/graphql/execute.json/www-site/pr-by-path;path=${cfPath}`;
const response = await fetch(gqlUrl);
const contentFragment = await response.json();
if (!contentFragment) {
showError(block, 'Content fragment not found');
}
block.replaceChildren(createDisplay(contentFragment));
} catch (error) {
// eslint-disable-next-line no-console
console.error('Content Fragment block error:', error);
showError(block, 'Failed to load content fragment');
}
}
Block CSS
/* Error State */
.content-fragment-error {
text-align: center;
padding: 4rem 2rem;
color: var(--color-error, #dc3545);
font-size: 1.1rem;
border: 1px solid var(--color-error, #dc3545);
border-radius: 8px;
background: rgb(220 53 69 / 10%);
}
/* Empty State */
.content-fragment-empty {
text-align: center;
padding: 4rem 2rem;
color: var(--text-color);
font-size: 1.1rem;
font-style: italic;
border: 2px dashed var(--color-gray-300);
border-radius: 8px;
background: var(--color-gray-50);
}
Activity: Press Release List & Detail
Block JSON
{
"definitions": [
{
"title": "Press Releases",
"id": "press-releases",
"plugins": {
"xwalk": {
"page": {
"resourceType": "core/franklin/components/block/v1/block",
"template": {
"name": "Press Releases",
"model": "press-releases"
}
}
}
}
}
],
"models": [],
"filters": []
}
Block JS
function getAEMHost() {
let host;
if (window.location.hostname.endsWith('adobeaemcloud.com')) {
host = 'https://author-p219104-e2263158.adobeaemcloud.com';
} else {
host = 'https://publish-p219104-e2263158.adobeaemcloud.com';
// or actual public facing domain
}
// Remove trailing slash if present
if (host.endsWith('/')) {
host = host.slice(0, -1);
}
return host;
}
async function loadFragment(cfPath) {
const gqlUrl = `${getAEMHost()}/graphql/execute.json/www-site/pr-by-path;path=${cfPath}`;
const response = await fetch(gqlUrl);
const contentFragment = await response.json();
const cfDiv = document.createElement('div');
const prHeading = document.createElement('h1');
prHeading.innerHTML = contentFragment.data.pressReleaseByPath.item.title;
const prDate = document.createElement('p');
prDate.innerHTML = contentFragment.data.pressReleaseByPath.item.date;
const prContent = document.createElement('div');
prContent.innerHTML = contentFragment.data.pressReleaseByPath.item.content.plaintext;
cfDiv.appendChild(prHeading);
cfDiv.appendChild(prDate);
cfDiv.appendChild(prContent);
return cfDiv;
}
function createDisplay(contentfragment) {
const cfDiv = document.createElement('div');
const listDiv = document.createElement('div');
listDiv.classList.add('pr-list');
const detailDiv = document.createElement('div');
detailDiv.classList.add('pr-detail');
contentfragment.data.pressReleaseList.items.forEach((pr) => {
const a = document.createElement('a');
// eslint-disable-next-line no-underscore-dangle
a.href = pr._path;
a.innerText = pr.title;
a.addEventListener('click', async (e) => {
e.preventDefault();
// eslint-disable-next-line no-underscore-dangle
detailDiv.replaceChildren(await loadFragment(pr._path));
});
listDiv.appendChild(a);
});
cfDiv.appendChild(listDiv);
cfDiv.appendChild(detailDiv);
return cfDiv;
}
export default async function decorate(block) {
try {
const gqlUrl = `${getAEMHost()}/graphql/execute.json/www-site/pr-all`;
const response = await fetch(gqlUrl);
const contentFragment = await response.json();
block.replaceChildren(createDisplay(contentFragment));
} catch (error) {
// eslint-disable-next-line no-console
console.error('Content Fragment block error:', error);
}
}
Block CSS
.press-releases {
border: 1px solid black;
a {
display: block;
margin-bottom: 1.2em;
}
& > div {
display: flex;
flex-direction: row;
.pr-list {
width: 30%;
}
.pr-detail {
width: 70%;
h1 {
margin-top: 0;
}
}
}
}
Reference Links
An Overview of the Concepts and Best Practices of Working with Content Fragments
Working with Content Fragments (Assets - Content Fragments)
Content Fragment Models (Assets - Content Fragments)
Managing Content Fragment Models