Drupal SearchAPI and result grouping

In this blog post I will present how, in a recent e-Commerce project built on top of Drupal7 (the former version of the Drupal CMS), we make Drupal7, SearchAPI and Commerce play together to efficiently retrieve grouped results from Solr in SearchAPI, with no indexed data duplication.

We used the SearchAPI and the FacetAPI modules to build a search index for products, so far so good: available products and product-variations can be searched and filtered also by using a set of pre-defined facets. In a subsequent request, a new need arose from our project owner: provide a list of products where the results should include, in addition to the product details, a picture of one of the available product variations, while keep the ability to apply facets on products for the listing. Furthermore, the product variation picture displayed in the list must also match the filter applied by the user: this with the aim of not confusing users, and to provide a better user experience.

Continue reading about Drupal SearchAPI and result grouping

Tags: , ,

Drupal Cross-Squad Knowledge Sharing

We do lots of Drupal projects @ Liip, mainly in the Zürich and Fribourg offices. Since Liip is organized in individual and independent squads, we do not have lots of touchpoints or projects which we do cross-office wise. But all the squads doing Drupal have one thing in common: A big interest in Drupal and the strong will to do projects successfully.

If I talk about a “squads doing Drupal”, then don’t think of Developers only, but also of Project Owners, UXers, Business Developers, Designers, Analytics Specialists and so on. With such squads in Zürich and Fribourg, things are done differently. Different sitebuilding, different workflows, different opinions and finally also different projects. This is on the one hand very interesting but on the other hand… weird. Being in the same company, doing the same kind of work but not the same way while not using the same toolbox and processes.

Continue reading about Drupal Cross-Squad Knowledge Sharing

Tags: , ,

Lektor Static CMS, put the fun back into Content Management

So yet another static website generator, I hear you saying.

It’s true that there are a lot of static generators, but if you look a bit closer you’ll soon realise that Lektor is really a different beast.
But how different? Before we discover its features, let me briefly step back and give you some context.

How it began

A few months ago, I was in the market for a static website generator for a private project.
Of course, I had already heard about Jekyll, Fabricator and a few others but I wanted to make an “informed buy” so I started to look around and eventually checked out StaticGen,
possibly the biggest listing of static generators.
Now, you know, word of mouth is much more powerful than billions of accurate researches so a colleague of mine, Jean-Christophe, recommended Lektor to me.
I started reading the documentation and after a few minutes I was sold.

Continue reading about Lektor Static CMS, put the fun back into Content Management

Tags: ,

An opensource Drupal theme for the Swiss Confederation

After having contributed to the official styleguide of the Swiss Federal Government and having implemented it on a couple of websites, we decided to go further and bring these styleguide into a theme for Drupal, a well-known, pluripotent and robust CMS we implement regularly at Liip.

Screenshot of Drupal theme for the Swiss Confederation

Continue reading about An opensource Drupal theme for the Swiss Confederation

Tags: , , ,

A quick look on the current state of Drupal 8 (ecosystem)

Eight months ago Drupal 8.0.0 was released. Exciting news for drupalists. Since then comparing D8’s features to its predecessor is a topic in daily business. «Can drupal 8 do what we can do now with 7 today?”. After playing around with D8 i get the feeling some crucial features are missing. Dries invited people to tell ”why we not use or migrate to drupal 8” – and got a clear answer: A majority of drupalist (60%) are waiting for certain modules. So the follow up question would be what are these modules.

Continue reading about A quick look on the current state of Drupal 8 (ecosystem)

Tags: , , ,

Load client side resources in a content centric application

We saw in a previous post, best-practices to optimize the client-side resources load, and by the way, reduce our web page’s loading time. Let’s keep in mind these concepts and solutions and assume that we develop a content-centric application in Java/JSP.

This application contains components that have many renditions for multi-channel usage. (As explained in our previous webmardi about content-centric application.)

Let’s take a component with a “in page” rendition, and a “standalone” rendition. So this component can be displayed integrated to a page, for example by sling or the JCR api, and as standalone HTML by a direct HTTP request. And in both cases, this component requires some client-side resources to be well displayed.

In the “standalone” usage of the component: We must refer the resources inside the component’s “standalone” rendition script:

Then in the “in-page” usage: We refer the resources in our “container” page rendition’s script.

We see in this inclusion that we must specify a “in-page” rendition that doesn’t include the resource again. And here is this “in-page” rendition:

Again we include our script in our container page rather than in the component, exactly to manage coherence of the resources inclusions.

This content centric application model, doesn’t solve the problem described in previous post: We still have to find the golden mean between too much or not enough granularity in the categories of the client-side resources.

But we see that renditions of a component are not dependent each other. Meaning, we can choose what resource to load in “standalone”, “in-page”, or any else renditions.

Note that if it’s not a problem to make “standalone” and “in-line” renditions dependent each other, you can put all the common code (the ul and foreach loop) in a common script, and include it with standard JSP methods.

AEM ClientLibs

The JCR/Sling based CMS “Adobe Experience Manager” comes with a great feature, designed to automate all these inclusions and to ensure a good coherence of your resources categories. This is the “clientlib” system.

First we create somewhere in the JCR, a node with the primary type “cq:ClientLibraryFolder”. This node will have a property “categories” where we’ll name one or many categories (for example “my-internal-lib”). In this node, we put our scripts (JS and CSS), that we want to be loaded, when we call (in a rendition jsp) the previously named category. That is the basic concept.

Added to this, “cq:ClientLibraryFolder” have these very useful properties:

Property Type Description
dependencies String[] List categories this one depends on
categories String[] List the categories that this folder constitute
embed String[] Embed the code of listed categories, in the categories this folder constitute.
channels String[] List the channels (related to devices or sites) for which the constituted categories are valid

Here’s a client-library-folder for our carousel component example:

  • carousel-clientlib – cq:ClientLibraryFolder
    dependencies: modernizr, internallib → any dependencies you need.
    categories: carousel → We call it “carousel”.

    • carousel.js → any external library you need)
    • carousel-init.js → any custom specific code you need).

In the rendition JSP, I call this category with a jsp tag:

  • The HTML will contain inclusions of all dependent scripts.
  • The call order is automatically calculated by the system, base on the dependencies chain.
  • A script will never be included more than once.
  • We don’t need two different renditions anymore. This one works fine for “standalone” and “in-page” usage of the component.

Use of clientlib system is not required by AEM, but at Liip in the AEM squad, we find the feature great. So we use it.

Unfortunately there’s a little performance problem with this. We know that JS should be loaded at the end of the body. To stay compliant to the content-centric model while providing these features, or for any reason I don’t know, AEM decided to print the inclusions right where the tag is used.

The easy solution we found at Liip to resolve this last problem is just to encapsulate the AEM tag in a custom tag:

In this encapsulation, we buffered the output generated by AEM’s clientlib system, until we print this output with:

A way to do big, clean, and scalable content-centric application, with very good client side performance.

AEM dedicated squad @Liip LS

In 2013, two of our big clients started considering Adobe Experience Manager (AEM) for their CMS needs. In the market of integrated mega-CMS we at Liip came under the impression that Open Source solutions were most of the time not considered by potential clients. To continue collaboration with these key clients, and to offer our high-quality services in this specific market, we have decided to invest in the creation of a dedicated project squad.

We were in contact with AEM before, working on a PHP connector for its data-storage layer (Jackrabbit JCR). Also this new line of service complements rather than replaces our existing service offer.

The partnership with Adobe started at the beginning of 2014. It let us explore the product deeper and assess the market opportunity behind it. By february 2015, the “AEM Startup Squad” was launched. This squad is composed of Fabrice, a senior Java developer with an already solid AEM background, four experienced “bizdev”-people and myself. This is our task force dedicated to reach our goals.

We are presently working on a few business opportunities to realize complete AEM projects or to develop interconnected applications to plug on existing AEM systems. For example Richemont group, which has to resolve many interconnection issues between the brands. Some client projects will therefore start soon.

At the same time, we continue building up our know how and get involved in the community by doing an internal project and by participating to learning sessions and meetups. It’s really a chance to have some time to grow up our skills without the constraints of client-projects. Thank to this, we are now confident to offer a very good expertise in AEM, with focus on following features:

  • The data storage layer and requests resolutions with JCR and Sling ;
  • Authoring concepts and processes ;
  • Components architecture and development ;
  • AEM Key features such as user management, client-context and workflows ;
  • Continuous Integration process & integration tests.

As new projects are coming very soon, we are still looking for developers to extend the squad and build many awesome project based on AEM at Liip. We are now well launched on our roadmap to have a cross-functional team focused on Adobe Marketing Cloud solutions at Liip.

Tags: , ,

Mezzanine CMS hackday


As we are a few Django lovers in Lausanne we (Sylvain, Noé and I) spent a hackday exploring Mezzanine, a very light CMS layer on top of this nice Python framework.

The goals of the day were:

  • list usual client requirements in terms of CMS
  • compare them to what Mezzanine offers out of the box
  • see how feasible is the rest
  • have some fun!

The dream

So we took our usual postits and came up with a list of CMS needs. We then voted and assigned a value to each of them to finally get the following: (1=most, 6=least important)

  • 1 editable static page
  • 1 media management
  • 1 menu management
  • 1 wysiwyg
  • 2 custom content type
  • 2 multilingual
  • 3 contact form
  • 3 easy linking from page to page
  • 3 register user
  • 3 roles/permissions
  • 4 create custom blocks
  • 4 photo gallery
  • 5 publication workflow
  • 5 user profile (custom fields)
  • 6 easy theme switch
  • 6 image resize
  • 6 inline edition
  • 6 seo
  • 6 url management

Of course this list is completely subjective but at least it gave us a pretty good start to evaluate Mezzanine.


The reality

We then had a look at Mezzanine doc and played a bit with the demo to see what it could offer out of the box. The documentation is quite good and the UI sufficiently intuitive that after a little while we could make a first estimation of what is possible from our list with very minimal coding. Here is the list updated:
(y = ok, n = not ok)

  • (y) editable static page
  • (y) media management (UI not fantastic)
  • (y) menu management (todo: check how to define other menus)
  • (y) wysiwyg (UI not fantastic)
  • (y) custom content type
  • (n) multilingual (obviously possible as it’s just django, but integration in the admin interface is not offered out of the box)
  • (y) contact form
  • (y) easy linking from page to page
  • (y) register user
  • (y) roles/permissions
  • (n) create custom blocks (explore mezzanine-blocks)
  • (y) photo gallery (UI not fantastic)
  • (y) publication workflow (basic, check how/if it can be extended)
  • (y) user profile (custom fields)
  • (?) easy theme switch (to be investigated)
  • (y) image resize
  • (y) inline edition (basic, not to be compared with createjs)
  • (y) seo
  • (y) url management

We were pretty happy with these initial results, even though having multiple languages is probably a must have for most of our clients.
At this point we had two choices, either investigate the multi-language issue or install and make a dummy project using Mezzanine which would verify our assumptions.
As we didn’t have any experience with this CMS we chose the second one.

MUL (Mezzanine Lausanne University or Mezzanine Unicorn Lovers)

The project would be called MUL and would at least fulfill the following requirements:

  • static pages
  • 1 language
  • 3 roles (teacher/student/admin)
  • custom content types:
  • activity (title, body, max nb of participants, teacher, sesssions)
  • session (date)
  • news (title, slideshow of images, body)
  • categories (activity kinds)
  • user profile
  • user registration
  • teacher can offer activities
  • student can subscribe to activities
  • teacher can see how many participants registered to their activities

Playing (aka let’s code!)

Creating custom content types in Mezzanine was really easy and we had activities and their related sessions in no time. The only thing is that we first wrongly assume we should extend the “Page” model before understanding that we didn’t want Activities to be mixed together (ie. hierarchically organized) with the others pages, so we finally extended the “Displayable” behaviour.
As Mezzanine “is just Django” creating relations between content types (activity/sessions) was a breeze and we could, on a single admin page, edit our activity and add multiple sessions.

As a developer point of view it’s a real pleasure to be able to define content types in code, as simple Django model, especially compared to let’s say Drupal content type (…) It makes it also way easier to collaborate on a project and share (git/db migration).
On top of that you get basic front-end editing: you just add a pre-defined template tag around your field and once logged in when browsing your site you see an “edit” button next to each rendered field! This is nowhere as powerful as what you can do with createjs for ex. but is a nice feature nevertheless.

As the included category possibilities were not enough for what we wanted (no hierarchy) we installed django-categories (remember “it’s just Django!”) and voila! we could organize our activities in a nice tree.

Mezzanine, through a fork of django-filebrowser, provides a simple but effective image management solution. By default all content types images / wysiwyg images are uploaded in a shared directory (different sub-folders) which makes it easy to re-use images.Thumbnail creation is handled through a template tag, with the usual “create if doesn’t exists, just use otherwise”.

With the very limited time we still got we added a Teacher profile (one to one relationship to Django User) and role, so that we could easily add some permission checks. Again fairly straightforward.

On the front-end side, Mezzanine uses Bootstrap by default, which gives a good starting point to layout content. The basic theme is easily extendable/overridable by simply creating new/extending existing templates. (For the Symfony2 lovers around, Twig was much inspired by Django templating system, so you’ll feel at home).

I personally had so much fun that i added student registration / subscription to activities on my spare time!

Mezzanine seems like a very nice way to tackle the CMS issue: provide devs a very thin layer containing necessary behaviours (ie. Sluggable, Displayable, Ownable..) as well as image management, and leaving you handle the rest through usual Django code. I only wish they would put some effort on i18n so that more is offered out of the box…
Thumbs up!

Tags: , ,

Some facts about Responsive Web Design

Responsive Web Design is, simply said, a web design approach aimed at crafting sites to provide an optimal viewing experience. RWD makes a website easy to read and navigate with a minimum of resizing, panning, and scrolling, across different browsers and platforms (desktop to tablets to phone) based on fluid grids, flexible images and media queries.

But why should you care about Responsive Web Design?

Previously, sites were chiefly designed for desktops. But the mobile web has became more popular. According to statistics the mobile internet is expected to overtake desktop internet usage this year. This makes it necessary to design websites that are flexible and can be viewed from almost any device.

Continue reading about Some facts about Responsive Web Design

Tags: , , ,

So when is the Symfony CMF release?

In January, Lukas wrote a collection of things left to do. Later I wrote a tentative release schedule that turned out to be too optimistic. I just updated that document with new dates. Sorry about this.

There are two actually quite cool reasons for the delays. One is that we had two projects at Liip where we had to integrate the CMF into existing projects. It was fun, but we found quite a lot of issues and missing features in Doctrine PHPCR-ODM that we fixed resp. implemented. (The Symfony2 Form component is incredibly powerful, but requires the persistance layer to work very exactly and we did not want any more workarounds and hacks to a achieve functionality.) The other reason is that many other people started using the CMF too. Some found issues that need to be fixed, others even managed to contribute fixes themselves – but which took time to review and comment on. Also, a lot of new features have been built or are currently being built.

One feature I am particularly happy with is that PHPCR-ODM can now cascade persist referrers. This is quite useful for example to embed route and menu editing into the edit form for static content, as shown in the screenshot. (This is already in the ContentBundle and should come into the sandbox with the next update.)

Getting to a release

As soon the above 2 client projects have stabilized, Lukas and I plan to focus on cleaning the base layers PHPCR and Jackalope to a point where we can tag release candidates, then bring Doctrine PHPCR-ODM to a state that can be called 1.0. We might have to postpone new features, but try to find all the interface changes and similar things to avoid BC breaks once 1.0 is stable.

Getting things out depends on contributions from the community too. While it is great to get new features, we now need to focus on cleaning up those we already have. On improving the documentation. On investigating bugs. The Release plan links the important missing pieces, if you want to dig into something.

There is the idea for a hackday in May or June. Please contact me or Lukas if you are interested. If we have enough interest, it is much more likely that we actually organize something.

I will present PHPCR at the Symfony Live conference in Paris beginning of April. I will also be at the hackday on Saturday if anybody is interested in meeting me there. Additionally, Thomas and me planned a (very focused) hackday on April 3rd to integrate SonataPagesBundle with PHPCR on the 3rd. If you are interested in helping with that integration, please contact me or Thomas.

Documentation hackday

This week, we also did a hackday at Liip, with focus on documentating some of those new features people built. I tried to collect what we achieved that day: