
Custom style definitions were fighting the Canvas cache
What YamlDiscovery changes about defining Canvas styles, and why the old approach kept going stale.
The friction
An editor asked for a new spacing option in a Canvas toolbar’s Style panel. Nothing exotic, just an extra choice between the existing “tight” and “generous” presets. I added it to the plugin class, cleared caches, reloaded the page. The option showed up in the dropdown. I picked it. Nothing happened. The section kept the old spacing until I did a full cache rebuild, at which point it worked, then broke again the next time someone else edited a style definition without knowing they had to do the same thing.
That’s not a bug you can point a debugger at. Everything about the code was correct. The problem was where the definitions lived and how Drupal decided when it was allowed to stop trusting its own cache of them.
How style definitions actually resolved
Canvas Builder’s Style panel doesn’t invent CSS at edit time. Each option (a spacing
preset, a colour, a border treatment) is a style definition: a small plugin that maps
a human label in the toolbar to a set of CSS custom property values applied to the
section. Those plugins are discovered the way most Drupal plugins are discovered, through
a plugin manager that extends DefaultPluginManager and, critically, implements
CachedDiscoveryInterface.
The definitions themselves were hardcoded: a PHP array, one entry per style, returned from a method on the plugin’s discovery class. That’s a completely normal way to define a small, fixed set of plugins. The trouble was that “small and fixed” stopped being true the moment editors wanted to add their own presets without a deploy, and the discovery class had no way to know that anything on disk had changed, because nothing was reading from disk. The plugin cache wasn’t stale because Drupal’s caching was wrong. It was stale because the thing it was caching, a hardcoded array, genuinely never changed from its own point of view, even when I’d just changed it.
What YamlDiscovery changes
Drupal\Core\Discovery\YamlDiscovery is core’s mechanism for defining plugins in YAML
files instead of PHP arrays, the same pattern behind *.libraries.yml and a good chunk
of Drupal’s own plugin systems. Swapping the style definitions to it did two things at
once, and only one of them was the one I was after.
The first was the obvious win: a style preset became a YAML file a theme could ship, rather than a PHP class a module had to own. Themers could add spacing and colour options without touching PHP at all.
spacing_relaxed: label: 'Relaxed' properties: '--section-gap': '4rem' '--section-padding-block': '3rem'The second, less obvious win was cache correctness. YamlDiscovery reads the filesystem
and hands its results to a CacheBackendDecorator. This is the part that actually fixed
the bug: Drupal’s plugin cache invalidation is keyed to know when YAML-sourced
definitions need re-scanning, in a way a hand-rolled hardcoded array never participated
in. The style panel wasn’t failing to invalidate its cache. It had no mechanism to tell
the cache system anything had changed, because the cache system only knows to ask
discovery classes it recognises as sources of truth. Moving to YamlDiscovery didn’t fix
a caching bug so much as it made the plugin manager cacheable correctly for the first
time. The previous version had been working by accident, on the assumption that its data
never changed, which held right up until an editor asked for one more spacing option.
What it took in practice
The migration itself was small: write the YAML schema, swap the plugin manager’s discovery method, keep the plugin ID format identical so no section on an existing page lost its assigned style. The part that took longer was making sure every existing hardcoded definition round-tripped through YAML with the same computed CSS custom properties, because a silent mismatch there would have been the same class of bug all over again, just moved one layer down.
What is still not fully settled
The open question is where per-editor overrides should live once presets come from
themes. If a theme ships spacing_relaxed and an editor nudges it slightly for one
section, is that a new definition, an inline override on the block, or a themeable
variant scoped to that page? Each answer has a different caching story, and I’d rather get
it right once than migrate a second time. If you’ve built per-instance overrides on top of
YAML-sourced plugin definitions and found a shape that didn’t reintroduce staleness, I’d
like to see it.