Summer 2010 release brings yet another requested feature to the platform. With this new feature, sites developers and administrators can tailor custom URLs to refer to their pages instead of utilizing Salesforce.com generated URLs by using programmatic mapping. This feature is geared for Sites developers and administrators and require using Visual Force pages. 

In this blog, I will describe this feature and how you can utilize it with a running example. I will conclude by giving some tips. 

Picture 65
 

Example: 

Lets illustrate the concept with a running example. This example is already available and you can see the content by using the URLs below. Here is a site registered with the following URL using Force.com sites: 

    http://sitesdemo.force.com/news

This URL will take you to the home page of the website. Note that this site uses open source CMSForce application that is downloaded more than 1500+ times from AppExchange so far. 

Naturally, the pages that you access will result in a URL similar to the following pattern as generated by Force.com: 

    http://sitesdemo.force.com/news/page?pageid=a0q30000000GbnBAAS


Note that the page in question is referring to a contact information form on our website where customers can leave details about their info. The URL in question is not probably what we want to expose to users, because:

  • The function of the page should be decoupled from its id. We should be able to assign a logical reference for the page and change the actual page as we necessary in the future. This allows us to retain the logical resource reference of the page but change its "implementation" in the background, which is determined by the internal URL.
  • It is not easy to remember the page Ids, and what they refer to in the URL. Although they can be "bookmarked" by external tools, it is more beneficial to have unique URLs that cater to a specific function that is "friendly" for users. 

Further, the URL rewriting helps search optimization. Therefore, it would be beneficial not to reveal the internal Force.com generated ID but expose something more intelligible for the users, something like 

    http://sidesdemo.force.com/news/friendly/contactus

Note that the external URL must have an unambiguous mapping to an internal page for this feature to work, otherwise it is ambiguous as to which page is really displayed and responsible for the content. 

The Specifics of Feature: 

It is very simple to utilize this feature. 

1) First an APEX class needs to be created to deal with mapping of URLs. Namely, the purpose of the APEX class is to handle the mapping external page references to internal page ids and vice versa. This Apex class serves two functions:

    • Relegating the externally visible URL to an internal page URL. 
    • Revealing the externally visible set of URLs that correspond to internal page URLs.  

Note that the latter mapping is necessary to obtain the externally visible URLs if the page references need to be exposed as content in a specific page. It is desirable to embed the externally visible URL in this case. The platform does the mapping automatically by using the mapping feature designated for this site to expose the pages related to the site by externally friendly URLs. This is why it is important to define both  these mappings, however the developer can omit one of the mappings by returning null. 

The Apex class needs to be global. 

2) The Apex class needs to be associated with a Site. All requests that come to the site will be "filtered" by this class which will handle the mapping and dispatch to the appopriate page, or "expose" the external URLs of the pages. 

This function is handled via an Administrator view, by choosing Setup ->  App Setup –> Sites. After this, the site for which URL rewriting will be handled is chosen. A page like this will be shown: 

Picture 62

Note that there is a field called URL Rewrite Class in this page. Set the name of the global Apex class that is created to handle URL writing in this field. For the sake of this example, this class will be called myRewriter which is explained in detail below 

Lets see how our example is constructed in detail below:

The Global Apex class: 

The Apex class needs to have the structure below. 

  • It has be a global class and must implement Site.UrlWriter interface.
  • It must have two global methods, mapRequestUrl and generateUrlFor respectively. The first one maps a single external URL to an internal URL. The second one generates external URLs for internal URLs. 

global class ApexClassName implements Site.UrlRewriter {

  global PageReference mapRequestUrl(PageReference externalUrl) {//}

   global List<PageReference> generateUrlFor(List<PageReference> myForcedotcomUrls) {//…}

}

Note that a developer may not need all of the methods and may choose to return a null

Here is the implementation of our the global Apex class that maps the URLs from our example: 

global class myRewriter implements Site.UrlRewriter {

 //Variables to represent the friendly URLs for pages

 String DIRECTORY = '/friendly/';

 //Variables to represent my custom Visualforce pages that display page information

 String VISUALFORCE_PAGE = '/page?pageid=';

 // The first global method for mapping external URL to an internal one

 global PageReference mapRequestUrl(PageReference myFriendlyUrl){

    String url = myFriendlyUrl.getUrl();

    if(url.startsWith(DIRECTORY)){

       String name = url.substring(DIRECTORY.length(),url.length());

       //Select the ID of the page that matches the name from the URL

       Page__c site_page = [select id from Page__c where name =:name LIMIT 1];

       //Construct a new page reference in the form of my Visualforce page

       return new PageReference(VISUALFORCE_PAGE + site_page.id);

    }

    //If the URL isn't in the form of a cmasforce page, continue with the request

    return null;

  }

  // The second global method for mapping internal Ids to URLs

  global List<PageReference> generateUrlFor(List<PageReference> mySalesforceUrls){

    //A list of pages to return after all the links have been evaluated

    List<PageReference> myFriendlyUrls = new

    List<PageReference>();

    for(PageReference mySalesforceUrl : mySalesforceUrls){

      //Get the URL of the page

      String url = mySalesforceUrl.getUrl();

      //If this looks like a page that needs to be mapped, transform it

      if(url.startsWith(VISUALFORCE_PAGE)){

        //Extract the ID from the query parameter

        String id= url.substring(VISUALFORCE_PAGE.length(), url.length());

        //Query for the name of the cmsforce page to put in the URL

        Page__c site_page2 = [select name from Page__c where id =:id LIMIT 1];

        //Construct the new URL

        myFriendlyUrls.add(new PageReference(DIRECTORY+ site_page2.name));

     }  

     else {

       //If this doesn't start like an cmsforce page, don't do any transformations

       myFriendlyUrls.add(mySalesforceUrl);

     }

  }

  //Return the full list of pages

  return myFriendlyUrls;

  }

}

The Result: 

Here is the page accessed with the external ID with 

http://sitesdemo.force.com/news/friendly/contactus


Picture 61
 

Please note that we are using this site to illustrate a specific example for the contact page only. All the pages referenced from a specific site's landing page, may need to utilize externalized URLs for reverse mapping.

Final Tips 

Developers should be cognizant to the fact that rewriting adds additional processing with every page load. In addition, the governor limits in processing a request will need to allow for the number of SOQL queries used in the specific Apex class registered for URL rewriting. Further, developers should utilize "with sharing" for their specific Apex class for enforcing security to prevent inadvertent data exposure as needed for their application. 

A careful reader will notice that there may be additional applications of this feature. Note that a page output is not limited to html, but a page can generate content that is suitable for an application by changing the content type. Therefore, the URL mapping technique discussed here can be utilized to generate content on demand by utilizing the externally exposed URLs in guiding the generated content. 

Acknowledgements

Many thanks to Bulent Cinarkaya and Aaron Fiske in providing the details of this feature, supporting example for this blog and reviews. 

  

Get the latest Salesforce Developer blog posts and podcast episodes via Slack or RSS.

Add to Slack Subscribe to RSS