Expand my Community achievements bar.

Extending the Apache Sling Sitemap Generator for AEM 6.5.11 and AEMaaCs | AEM Community Blog Seeding

Avatar

Administrator

12/8/21

BlogImage.jpg

Extending the Apache Sling Sitemap Generator for AEM 6.5.11 and AEMaaCs by Nikhil Kumar

Abstract

As mentioned in the earlier article of Apache Sling Sitemap Generator we will be exploring on how we extend it to have out extended Apache Sling Sitemap with properties like lastModifiedData, priority and frequency.

As Apache Sling Sitemap bundle is open-source. So we will see how we can extend it to handle our custom properties. We can refer it’s README.md file for the whole process to extend the Apache Sling Sitemap Generator.

We will first start with creating or Java class MySitemapGenerator and with a higher Ranking (let’s say 20 here). As the PageTreeSitemapGeneratorImpl in the components console. already have a ranking of 10. Now we will go ahead and create MySitemapGenerator that extends the abstract class ResourceTreeSitemapGenerator.


package com.mynewsite.core.service.impl;

import java.util.Calendar;
import java.util.Optional;

import org.apache.sling.api.resource.Resource;
import org.apache.sling.sitemap.SitemapException;
import org.apache.sling.sitemap.builder.Sitemap;
import org.apache.sling.sitemap.builder.Url;
import org.apache.sling.sitemap.spi.common.SitemapLinkExternalizer;
import org.apache.sling.sitemap.spi.generator.ResourceTreeSitemapGenerator;
import org.apache.sling.sitemap.spi.generator.SitemapGenerator;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.propertytypes.ServiceRanking;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.day.cq.commons.jcr.JcrConstants;
import com.day.cq.wcm.api.Page;

@Component(service = SitemapGenerator.class)
@ServiceRanking(20)
public class MySitemapGenerator extends ResourceTreeSitemapGenerator {

private static final Logger log = LoggerFactory.getLogger(MySitemapGenerator.class);

@Reference
private SitemapLinkExternalizer externalizer;

@Override
protected void addResource(final String name, final Sitemap sitemap, final Resource resource)
throws
SitemapException {

final Page page = resource.adaptTo(Page.class);
final String location = this.externalizer.externalize(resource);
final Url url = sitemap.addUrl(location);
final Calendar lastmod = Optional.ofNullable(page.getLastModified())
.orElse(page.getContentResource()
.getValueMap()
.get(JcrConstants.JCR_CREATED, Calendar.class));
if (lastmod != null) {
url.setLastModified(lastmod.toInstant());
url.setPriority(2);

}
log.debug("Added the {} to Extended Sitemap", url);
}
}

Read Full Blog

Extending the Apache Sling Sitemap Generator for AEM 6.5.11 and AEMaaCs

Q&A

Please use this thread to ask the related questions.

8 Comments

Avatar

Level 2

2/18/22

As per the article if we add service ranking the custom generator is getting picked, but if we use scheduler and add the Custom Generator in the Include Generators list of OSGI config then its not picking the custom, still OOTB Sitemap generator is getting called.

 

Am i missing something here, or this is a known issue?

Avatar

Level 1

5/25/22

Thanks @kautuk_sahni  for sharing this. I am curious know how the multiple externalizer domains will be handled with this implementation with SitemapScheduler. Eg. I have 2 website domains in on my publish instance :

Domain 1 - https://demo1.com 

Domain 2 - https://demo2.com

Domain 1 is configured to point to /content/domain-1 on dispatcher

Domain 2 is configured to point to /content/domain-2 on dispatcher

 

I also setup a sitemapscheduler to generate sitemap at specific time interval.

 

Now for domain-1/sitemap.xml, it should generate sitemap with https://demo1.com prefixed in path while for domain-2 it should have https://demo2.com in sitemap urls.

 

Do we need to write 2 separate implementations of sitemap generators by passing different externalizer keys? Even if we try to have 2 implementations, implementation will higher ranking will be in affect other one will be ignored. Also, how the scheduler will be forced to generate 2 separator sitemap implementations?

 

 

Just trying to think over it, may be we need to customize the SitemapLinkExternalizer  implementation and use this custom externalizer into our MySitemapGenerator  should work. OOTB SitemapLinkExternalizer implementation may not work for this scenario. Any thoughts?

Thanks,

 

 

 

 

 

 

 

 

 

Avatar

Community Advisor

5/30/22

@rajeevy691 - We can configure multiple sitemap generator at the OSGI Config level. Also if you want to have custom implementation, you can update the above extended class to have different set of priority for different domain. As the priority is set at the URL level.

Avatar

Community Advisor

5/30/22

@bnagesh  - I guess we need to provide the service ranking to make it work, or else it picks up the OOTB sitemap.

Avatar

@Nikhil-Kumar Yes. Service ranking is needed, and the generator to be invoked/exclude can be mentioned under osgi configs.

 

Your blog helped me a lot thank you.

Avatar

Level 10

10/28/22

If someone is using scr annotations.. as we are unfortunately,

@component( immediate = true)
@service(value = SitemapGenerator.class)
@Properties({ @property(name="service.ranking",intValue = 40)})

Service ranking can be troublesome indeed. Took me  for a jolly ride

 

We are on 6.5.12 and 

<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.sitemap</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>com.adobe.cq.wcm</groupId>
<artifactId>com.adobe.aem.wcm.seo</artifactId>
<version>1.0.6</version>

</dependency>

Avatar

Level 4

12/12/22

@Nikhil-Kumar Thanks for this article. It helped me.  

 

If I want to get fully qualified URL I mean to add hostname before content path in <loc> how can we do that?

currently page path is : /content/we-retails/ue/en/testpage

It should be: http://localhost:4502//content/we-retails/ue/en/testpage

Avatar

Level 10

12/12/22

I ended up creating a custom site map generator and use 

Externalizer ext = resource.getResourceResolver().adaptTo(Externalizer.class) 

ext.publishLink(resource.getResourceResolver(),location)+”.html”


please take care of the quotes 

@supriya-hande 

hope this helps