### Starting Local AEM Development Server (Bash) Source: https://www.aem.live/developer/tutorial This snippet demonstrates how to navigate into the newly cloned project directory using cd . Following that, the aem up command is used to start the local AEM development server, typically accessible at http://localhost:3000/, allowing developers to immediately see changes made to .css or .js files. ```bash cd aem up ``` -------------------------------- ### Setting Up Local Development Environment with AEM CLI Source: https://www.aem.live/docs/faq This command sequence is used to set up a local development environment for Edge Delivery Services. It first globally installs the AEM Command Line Interface (CLI) and then starts a local server. This setup allows developers to see real-time updates to their code and preview content accurately using production data. ```Shell npm install -g @adobe/aem-cli && aem up ``` -------------------------------- ### Configuring a Simple Sitemap in AEM (YAML) Source: https://www.aem.live/developer/sitemap This YAML configuration defines a basic sitemap named 'example'. It specifies that the sitemap's data source is `/query-index.json` and its output destination will be `/sitemap-en.xml`. This setup is suitable for projects with a single index containing all pages for the sitemap. ```YAML sitemaps: example: source: /query-index.json destination: /sitemap-en.xml ``` -------------------------------- ### Assigning Sites.Selected Application Role (Graph Explorer - Example) Source: https://www.aem.live/docs/setup-customer-sharepoint This is a concrete example of a POST request to the Microsoft Graph API, demonstrating how to assign the 'Sites.Selected' application role. It uses specific example IDs for the 'principalId', 'resourceId', and 'appRoleId' obtained from previous steps, illustrating the final assignment operation. ```HTTP https://graph.microsoft.com/v1.0/servicePrincipals/6761ada0-733b-4a02-98b2-3db970834fe0/appRoleAssignedTo Content-type: application/json { "principalId": "6761ada0-733b-4a02-98b2-3db970834fe0", "resourceId": "5159db96-7193-414e-9730-b1d1e4448443", "appRoleId": "883ea226-0bf2-4a8f-9f9d-92c9162a727d" } ``` -------------------------------- ### Installing AEM CLI and Cloning Project Repository (Bash) Source: https://www.aem.live/developer/tutorial This snippet provides the commands to globally install the Adobe AEM Command Line Interface (CLI) using npm, which is essential for AEM development. It then shows how to clone a specific AEM project repository from GitHub, replacing and with the actual project details, to bring the project files to the local machine. ```bash npm install -g @adobe/aem-cli git clone https://github.com// ``` -------------------------------- ### Configuring AEM Sidekick Library in HTML Source: https://www.aem.live/docs/sidekick-library This HTML snippet defines the `library.html` file required for the AEM Sidekick plugin. It loads the sidekick library from `aem.live` and initializes a `sidekick-library` custom element, configuring it with a `base` path to the library's JSON configuration. This setup is crucial for the sidekick to function correctly. ```HTML Sidekick Library ``` -------------------------------- ### Example: Retrieving SharePoint Site ID Source: https://www.aem.live/docs/setup-customer-sharepoint An example of a GET request to the Microsoft Graph API to retrieve the SiteId for a specific SharePoint site. The response includes the 'id' field, which contains the unique identifier needed for further permission management. ```HTTP GET https://graph.microsoft.com/v1.0/sites/adobeenterprisesupportaem.sharepoint.com:/sites/hlx-test-project { ... "id": "adobeenterprisesupportaem.sharepoint.com,03cc3587-0e4d-405e-b06c-ffb0a622b7ac,5fbc1df5-640c-4780-8b59-809e3193c043", ... } ``` -------------------------------- ### Example `window.location` Object in Sidekick Library Iframe Source: https://www.aem.live/docs/sidekick-library This JSON snippet illustrates the typical values of the `window.location` object when code is executed within an iframe loaded via `srcdoc` in the Sidekick Library. It shows that properties like `host`, `hostname`, and `origin` are empty or null, and `href` is `about:srcdoc`. ```JSON { "host": "", "hostname": "", "href": "about:srcdoc" "origin": "null" "pathname": "srcdoc" "port": "" "protocol": "about:" } ``` -------------------------------- ### Debugging AEM Index Configuration with CLI Source: https://www.aem.live/developer/indexing This AEM CLI command starts the development server and prints the index record whenever the query configuration changes. It is useful for finding the correct CSS selectors during index configuration debugging. ```Shell aem up --print-index ``` -------------------------------- ### Configuring Fastly `recv` Subroutine with VCL Source: https://www.aem.live/docs/byo-cdn-fastly-setup This VCL snippet for the `recv` subroutine handles initial requests at the edge delivery node. It remembers the query string in `X-QS` and then strips it from the request URL for most paths, except for media, specific image types, JSON, and authentication paths, to optimize caching. ```VCL if (fastly.ff.visits_this_service == 0) { # edge delivery node if (req.url.qs != "") { # remember query string set req.http.X-QS = req.url.qs; if (req.url.path !~ "/media_[0-9a-f]{40,}[/a-zA-Z0-9_-]*\\.[0-9a-z]+$" && req.url.ext !~ "(?i)^(gif|png|jpe?g|webp)$" && req.url.ext != "json" && req.url.path != "/.auth") { # strip query string from request url set req.url = req.url.path; } } } ``` -------------------------------- ### Configuring Sidekick Plugin in `config.json` for Library Integration Source: https://www.aem.live/docs/sidekick-library This JSON snippet defines the configuration for a Sidekick plugin, specifically the 'library' plugin. It specifies the plugin's ID, title, target environments, URL to load the plugin, and paths where it should be included, enabling the Sidekick Library to appear. ```JSON { "project": "Example", "plugins": [ { "id": "library", "title": "Library", "environments": ["edit"], "url": "/tools/sidekick/library.html", "includePaths": ["**.docx**"] } ] } ``` -------------------------------- ### Extending Sidekick Library with External Configuration in JavaScript Source: https://www.aem.live/docs/sidekick-library This JavaScript snippet illustrates how to configure the Sidekick Library to merge a base library with an extended library from a different origin. This allows authors to access a combined list of blocks from multiple sources. ```JavaScript const library = document.createElement('sidekick-library') library.config = { base: '/tools/sidekick/library.json', extends: 'https://main--repo--owner.hlx.live/tools/sidekick/library.json' } ``` -------------------------------- ### Installing AEM CLI Globally with npm Source: https://www.aem.live/developer/cli-reference This command installs the AEM Command Line Interface globally on your system using npm. A global installation allows you to run the 'aem' command from any directory in your terminal. ```Shell $ npm install -g @adobe/aem-cli ``` -------------------------------- ### Configuring SharePoint Mountpoint in fstab.yaml Source: https://www.aem.live/docs/setup-customer-sharepoint This YAML snippet demonstrates how to configure a mountpoint in fstab.yaml to link the root path (/) of your AEM project to a specific SharePoint folder. It uses an example URL pointing to a website folder within a SharePoint site, enabling AEM to access content from that location. ```YAML mountpoints: /: https://adobeenterprisesupportaem.SharePoint.com/sites/hlx-test-project/Shared%20Documents/website ``` -------------------------------- ### Configuring Custom Sidekick Library Plugin in JavaScript Source: https://www.aem.live/docs/sidekick-library This JavaScript snippet demonstrates how to define a custom 'tags' plugin within the Sidekick Library configuration. It specifies the plugin's source file and additional properties that will be accessible to the plugin via its context argument. ```JavaScript const library = document.createElement('sidekick-library') library.config = { base: '/tools/sidekick/library.json', plugins: { tags: { src: '/tools/sidekick/plugins/tags/tags.js', foo: 'bar' } } } ``` -------------------------------- ### Implementing AEM Sidekick Plugin `decorate` Method - JavaScript Source: https://www.aem.live/docs/sidekick-library This snippet defines the `decorate` asynchronous function, which is the entry point for an AEM Sidekick plugin. It is invoked when a user loads the plugin, receiving the HTML container for rendering, data from the plugin sheet, an optional search query, and any registered context properties. This method is where the plugin's user interface and core logic should be implemented. ```JavaScript /** * Called when a user tries to load the plugin * @param {HTMLElement} container The container to render the plugin in * @param {Object} data The data contained in the plugin sheet * @param {String} query If search is active, the current search query * @param {Object} context contains any properties set when the plugin was registered */ export async function decorate(container, data, query, context) { // Render your plugin } ``` -------------------------------- ### Enabling Push Invalidation in Fastly `miss` and `pass` Subroutines with VCL Source: https://www.aem.live/docs/byo-cdn-fastly-setup This VCL snippet is applied to both the `miss` and `pass` subroutines. It sets two request headers: `X-BYO-CDN-Type` to "fastly" and `X-Push-Invalidation` to "enabled", which is crucial for enabling push invalidation and allowing for longer cache TTLs. ```VCL set bereq.http.X-BYO-CDN-Type = "fastly"; set bereq.http.X-Push-Invalidation = "enabled"; ``` -------------------------------- ### Configuring Blocks Plugin with Full-Form Custom Viewports (JavaScript) Source: https://www.aem.live/docs/sidekick-library This JavaScript snippet illustrates how to define custom viewport sizes for the Blocks plugin using a detailed object array. Each object specifies `width`, `label`, `icon`, and an optional `default` property, providing granular control over preview dimensions and their representation. ```JavaScript const library = document.createElement('sidekick-library') library.config = { base: '/tools/sidekick/library.json', plugins: { blocks: { viewPorts: [ { width: '599px', label: 'Small', icon: 'device-phone', }, { width: '899px', label: 'Medium', icon: 'device-tablet', }, { width: '100%', label: 'Large', icon: 'device-desktop', default: true, } ] } } } ``` -------------------------------- ### Unsetting Response Headers in Fastly `deliver` Subroutine with VCL Source: https://www.aem.live/docs/byo-cdn-fastly-setup This VCL snippet for the `deliver` subroutine unsets the `Age` header from all responses. Additionally, it unsets the `X-Robots-Tag` header for all paths except those ending with `.plain.html`, providing control over how search engines crawl and index content. ```VCL unset resp.http.Age; if (req.url.path !~ "\\.plain\\.html$") { unset resp.http.X-Robots-Tag; } ``` -------------------------------- ### Finding Sites.Selected Application Role ID (Graph Explorer) Source: https://www.aem.live/docs/setup-customer-sharepoint This GET request to the Microsoft Graph API retrieves all application roles defined by the Microsoft Graph service principal (using the previously obtained 'resourceId'). The response is then parsed to find the 'id' for the 'Sites.Selected' application role, which will be used as the 'appRoleId' in the assignment request. ```HTTP GET https://graph.microsoft.com/v1.0/servicePrincipals/5159db96-7193-414e-9730-b1d1e4448443/appRoles ``` -------------------------------- ### Configuring Blocks Plugin for Image Encoding (JavaScript) Source: https://www.aem.live/docs/sidekick-library This JavaScript snippet demonstrates how to configure the Blocks plugin within a `sidekick-library` instance to enable image encoding. Setting `encodeImages` to `true` is crucial for environments with Zero Trust Network Access (ZTNA) services like Cloudflare Access, ensuring images are correctly handled during copy/paste operations. ```JavaScript const library = document.createElement('sidekick-library') library.config = { base: '/tools/sidekick/library.json', plugins: { blocks: { encodeImages: true, } } } ``` -------------------------------- ### Preserving Query Strings in Fastly `deliver` Subroutine with VCL Source: https://www.aem.live/docs/byo-cdn-fastly-setup This VCL snippet for the `deliver` subroutine ensures that the original request's query string is preserved in redirect locations (HTTP 3xx statuses) when the response location does not already contain a query string. This is important for maintaining context across redirects. ```VCL if (fastly.ff.visits_this_service == 0) { # on edge delivery node if ( http_status_matches(resp.status, "301,302,303,307,308") && req.http.X-QS && resp.http.location && resp.http.location !~ "\\?.*\\z" ) { # preserve request query string in redirect location set resp.http.location = resp.http.location "?" req.http.X-QS; } } ``` -------------------------------- ### Managing Loader Visibility in AEM Sidekick Plugin (JavaScript) Source: https://www.aem.live/docs/sidekick-library This snippet illustrates how to show and hide a loading indicator within the AEM Sidekick UI by dispatching `PLUGIN_EVENTS.SHOW_LOADER` and `PLUGIN_EVENTS.HIDE_LOADER` custom events. This is useful for indicating ongoing asynchronous operations to the user. ```JavaScript import { PLUGIN_EVENTS } from 'https://www.aem.live/tools/sidekick/library/events/events.js'; export async function decorate(container, data, query) { // Show loader container.dispatchEvent(new CustomEvent(PLUGIN_EVENTS.SHOW_LOADER)) ... // Hide loader container.dispatchEvent(new CustomEvent(PLUGIN_EVENTS.HIDE_LOADER)) } ``` -------------------------------- ### Configuring Blocks Plugin with Short-Form Custom Viewports (JavaScript) Source: https://www.aem.live/docs/sidekick-library This JavaScript snippet shows how to set custom viewport sizes for the Blocks plugin using a simplified array format. The array `[600, 900]` defines two custom widths, overriding the default mobile and tablet viewport sizes for previewing content. ```JavaScript const library = document.createElement('sidekick-library') library.config = { base: '/tools/sidekick/library.json', plugins: { blocks: { viewPorts: [600, 900], } } } ``` -------------------------------- ### Retrieving SharePoint Site ID using Microsoft Graph API Source: https://www.aem.live/docs/setup-customer-sharepoint This GET request to the Microsoft Graph API is used to retrieve the unique SiteId for a specific SharePoint site. The host-name and server-relative-path parameters identify the target site. This ID is crucial for subsequent operations like setting permissions. ```HTTP GET https://graph.microsoft.com/v1.0/sites/{host-name}:/{server-relative-path} ``` -------------------------------- ### Utility Functions for `window.location` in Sidekick Library Blocks (JavaScript) Source: https://www.aem.live/docs/sidekick-library These JavaScript functions provide reliable ways to retrieve the true origin and href of the current page when a block is running within the Sidekick Library's `srcdoc` iframe. `getOrigin` returns the parent's origin, and `getHref` constructs the full URL using a path query parameter from the parent. ```JavaScript /** * Returns the true origin of the current page in the browser. * If the page is running in a iframe with srcdoc, the ancestor origin is returned. * @returns {String} The true origin */ export function getOrigin() { const { location } = window; return location.href === 'about:srcdoc' ? window.parent.location.origin : location.origin; } /** * Returns the true of the current page in the browser.mac * If the page is running in a iframe with srcdoc, * the ancestor origin + the path query param is returned. * @returns {String} The href of the current page or the href of the block running in the library */ export function getHref() { if (window.location.href !== 'about:srcdoc') return window.location.href; const { location: parentLocation } = window.parent; const urlParams = new URLSearchParams(parentLocation.search); return `${parentLocation.origin}${urlParams.get('path')}`; } ``` -------------------------------- ### Checking AEM Page Index via Admin Service API Source: https://www.aem.live/developer/indexing This URL endpoint allows you to check the index representation of a page. Replace the placeholders with your GitHub owner, repository, branch, and the resource path to the page. The response will be a JSON object with the index data. ```URL https://admin.hlx.page/index//// ``` -------------------------------- ### Displaying Toast Messages in AEM Sidekick Plugin (JavaScript) Source: https://www.aem.live/docs/sidekick-library This snippet demonstrates how to dispatch a custom event to show a toast message in the AEM Sidekick UI. It uses `PLUGIN_EVENTS.TOAST` and includes `message` and `variant` in the event detail for customization. The `variant` can be 'positive' or 'negative' to indicate success or error. ```JavaScript import { PLUGIN_EVENTS } from 'https://www.aem.live/tools/sidekick/library/events/events.js'; export async function decorate(container, data, query) { // Show a toast message container.dispatchEvent(new CustomEvent(PLUGIN_EVENTS.TOAST, { detail: { message: 'Toast Shown!', variant: 'positive | negative' } })) } ``` -------------------------------- ### Customizing Table Header Colors with CSS Variables Source: https://www.aem.live/docs/sidekick-library This CSS snippet demonstrates how to customize the background and foreground colors of table headers when pasting blocks, section metadata, or general metadata from the Blocks plugin. It uses CSS variables (`--sk-block-table-background-color`, etc.) defined within the `:root` selector in `library.html` to set default styles. ```CSS ``` -------------------------------- ### Configuring AEM Sidekick Plugin Default Export - JavaScript Source: https://www.aem.live/docs/sidekick-library This code snippet demonstrates how to use the default export in an AEM Sidekick plugin to customize its display name and enable search functionality. Setting `searchEnabled` to `true` will display a search icon in the library header, and if a user enters a query, the plugin's `decorate()` function will be re-triggered with the search string passed in the `query` parameter. ```JavaScript export default { title: 'Tags', searchEnabled: true, }; ``` -------------------------------- ### Example XML Sitemap Entry with hreflang for AEM Source: https://www.aem.live/developer/sitemap This XML snippet shows a typical entry in an AEM-generated sitemap, demonstrating how `hreflang` attributes are used to link alternate language versions of a page. It includes the canonical URL (`loc`) and `xhtml:link` elements for English and French alternatives, assuming a common suffix for related pages. ```XML https://wwww.mysite.com/welcome ``` -------------------------------- ### Finding Enterprise Application Service Principal ID (Graph Explorer) Source: https://www.aem.live/docs/setup-customer-sharepoint This GET request to the Microsoft Graph API retrieves the service principal details for a specific enterprise application using its 'appId'. The 'id' field from the response's 'value' array will be used as the 'principalId' for subsequent operations, representing the managed identity to which the role will be assigned. ```HTTP GET https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq '83ab2922-5f11-4e4d-96f3-d1e0ff152856' ``` -------------------------------- ### Akamai Fast Purge API Credentials Example Source: https://www.aem.live/docs/setup-byo-cdn-push-invalidation This snippet illustrates the structure of the Akamai Fast Purge API credentials. These values (host, client_token, client_secret, access_token) are crucial for authenticating and authorizing requests to the Akamai Fast Purge API, enabling actions such as deleting content by URL or cache tag. Users must generate their own unique credentials following Akamai's documentation. ```Plain Text host = akaa-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.luna.akamaiapis.net client_token = akab-XXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX client_secret = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX access_token = akab-XXXXXXXXXXXXXXXX-XXXXXXXXXXXXXXXX ``` -------------------------------- ### Filtering Excel Data for Indexed Content Source: https://www.aem.live/developer/indexing This Excel formula is used within the `helix-default` sheet of `query-index.xlsx` to automatically populate it. It filters rows from `Table1` (presumably `raw_index`) to exclude any entries where the `robots` property is set to `noindex`, ensuring only indexable content is copied to the `helix-default` sheet. ```Excel =FILTER(Table1,NOT(Table1[robots]="noindex")) ``` -------------------------------- ### Finding Microsoft Graph API Service Principal ID (Graph Explorer) Source: https://www.aem.live/docs/setup-customer-sharepoint This GET request to the Microsoft Graph API retrieves the service principal details for the Microsoft Graph API itself, identified by its well-known 'appId'. The 'id' field from the response's 'value' array will be used as the 'resourceId' for subsequent operations, representing the resource that defines the application role. ```HTTP GET https://graph.microsoft.com/v1.0/servicePrincipals?$filter=appId eq '00000003-0000-0000-c000-000000000000' ``` -------------------------------- ### Basic HTML Structure of a Block Source: https://www.aem.live/developer/markup-sections-blocks This snippet illustrates the fundamental HTML structure generated for a simple content block. Blocks are rendered as nested `
` tags, with the outermost `
` carrying the block's name as a CSS class. Inner `
` elements represent rows and columns of content entered by the author. This example shows a single-cell block containing a paragraph. ```HTML

Hello, World.

``` -------------------------------- ### SharePoint Website Root URL Format in fstab.yaml Source: https://www.aem.live/docs/setup-customer-sharepoint This snippet shows the general URL format required for configuring the SharePoint website root in the fstab.yaml file. It specifies the tenant, SharePoint site, and the path to the website folder within Shared Documents. This URL is crucial for AEM to correctly mount the SharePoint content. ```YAML https://.SharePoint.com/sites//Shared%20Documents/website ``` -------------------------------- ### Creating Enterprise Application via PowerShell Source: https://www.aem.live/docs/setup-customer-sharepoint This PowerShell snippet shows how to create an Enterprise application. First, it connects to Microsoft Graph with the necessary 'Application.ReadWrite.All' scope. Then, it uses 'New-MgServicePrincipal' to create the service principal, specifying the 'AppId' and adding the 'WindowsAzureActiveDirectoryIntegratedApp' tag to ensure visibility in the Azure UI. ```PowerShell PS> connect-MgGraph -Scopes "Application.ReadWrite.All" PS> New-MgServicePrincipal -AppId e34c45c4-0919-43e1-9436-448ad8e81552 -Tags WindowsAzureActiveDirectoryIntegratedApp ``` -------------------------------- ### Configuring robots.txt for Sitemap Discovery Source: https://www.aem.live/docs/go-live-checklist This snippet illustrates a standard `robots.txt` configuration. It grants all user agents permission to crawl the entire site and explicitly declares the URL of the sitemap, which is vital for search engine optimization (SEO) as it helps search engines efficiently discover and index the website's content. This configuration is essential for ensuring proper indexing and avoiding duplicate content issues. ```robots.txt User-agent: * Allow: / Sitemap: https:///sitemap.xml ``` -------------------------------- ### Assigning Sites.Selected Application Role using PowerShell Source: https://www.aem.live/docs/setup-customer-sharepoint This PowerShell script assigns the 'Sites.Selected' application role to a specified enterprise application's service principal. It first retrieves the service principals for the target application and Microsoft Graph, then finds the 'Sites.Selected' app role ID, and finally creates the app role assignment. Remember to replace `$ObjectId` with your enterprise application's ID. ```PowerShell $ObjectId = "abcdef-1234-49b6-b660-cc85b34fe516" <<------ replace with your enterprise app id $AAD_SP = Get-AzureADServicePrincipal -SearchString "Microsoft Graph"; $AAD_SP $MSI = Get-AzureADServicePrincipal -ObjectId $ObjectId if($MSI.Count -gt 1) { Write-Output "More than 1 principal found, please find your principal and copy the right object ID. Now use the syntax $MSI = Get-AzureADServicePrincipal -ObjectId " Exit } $AAD_AppRole = $AAD_SP.AppRoles | Where-Object {$_.Value -eq "Sites.Selected"} New-AzureADServiceAppRoleAssignment -ObjectId $MSI.ObjectId -PrincipalId $MSI.ObjectId -ResourceId $AAD_SP.ObjectId[0] -Id $AAD_AppRole.Id ``` -------------------------------- ### Basic AEM Sidekick Configuration in JSON Source: https://www.aem.live/developer/sidekick-development This JSON snippet shows a basic `config.json` structure for customizing the AEM Sidekick. It allows setting a project name and defining an empty array for plugins. This file should be placed at `/tools/sidekick/config.json` in your project's GitHub repository. ```JSON { "project": "My project", "plugins": [] } ``` -------------------------------- ### Configuring a Standard Palette AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration sets up a URL-based plugin for AEM Sidekick that opens its target URL ('/tools/sidekick/foo-palette.html') within a floating palette instead of a new browser tab. The `isPalette` property is set to `true` to enable this behavior, creating a standard palette. ```JSON { "plugins": [ { "id": "foo", "title": "Foo", "url": "/tools/sidekick/foo-palette.html", "isPalette": true } ] } ``` -------------------------------- ### Creating Enterprise Application via MSGraph API Source: https://www.aem.live/docs/setup-customer-sharepoint This snippet demonstrates how to create an Enterprise application using a POST request to the Microsoft Graph API's servicePrincipals endpoint. It includes the 'appId' and the 'WindowsAzureActiveDirectoryIntegratedApp' tag, which is necessary for the application to be visible in the Azure UI. The 'Content-type' header specifies JSON for the request body. ```HTTP POST https://graph.microsoft.com/v1.0/servicePrincipals Content-type: application/json { "appId": "e34c45c4-0919-43e1-9436-448ad8e81552", "tags": [ "WindowsAzureActiveDirectoryIntegratedApp" ] } ``` -------------------------------- ### Configuring a Container AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration demonstrates how to create a container plugin named 'Tools' using `isContainer: true`. It then places another plugin, 'Foo', inside this container by setting its `containerId` to 'tools'. Container plugins group related functionalities, saving space in the toolbar and toggling a dropdown when clicked. ```JSON { "plugins": [ { "id": "tools", "title": "Tools", "isContainer": true }, { "id": "foo", "containerId": "tools", "title": "Foo", "event": "foo" } ] } ``` -------------------------------- ### Displaying AEM CLI General Help Source: https://www.aem.live/developer/cli-reference This command displays the general help information for the AEM CLI, listing all available top-level commands and global options. It's useful for quickly understanding the CLI's capabilities. ```Shell $ aem --help ``` -------------------------------- ### Adding Write Permissions to SharePoint Site using Microsoft Graph API Source: https://www.aem.live/docs/setup-customer-sharepoint This POST request to the Microsoft Graph API adds write permissions to a specific SharePoint site using its previously obtained SiteId. The request body specifies the 'write' role and grants it to a defined application identity, identified by its ID and display name. Site Admin permissions and additional 'Sites' scopes consent are prerequisites. ```HTTP POST https://graph.microsoft.com/v1.0/sites/adobeenterprisesupportaem.sharepoint.com,03cc3587-0e4d-405e-b06c-ffb0a622b7ac,5fbc1df5-640c-4780-8b59-809e3193c043/permissions Content-type: application/json { "roles": [ "write" ], "grantedToIdentities": [ { "application": { "id": "83ab2922-5f11-4e4d-96f3-d1e0ff152856", "displayName": "AEM Content Integration" } } ] } ``` -------------------------------- ### Configuring a Badge AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration creates a 'Stage' badge plugin for AEM Sidekick, which is rendered as a decorative label on the right side of the toolbar. The `isBadge` property is set to `true`, and the `environments` array specifies that this badge should only appear in the 'preview' environment. Badges are not clickable and serve a purely informational purpose. ```JSON { "plugins": [ { "id": "stage", "title": "Stage", "isBadge": true, "environments" ["preview"] } ] } ``` -------------------------------- ### Adding AEM Content Integration Service Principal using PowerShell Source: https://www.aem.live/docs/setup-customer-sharepoint This snippet provides PowerShell commands to add the AEM Content Integration enterprise application as a service principal in Azure Active Directory. It first connects to Microsoft Graph with necessary permissions (`Application.ReadWrite.All`) and then creates the service principal using its `AppId` and `Tags`. ```PowerShell PS> connect-MgGraph -Scopes "Application.ReadWrite.All" PS> New-MgServicePrincipal -AppId 83ab2922-5f11-4e4d-96f3-d1e0ff152856 -Tags WindowsAzureActiveDirectoryIntegratedApp ``` -------------------------------- ### Initializing Adobe FEDS Configuration (JavaScript) Source: https://status.adobe.com/products/503489 This snippet initializes the `window.fedsConfig` object, which configures the Adobe Global Navigation (FEDS) system. It sets the locale, disables sticky behavior, defines content experience, subnav theme, and a function for the footer's region modal to display a language change modal. It also includes privacy settings for OneTrust. ```JavaScript var modal,langLocale=document.querySelector("html").getAttribute("data-gnav-lang-key");window.fedsConfig={locale:langLocale||window.locale||"en",disableSticky:!1,content:{experience:"acom"},subnav:{theme:{base:"light",gradient:{toColor:"#FAFAFA",fromColor:"#FAFAFA",opacity:1}}},footer:{regionModal:function(){(modal=document.getElementById("changeLanguageModal")).style.display="block"}},privacy:{otDomainId:"7a5eb705-95ed-4cc4-a11d-0cc5760e93db",footerLinkSelector:'\\[data-feds-action=\"open-adchoices-modal\"\]'}} ``` -------------------------------- ### Audit Log Entry for Preview Operation (Audit Log Format) Source: https://www.aem.live/docs/auditlog This snippet shows the audit log entry for a 'Preview' operation triggered via Sidekick. It indicates that the operation uses the HTTP POST method and targets the `/preview` route. ```Audit Log Format method: POST, route: /preview ``` -------------------------------- ### Assigning Application Role to Managed Identity (Graph Explorer - Generic) Source: https://www.aem.live/docs/setup-customer-sharepoint This POST request to the Microsoft Graph API assigns an application role to a service principal. It requires the 'principalId' of the managed identity, the 'resourceId' of the resource defining the role, and the 'appRoleId' of the specific role to be assigned. The request body is a JSON object containing these three IDs. ```HTTP POST https://graph.microsoft.com/v1.0/servicePrincipals/${principalId}/appRoleAssignedTo Content-Type: application/json { "principalId": "${principalId}", "resourceId": "${resourceId}", "appRoleId": "${appRoleId}" } ``` -------------------------------- ### HTML Structure for AEM Sidekick Custom JSON Viewer (HTML) Source: https://www.aem.live/developer/sidekick-development This HTML snippet provides the basic structure for a custom JSON viewer page, intended to be hosted at the `viewer` path defined in the special views configuration. It includes meta tags for character set and viewport, links to an external CSS file (`custom-json-viewer.css`), and references a JavaScript file (`custom-json-viewer.js`) for custom logic. ```HTML Custom JSON Viewer ``` -------------------------------- ### Audit Log Entry for Publish Operation (Audit Log Format) Source: https://www.aem.live/docs/auditlog This snippet shows the audit log entry for a 'Publish' operation triggered via Sidekick. It indicates that the operation uses the HTTP POST method and targets the `/live` route. ```Audit Log Format method: POST, route: /live ``` -------------------------------- ### Defining a URL-based AEM Sidekick Plugin in JSON Source: https://www.aem.live/developer/sidekick-development This JSON snippet illustrates how to define a URL-based plugin within the AEM Sidekick configuration. When the plugin button is clicked, it opens the specified `url` in a new tab. Essential properties include a unique `id`, a `title` for the button, and the `url` to be opened. ```JSON { "plugins": [ { "id": "foo", "title": "Foo", "url": "/tools/sidekick/foo.html" } ] } ``` -------------------------------- ### Configuring CDN Opt-In Header for Cache TTLs (Plain Text) Source: https://www.aem.live/docs/setup-byo-cdn-push-invalidation This snippet specifies the 'X-Push-Invalidation' header that the production CDN must send to the origin server. Its purpose is to signal the origin to enable long cache Time-To-Live (TTL) values, optimizing content delivery and reducing origin load. ```Plain Text X-Push-Invalidation: enabled ``` -------------------------------- ### Configuring a Standard Popover AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration defines a URL-based plugin for AEM Sidekick that opens its target URL ('/tools/sidekick/foo-popover.html') within a popover, centered above the plugin's button, instead of a new tab. The `isPopover` property is set to `true` to enable this behavior. ```JSON { "plugins": [ { "id": "foo", "title": "Foo", "url": "/tools/sidekick/foo-popover.html", "isPopover": true } ] } ``` -------------------------------- ### Defining Special View for JSON Files in AEM Sidekick (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration defines a "special view" within the AEM Sidekick. When a tab's URL matches the `path` pattern (`**.json`), the sidekick redirects to the specified `viewer` URL (`/tools/sidekick/custom-json-viewer/index.html`). This enables custom rendering logic for specific media types, with the original resource URL passed as a query parameter. ```JSON { "specialViews": [ { "title": "Custom JSON Viewer", "path" : "**.json", "viewer": "/tools/sidekick/custom-json-viewer/index.html" } ] } ``` -------------------------------- ### Adding AEM Content Integration Service Principal using Microsoft Graph API Source: https://www.aem.live/docs/setup-customer-sharepoint This snippet demonstrates how to add the AEM Content Integration enterprise application as a service principal in Azure Active Directory using a POST request to the Microsoft Graph API. It specifies the `appId` and `tags` for the service principal, enabling the application to be recognized within Azure AD. ```HTTP Request POST https://graph.microsoft.com/v1.0/servicePrincipals Content-type: application/json { "appId": "83ab2922-5f11-4e4d-96f3-d1e0ff152856", "tags": [ "WindowsAzureActiveDirectoryIntegratedApp" ] } ``` -------------------------------- ### Restricting Sidekick Access: Allowing Specific Hosts (JSON) Source: https://www.aem.live/docs/sidekick-security This configuration demonstrates a restrictive approach where the AEM Sidekick extension is blocked from all URLs (`http*://*/*`) except those explicitly listed in `runtime_allowed_hosts`. This ensures maximum security while allowing interaction with essential AEM-related domains and local development environments. It complements the `host_permissions` defined in the extension's manifest file. ```JSON { "igkmdomcgoebiipaifhmpfjhbjccggml": { "runtime_blocked_hosts": ["http*://*/*"], "runtime_allowed_hosts": [ "https://admin.hlx.page/*", "https://rum.hlx.page/*", "http://localhost:3000/*", "https://*.sharepoint.com/*", "https://*--project--example.aem.*/*" ] } } ``` -------------------------------- ### JavaScript Logic for AEM Sidekick Custom JSON Viewer (JavaScript) Source: https://www.aem.live/developer/sidekick-development This JavaScript snippet implements the core logic for the custom JSON viewer. It retrieves the original resource URL from the current page's query parameters, fetches the content, parses it as JSON, and then displays the formatted JSON data within a `
` tag in the document body. It includes error handling for failed fetches or parsing.

```JavaScript
try {
  // get the resource URL from the url query parameter
  const url = new URL(window.location.href).searchParams.get('url');
  if (url) {
    const res = await fetch(url);
    if (res.ok) {
      const text = await res.text();
      const data = JSON.parse(text);
      // do something with the data, e.g.
      document.body.innerHTML = `\n        
\n          ${JSON.stringify(data, null, 2)}\n        
\n `; } else { throw new Error(`failed to load ${url}: ${res.status}`); } } } catch (e) { console.error('error rendering custom json view', e); } ``` -------------------------------- ### Configuring a Custom-Sized Palette AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration extends the palette plugin by specifying a custom size and position using the `paletteRect` property. The `paletteRect` string defines the CSS properties for the palette's dimensions and placement, allowing for precise control over its appearance on the page. ```JSON { "plugins": [ { "id": "foo", "title": "Foo", "url": "/tools/sidekick/foo-palette.html", "isPalette": true, "paletteRect": "top:150px;left:7%;height:675px;width:85vw;" } ] } ``` -------------------------------- ### Audit Log Entry for Delete Operation (Audit Log Format) Source: https://www.aem.live/docs/auditlog This snippet shows the audit log entry for a 'Delete' operation triggered via Sidekick. It indicates that the operation involves two steps: first, an HTTP DELETE method to the `/preview` route, and then another HTTP DELETE method to the `/live` route. ```Audit Log Format method: DELETE, route: /preview method: DELETE, route: /live ``` -------------------------------- ### Listening to AEM Sidekick Events in JavaScript Source: https://www.aem.live/developer/sidekick-development This snippet demonstrates how to listen for custom AEM Sidekick events, such as 'foo', in your project's JavaScript code. It handles scenarios where the sidekick is already loaded or waits for the 'sidekick-ready' event before attaching the listener. The event payload is accessed via `event.detail`. ```JavaScript const doFoo = ({ detail: payload }) => { console.log('something happened', payload); // your custom code goes here }; const sk = document.querySelector('aem-sidekick'); if (sk) { // sidekick already loaded sk.addEventListener('foo', doFoo); } else { // wait for sidekick to be loaded document.addEventListener('sidekick-ready', () => { // sidekick now loaded document.querySelector('aem-sidekick') .addEventListener('foo', doFoo); }, { once: true }); } ``` -------------------------------- ### Aggregating Multiple AEM Indexes into a Single Sitemap (YAML) Source: https://www.aem.live/developer/sitemap This YAML configuration shows how to combine content from multiple language-specific query indexes (e.g., Danish and Norwegian) into a single sitemap file (`/sitemap.xml`). By specifying the same `destination` for different language entries, AEM aggregates their content, which is useful for managing sitemap limits for search engines. ```YAML sitemaps: example: lastmod: YYYY-MM-DD languages: dk: source: /dk/query-index.json destination: /sitemap.xml hreflang: dk alternate: /dk/{path} no: source: /no/query-index.json destination: /sitemap.xml hreflang: no alternate: /no/{path} ``` -------------------------------- ### Configuring Multiple Language Sitemaps in AEM (YAML) Source: https://www.aem.live/developer/sitemap This YAML configuration defines how AEM generates multiple sitemaps for different languages (English and French). It specifies the `lastmod` date, the source query index for each language, the destination sitemap file, and the `hreflang` attribute. The `alternate` property defines a path pattern for alternate language versions. ```YAML sitemaps: example: lastmod: YYYY-MM-DD languages: en: source: /en/query-index.json destination: /sitemap-en.xml hreflang: en fr: source: /fr/query-index.json destination: /sitemap-fr.xml hreflang: fr alternate: /fr/{path} ``` -------------------------------- ### Handling Custom AEM Sidekick Plugin Events (JavaScript) Source: https://www.aem.live/developer/sidekick-development This JavaScript code demonstrates how to listen for a custom event ('custom:foo') dispatched by an AEM Sidekick event-based plugin. It checks if the sidekick is already loaded or waits for the 'sidekick-ready' event, then attaches an event listener to execute custom logic when the plugin button is clicked. The event detail contains the current sidekick state. ```JavaScript const doFoo = ({ detail: payload }) => { console.log('a custom event happened', payload); // your custom code goes here }; const sk = document.querySelector('aem-sidekick'); if (sk) { // sidekick already loaded sk.addEventListener('custom:foo', doFoo); } else { // wait for sidekick to be loaded document.addEventListener('sidekick-ready', () => { // sidekick now loaded document.querySelector('aem-sidekick') .addEventListener('custom:foo', doFoo); }, { once: true }); } ``` -------------------------------- ### Configuring an Event-based AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration defines an event-based plugin for AEM Sidekick. When the 'Foo' button is clicked, a custom 'foo' event is dispatched, allowing custom JavaScript code to react to this action. This type of plugin is restricted to Development, Preview, Live, and Production environments. ```JSON { "plugins": [ { "id": "foo", "title": "Foo", "event": "foo" } ] } ``` -------------------------------- ### Configuring Custom Edit URL for AEM Sidekick (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON snippet configures the AEM Sidekick to use a custom URL for the 'Edit' button. It defines `editUrlLabel` for the button's text and `editUrlPattern` which supports placeholders like `{{contentSourceUrl}}` and `{{pathname}}` to dynamically construct the edit URL. This allows integration with non-SharePoint/Google Drive content sources. ```JSON { "editUrlLabel": "Your Editor", "editUrlPattern": "{{contentSourceUrl}}{{pathname}}?cmd=open" } ``` -------------------------------- ### Configuring a Custom-Sized Popover AEM Sidekick Plugin (JSON) Source: https://www.aem.live/developer/sidekick-development This JSON configuration allows customization of a popover plugin's dimensions using the `popoverRect` property. This string defines the `width` and `height` of the popover, enabling control over its size while maintaining its centered position above the plugin button. A `theme` query parameter is also appended to the URL for styling. ```JSON { "plugins": [ { "id": "foo", "title": "Foo", "url": "/tools/sidekick/foo-popover.html", "isPopover": true, "popoverRect": "width:300px;height:200px;" } ] } ``` -------------------------------- ### Configuring Multiple hreflangs for a Single AEM Subtree (YAML) Source: https://www.aem.live/developer/sitemap This YAML configuration demonstrates how to assign an array of `hreflang` values to a single language subtree (`la`). This allows a single source to be associated with multiple regional or linguistic variations (e.g., `es-VE`, `es-SV`, `es-PA`) in the generated sitemap, ensuring comprehensive alternate linking. ```YAML sitemaps: example: lastmod: YYYY-MM-DD languages: la: source: /la/query-index.json destination: /sitemap-la.xml hreflang: - es-VE - es-SV - es-PA ```