APIs and Extensibility
The customization of a CMS is accomplished on two levels. There’s templating, which is fully expected in almost every implementation and is handled by a combination of HTML and templating code. Then there are deeper customizations to change or add to the operation of the CMS itself. These customizations are normally done in the native language of the CMS (PHP, C#, Java, etc.).
Editors might assume that the extensibility of the CMS applies only to developers, but it actually has a significant impact on the entire team. When developers respond to an editor’s request by saying, “We can’t do that,” it’s often because the extensibility of the CMS has failed them in some way, and they simply have no way to accomplish what the editor wants to do.
Some systems have elegantly designed methods of accessing content and limitless ways of manipulating it, while others are clunky and frustrating and almost seem to be working against the developers, rather than with them. Some systems are designed from the ground up to be programming platforms that incorporate and cooperate with code developed by the integrator. Other systems are closed off from this to some degree, either intentionally due to architecture limitations (multitenant SaaS, for example), or because of the product design.
Ultimately, the extensibility of a CMS can be traced back to a core question: did the vendor expect anyone to extend it? I’ve worked with CMS vendors who were surprised to find out what we were trying to do with their systems. Some of them just never expected that a developer might try to work with the system in a particular way, either due to naïveté or due to the targeting of a different use case. Other systems are little more than raw APIs against which it’s expected the integrators will implement their own interfaces and functionality.
The Code API
The application programming interface (API) behind any software product is the set of programming tools that a developer is given to work with content from code.
For example, here’s some code from Episerver to retrieve the title of a page of content in C#:
var repo = ServiceLocator.Current.GetInstance<IContentRepositoryService>();
var myPage = repo.Get<TextPage>(new ContentReference(123));
var title = myPage.Property["PageTitle"].Value;
The concepts represented in this code – the existence of the repository as an injected service, the content object available as strongly typed TextPage
object, the identification of content by numeric ID, the properties of content represented by a keyed dictionary – represent the API available for this particular CMS. The underlying language is C#, but the API is the vocabulary and tools provided to C# to work with Episerver.
For comparison, here’s the same general code in Concrete5 (PHP):
$my_page = Page::getByID(123);
$title = $page->getAttribute('PageTitle');
In Magnolia (Java, using JCR):
Session session = MgnlContext.getJCRSession("myWorkspace");
Node myPage = session.getNodeByIdentifier(123);
String title = myPage.getProperty("pageTitle").getString();
And in Plone (Python):
from plone import api
my_page = api.content.get(UID=123)
title = my_page.page_title
The specifics are clearly different, but the general goal and result are the same. The API is the set of tools available to developers from code. (It’s worth noting that the preceding code samples are from APIs generally considered to be quite competent. Less capable APIs would have less elegant samples.)
Recently, I’ve been teaching my 14-year-old daughter how to drive
The same is true of an API. Consistency and predictability are key. An API should have a consistent interface that a developer can predict. This has actually been named the Principle of Least Astonishment
The dynamics of general software development is a topic far beyond the scope of this book, but the quality of the API of any piece of software is driven by how the software was built over time. Software is often built haphazardly, and the API evolves as needed – a product manager or sales rep says, in a panic, “We need feature X to sell the product!” and the development team hurriedly writes feature X, changing the API along the way in whatever way it has to.
A more reasonable development team plans and writes the API first, so it has the capacity to anticipate the needs of the product and sales teams, and new features fit into the larger logical model and philosophy of how the CMS models and manages its content. This software tends to be written proactively from the API outward, instead of reactively from the “feature of the day” inward. The API drives the features, not the other way around.
Evaluating APIs can be difficult. Occasionally, an API that appears to be competent has an idiosyncrasy buried deep inside it that a development team runs into at 3 a.m. while trying to get a change out the door and it stops them dead in their tracks.
To mitigate this, it’s helpful when a CMS adopts a known development framework and leverages its tools, conventions, and philosophies, as that gives developers some measure of familiarity with it from the start.
For example:
- Many .NET systems are based entirely on the ASP.NET MVC framework. These systems are MVC applications first and just happen to have a CMS behind them. Any .NET developer with some understanding of the styles and conventions of MVC will immediately be right at home.
- Many PHP systems are adopting the Symfony MVC framework to handle the basic tasks of routing and data management, making extension of those systems quite easy for existing Symfony developers.
When trying to determine the competence of the underlying API, the only reasonable method is a code-level walkthrough for your developers by a vendor’s technical team. You should require answers to at least the following questions:
- How do you retrieve content from code? Once you have content in code, how can you manipulate it and save a new version?
- How granular can code-level retrieval be? How many different ways can you search for content? Can you get a list of content based on X different criteria and have it ordered by one of more of those criteria?
- How can you create new content from code?
- How can you implement new functionality, which may not even be content-related? How can custom code for your organization live alongside the CMS’s code?
- What code-level events, hooks, or triggers are available? When content is published, for instance, can your code detect that event and inject new logic into the process?
- What ability exists to run command-line or scheduled jobs from inside the CMS interface?
- How can the administrative interface be customized to allow for the management of custom functionality?
- Is the API only accessible from code local to the CMS installation, or are there web services or other remote APIs available?
APIs are notoriously idiosyncratic. Once again, there is no Grand Unified Theory of Content Management, so there is no Grand Unified API either
Additionally, the quality of an API often has no relation to the quality of the product from a user or editor standpoint. Some very slick-looking systems have atrociously difficult APIs behind them that continually frustrate developers, while other systems that appear simplistic have incredible power and elegance from code. (Which, ironically, might be why they look simplistic out of the box – they’re simply so easy to customize that most customers do so considerably.)
Again, the only way to ensure and validate the competence of a CMS API is for your developers to actually work with it.
Event Models
One of the problems with any packaged software is inserting logic into it, so that custom code will execute amongst the system’s core code. One solution would be to dig into the source code, and just paste new code in places where you want it to execute. Clearly, however, this opens up numerous problems of maintainability and stability, not to mention that source code is simply not provided with many commercial systems.
A more manageable way to achieve this result is by using what’s known as an event model. Event-based programming is not at all specific to CMSs; it’s a common programming architecture.
When code executes, it can raise events. An event is a declaration that something has happened inside the executing software. External code can “subscribe” to these events, in effect saying, “When thing X happens, execute this block of code.” This code is generically known as an event handler.
Event handlers do not need to know exactly where the events occur in the CMS code. Developers simply need to know what events are available, and what information those events provide when they are raised. Any code inside the CMS could raise the event, and so long as an event handler is subscribed, it will execute. More than one event handler might be subscribed to an event, and they will normally execute in the order they were subscribed.
Events usually provide information to a handler about what has occurred. This information might simply be a notification, so that code can be written to take action when something occurs. Other events might provide information that the event handler can change. In these cases, the event is giving the subscribing code the opportunity to change how the system functions by hooking into code and changing values as necessary. In effect, the code is saying, “I’m about to perform task X. Before I do this, would you like to give me any advice?”
Most systems will provide some event model to which your custom code can subscribe. There is no standard list of events that a CMS should raise, but most events will be based around the changing state of content during its lifecycle. From inception to final deletion, a content object might raise dozens of events.
Some examples (referenced events are invented, but common):
A website is heavily cached by a content delivery network (CDN) to provide faster content delivery times around the world. Whenever new content is published, the CDN needs to be notified of the URL of the affected content so that its cache can be cleared and it can retrieve the updated content. For example, an event handler could subscribe to the “After Content Published” event and make a call to the CDN’s API with the URL of the published content.
The editor-in-chief is getting frustrated with editors using acronyms instead of full names. A event handler could subscribe to the “Before Content Saved” event and be provided with content that was about to be saved to the repository. The event handler could scan the text for acronyms and replace them (for example, changing the text string “FBI” to “Federal Bureau of Investigation”). The corrected text would be saved to the repository instead.
Pricing for events is not announced until 30 days prior to the event. Rather than build and enforce this logic in dozens of places in the templates (and trust template developers to always use it), a developer instead subscribes to the “Attribute Displaying” event. When the requested attribute is Price, and the Start Date is more than 30 days away, an attribute value of “Not Available” is returned.
It’s common for two events to “bookend” code. A “before” event will be raised before the code, often providing information to handlers that can be changed to affect how the ensuing code will run. The code will execute, then an “after” event will be raised. The same information will usually be provided to the after event, but modifying it will have no effect
If events seem suspiciously like workflow, that’s not entirely wrong. The differences are subtle:
- Editors do not directly invoke events, like they might with a workflow. An event occurs indirectly, usually as a result of some action taken on content.
- Events execute at a single moment in time. They normally do not create a persistent process that outlives the event itself.
- Events usually force the calling code to wait for them to complete execution. Calling code executes subscribed events in order, waiting for each to complete, before it is allowed to continue.
- Events have no user interface, as they neither expect nor allow user input.
Some things accomplished with workflow might instead be implemented in event handlers, and vice versa.
In some systems, events are called “hooks” (to represent the idea of “hooking into” things that happen in the CMS code); in other systems they’re called “triggers” or “actions.”
As a way of illustration, here’s an example of subscribing to an event in Episerver (in C#) to execute a method called NotifyCDN
after content is published (the first of our earlier examples):
DataFactory.Instance.ContentPublished += NotifyCDN;
(Note that this is standard C# event-based programming syntax, not anything specific to Episerver.) In this instance, the event handler (the method NotifyCDN
) would be provided with a reference to the content that was just published, so that it could find its URL and send an invalidation request to the CDN.
Sitecore uses XML configuration files to specify event handlers:
<event name="item:published">
<handler type="EventHandlers, MySiteAssembly" method="NotifyCDN"/>
</event>
WordPress allows developers to specify events by adding “actions” (in PHP):
add_action ( 'publish_post', 'notify_CDN' );
Event-based programming is not at all specific to CMSs, but rather is an important way for developers to extend the functionality of any system. An event model allows a clear, maintainable way for custom code to be injected into an otherwise closed system.
Plug-in Architectures
Closely related to the API that a system offers is the ability for customizations to be packaged and distributed, either commercially or via open source solutions. Some systems have vast extensions to their core functionality available though bundles of code variously called plug-ins, add-ons, extensions, components, or modules (we’ll use “plug-in”).
A “plug-in architecture,” therefore, is a set of established API concepts, events, and attachment points that lets a developer create some functionality for a CMS, and then bundle it in some form that can then be installed on another installation of that CMS.
Open source CMSs usually have well-developed plug-in architectures, due to the nature of their development. Open source software is driven by a community of developers, and the plug-in architectures are often created to ensure the integration of new functionality in a uniform way when a large, distributed group of people are contributing. Additionally, the increased user communities of open source systems result in many different people trying many different things. The sheer volume of implementations tends to result in more code spinning off into available plug-ins.
Commercial software, in contrast, has an official organization behind it, and the assumption is that this organization will be providing functionality. Additionally, license fees will naturally reduce the user base compared to open source alternatives, so there will be fewer implementations. Those implementations will be performed by organizations that, on average, tend to be less embracing of open source as a philosophy and more protective of their code.
The number and quality of plug-ins available is usually directly related to the adoption of a particular platform. Systems like WordPress and Drupal have thousands of available plug-ins to fulfill almost any requirement. Indeed, for many systems, the most valuable skill a developer can possess is a deep knowledge of what functionality is available through the respective plug-in libraries. A large part of any implementation with these systems is the selection, configuration, and adaption of the most appropriate plug-ins to accomplish the stated requirements.
The downside of plug-ins is issues with security, maintainability, and consistency. When a plug-in is injected into an installation, a third party essentially has access to the environment. The integrator is assuming that this plug-in is reliable, well tested, and doesn’t create security holes (inadvertently, or by sinister intent).
Additionally, the implementation is now bound to the plug-in. Once an implementation depends on a plug-in, then it becomes beholden to that plug-in in addition to the core CMS code. If an upgrade for the CMS is available, but a critical plug-in doesn’t work with the new version, the upgrade has to wait until the plug-in is updated, replaced, or modified directly (which then divorces it from the original source code, likely rendering it nonupdateable in the future).
Finally, the editorial experience on a site supported by many plug-ins might be inconsistent. You essentially now have a CMS developed by many people who didn’t necessarily communicate or plan their functionality to work well together. Most communities have standards and conventions that hopefully are followed by plug-in developers, but you might find plug-ins that deviate considerably from the UX standards and even the core architecture of the system.
I’ve seen plug-ins that were essentially small applications of their own, just dropped onto the larger CMS without any attempt to integrate with the underlying user experience or design. Working with these plug-ins was almost like working in a completely different software package, somehow embedded inside my CMS. Training and adoption might suffer in these situations.
Some CMS vendors have a process of “certifying” plug-ins, whereby they will inspect a plug-in for security, performance, and compliance with best practices and give it a stamp of approval. This is usually done for a fee, which generally limits it to plug-ins that are sold commercially.
Note that certifying a plug-in doesn’t necessarily mean supporting it. If something goes wrong with an implementation, the vendor will want to know what plug-ins are installed and will likely be quick to point the finger at one or more plug-ins and simply refer the customer to the plug-in developers for support. And since many plug-ins are open source, there is usually no formal support to speak of.
As with anything, there are advantages and disadvantages, and not all plug-ins are created equal. Some are well known, used by thousands of implementations, and considered almost standard tools necessary when using a particular CMS. Others are just one-off code that a developer somewhere decided someone else might find useful. Make sure you know where your desired plug-in falls on that range.
Customizing the Editorial Interface
It’s often helpful to customize the editorial interface to add implementation-specific functionality. Editors might need additional links, buttons, and reporting information directly in the interface from which they edit content.
These customizations might be global to all editors. For example, seeing Google Analytics data alongside content is often helpful. In other cases, editors might be able to customize the interface just for themselves, by adding gadgets or widgets to provide information they find helpful that others might not.
In many cases, developers will seek to turn off functionality that’s not being used to avoid confusion and the need for support. Streamlining the editorial interface as much as possible is helpful, even more so when this can be done on a per-editor basis. As discussed earlier, different editors have different needs, and the ability to display a specific feature for just a few power editors reduces the chance of inadvertent error, and likely makes all editors less nervous about making a mistake.
Customizing Rich Text Editors
Rich text editors might also need configuration and customization. Most systems implement one of two common JavaScript-based, open source rich text editors: TinyMCE or CKEditor. A smaller number of others use commercial editors such as EditLive! by Ephox or RadEditor by Telerik, and an even smaller number implement their own custom rich text editors.
Here are some common customizations:
- Enabling or disabling of buttons on the interface
- Customization of styling information, such as the list of classes or block elements that can be applied
- Configuration of HTML validation or “cleaning” processes, which enforce allowable HTML tags and remove invalid markup
- Enabling or disabling of access to the HTML source
- Customization of various pop-up interfaces, such as the image or table insertion interface
- Adding custom plug-ins, including buttons that execute arbitrary client-side code (a JavaScript function, for example)
- Styling the contents of the rich text editor to match the final site output
Both TinyMCE and CKEditor have well-documented plug-in and extensibility architectures. A CMS using one of these editors should provide some way to load the required files and inject the JavaScript code necessary to load the plug-in on startup.
Repository Abstraction
It’s assumed that most of the content in a CMS installation will be stored in the CMS repository itself. However, this doesn’t have to be the case.
Some systems will allow for the abstraction of parts of the repository. The code to actually gather the data for content objects is swappable and can be delegated to other code and other sources. Custom code can allow some data to come from other storage sources, and be presented and manipulated just like content that actually lives in the repository. This might happen for only specific content objects or locations in the geography.
For example:
An organization maintains its news releases in Microsoft SharePoint. The support team also wants these releases displayed on the website. The CMS repository might be abstracted so that a section of the geography (the children of the News page, for example) will actually retrieve content in real time from SharePoint, presenting this information as if the news releases actually resided in the repository itself. Visitors (and perhaps even editors) might never be aware that this content isn’t actually stored in the repository.
Technical writers store product code samples as Markdown files in Git. The CMS repository might be abstracted to connect to Git in real time and list the files contained within it as child content objects of a Code Samples page.
Users of the Unix operating system might recognize this as the concept of “mounting a filesystem.” In Unix, a completely separate filesystem (System B, we’ll say) can be mapped to what appears to be a simple directory in System A. Users navigating through System A might enter a certain directory, and – unbeknownst to them – actually be browsing the filesystem on an entirely different machine.
Repository abstraction is essentially the same thing: a section of the repository might “mount” some other system to provide data. Data exchange between the CMS and the source system takes place silently in the background. Some systems can even write data back to the external source, so an editor might change an object in the CMS and not realize he’s actually changing data in a completely separate system, somewhere else entirely.
Clearly, this is an advanced feature, and there’s a judgment call to be made as to when this is more appropriate than simply importing the content to the repository and updating it when it changes. Depending on an external data source for real-time access raises issues of performance, network latency, security, and stability. However, in cases where external data might be accessed outside the CMS – by making a direct database query using SQL, for instance – abstracting the repository to present that data as content can increase consistency and simplify templating.
Pluggable Authentication
One of the drawbacks of bringing new software into an organization is having a new set of credentials to manage, and for users to remember. One of the easiest ways for users to feel that a system is an integrated part of their organization is to allow them to use the same credentials they use for other systems. Adding yet another set of credentials creates password fatigue, which usually results in sticky notes containing passwords attached to the sides of monitors.
Many CMSs will allow their systems to either be integrated with common methods of authentication, or be swapped entirely for a custom system. Integration with Microsoft’s Active Directory is common, as is more generic LDAP integration. Some systems have OAuth, OpenID, or Facebook Connect integration, allowing users to log in by authenticating against their Google or Facebook accounts.
In the event an organization is using a less well-known or even custom authentication system, code can sometimes be developed and provided to the CMS to handle authentication tasks. In these cases, it’s clearly incumbent on the implementing developers to provide well-tested code, as the CMS will be only as secure as this code allows. The CMS will communicate only with this custom code, and will assume it’s authenticating users in a secure and rigorous manner.
Note that pluggable authentication and shared credentials does not necessarily mean single sign-on. To achieve single sign-on, your editors sign into one system and are seamlessly authenticated across multiple other systems – your CMS included, hopefully. Even if you hook your CMS up to your Active Directory provider, the editors will still need to enter their credentials, but they’ll be the same credentials that they use everywhere else, which is helpful in itself.
Web Services
Many systems will provide a web service interface to allow remote interaction with the CMS over HTTP. Systems vary by (1) the specific web service protocol used, and (2) the depth of the interaction allowed.
SOAP (Simple Object Access Protocol) was the standard web service protocol for years, but that position has been usurped by REST (REpresentational State Transfer)
Some web services are read-only, but other systems strive to provide complete exposure to their APIs over a web services. Some systems go a step further and run their own user interfaces from their web service. Abstraction levels in many programming languages and frameworks have advanced to the point where a web service can be accessed via a common API, and even swapped out underneath that.
If a system’s web service API falls short, custom web services can be implemented fairly easily. In many cases, there’s little difference between a normally templated content object and a REST service request. Templating languages that generate HTML can usually generate XML or JSON just as easily, and creating custom web service endpoints for specific situations is quite common. Some implementations might even deliver XML or JSON versions of any content simply by appending a designated argument to the query string (e.g., ?format=json
).
RSS is also well suited as a simple API for the delivery of content, and benefits from some level of standardization. RSS feeds can be extended with custom, namespaced tags to deliver more than the traditional blog-based feed of content, and RSS is just as adept at delivering aggregations or single content items.
Scheduled or on-Demand Jobs
In many situations, CMS editors and administrators just need to execute arbitrary code, either on demand or scheduled and unattended. This code usually doesn’t need user input and has no visual interface component. It is typically intended to perform batch manipulation of content. Many systems will offer some framework for implementing this code, generally referred to as a “job.”
For example:
Many systems will have a job that checks hyperlinks on a scheduled basis. The job will retrieve all content, examine it for external URLs, then send a request to each of those URLs to ensure they’re still valid. URLs that are no longer reachable might be flagged for review, added to a report, or emailed to an administrator.
An editor-in-chief might want to impose strict editorial guidelines to ensure compliance with governance policies. A scheduled job might run every night, find all content changed since the last execution, and process it to ensure governance policies have been followed: images have
ALT
tags, usages of the company’s name are followed by a trademark symbol, periods are only followed by a single space, etc.The information security department might require that certain site content be written out to a flat file once per month and entered into a enterprise content management system for auditing by a regulatory agency.
A product name might change, and all website references must change as well. A job can be developed to review tens of thousands of content objects and change references from the old name. This job can be installed, executed, then removed once the results have been confirmed.
During content migration (see Content Migration), the entire migration script might be implemented as an on-demand job. The developer might execute the job, review the results, modify the script, then execute it again.
Yes, you can drive at 14 in South Dakota. This revelation is often greeted with abject horror by people in more restrictive parts of the country.
Additionally, usability expert Don Norman has referred to the “conceptual model” of something, which is the mental understanding of how a user expects it to work. Norman was speaking about consumer products, but the same thing is true of an API: the system should strive to work the way most developers expect it to work.
Though attempts have been made. Content Management Interoperability Services (CMIS) and the Content Repository API for Java (JCR) are both attempts to unify the API-level handling of content. They have met with varying degrees of success and have limited implementations in the marketplace, mostly in larger, enterprise systems.
In some systems, an “ing/ed” convention is used. Before events are “ing” and after events are “ed” (e.g., “Content Publishing” and “Content Published.”)
Many developers wouldn’t call REST a “protocol,” but would rather consider it a convention or philosophy.