Knowledge Base

Programmable Layouts:
Best Practice Tips

Last Modified:
19 Apr 2024
User Level:
Power User

Description

Programmable Layouts are an incredibly powerful feature; they give you access to a range of capabilities beyond what you can do in the TERMINALFOUR UI alone. So if you need to only publish content that meets a set of criteria you can use Programmable Layouts to do it. With JavaScript. However, great power brings great responsibility so to prevent problems like publish errors you should be aware of some best practice guidelines. Similarly, if you haven't used Programmable Layouts in a while then you should be aware of more up to date techniques because Programmable Layouts, like any product feature, can be updated with a new product release. 

Programmable Layout imports

Avoid using importPackage () and instead only import the class that is required in the Programmable Layout. Conflicts or other issues can arise when there are two classes of the same name from different packages.

When reviewing Programmable Layouts check the following:

  • Are the imports actually being used in the code? If not, they should be removed
  • Are imports using old/unused code? If so, replace those imports with the new code
  • Are Managers being imported? The cache should be used in place of Managers. If Managers are required, the ApplicationContextProvider.getBean() should be used instead

If a class has to be imported, avoid using the fully qualified name when invoking a method from that class. Example:

new java.io.StringWriter ();
    //Should be
    newStringWriter ();

Conditionals for running Programmable Layouts

Most Programmable Layout code may not need to run at all in a specific Section, especially if you are using the "SectionMetaDescription" technique. Checks like conditional statements should be placed at the beginning of your code to run the Programmable Layout code only when it required. This increased performance and ensures that code is only run when it is required.

Below is a simple example of what we mean by conditionals for running the Programmable Layout. The code will only run when the content has an ID above 100. So this document.write is never run for those Content Items with IDs less than 100.

 try {
    if (content.getID > 100) {
        document.write ("Hello world");
    }
}
catch(error) {
    document.write (error);
}

ApplicationContextProvider usage

Be advised that the class ApplicationContextProvider will be removed in a future release. Since there is currently no alternative, it will remain for now.

It's intended that future versions may have ApplicationContextProvider loaded in, so it may be possible to use context.getBean ().This is awaiting implementation. 

The ApplicationContextProvider.getBean () method can be used to import other classes into your Programmable Layout as in this snippet:

var userMgr = ApplicationContextProvider.getBean (IUserManager);

Note that the IUserManager does not have .class after its name. and an error will be thrown if it is added. The code below will fail:

var userMgr = ApplicationContextProvider.getBean (IUserManager.class)

Use of Managers

If the Managers you intend to use have an interface, then they are likely to be new and should be used in preference over those that don't.  An example of this can be seen below:

  • ServerSideLinkManager does not implement an interface. This is the old manager and should not be used
  • ServerSideLinkManagerImpl does implement an interface called IServerSideLinkManager. Notice the "I" in front of the interface and then the "Impl" at the end of the class name of the manager. This is the new manager and should be used

Managers vs cache

Managers go to the database and, as a rule, should be avoided. Go to the cache instead. For example, the cahe should be used instead of TemplateManager, to prevent potential performance issues.

Other examples of known old managers:

Old v7 Manager New v8 Manager Interface New Manager Implementation

ContentManager

IContentManager ContentManagerImpl

HierarchyManager

IHierarchyManager HierarchyManagerImpl

MediaManager

IMediaManager MediaManagerImpl
ServerSideLinkManager IServerSideLinkManager ServerSideLinkManagerImpl
TemplateManager IContentTypeManager ContentTypeManagerImpl
UserManager IUserManager UserManagerImpl

Available variables

Below is a list of variables that are autowired and are available in a Programmable Layout by default. Do not overwrite the variables above. Doing so will cause publishing errors and may yield other unanticipated results.

Name of variable Object type Description Example
document T4StreamWriter Used to write out strings to the page document.write ('Hello');
dbStatement Statement Database statement used to accessed DB  
isPreview Boolean Is the current mode preview? true or false
content Content The current Content Item being processed content.getID();
section CachedSection The current Section being processed Section.getParentID();
language String The language of the currently publishing/previewing content English content: 'en'
publishCache PublishCache The publish cache, which is generated at the beginning of the publish publishCache.getTemplateFormatting(dbStatement, 1, 'text/html');
contentList CachedContent array Returns a cached content array of the current context  
template Template object The current content's Content Type template.getID ();
templateFormat TemplateFormat object The current content's Content Layout templateFormat.getFormatting ();
oCache Cache The system cache oCache.get(234); //Get CachedSection ID: 234

Managing database connections

Managing DB Connections - dbStatement vs ConnectionManager.getManager().getConnection()

Newer Managers do not require the passing of connections or statements

It is very important that proper care, such as closing database connections, is given to cleaning up code after execution.

Cached content APPROVED versus CURRENT

CachedContent.CURRENT should be used on Preview but never on publish. Instead CachedContent.APPROVED should be used on Publish.

Catching and dealing with errors

It is important to catch and handle errors in your Programmable Layout code. Since the API may not always do this for you, you should add try...catch blocks around programmable code is to catch exceptions and errors with the code.

Some tips

It is advised to always surround all Programmable Layout code with try...catch statements.

Try...catch blocks should output the information of the content/Section/Content Type/Page Layouts IDs so it is easily identifiable if an error occurs. See below for examples.

try{
    document.write("Hello");
}
catch(err){
    document.write(err + "err in content ID: " + content.getID() + ". Section ID: " + Section.getID());
}

This will output errors to the Tomcat logs:

try{
    document.write("Hello");
}
catch(err){
    Print(err + "err + "err in content ID: " + content.getID() + ". Section ID: " + Section.getID());
}

Other general information on Programmable Layouts

  • You should NOT overwrite the reserved variables  – content, oCache, Section etc.
  • Do not import Packages as this is not best practice