Plone

published Nov 03, 2021

This is here to serve as contents for the atom/rss feed for Plone, also read by planet.plone.org.

Lightning talks Friday

published Oct 06, 2023

Lightning talks on Friday at Plone conference 2023, Eibar, Basque Country.

Jakob Kahl: Beethoven Sprint

We will again host the Beethoven Sprint in Bonn, 13-17 May 2024.

Lukas: PloneGov-BR

Plone portal from Brasil. https://github.com/plonegovbr

1.2 billion page view per year, 28 sites, 800k+ content items.

Plone conference Brasilia 18-24th November 2024.

Victor Fernandez de Alba: Volto PLIPs

PLone Improvement Proposals for Volto. See on GitHub.

Mikel Larreategi: Version inspection

What to do when Maurits tells you to update five packages with security fixes? We made a product for this. DigitalOcean API to get all the project lists, scp to get the instance files (bin.instance, yarn.lock), and search.

CodeSyntax: #PrettyEibar awards ceremony

The winner is Kim Nguyen with a picture of a blue house.

Michael McFadden: Have you heard about Tau?

The Tau manifesto. Tau is 2 times pie. Pie is only half the story. 1 tau is 1 turn. Much easier to teach to children. See https://tauday.com/tau-manifesto.

Kim Nguyen: Do you want customers?

Do you want glory? Do you want to help Plone? Help Plone help you. Get your Plone provider listing today!

Go to https://plone.org/providers and register.

Dylan Jay: Python meetups

In 2014 I moved from Australia to Bangkok. I started a meetup for Python. We are at meetup 94 now. There is a PyCon in Thailand December 13-15 this year.

Do you live in a town that does not have Python meetups? Create one! Build it and they will come. You need a venue. Anyone who is interested in developers, can help you. How do you get people to talk: twist their arm, get them drunk. Have two short talks rather than one big one.

The Python foundation now pays for meetups. You can use meetup.com, but you do not have to. You need a code of conduct. I needed a page, I used pyscript, Python in the browser.

Philip Bauer: Erico, I want a beer

Erico promised me a beer if I did something useful for him. Open an Plone site, do exportimport, you can now export it to one file per item.

Mikel Larreategi: Some random things

I had ideas for talks, but did not do it, so quickly they are here. 

pas.plugins.oidc. Created by Mauro Amico. OpenID Connect is a layer of identification. You can install the PAS plugin in Plone and talk to such a server [works in a test setup for me as well, Maurits]. Works with various identity providers, like Google Workspace, Keycloak, EU Login. Click a link, redirect to the provider and identify there, callback, internal connection to provider, user is created in Plone and group management granted. We use it in production in two scenarios. See https://github.com/collective/pas.plugins.oidc.

Lichess: Open source chess server. Free, free, free, no ads, no tracking. 93M games played last month. I wanted to translate it into Basque. They use CrowdIn. Can we use something similar for Plone? Weblate maybe? We use this at CodeSyntax. Perhaps I will work on this the coming months for the core Plone translations.

This Plone conference started at Beethovensprint 2022. Last of of the sprint, after last dinner, with last beer in our hands, a few guys were there and approached us: "You are going to organise the conference, right?"

Thank you everyone!

Plone Foundation annual meeting

published Oct 06, 2023

Open annual meeting of the Plone Foundation membership at Plone conference 2023, Eibar, Basque Country.

This year the Foundation membership voted in favour of a change to the bylaws, making it more inclusive, and moving to two cohorts for the Plone Foundation board, each cohort serving for two years.

New Foundation members this year: Mauro, Tanya, Jan, Karel, André, Brian, Joao, Martin. We have 100 active members from 21 countries. It you are an emeritus member and want to reactivate, contact the board.

There is a new contributor agreement process, more digital now, not fully automated yet, but easier to handle. There were 43 real new contributors, not including some hopeful GSoc students that never did anything. There were 5 real active GSoc students, thank you for your work, and thank you Google for sponsoring this. Others see that we are handling this well as organisation. And we try to bring the students here to the conference to present their work. Unfortunately there are strict rules in the EU making it hard to get visa for everyone.

Election for the next Plone Foundation Board of Directors. The result of the vote is in. For a one year term: Brian Davis, Kim Paulissen, Martin Peeters, Paul Roeland. For a two year term: Eric Brehault, Guido Stevens, Mikel Larreategi. Congratulations. Thank you outgoing directors: William, Jens, T. Kim and Erico.

Meeting adjourned.

David Ichim: What's new in Plone 6 frontend for developers

published Nov 08, 2021

Talk by David Ichim at the online Plone Conference 2021.

Distilled from the latest work done in Volto, we're showcasing some patterns, features, or enhancements that have landed in Volto from the last year to the present. We will also have a glimpse of what is ahead in the future of Volto with the new features roadmap.

In the past year we had four major releases, 40 minor releases, 36 alpha releases, 25 patch releases, for a total of 105 releases. Plus some new tooling and tool releases, like plone i18n and plone generator.

New Volto config, dubbed as Volto's Configuration Registry, introduced to fix circular import dependency problems. Hot Module Reloader was fixed. Read the upgrade guide.

New i18n (internationalisation) infrastructure. This is now a separate package. Same is used for generation of i18n in add-ons.Read the upgrade guide.

Forms as schema. Forms should be constructed from schemas instead of by hand. InlineForm allows us to create forms for blocks from a schema. Blocks can have variations, or we can extend it. Read the edit component documentation.

New widgets:

  • Object List Widget. Similar to the original DataGridField. Used in core by the Search Block facets.
  • Object Browser Widget is now a separate widget, instead of part of a block, and now allows the addition of external content.
  • Querystring Widget. Behaves like its counterpart from plone.app.querystring. Allows to create search criteria, used by the search block.
  • URL Widget. Used on text inputs, it knows to validate their value as a url, both internal and external.
  • Vocabulary Terms Widget for a JSONField, acts as a source for a SimpleVocabulary or Choice field. Play with it in the storybook.

New core blocks:

  • Search block
  • Teaser block (ongoing work).

Pluggable framework, similar to React's Portal component. See the talk by Tiberiu and see the Pluggables development recipe.

Storybook provides a sandbox to build and test visual components in isolation. Currently it is only setup to be used by Volto core. We need help with work to have storybook setup with adding. See the Storybook talk held by Victor, and see the storybook itself.

Critical CSS: inline the critical CSS for improved performance. Run critical-cli to output critical.css. This is then inlined in the headers, while regular CSS is moved to the bottom of the body. See the deployment documentation.

Lazy Loading utilities. Introduced injectLazyLibs HOC wrapper to inject lazy-loaded libraries as properties to your components. These components are only loaded once all your main libs are loaded.

Express.js middleware. Volto uses this for SSR and static resources serving. You can now write custom middleware and add it to settings.expressMiddleware.

API expanders allow the expansion of different API endpoints from Volto with calls from your custom endpoints. Avoid adding too many expanders if they are not critical to the initial page.

External routes: useful when another application is published under the same top domain as Volto. If Volto would fetch the content for that path, it will break. You can disable this path in config.settings.externalRoutes. You can also use regular expressions.

Seamless mode, introduced in Volto 13, enhanced in Volto 14, which has already seen a lot of alpha releases. Originally, we tried to unify both frontend and backend servers under the same path, but this was tricky, causing various problems. We settled on a new ++api++ traversal for getting information from the backend. Also, to come closer to zero config, you can now pass environment variables at runtime instead of build time. This means you can generate one build, and use this in all environments (testing, production). Read the deployment documentation.

Context navigation component. This is a navigation portlet component, similar to Classic Plone. The view is there, but you need to enable it. See the development recipe.

There is some work in progress:

  • Slots are Volto's answer to portlets, see the Volto Slots talk by Tiberiu Ichim for more details.
  • Image proxy: image scale generation done by a middleware instead of plone.scale.
  • Authentication from backend.
  • Replace Draft.js editor with Volto Slate. What is missing is a migration tool from one to the other. But work has started on a block conversion tool.
  • Async blocks that work with SSR.
  • Defaults in blocks form.

Future work:

  • Defaults in all widgets
  • Enable blocks enhancers in all blocks
  • Storybook in add-ons
  • Use newest react-intl package
  • Refactor the folder contents component
  • Form editing text enhancements, making it easier to modify text inputs.
  • A "group block" included with Volto
  • Quanta toolbar

I did nothing, I just brag about what others have done. So thank you Volto early adopter community!

Tiberiu Ichim: Volto Pluggables

published Nov 08, 2021

Talk by Tiberiu Ichim at the online Plone Conference 2021.

This presentation is an introduction to the new Volto developer-targeted feature, the Pluggables framework. It is more an argument for extensibility in CMS UI and in Volto.

Basically, with Pluggable a central component provides a pluggable slot that other components can fill, like this:

<div className="toolbar">
<Pluggable name="toolbar-main" />
</div>
// ...
<Plug id="quicklinks" pluggable="toobar-main">
<Button />
</Plug>

This is a Volto port of https://github.com/robik/react-view-slot.

The big picture:

  • I work with Eaudeweb Romania
  • Our client EEA is an early adopter of Volto
  • The strategy is: move everything to Volto
  • But the EEA sites are less brochure, the CMS side is really strong.
  • We build powerful UIs for power users.
  • The EEA already has 91 Volto repositories on GitHub. How can we scale that? Can we write an add-on to make it easier to write an add-on?

In React, data flow is top to bottom. A parent component passes properties to children and children communicate with the parent by emitting events. This makes sense and works well. For "out of tree" data you need Redux. There is no protocol for add-hoc communication between components.

UI state is fluid. Extensibility means reusability and scalability. This is hard. You need to design upfront. Plone backend uses the Zope Component Architecture, which means pluggability is baked in, it is very natural. You can view Pluggables as viewlets-on-demand, but they are really not. But yes, you can think about a Pluggable as a viewletmanager and a Plug as a viewlet.

You can overwrite a Plug with a Plug, by registering it with the same id. So if the original Plug gives you color blue, you can overwrite it with color red.
You can do custom rendering of Plugs within your Pluggable, by iterating over all Plugs and for example wrapping each in a div with a class name.

Showcase: volto-workflow-progress (main toolbar plugin) and volto-editing-progress ("sidebar" for plugin).

Limitations:

  • No Server Side Rendering
  • Watch out for dependency lists.
  • Limited adoption for now.

Implementation in pseudocode:

First the context:

<PluggablesProvider>
<Pluggable name="top" />
<Plug name="delete" />
</PluggablesProvider>

Then the dumb version of the Plug:

const Plug = ({id, children}) => {
const { register } = useContext(PluggablesProvider.Context);

React.useEffect(() => {
register(id, () => children);
});

return null;
}

Takes a bit of study, but in the end it is not so hard.
The Pluggable becomes a bit simpler:

const Pluggable = (name) => {
const { getPlugs } => useContext(PluggablesProvider.Context);
return getPlugs(name).map(f => f());
}

Site updated from Plone 2.5 to Plone 6.0

published Nov 04, 2021

It only took ten years of making plans.

I am one of the Plone Release Managers, and have been working on Plone 6, which is now in alpha stage. But my personal website was still using the ancient Plone 2.5:

Screenshot of my website end of October 2021: still Plone 2.5

Often I have made plans to update my site to:

  • Plone 3
  • Grok
  • Plone 4
  • Plone 5
  • Plone 5.2
  • finally Plone 6

Long ago it was clear to me that an inline migration would not be practical. It would take too many steps: update the code to Plone 3.3, migrate the data, to Plone 4.3, migrate data, to Plone 5.2 Python 2.7, migrate data, Plone 5.2 Python 3, migrate data, Plone 6, migrate data.

Additionally, the question was how to handle the weblog, which is the main content. This was using Products.Quills, a Plone add-on for blogs. Updating to Plone 3 could have worked at the time, but this was made harder by some some custom code I added. This enabled me to use it as a podcast. I used this to enrich some of my summaries of sermons from my church with the actual audio of the sermon. I doubted whether to even include this content in Plone 6, as the last sermon was from 2008. I hate breaking links, so I kept it, although a bit hidden.

Another point that needed some extra attention, was that most, if not all, blog entries were not written in html, but in ReStructuredText. I make a lot of summaries of talks when there is a Plone Conference. The html editor on Plone 2.5 did not work anymore, or I disabled it to a simple textarea. I always open up the same text editor that I use for programming (previously Emacs, currently VSCode), and type the summary there. I much prefer writing ReStructuredText there, especially when I simply need text without any markup. I then paste it in Plone, without fear of losing all my work when my internet connection dies.

Lastly, I have an RSS/atom feed which is used by planet.plone.org and maybe others to stay updated when I add a new blog entry. I did not want this url to change.

Anyway, about six years ago I decided that I would use collective.jsonify to export my site, and then import it using transmogrifier. But time passed without any progress. This year, collective.exportimport was shaping up to be the preferred way to import the data. For export you can use it in Plone 4.3 as well, but definitely not in Plone 2.5.

At the beginning of this week I looked at jsonify. Didn't I have a local copy of my website on my laptop, with collective.jsonify installed? No! And it was not installed on the live site either. And installation would be hard, because the site uses Python 2.4, and currently you cannot even reach PyPI with older versions of Python 2.7.

Mildly panicked, I started on a custom script to export the content, still as json. Some details aside, this actually was not so hard. I looked at what collective.exportimport expected, and created the Python list of dictionaries accordingly. Then do a simple json.dumps() call and you are done. Except that this gave an ImportError: the json module is not available in Python 2.4. Okay, install simplejson package. But you need PyPI access for that, which does not work. Workaround:

  • Manually download an egg of Python 2.4-compatible simplejson 1.7 and save it in the buildout directory.
  • cp bin/instance bin/instance-json
  • Edit the new script and add the simplejson egg to the system path.
  • bin/instance-json run export_mvrsite25.py

After that, it was not too hard anymore. I used plonecli to create a new add-on with Plone 6.0.0a1. I actually do not yet use the add-on code, except for loading a minor patch that I added, but this gave a reasonable, modern Plone 6 buildout. Create a Classic Plone site, tweak a few settings (let Folder use folder_workflow, allow English and Dutch, navigation depth 1, enable syndication, configure caching and mail), import the content with collective.exportimport, edit a bit, and done.

The weblog now consists of standard Folders and Pages. To improve the view, I added a Collection, showing the latest pages first, and showing all content of the last seven blogs. I enabled syndication here, so it has an RSS/atom feed.

The weblog has always advertised two atom feeds:

  1. One for all weblog entries, at https://maurits.vanrees.org/weblog/atom.xml
  2. One for weblog entries with keyword 'plone' at https://maurits.vanrees.org/weblog/topics/plone/@@atom.xml

In the new site, the first one kind-of worked out of the box, but it only showed the items that were directly in the weblog folder, and this is not where my weblog entries are. I solved this with a patch to Products.CMFPlone.browser.syndication.views.FeedView: when atom.xml is viewed on a folder, check if it has a default page, and show the atom.xml of this default page instead. In this case, the default page is a Collection with the correct settings. So the general feed will keep working.

For the second one, my first idea was to create a folder 'topics' and within it a Collection with id 'plone'. Problem: 'plone' is a reserved word and cannot be used as id of a content item, so the id became 'plone-1'. Solution here: create the 'plone-1' collection directly in the weblog folder, and do a redirect in the frontend server (nginx):

 rewrite ^/weblog/topics/plone/@@atom.xml /weblog/plone-1/atom.xml last;

And that's it! My website is now on Plone 6.0.0a1:

Screenshot of Site overview in new site.

There are some more details that I could go into, like splitting up the buildout into multiple parts, with tox as main way to build everything, in preparation for moving more and more parts to pip-only. But that will have to be for another time.

Meanwhile: have a look around, and enjoy the fresh look!