Expand my Community achievements bar.

SOLVED

Handle links without .html extension

Avatar

Level 3

We have a dialog to select pages or assets from the content tree using the xtype pathfield. The purpose of the selection is to create a link on a page. Since assets are saved with the extensions, and pages aren’t, the link correctly directs the user to the assets, but not to the pages (because the page url doesn’t have the HTML extension).

 

These are the solutions we considered so far::

1 - linkPattern property in the dialog, to automatically append the HTML extension to the selected node. The problem is that it is also applied to assets, resulting in a wrong path (e.g. /content/dam/mysite/photo.jpg.html).

2 - Rewrite URL for page requests, using Apache (/content/mysite/home -> /content/mysite/home.html). It would fix the problem, but since we have a shared environment, we try to avoid  any solutions that may affect other sites.

3 - Using https://sling.apache.org/documentation/the-sling-engine/mappings-for-resource-resolution.html. It would map extensionless urls and redirect to the correct link with the HTML extension. The mapping would be done only under this site.

4 - Create a workflow triggered by page creation. It would set a vanity url to the same path without the extension.


It there a better solution to solve our problem? The best would be something simple to configure (one point) and restricted to the site structure.

1 Accepted Solution

Avatar

Correct answer by
Administrator

Hi murilod74686477 

Please have a look at some of reference links for you query:

Link:- http://www.citytechinc.com/us/en/blog/2013/04/extensionless-urls-in-adobe-experience-manager.html

//

xtensionless links:

     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Handle request with no slash and no extension
RewriteCond %{REQUEST_URI} !^/content/dam/.*
RewriteCond %{REQUEST_URI} !.*\..*$
RewriteCond %{REQUEST_URI} !.*/$
RewriteRule (.*)$ $1/ [R,QSA]
 
# Handle requests to pages ending with .html
RewriteCond    %{REQUEST_URI} !^/content/dam/.*
RewriteCond    %{REQUEST_URI} .*.html$
RewriteRule    (.*).html$ $1/ [R,QSA]
 
# Handle requests to pages ending with a trailing slash
RewriteCond     %{REQUEST_URI} !^/content/dam
RewriteCond     %{REQUEST_URI} .*/$
RewriteCond     %{REQUEST_URI} !^/$
RewriteRule     (.*)/$ $1.html [PT,L,QSA]

// 

                                                                                                                                                                                                                                                                                
ackage com.citytechinc.rewriter.linkchecker;
  
 import java.io.IOException;
  
 import org.apache.cocoon.xml.sax.AbstractSAXPipe;
 import org.apache.sling.rewriter.ProcessingComponentConfiguration;
 import org.apache.sling.rewriter.ProcessingContext;
 import org.apache.sling.rewriter.Transformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
  
 import com.citytechinc.web.services.URLAdapter;
  
 public class LinkTransformer extends AbstractSAXPipe implements Transformer {
  
 private static final Logger LOG = LoggerFactory.getLogger(LinkTransformer.class);
  
 private Boolean enableRemoveExtensions;
 private URLAdapter adapter;
  
 public LinkTransformer(final URLAdapter adapter) {
 enableRemoveExtensions = adapter != null
 && adapter.getOldExtensions() != null
 && adapter.getOldExtensions().size() > 0
 && adapter.getNewExtension() != null;
  
 LOG.info("LinkTransformer created. Enabled = " + enableRemoveExtensions);
  
 this.adapter = adapter;
 }
  
 @Override
 public void dispose() {
  
 }
  
 @Override
 public void init(final ProcessingContext context, final ProcessingComponentConfiguration config)
 throws IOException {
 }
  
 @Override
 public void startElement(final String uri, final String name, final String raw, final Attributes attrs)
 throws SAXException {
  
 final AttributesImpl attributes = new AttributesImpl(attrs);
 LOG.info("Processing element: " + raw);
 final String href = attributes.getValue("href");
 if (href != null && href.startsWith("/")) {
 LOG.info("Processing internal link href: " + href);
  
 for (int i = 0; i < attributes.getLength(); i++) {
 if ("href".equalsIgnoreCase(attributes.getQName(i))) {
 attributes.setValue(i, enableRemoveExtensions ? removeExtension(href) : href);
 }
 }
 }
  
 super.startElement(uri, name, raw, attributes);
 }
  
 private String removeExtension(final String url) {
 return adapter.adaptUrl(url);
 }
 }
                                                                                                        
package com.citytechinc.rewriter.linkchecker;
  
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.rewriter.Transformer;
 import org.apache.sling.rewriter.TransformerFactory;
 import com.citytechinc.web.services.URLAdapter;
  
 @Service(value = TransformerFactory.class)
 @Component
 public class LinkTransformerFactory implements TransformerFactory {
  
 @Property(
 value = "mylinktransformer",
 propertyPrivate = true)
 static final String PIPELINE_TYPE = "pipeline.type";
  
 @Reference
 private URLAdapter urlAdapter; // A class with one method that replaces ".html" with "/", given a URL.
  
 public final Transformer createTransformer() {
 return new LinkTransformer(urlAdapter);
 }
 }

Link:- https://gist.github.com/ryanlunka/5336471

 

Link:- http://www.wemblog.com/2011/08/how-to-remove-html-extension-from-url.html

Link:- https://helpx.adobe.com/experience-manager/using/creating-link-rewrite.html (community article)

link:- http://aem.matelli.org/url-mapping-and-deep-linking/

I hope this would help you.

Thanks and Regards

Kautuk Sahni



Kautuk Sahni

View solution in original post

2 Replies

Avatar

Level 10

Hi,

I guess the simplest solution is you can take care of this at development side in JSP or Sightly file. Below code shows using JSTL in JSP

<c:choose> <c:when test="${(fn:startsWith(listLink,'/content/dam')) || (fn:contains(listLink,'.'))}"> <c:set var="listLink" value="${listLink}"/> </c:when> <c:otherwise> <c:set var="listLink" value="${listLink}.html"/> </c:otherwise> </c:choose>

Avatar

Correct answer by
Administrator

Hi murilod74686477 

Please have a look at some of reference links for you query:

Link:- http://www.citytechinc.com/us/en/blog/2013/04/extensionless-urls-in-adobe-experience-manager.html

//

xtensionless links:

     
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# Handle request with no slash and no extension
RewriteCond %{REQUEST_URI} !^/content/dam/.*
RewriteCond %{REQUEST_URI} !.*\..*$
RewriteCond %{REQUEST_URI} !.*/$
RewriteRule (.*)$ $1/ [R,QSA]
 
# Handle requests to pages ending with .html
RewriteCond    %{REQUEST_URI} !^/content/dam/.*
RewriteCond    %{REQUEST_URI} .*.html$
RewriteRule    (.*).html$ $1/ [R,QSA]
 
# Handle requests to pages ending with a trailing slash
RewriteCond     %{REQUEST_URI} !^/content/dam
RewriteCond     %{REQUEST_URI} .*/$
RewriteCond     %{REQUEST_URI} !^/$
RewriteRule     (.*)/$ $1.html [PT,L,QSA]

// 

                                                                                                                                                                                                                                                                                
ackage com.citytechinc.rewriter.linkchecker;
  
 import java.io.IOException;
  
 import org.apache.cocoon.xml.sax.AbstractSAXPipe;
 import org.apache.sling.rewriter.ProcessingComponentConfiguration;
 import org.apache.sling.rewriter.ProcessingContext;
 import org.apache.sling.rewriter.Transformer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.xml.sax.Attributes;
 import org.xml.sax.SAXException;
 import org.xml.sax.helpers.AttributesImpl;
  
 import com.citytechinc.web.services.URLAdapter;
  
 public class LinkTransformer extends AbstractSAXPipe implements Transformer {
  
 private static final Logger LOG = LoggerFactory.getLogger(LinkTransformer.class);
  
 private Boolean enableRemoveExtensions;
 private URLAdapter adapter;
  
 public LinkTransformer(final URLAdapter adapter) {
 enableRemoveExtensions = adapter != null
 && adapter.getOldExtensions() != null
 && adapter.getOldExtensions().size() > 0
 && adapter.getNewExtension() != null;
  
 LOG.info("LinkTransformer created. Enabled = " + enableRemoveExtensions);
  
 this.adapter = adapter;
 }
  
 @Override
 public void dispose() {
  
 }
  
 @Override
 public void init(final ProcessingContext context, final ProcessingComponentConfiguration config)
 throws IOException {
 }
  
 @Override
 public void startElement(final String uri, final String name, final String raw, final Attributes attrs)
 throws SAXException {
  
 final AttributesImpl attributes = new AttributesImpl(attrs);
 LOG.info("Processing element: " + raw);
 final String href = attributes.getValue("href");
 if (href != null && href.startsWith("/")) {
 LOG.info("Processing internal link href: " + href);
  
 for (int i = 0; i < attributes.getLength(); i++) {
 if ("href".equalsIgnoreCase(attributes.getQName(i))) {
 attributes.setValue(i, enableRemoveExtensions ? removeExtension(href) : href);
 }
 }
 }
  
 super.startElement(uri, name, raw, attributes);
 }
  
 private String removeExtension(final String url) {
 return adapter.adaptUrl(url);
 }
 }
                                                                                                        
package com.citytechinc.rewriter.linkchecker;
  
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.Service;
 import org.apache.sling.rewriter.Transformer;
 import org.apache.sling.rewriter.TransformerFactory;
 import com.citytechinc.web.services.URLAdapter;
  
 @Service(value = TransformerFactory.class)
 @Component
 public class LinkTransformerFactory implements TransformerFactory {
  
 @Property(
 value = "mylinktransformer",
 propertyPrivate = true)
 static final String PIPELINE_TYPE = "pipeline.type";
  
 @Reference
 private URLAdapter urlAdapter; // A class with one method that replaces ".html" with "/", given a URL.
  
 public final Transformer createTransformer() {
 return new LinkTransformer(urlAdapter);
 }
 }

Link:- https://gist.github.com/ryanlunka/5336471

 

Link:- http://www.wemblog.com/2011/08/how-to-remove-html-extension-from-url.html

Link:- https://helpx.adobe.com/experience-manager/using/creating-link-rewrite.html (community article)

link:- http://aem.matelli.org/url-mapping-and-deep-linking/

I hope this would help you.

Thanks and Regards

Kautuk Sahni



Kautuk Sahni