List component using Tags and multiple paths/folders | Community
Skip to main content
ChrisPhillipsUC
Level 2
February 11, 2026
Question

List component using Tags and multiple paths/folders

  • February 11, 2026
  • 1 reply
  • 5 views

We had a query from one of our AEM authors to see if the list component could search and display Tagged pages in multiple folders/paths. 

Scenario:

All our news pages follow the same structure /news/year e.g:

/news/2026
/news/2025
/news/2024
etc

Each containing 200+ pages in each year folder and tagged accordingly. 

The University library in this instance, want to show all items tagged with “library” in folders 2026/2025/2024 and possibly more.

If they use the List component (using Tags) it doesnt allow the option to search in the child pages. 
If they use Child option, it allows you to chose a single parent and # of child pages but doesn’t allow you to filter by tag. 

So, question:

Can this component be modified or has someone used this in a way where a AEM Author/Editor can add multiple paths AND search by tag.

 


 

 

1 reply

PGURUKRISHNA
Level 4
February 11, 2026

Hey ​@ChrisPhillipsUC Create a custom Sling Model that:

  1. Accepts multiple parent paths (multifield in dialog)

  2. Accepts tag selection

  3. Queries child pages across all paths

  4. Filters results by tags

  5. Returns aggregated list items

Implementation

1. Sling Model Interface

package com.myproject.core.models;

import com.adobe.cq.wcm.core.components.models.List;

public interface MultiPathTaggedList extends List {
String[] getParentPaths();
}

2. Sling Model Implementation

package com.myproject.core.models.impl;

import com.adobe.cq.wcm.core.components.models.List;
import com.adobe.cq.wcm.core.components.models.ListItem;
import com.day.cq.tagging.Tag;
import com.day.cq.tagging.TagManager;
import com.myproject.core.models.MultiPathTaggedList;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.models.annotations.*;
import org.apache.sling.models.annotations.injectorspecific.*;
import org.apache.sling.models.annotations.via.ResourceSuperType;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.stream.*;

@Model(
adaptables = SlingHttpServletRequest.class,
adapters = {MultiPathTaggedList.class, List.class},
resourceType = "myproject/components/multipath-list",
defaultInjectionStrategy = DefaultInjectionStrategy.OPTIONAL
)
public class MultiPathTaggedListImpl implements MultiPathTaggedList {

@Self @Via(type = ResourceSuperType.class)
private List delegate;

@Self
private SlingHttpServletRequest request;

@ValueMapValue
private String[] parentPaths;

@ValueMapValue
private String[] tags;

private Collection<ListItem> items;

@PostConstruct
protected void init() {
if (parentPaths != null && parentPaths.length > 0 && tags != null && tags.length > 0) {
ResourceResolver resolver = request.getResourceResolver();
TagManager tagManager = resolver.adaptTo(TagManager.class);
Set<String> tagIds = new HashSet<>(Arrays.asList(tags));

items = Arrays.stream(parentPaths)
.map(resolver::getResource)
.filter(Objects::nonNull)
.flatMap(parent -> StreamSupport.stream(parent.getChildren().spliterator(), false))
.filter(res -> hasMatchingTag(res, tagManager, tagIds))
.map(SimpleListItem::new)
.collect(Collectors.toList());
} else {
items = delegate.getListItems();
}
}

private boolean hasMatchingTag(Resource resource, TagManager tagManager, Set<String> requiredTags) {
Tag[] pageTags = tagManager.getTags(resource);
return pageTags != null && Arrays.stream(pageTags)
.map(Tag::getTagID)
.anyMatch(requiredTags::contains);
}

@Override
public Collection<ListItem> getListItems() {
return items != null ? items : Collections.emptyList();
}

@Override
public String[] getParentPaths() {
return parentPaths;
}

@Override public boolean linkItems() { return delegate.linkItems(); }
@Override public boolean showDescription() { return delegate.showDescription(); }
@Override public boolean showModificationDate() { return delegate.showModificationDate(); }
@Override public String getDateFormatString() { return delegate.getDateFormatString(); }

private static class SimpleListItem implements ListItem {
private final Resource resource;
SimpleListItem(Resource resource) { this.resource = resource; }

@Override public String getTitle() {
return resource.getValueMap().get("jcr:title", resource.getName());
}
@Override public String getURL() { return resource.getPath() + ".html"; }
@Override public Resource getResource() { return resource; }
}
}

 

3. Component Definition (

_cq_dialog/.content.xml

)

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:granite="http://www.adobe.com/jcr/granite/1.0"
xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0" xmlns:nt="http://www.jcp.org/jcr/nt/1.0"
jcr:primaryType="nt:unstructured" jcr:title="Multi-Path Tagged List"
sling:resourceType="cq/gui/components/authoring/dialog">
<content jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<tabs jcr:primaryType="nt:unstructured" sling:resourceType="granite/ui/components/coral/foundation/tabs">
<items jcr:primaryType="nt:unstructured">
<properties jcr:primaryType="nt:unstructured" jcr:title="Properties"
sling:resourceType="granite/ui/components/coral/foundation/container">
<items jcr:primaryType="nt:unstructured">
<parentPaths jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/multifield"
fieldLabel="Parent Paths" required="{Boolean}true">
<field jcr:primaryType="nt:unstructured"
sling:resourceType="granite/ui/components/coral/foundation/form/pathfield"
name="./parentPaths" rootPath="/content"/>
</parentPaths>
<tags jcr:primaryType="nt:unstructured"
sling:resourceType="cq/gui/components/coral/common/form/tagfield"
fieldLabel="Tags" multiple="{Boolean}true" name="./tags" required="{Boolean}true"/>
</items>
</properties>
</items>
</tabs>
</items>
</content>
</jcr:root>

 

4. Component 

.content.xml
<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0" xmlns:cq="http://www.day.com/jcr/cq/1.0" xmlns:jcr="http://www.jcp.org/jcr/1.0"
jcr:primaryType="cq:Component"
jcr:title="Multi-Path Tagged List"
sling:resourceSuperType="core/wcm/components/list/v3/list"
componentGroup="My Project"/>

Usage Authors can now:

  • Add multiple paths: 

    /content/news/2024
    /content/news/2025
    /content/news/2026
  • Select tags: 

    library
  • Component automatically searches all child pages in those paths and filters by tag

The component leverages 

sling:resourceSuperType

 to inherit all rendering and display options from the Core Components List.