Friday, April 8, 2022

AEM Experience Manager(AEM): Content Sharing Approaches

 In most cases, we need to share the CMS content with external systems to support the Omni channel's headless experiences or other use cases to support content sharing.

In this post, let us see the options available to share the AEM content with external systems.

The graph QL API shares the content fragments to enable the headless content experience with the external system. The structured data can be managed through Content Fragments in AEM and shared through Graph QL API to support the omnichannel experiences. The latest AEM 6.5 and AEM as a Clod Services versions support Graph QL API; the Graph QL API currently supports only exposing content fragments externally, not for the regular page content.

Refer to the following URL for more details on using Graph QL to API to share content fragments with external systems — https://medium.com/tech-learnings/how-to-deliver-headless-content-through-graphql-api-and-content-fragments-da2b2d22df06

Sling Model Exporter allows annotations — @Exporter(name = "jackson", extensions = "json") to be added to Sling Models that define how the Model can be exported as JSON. The page JSON data can be accessed by adding a model selector — this prints all the data exposed through different sling models.

http://localhost:4502/content/wknd/us/en.model.tidy.json (tidy selector formats the JSON response)

The sling exporter exposes all the components model data enabled on this page as a JSON response. The JSON response can render the page in an external channel to enable the headless experience.

The content as a service supports authoring of the Content fragments into a page and exposes the content through JSON exporter(by adding .model selector as discussed above)

Refer to https://experienceleague.adobe.com/docs/experience-manager-learn/foundation/development/understand-sling-model-exporter.html?lang=en for more details on Sling Model Exporter.

The Query Builder offers an easy way of querying the content repository of AEM. The REST API provides the functionality to execute JCR queries through HTTP requests and respond with JSON.

The JSON REST API can share the data to an external system, mainly the metadata about pages and assets, e.g., useful when the onsite search platform requires additional metadata for indexing Assets.

http://localhost:4502/bin/querybuilder.json?p.hits=selective&p.limit=-1&p.properties=jcr%3apath%20jcr%3acontent%2fmetadata%2fdc%3atitle%20jcr%3acontent%2fmetadata%2fdc%3adescription&path=%2fcontent%2fdam&type=dam%3aAsset

Change the query to fetch the required content properties on the JSON response.

{
"success": true,
"results": 5,
"total": 5,
"more": false,
"offset": 0,
"hits": [
{
"jcr:path": "/content/dam/sampledata",
"jcr:content": {
"metadata": {}
}
},
{
"jcr:path": "/content/dam/spaeditableareas/asset.jpg",
"jcr:content": {
"metadata": {}
}
},
{
"jcr:path": "/content/dam/spassr/asset.jpg",
"jcr:content": {
"metadata": {}
}
},
{
"jcr:path": "/content/dam/wknd/test.csv",
"jcr:content": {
"metadata": {}
}
},
{
"jcr:path": "/content/dam/wknd/asset.jpg",
"jcr:content": {
"metadata": {
"dc:description": "test description",
"dc:title": "test title"
}
}
}
]
}

Please note /bin/querybuilder.json URL will be blocked through the dispatcher for external-facing website domains due to security and performance impacts.

You can define a dedicated internal domain to share the data or directly access the Query builder JSON API from the Author server.

Refer to https://experienceleague.adobe.com/docs/experience-manager-64/developing/platform/query-builder/querybuilder-api.html?lang=en for more details on Query Builder API.

The AEM prints all the resources as Atom and RSS feeds; this will help share some basic data as feeds to the external systems.

The below feed URL's can be used to print the resources as a feed through the OOTB functionality.

http://localhost:4502/content/wknd/us/en.feed.atom.xml
http://localhost:4502/content/wknd/us/en.feedentry.atom.xml
http://localhost:4502/content/wknd/us/en.feed.rss.xml
http://localhost:4502/content/wknd/us/en.feedentry.rss.xml
<?xml version="1.0" encoding="UTF-8"?>
<feed
xmlns="http://www.w3.org/2005/Atom">
<title type="html">en1</title>
<author>
<name>
<![CDATA[admin]]>
</name>
<email>admin@localhost</email>
</author>
<id>http://localhost:4502/content/wknd/us/en.feed.xml</id>
<link rel="alternate" type="text/html" href="http://localhost:4502/content/wknd/us/en.html"/>
<link rel="self" type="application/atom+xml" href="http://localhost:4502/content/wknd/us/en.feed.xml"/>
<updated>2021-12-28T17:22:58Z</updated>
<entry>
<title type="html">en</title>
<summary type="html"/>
<author>
<name>
<![CDATA[admin]]>
</name>
<email>admin@localhost</email>
</author>
<id>http://localhost:4502/content/wknd/us/en/test.feed.xml</id>
<updated>2021-12-28T17:22:58Z</updated>
<published>2021-12-28T17:22:58Z</published>
<category term=""/>
<link rel="alternate" type="text/html" href="http://localhost:4502/content/wknd/us/en/test.html"/>
<link rel="replies" type="text/html" href="http://localhost:4502/content/wknd/us/en/test.html#comments"/>
<content xml:base="http://localhost:4502/content/wknd/us/en" type="html"/>
</entry>
</feed>

QueryBuilder Feed: Query Builder feed helps print the feed data for the resources fetched through Query Builder API. Modify the query parameters to fetch the feed details for the required resources.

http://localhost:4502/bin/querybuilder.feed?p.limit=100&path=%2fcontent%2fdam%2fwknd&type=dam%3aAsset<feed
xmlns="http://www.w3.org/2005/Atom"
xmlns:os="http://a9.com/-/spec/opensearch/1.1/">
<title type="text">CQ Feed</title>
<id>http://localhost:4502/bin/querybuilder.feed?p.limit=100&amp;path=/content/dam/wknd&amp;type=dam:Asset</id>
<link href="http://localhost:4502/bin/querybuilder.feed?p.limit=100&amp;path=%2fcontent%2fdam%2fwknd&amp;type=dam%3aAsset" rel="self"></link>
<updated>2022-04-08T18:15:47.645Z</updated>
<os:itemsPerPage>100</os:itemsPerPage>
<os:totalResults>2</os:totalResults>
<os:startIndex>0</os:startIndex>
<entry
xmlns:media="http://search.yahoo.com/mrss/">
<title type="html">test.csv</title>
<link href="http://localhost:4502/content/dam/wknd/test.csv"></link>
<content type="html">&lt;img src="http://localhost:4502/content/dam/wknd/test.csv/jcr:content/renditions/cq5dam.thumbnail.140.100.png" alt="test.csv"/&gt;</content>
<media:content url="http://localhost:4502/content/dam/wknd/test.csv" type="text/csv"></media:content>
<id>http://localhost:4502/content/dam/wknd/test.csv</id>
<published>2021-12-28T23:44:16.614Z</published>
</entry>
<entry
xmlns:media="http://search.yahoo.com/mrss/">
<title type="html">test title</title>
<link href="http://localhost:4502/content/dam/wknd/asset.jpg"></link>
<content type="html">&lt;img src="http://localhost:4502/content/dam/wknd/asset.jpg/jcr:content/renditions/cq5dam.thumbnail.140.100.png" alt="test title"/&gt;</content>
<media:content url="http://localhost:4502/content/dam/wknd/asset.jpg" type="image/jpeg"></media:content>
<id>http://localhost:4502/content/dam/wknd/asset.jpg</id>
<published>2021-12-28T17:22:58.137Z</published>
</entry>
</feed>

The OOTB feed renderers(Servlets) can be overridden to share additional data through the feeds.

To obtain the page information, send a request to the PageInfo servlet to get the page metadata in JSON format. The PageInfo servlet returns information about resources in the repository. The servlet is enabled in https://<server>:<port>/libs/wcm/core/content/pageinfo.json; access the page info by sending the content path. Use the infinity selector to get the additional details about the page.

http://localhost:4502/libs/wcm/core/content/pageinfo.json?path=/content/wknd/us/enhttp://localhost:4502/libs/wcm/core/content/pageinfo.infinityjson?path=/content/wknd/us/en

Refer to https://experienceleague.adobe.com/docs/experience-manager-64/developing/components/pageinfo.html?lang=en for more details on the page info servlet.

Packages enable the importing and exporting of AEM repository content. For example, you can use packages to install new functionality, transfer content between instances, and back up repository content. Refer to the following URL https://experienceleague.adobe.com/docs/experience-manager-64/administering/contentmanagement/package-manager.html?lang=en for more details.

The content can also be exported in XML, XLIF, or JSON format as a package to support the manual translation workflow — Refer to the following URL https://medium.com/tech-learnings/adobe-experience-manager-aem-content-translation-deep-dive-part2-d4b75cade77b for more details on content translation.

Page Exporter:

The packages built through the Package Manager are more understandable by the AEM platform; The page exporter can be used to export a page as a complete web page including images, .js, and .css files.

You should enable the export configuration template for your site — the export configuration template exists for your site. The page can be exported as a ZIP once the export configurations are enabled by using the following URL format — <page-name>.export.zip, e.g http://localhost:4502/content/test.export.zip

Refer to The Page Exporter | Adobe Experience Manager for more details on Page Exporter.

Web scraping is an automatic method to obtain large amounts of data from websites. In this approach, we are not sharing the data directly from AEM, but you can use some scrapping tools/scripts to fetch the required content from any publically available websites, including AEM-hosted websites.

You can create custom servlets/services to share the required data in any format(e.g., JSON, XML, feed, etc.). Create custom servlets/services if non of the OOTB options support the required data sharing.

In AEM, any basic page data can be rendered as a JSON, e.g., http://localhost:4502/content/wknd/us/en.tidy.json (tidy selector formats the JSON while printing)

http://localhost:4502/content/wknd/us/en.tidy.infinity.json

The infinity selector can be used to print additional details about the page.

The Assets HTTP API allows for create-read-update-delete (CRUD) operations on digital assets, including metadata, renditions, comments, and structured content using Experience Manager Content Fragments. It is exposed at /api/assets and is implemented as REST API.

The API service document can be accessed through http://localhost:4502/api.json.

For example, the CURD operations can be performed in any assets, including the Content Fragments.

http://localhost:4502/api/assets/wknd/test.json (Content Fragment)

{
"links": [
{
"rel": [
"self"
],
"href": "http://localhost:4502/api/assets/wknd/test.json"
},
{
"rel": [
"parent"
],
"href": "http://localhost:4502/api/assets/wknd.json"
}
],
"class": [
"assets/asset"
],
"actions": [
{
"method": "DELETE",
"name": "delete",
"href": "http://localhost:4502/api/assets/wknd/test",
"title": "Delete"
},
{
"method": "PUT",
"name": "update-fragment",
"href": "http://localhost:4502/api/assets/wknd/test",
"type": "application/json",
"title": "Update Content Fragment"
}
],
"properties": {
"metadata": {},
"created": 1649447482461,
"description": "ssss",
"title": "test",
"contentFragment": true,
"createdBy": "admin",
"elementsOrder": [
"data1",
"data2"
],
"elements": {
"data2": {
"variationsOrder": [
"var1"
],
"translatable": false,
":type": "string",
"variations": {
"var1": {
":type": "string",
"dataType": "string",
"description": "",
"title": "var1",
"multiValue": false,
"value": "Test Var Data2"
}
},
"dataType": "string",
"title": "Data2",
"multiValue": false,
"value": "Test Data2"
},
"data1": {
"variationsOrder": [
"var1"
],
"translatable": false,
":type": "string",
"variations": {
"var1": {
":type": "string",
"dataType": "string",
"description": "",
"title": "var1",
"multiValue": false,
"value": "Test Var Data 1"
}
},
"dataType": "string",
"title": "Data1",
"multiValue": false,
"value": "Test Data 1"
}
},
"name": "test",
"modified": 1649447706954,
"modifiedBy": "admin",
"cq:model": {
"path": "/conf/global/settings/dam/cfm/models/sampledata"
},
"srn:paging": {
"total": 0,
"offset": 0,
"limit": 20
}
}
}

Retrieve an asset folder listing -http://localhost:4502/api/assets/wknd.json

Retrieve the properties of an asset — http://localhost:4502/api/assets/wknd/asset.jpg.json

Refer to https://experienceleague.adobe.com/docs/experience-manager-65/assets/extending/mac-api-assets.html?lang=en for more details on Asset HTTP API.

Adobe Experience Manager Assets lets you share assets, folders, and collections as a URL with members of your organization and external entities, including partners and vendors. Sharing assets through a link is a convenient way of making resources available to external parties without first logging into Assets.

Refer to https://experienceleague.adobe.com/docs/experience-manager-64/assets/administer/link-sharing.html?lang=en for more details on asset share functionality.

Please ensure the security and the performance are factored in before sharing the AEM repository content externally; as best practices, most of the JSON endpoints are recommended to be filtered by the dispatcher to secure the AEM publish server. Ensure the endpoints are exposed to intended users with proper authentications.

Considering the headless implementation based on the current status, use GraphQL API and Content Fragment to expose the structured content with the external systems. Also, use Content Service/Model Exporter to share any page content with external systems.

Also, the Experience Fragment can be used to define the shared experiences and share them as an HTML/JSON to any external systems.

Monday, April 4, 2022

What is an HTML template tag? | How to use HTML template tag in AEM(Adobe Experience Manager)

 In this post, let us explore what an HTML template tag is and how to use an HTML template tag within AEM components.

The <template> tag stores HTML code fragments, which can be cloned and inserted into an HTML document.

The tag's content is hidden from users being stored on the client-side. It is inert until activated using JavaScript — the content inside the template tag is not loaded, e.g., Script doesn't run, images don't load, and audio doesn't play until the template is used/activated through javascript. The HTML is not to be rendered immediately when a page is loaded but maybe instantiated subsequently during runtime using JavaScript.

Template elements can be placed anywhere inside of <head>, <body>, or <frameset> and can contain any syntactically correct HTML.

The template tag helps render the repeated content through a predefined template — clone the predefined template, fill the dynamic content, and render it to the page. It can also be helpful when you want to use the same content multiple times in your HTML document without any change.

Test if the browser supports the HTML template element before activating through JavaScript.

if ('content' in document.createElement('template')) {

For example, create a template to display multiple user details on the HTML page.

Create a parent div placeholder to append the userlist

<div class="user-details--list"> </div>

Create the template to render the required user details.

<template id="template--user-details--list-item">
<div class="user-details--list-item">
<p class="user-details--list-item--fname"></p>
<p class="user-details--list-item--lname"></p>
<p class="user-details--list-item--city"></p>
<p class="user-details--list-item--state"></p>
<p class="user-details--list-item--country"></p>
</div>
</template>

Enable the JavaScript to activate the content (you can also fetch the details dynamically from an external service and render them to the page through a template)

if ('content' in document.createElement('template')) { 

var userDetailsTemplate = document.querySelector('#template--user-details--list-item');
var userDetailsList = document.querySelector(".user-details--list");

//User1

For AEM, create a client library(e.g., wknd.site.template) with the required JS(refer above)

Create a Component with the required placeholder and the template. I also include the client library at the component level; you can include it globally if needed.

<div class="user-details--list"> </div>

Now author the component to the required page. The user details will be rendered to the page(enable the necessary styling)— you can also fetch the dynamic data and render it easily through the template.

Wednesday, March 23, 2022

Editable Template Strategy — AEM(Adobe Experience Manager)

 Some of my last posts explained the Website Structure in AEM — Multi-Site Manager(MSM), Reusing the same template across multiple websites; in this post, let us discuss the Editable Template Strategy to support the multi-sites on the AEM platform.

  • How to organize the editable template?
  • Who manages the editable template?
  • Can we reuse the editable templates across multiple
  • Page properties — Page priorities on different page types, e.g., root page, product page, etc
  • Policy Variations
  • Style System Variation
  • Allowed Components
  • Theming variations — Supporting different themes.
  • Reusability
  • Impact — a dynamic connection between the page and the template is maintained; changes to the template structure will reflect any pages created with that template (initial content changes will not reflect).
  • Access management

Template Strategy:

You should be able to adopt any number of Editable template strategies; some of them are below.

  • Content Template — Template with a default header and footer and empty container between header and footer for authoring
  • Empty Template — Empty template with the container to author the components.
  • Product Template — Template to support the product pages

Template Management:

Template management is another critical factor; who manages the editable templates Development team vs. template-authors, also manage through code repository vs. directly through template editor.

  • Enable the changes through deployment; the source of truth is the git repo
  • Still enable a back sync from production author back to code repo to sync any changes enabled directly in prod author
  • Enable the changes directly through prod author; the source of truth is the prod author

Page component:

The Editable Templates are always created based on a Page Component and template type. Whenever possible, ensure the same page component is used to create the templates — some cases exception to create own page components to support unique scenarios.

Guidelines:

  • Restrict the templates to specific content paths
  • Training for template authors — Ensure the template authors are aware of the Editable template management, mainly the dynamic relationship between the Editable templates and the pages created through that — any change in the editable templates(apart from the initial content will impact the existing pages.
  • Enable the required access management for editable templates — ensure only the specific people (template-authors) have access to manage the editable templates.
  • Never enter any information that needs to be internationalized into a template. For internalization purposes, recommended using the localization feature of the Core Components.
  • Ensure template guidelines are created for authors — this will guide the template authors to use the suitable template for page creation.
  • Allow only the components enabled for authoring.