Problem/Motivation
DX of creating hook_theme implementations in a hook is not good.
Also, it is difficult for themers to find the contents of these functions. The plan has been that themers shouldn't have to read any PHP if possible.
Furthermore, themes could be declared in the same way as layouts in the layout api module, giving the ability to declare aditional themes (see block styles module as example) and aditional information for example as thumbs for a richer administration UI.
Proposed resolution
Move into configuring hook_theme implementations inside yml. That would be a self-documenting way to specify contents of hook_theme implementations. This would be especially powerful in combination with #2809683: Make it required to specify variables passed to templates.
Deprecate hook_theme from Drupal 8 and mark it to be removed from Drupal 9.
Remaining tasks
User interface changes
API changes
Data model changes
| Comment | File | Size | Author |
|---|---|---|---|
| #45 | interdiff_2809689_42_45.txt | 2.71 KB | YurkinPark |
| #45 | 2809689_45.patch | 35.03 KB | YurkinPark |
| #16 | 2809689-hook_theme_yaml-16-interdiff.txt | 6.88 KB | tim.plunkett |
| #16 | 2809689-hook_theme_yaml-16.patch | 31.21 KB | tim.plunkett |
| #12 | 2809689-hook_theme_yaml-12.patch | 31.99 KB | tim.plunkett |
Comments
Comment #2
joelpittet+1 for this issue. Currently the default values though can be anything in PHP and are mostly array or scalar values. Though we can put objects in there. Would it be possible to define say a default object in yml config? For example:
new Attribute(['class' => ['happy']])or will we have to explicitly exclude typed data?Comment #3
lauriiiThis does the conversion for modules. We still need to figure out what to do with themes and other extensions.
Comment #5
lauriiiComment #7
joelpittet=> looks like a typo
But the fails are about the interface not implementing a method it seems
Comment #8
dawehnerIs there a reason we don't leverage
\Drupal\Component\Discovery\YamlDiscoveryhere? It could simplify this a bit, I guess.An alternative could be also to use
'%container.modules%'which provides the path you need. Even if not, you could use$module->getPath()here.wait, is that valid syntax?
Comment #9
wim leers#8.1++
Comment #10
lauriiiWe should move to use YamlDiscovery after we stop supporting theme hooks. At this point, I don't think YamlDiscovery makes it any simpler. The #8.1 alternative sounds good for now.
Comment #11
sam152 commentedIs there a reason plugins aren't appropriate for replacing hook_theme?
Comment #12
tim.plunkettThis switches to using YamlDiscovery. Still using the moduleHandler since we need it for that now.
Also fixes the test fails.
Here's the thing: the changes to help are incorrect. Yes @joelpittet is right, that's invalid syntax.
Additionally, the YAML file is nested under a
components:section. Why? That's not handled by the patch at all. And what else would possibly go in there?Comment #13
tim.plunkettAlso, why is this only used for modules? Why not opt in everything: themes, base themes, theme engines.
Finally, are we sure we want to disable checking hook_theme() if a *.theme.yml file is present? If so, we need tests for that. If not, we need to fix it and also add tests.
Comment #14
tim.plunkettTo answer #11:
Elements (#type) are plugins. But that is because they have functionality associated with them, like #pre_render and #process and #value_callback methods. Additionally, they can be altered or swapped out.
Theme hooks (#theme) have none of that. Another module should be altering the #theme hook of another module (or theme!)
Comment #16
tim.plunkettTurns out there was sufficient test coverage for the help.module changes.
Implement DiscoverableInterface directly
Check for a components key.
Comment #17
sam152 commentedSorry for being difficult, just not understanding the reasoning. There are other types of plugins which are simple yaml definitions with a simple provided class backing it. Breakpoints come to mind. Plugin managers solve the discovery aspect for you and altering plugin definitions is optional. Are the semantics really that far apart? Do we need another concept to define "thing like a plugin but not", wherever the differences lie. Libraries come to mind as another plugin-like snowflake implementation. Could the plugin API be extended to match the desired behaviour?
Comment #18
tim.plunkettBreakpoints become objects that are directly interacted with.
Theme hooks are not, they are immediately consumed by the Registry class, and not exposed on runtime due to caching.
Permissions are also YAML files but not plugins, for a similar reason.
Comment #19
lauriii#13.1 We should extend this for all extension types. I didn't do this yet since I wanted to give myself some time to think what would be the best approach for refactoring
Registry::buildwithout breaking the BC.#13.2 The reason it is nested under components is that we might require some metadata from the modules in future. See #2809679: Add versions for render arrays
We might still have to call hook_theme always since hook_theme has few parameters and because of that, there could be some logic inside hook_theme functions. Not sure what would be a valid use case for these though and if that should be something that we need to consider while moving these to yml.
Comment #20
tim.plunkettOkay so here's another argument for using plugin-based discovery: derivatives.
I'm currently working on a patch that has a foreach loop in hook_theme. That would map perfectly to derivatives.
Comment #21
dawehnerMy initial reaction was, why would you ever need plugins here, but then there are some good arguments for plugins:
Comment #22
joelpittetMay be missing the point in the issue summary when suggesting plugins:
A YAML file seems a bit more approachable for the simple cases, the more elaborate cases may be useful as plugins but I don't think that is the intent behind this issue.
Can we/should we do both? Follow-up?
Comment #23
tim.plunkettWe can do YAML based discovery, without annotated classes. But with derivatives as an option for more complex needs.
Comment #24
tim.plunkettInitial rough conversion to plugin discovery.
Had to remove the "components" top level key. Also changed it to *.theme_implementations.yml for now, because I'm not sure we want to squat *.theme.yml
Comment #25
dawehnerGiven we don't need it most of the time, I'm wondering whether this should be a lazy service.
I would have expected to have this hook to be part of the plugin manager conceptually. Wait, its actually there.
Comment #26
lauriiiComment #27
tim.plunkettThe first big problem here is the passing of $existing to hook_theme(). Each implementation gets the *processed results* of all the implementations that ran before it.
However, the only places in core that use that are theme engines: nyan_cat_theme() and twig_theme().
Zero themes or modules use ANY of those provided pararameters, even in tests.
Furthermore, theme engines cannot provide YAML files.
The lack of test coverage makes me very nervous about refactoring/rewriting this.
Also, I am not actively working on this, unassigning.
Comment #28
joelpittet@tim.plunkett you are right those params don't get used except theme engines and there is a bug in it that I've sorted that out a bit here: #2817103: Theme registry doesn't find templates in subfolders for self-defined theme hooks
Comment #29
lauriiiComment #30
fabianx commented-1 to a plugin based approach
We will need a refactoring of this at some point in time, but I think we should do that with the introduction of a new API - there is too much baggage we need to refactor anyway.
--
Simple proposal to get this in without many changes:
- Allow specifying the owner (module) in the the returned info structure of hook_theme(). (@internal, but useful for edge cases)
- Return all information from the YamlDiscovery (modules, themes) in this one theme hook, but set
e.g.
- Allow this owner override to replace the data that would be auto-populated by the theme registry depending on where the hook comes from
Advantages:
- Zero disruption for existing code
- Only API additions
- Minimal changes in the internals of the theme system
- hook_theme is still available for more complex cases
-----
Edit:
To clarify, those theme hooks collected via the new mechanism could also be plugins - that is okay. My -1 was more to the implementation, in the end the consumer does not care where the structured info array comes from - be it YAML or a plugin or both ...
I just would like to change the theme system itself as less as possible for it - because as Tim rightly said: We lack test coverage.
So having system_theme() just report the hooks for all modules + themes seems like a good idea to reduce the complexity of the change.
However we have to be careful of order of overwrites, though I am not sure how defining the same theme hook twice is supported right now.
Comment #32
hatuhay commentedI openned this issue a while ago Declare themes on YAML file as an alternative to hook_theme
Styles API is doing something in my understanding should be done by CORE.
That is exactly what is discussed here.
Comment #33
hatuhay commentedComment #34
hatuhay commentedComment #35
tim.plunkett@hatuhay except that layouts are plugins, which contradicts #30
Comment #36
hatuhay commented@tim.plunkett talking about the way they are declared, not how the declaration is handled.
Meanning the posibility to declare themes for specific components (like blocks, fields and regions) in modules or themes to extend other modules or themes.
And adding extra UI information like thimbnails or descriptions.
Comment #39
markhalliwellThis is great! I think we could take it one step farther and make it a part of #2869859: [PP-1] Refactor theme hooks/registry into plugin managers which could allow YAML plugins to be discovered.
Comment #40
markhalliwellComment #42
YurkinPark commentedI have adapted patch for last dev branch
Comment #44
savkaviktor16@gmail.com commentedComment #45
YurkinPark commentedComment #47
markhalliwellSorry, I think I misspoke in #39...
I was originally marking issues as "Needs work/reroll" because I was simply going through the backlog of issues.
Then when I started making the comment and mentioned the other issue, I forgot to change the status to a dup of #2869859: [PP-1] Refactor theme hooks/registry into plugin managers. That issue is basically the same as this but allows us to put an entire plugin manager behind the discovery process.