Mathias Leimgruber: Plone 6 Classic UI - A Success Story
Talk by Mathias Leimgruber at Plone Conference 2025 in Jyväskylä, Finland.
I am a full stack dev, over 15 years of experience with Plone, attended several conferences around 2010, and I never thought I would own a company. Fun fact: I immigrated during Covid to the US, to join my lovely wife!
I founded webcould7 in April 2022, in Lucerne, Switzerland, together with Christoph Brütsch. We wanted to build and ship an actually standardized product. Release management: 4 times a year.
Problem: we are a new, small company, upgrades for some Plone 4 and 5 clients were urgent, I am not a designer, and how to deploy?
We chose Plone 6 Classic UI. We had pressure to go to market fast, and I had experience with the Classic UI. We could focus on the backend, and have content be created there. And then the rest api as interface to the world. This way we can have a slower release cycle on the backend, and the frontend can move faster. The frontend is 100% geared to the customer, and backend to the content creators. I begin with TTW content types, and some Python Scripts, to get a quick start.
Why not Volto? For e a steep learning curve: React, Next, new design patterns. Volto is good for wysiwyg, but that is not important for me at all. We wanted a different UI for editors and visitors.
We have our product: 7inOne. In the theme we only changed the color, so it is pretty standard Plone. If anything is changed in core, we get it quickly.
We made a Page Builder. Using grid from Bootstrap, and add blocks in there. Similar structure to Volto, really. I implemented a Trash option. Since we don't have wysiwyg, we have a preview split screen so you can see how it looks. Also mobile preview.
I have built a working copy / versioning variant. I could not use plone.app.iterate for various reasons. You can ask multiple co-editors for reviews.
PDF with weasyprint.
External API integration. You can load data from an external API. Stores results in a Dexterity field, or in Redis. Json only. You can tell it how often it should load data automatically.
We use collective.elasticsearch
. We added an endpoint @es-search
if you want to explicitly search there in the normal Plone way. Implemented @raw-search
endpoint where you basically send raw elastic search queries, except that we add allowedRoledAndUser=[]
as security measure.
We use pas.plugins.oidc
for SAML/oidc authentication. And wcs.samlauth
.
Then we want to improve performance:
- With Py-spy we can make flamegraphs to see what is happening.
- We made opinionated improvements to the REST API, some internal caching (navigation), automatically prevent recursive "expands", always disable diazo (so the transforms), auto apply a sort_limit to queries where possible.
- Cache as much as possible.
We use Redis and RQ Python for async and scheduled tasks.
It is all built on Kubernetes, and using CloudFlare.
The backend and API are on different sub domains. Backend is only for authenticated users.
For some clients we do the frontend ourselves, for others there is a third party. We give them the Plone REST API documentation, with some extra guidelines:
- Do not use
expand
for@navigation
and@contextnavigation
. - Dedicated frontend routes for search, dashboards, etc, with limited caching.
- Implement a small client to handle redirects and status like 404 and 500
baselland.ch was the first customer with which we went live with this system. In 1 year the frontend had no downtime. The backend 45 minutes, due to a Kubernetes upgrade and some CloudFlare issues. Total of 29 releases installed. From Plone 6.0 beta to 6.1.2.
For all clients the backend is always the same (7inOne). Just the configuration differs.
Some of the challenges:
- Performance of the Kubernetes cluster, it remains a bit of a mystery to me. Storage I/O speed, especially catalog access is slow after a restart.
- There is one developer for the backend: me. I'm always right... Only one opinion, no diversity.
- Testing: where to start and where to stop.
Lessons learned:
- The Plone REST API is great. Its documentation is awesome.
- Using Plone as a headless CMS works.
- Technical documentation are usually too late, but AI helps.
- Not everything needs to be automated, even though I love to do that, it is not always worth the time.
- Kubernetes: the ZODB needs fast storage, use physical servers (cheaper)
- Get help! I should have asked other people first in some cases.
- Caching, caching, caching. Try to cache everything and invalidate.