Skip to main content

Adobe

How to show/hide page properties based on template in AEM 6.4

Recently, we had a requirement to show specific page properties for community pages that are based on the community editable template. As you know, in AEM 6.4, editable templates usually share the same page component, which means the same page properties dialog. Now, you could create a new page component (community-page) and inherit the master page component then ad the desired page properties. But there is another way!

Photo by Max van den Oetelaar on Unsplash

Granite Render Condition  

The granite render conditions allow you to show/hide resources based on a condition. Nate Yolles has an excellent post on the topic. Additionally there is a path based ACS commons render condition.

Reading the render condition docs and Nate Yolles post are essential to understanding the rest of this article.

 

Handling my specific use-case

back to my use case, I want to hide page property resources based on the template of the page authored. In AEM 6.4, page properties are handled in a specific UI with a specific url:
http://localhost:4502/mnt/overlay/wcm/core/content/sites/properties.html?item=/content/my-company/my-page
Now, I just need to write a render condition that will obtain the “item” param (page path) then from there I can get the page and its template and compare it to my specific template path. Here is what I arrived at:

<%@include file="/libs/foundation/global.jsp"%>
<%@page session="false"
        import="com.adobe.granite.ui.components.Config,
          com.adobe.granite.ui.components.rendercondition.RenderCondition,
          com.adobe.granite.ui.components.rendercondition.SimpleRenderCondition,
          com.mycompany.core.utils.TemplateRenderConditionUtil,
          org.apache.sling.api.resource.Resource,
          org.apache.sling.api.resource.ValueMap,
          com.adobe.granite.ui.components.ComponentHelper,
          com.adobe.granite.xss.XSSAPI,
          com.day.cq.i18n.I18n"%>
<%--###
Template
======
.. granite:servercomponent:: /apps/my-company/granite/rendercondition/template
   :rendercondition:
   A condition that renders page properties based on page template path
   It has the following content structure:
   .. gnd:gnd::
      [granite:RenderConditionsTemplate]
      /**
       * The template path to match
       */
      - templatePath (String)
###--%>
<sling:defineObjects/>
<%
final ComponentHelper cmp = new ComponentHelper(pageContext);
Config cfg = cmp.getConfig();
String path = cfg.get("templatePath", "");
boolean vote = TemplateRenderConditionUtil.isTemplate(slingRequest, request, path);
request.setAttribute(RenderCondition.class.getName(), new SimpleRenderCondition(vote));
%>

As you can see, I get the configured templatePath then pass it to TemplateRenderConditionUtil#isTemplate.
here is the code for TemplateRenderConditionUtil

Please note: the code here should be straight-forward to follow assuming you are familiar with java 8 lambdas.

 

package com.mycompany.core.utils;
import com.day.cq.wcm.api.Page;
import com.day.cq.wcm.api.Template;
import java.util.Optional;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.apache.sling.api.SlingHttpServletRequest;
public class TemplateRenderConditionUtil {
  private static final String PAGE_PROPERTIES = "wcm/core/content/sites/properties";
  public static boolean isTemplate(
    SlingHttpServletRequest slingHttpServletRequest,
    HttpServletRequest httpServletRequest,
    String templatePath) {
    // error if any of the passed params is null.
    if (slingHttpServletRequest == null
        || httpServletRequest == null
        || StringUtils.isBlank(templatePath)) {
      throw new IllegalArgumentException("One of the passed parameters is null.");
    }
    // the dialog is a page properties dialog
    if (StringUtils.contains(httpServletRequest.getPathInfo(), PAGE_PROPERTIES)) {
      // get the actual page path
      String pagePath = httpServletRequest.getParameter("item");
      // get page template path and check it
      return Optional.ofNullable(slingHttpServletRequest.getResourceResolver())
          .map(resourceResolver -> resourceResolver.getResource(pagePath))
          .map(pageResource -> pageResource.adaptTo(Page.class))
          .map(Page::getTemplate)
          .map(Template::getPath)
          .map(path -> StringUtils.contains(path, templatePath))
          .orElse(false);
    }
    return false;
  }
}

 
Now you can add a granite:rendercondition node under any of your properties to show/hide them based on template path. Here is an example:

<community jcr:primaryType="nt:unstructured"
    sling:resourceType="granite/ui/components/coral/foundation/form/fieldset"
    jcr:title="Community Properties">
    <items jcr:primaryType="nt:unstructured">
        <communityName
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/form/textfield"
            disabled="{Boolean}true"
            emptyText="Community ShortName"
            fieldLabel="Community Shortname"
            name="./communityShortname" />
        <communityColor
            jcr:primaryType="nt:unstructured"
            sling:resourceType="granite/ui/components/coral/foundation/form/select"
            fieldLabel="Community Color"
            name="./communityColor">
            <datasource
                jcr:primaryType="nt:unstructured"
                sling:resourceType="acs-commons/components/utilities/genericlist/datasource"
                path="/etc/acs-commons/lists/community-color" />
        </communityColor>
    </items>
    <granite:rendercondition
        jcr:primaryType="nt:unstructured"
        sling:resourceType="my-company/granite/rendercondition/template"
        templatePath="/conf/my-company/settings/wcm/templates/community-page"/>
</community>

my community fieldset will now only show for pages that are created from template: /conf/my-company/settings/wcm/templates/community-page

Thoughts on “How to show/hide page properties based on template in AEM 6.4”

  1. As you can see in the post, the render condition on granite widget (in dialog) is used in this manner:


    granite:rendercondition
    jcr:primaryType="nt:unstructured"
    sling:resourceType="my-company/granite/rendercondition/template"
    templatePath="/conf/my-company/settings/wcm/templates/community-page"

    You can see the `sling:resourceType` is `my-company/granite/rendercondition/template`
    this means it will first look under /libs then /apps.
    I put mine, as you should under `/apps/my-company/granite/rendercondition/template`

    You can put yours in any path you like.

  2. I just tried it locally (referencing the jsp path in the sling:resourceType attribute of the grante:rendercondition node) and it worked great, thanks for the post! This opens up a lot of opportunities.

  3. Hi,

    Is there any possibilty to provide mutiple template paths for “templatePath”. I want to achieve same feature for more than 1 template. Thank you in advance.

  4. Does it work with AEM 6.5?
    Imported class – com.kf.core.utils.TemplateRenderConditionUtil
    ERROR-
    rg.apache.sling.api.scripting.ScriptEvaluationException: org.apache.sling.scripting.jsp.jasper.JasperException: Unable to compile class for JSP:

    An error occurred at line: 26 in the jsp file: /apps/kf/granite/rendercondition/template/template.jsp
    TemplateRenderConditionUtil cannot be resolved
    23: final ComponentHelper cmp = new ComponentHelper(pageContext);
    24: Config cfg = cmp.getConfig();
    25: String path = cfg.get(“templatePath”, “”);
    26: boolean vote = TemplateRenderConditionUtil.isTemplate(slingRequest, request, path);
    27: request.setAttribute(RenderCondition.class.getName(), new SimpleRenderCondition(vote));
    28: %>

    Could you please suggest me solutions.

    Thanks in advance.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Ahmed Musallam, Adobe Technical Lead

Ahmed is an Adobe Technical Lead and expert in the Adobe Experience Cloud.

More from this Author

Categories
Follow Us
TwitterLinkedinFacebookYoutubeInstagram