Introduction
Personalization has started to become a common requirement for most websites. The content of a webpage needs to be personalized based on multiple criteria such as location, user preferences, personal user information, different cookies, etc.
We will be covering the type of personalization in this document, where a single page caters to multiple audiences/user types. Some typical examples include pages based on user personal information/preferences where:
- Lists are sorted differently and sort criteria are evaluated from the personalization criteria
- Additional content blocks are shown
- Content blocks are replaced
- Links and menus visibility is controlled
Whenever we need to implement personalization on a Drupal site, there is a general tendency to choose a javascript based client-side solution. While there is nothing wrong with that, the only caveat I see most of the time is the unavailability of contributed modules/framework, which does most of the plumbing stuff and allows us to configure/implement only the business logic and achieve personalization in minimum effort.
Specific tools like Acquia Lift cater to enterprise-grade personalization, but there are a few Open Source options.
The rationale behind using client-side/javascript implementation to achieve personalization most of the time is to move the actual changing of the document to the client-side, thereby making pages cacheable.
How to Handle Personalization?
Handling personalization with server-side code and caching it effectively has often proved to be a painful experience. The most critical problem here is maintaining or storing multiple varied cached copies of the personalized page, choosing and serving the right cached content based on the varying condition. Most modern websites nowadays use an external caching system, or some even use a combination of them with CDN/ESI tools to get geographical performance advantages. Some of the common examples of external caching systems include Varnish, Akamai, Fastly, Cloudflare, etc., and this adds to our problem of personalizing pages on the server. And this is where JavaScript/client-side solutions often come to the rescue. It solves the caching issues either by:
- Loading all the content in one go and then show/hide personalized bits based on relevant conditions.
- Loading the common/non-personalized content with page load from server/cache and loading the personalized bits via AJAX calls.
We had a similar requirement in one of our current projects and to add complexity to the existing problem, we were using Site Studio in that project. Initially, it looked a lot more complex to implement personalization on a Site Studio based site, be it a client-side or server-side solution. At the time of writing, Acquia Lift was also not compatible with Site Studio.
Luckily, we found an impressive integration between the Site Studio and Context module, which Site Studio provides out of the box. Site Studio elements can be made conditionally visible based on contexts. A single context can be composed of multiple conditions that are highly configurable. Multiple contexts can be applied to a single Site Studio element to evaluate its visibility where either all of them or only one of them needs to be true. Drupal core provides some conditions out of the box like user role, language, etc. It also provides a plugin-based API that allows us to create custom conditions. This opened quite many opportunities for us to implement and think about personalizing pages driven via Site Studio elements, components, and templates.
Drupal condition plugin API allows us to define the cache context and tags for the conditions.
For every visibility context applied to a Site Studio element, the cache context from their composing/internal conditions contributes to the cache context of the host (layout canvas) field and effectively to the (host entity) node page subsequently via cache context bubbling. This solved our problem of maintaining varied cache copies of the same page based on varying conditions within Drupal which we got every time.
Now, the only problem we were left with was handling cache variations in our external caching system, Varnish. This was also quickly solved since Varnish allows us to store and retrieve varied cached responses with the help of a Vary header. Varnish VCL can be configured to identify/serve personalized page requests based on conditions that can come in the form of request headers, cookies, etc. Acquia cloud varnish VCL is preconfigured to listen and vary page caches based on certain named cookies and usage of vary header in the drupal response.
The same principle holds for almost all the major external caching systems, but an additional effort of identifying the right means to do that and configuring them is required.
Conditions created by drupal condition API can also be used to control the visibility of blocks. Any condition added via a custom module is exposed as a configuration in block visibility settings form and the block responds to these settings. This extends the idea of personalization from nodes to blocks, which covers the two most essential and foundational building blocks of a drupal page.
The integration between the context and Site Studio module and how it helped us personalize Site Studio pages demonstrates the power of the context module.
It gives us enough details to think about its use in other major contributed modules and also possibly think about an alternative way of solving personalization problems in general (outside of Site Studio), which works end-to-end. Do try this with your projects and let us know your experience!
For more on personalization, see how you can take advantage of Decision API and the “Relevancy sorting” option of Solr search to implement personalization search results in Drupal with Acquia Lift.
Leave us a comment