This is part of #2015147: [meta] Improve the DX of drupal_render(), renderable arrays and the Render API in general
Currently it is pretty confusing and requires some research to figure out when #theme and #type should be used to render a given HTML element with the Render API.
Since #type can set a default #theme through element_info() it makes sense that #type should actually be the "de facto" starting point for building any renderable array and #theme can just be used to set overrides when the default #theme is not sufficient.
To achieve this we need a few things:
- Every #theme currently set by core in hook_theme() needs a corresponding #type set in hook_element() if it doesn't have one already.
- Every #theme with a corresponding #type already needs to actually be compatible, eg. taking the same parameters, doing the same sanitisation, not using #markup as the default render for the #type, etc..
- Renderable arrays used by core should always be built starting with #type so that core leads by example - this has to be done last and will probably end up being its own meta issue.
There has been a general movement towards this for a while now, but I'm unaware of any existing meta issue bringing them all together and formalising the process so I opened this one.
Introducing new element types for existing "base" theme hooks
For the most basic additions all we need is something like the following for #theme 'foo' and module 'bar':
/**
* Implements hook_element_info().
*/
function bar_element_info() {
$types = array();
$types['foo'] = array(
'#theme' => 'foo',
);
return $types;
}
For these most basic conversions, if #2005970: In renderable arrays, #type should provide a #theme suggestion, similar to how drupal_prepare_form() works ever lands it will remove the need to explicitly set all these #theme defaults but it's unlikely the patch in that issue will land if we don't have a comprehensive set of #types that are compatible with matching #themes - It's kind of chicken or the egg, so we have to start somewhere.
Not everything in this list is this simple however, some are looking to introduce more advanced functionality in the form of new #pre_render callbacks.
It is important to realise that theme hooks may be theming forms based on a form ID, which is set as a theme suggestion in drupal_prepare_form() - this is an example of render defaults being merged into a render array outside the "element type" system. In these cases, defining a #type is useless but I don't know of any easy way to test whether a hook is implementing a form ID based suggestion or not.
There are plenty of other theme hooks that are already overriding a default #theme for a given #type for a specific use-case or are implementing a suggestion - These do not need their own #type. Figuring out what makes sense as an element #type and what only exists as a #theme override/suggestion can take a little research and discussion on a case-by-case basis.
#theme hooks that are only intended to be used with #theme_wrappers do not need a matching #type element.
The concept of a "base" theme hooks are those that are used in core with no #type currently set and that aren't implementing a form ID suggestion.
Categories
A - super simple
If #theme works, the theme hook uses variables instead of 'render element', the theme hook doesn't render #children (we're not using #theme_wrappers anywhere) then all we need to do for this is take:
$foo = array('#theme' => 'foo');
define a type in hook_element_info() that sets the #theme:
bar_element_info() {
....
$types['foo'] = array(
'#theme' => 'foo',
);
Then we can replace the #type with #theme in the original array wherever it appears:
$foo = array('#type' => 'foo');
Issues
- #1595614: [meta] Remove all the theme functions and templates in core that simply output a link. Replace with #type 'link' render arrays
- #2086619: #theme 'maintenance_page' should be based on #type 'page'
Deprecated list, see comment #7 (clean me out, find the wheat in all this chaff please):
- #2025661: Introduce #type equivalents for each theme hook in aggregator.module Assigned to: dmitrii
- #1300744: Introduce #type 'links'
- #2025665: Introduce #type 'block'
- #2025669: Introduce #type 'custom_block_add_list'
- #2025677: Introduce #type equivalents for each theme hook in book.module
- #2025681: Introduce #type 'ckeditor_settings_toolbar'
- #2025687: Introduce #type 'color_scheme_form'
- #2025689: Introduce #type elements for base theme hooks in comment.module
- #2025703: Introduce #type elements for base theme hooks in field.module Assigned to: dmitrii
- #2025709: Introduce #type elements for base theme hooks in file.module
- #2035971: Introduce #type elements for base theme hooks in filter.module
- #2035973: Introduce #type elements for base theme hooks in forum.module
- #2035977: Introduce #type elements for base theme hooks in image.module
- #2035979: Introduce #type elements for base theme hooks in language.module
- #2035981: Introduce #type elements for base theme hooks in link.module
- #2036155: Introduce #type elements for base theme hooks in locale.module
- #2036163: Introduce #type elements for base theme hooks in node.module
- #2036165: Introduce #type elements for base theme hooks in overlay.module
- #2036167: Introduce #type elements for base theme hooks in picture.module
- #2036169: Introduce #type elements for base theme hooks in rdf.module
- #2036171: Introduce #type elements for base theme hooks in search.module
- #2036173: Introduce #type elements for base theme hooks in simpletest.module
- #2036177: Introduce #type elements for base theme hooks in system.module
- #2036183: Introduce #type elements for base theme hooks in taxonomy.module
- #2036185: Introduce #type elements for base theme hooks in toolbar.module
- #2036189: Introduce #type elements for base theme hooks in update.module
- #2036191: Introduce #type elements for base theme hooks in user.module
- #2036203: Introduce #type elements for base theme hooks in views.module
- #2036207: Introduce #type elements for base theme hooks in views_ui.module
Ensuring #type/#theme compatibility between hooks/elements with the same name
There's a few things that can happen here.
All things equal, it would be ideal if when a #type declares a default #theme hook they both have the same name. This won't always be possible, an obvious example is when multiple #types share the same #theme hook, but we should try to consolidate things where we can.
- #2025707: Remove unused #theme "file_widget"
- #2025699: Consolidate 'datetime'/'datetime_form' and 'datelist'/'datelist_form' #type and #theme names for consistency
Any #type that declares a #theme of the same name that also declares #pre_render or #post_render callbacks must use the same parameter names that the #theme hook is expecting, or at the very least not conflict/preclude the #theme hook from operating in the desired way when #type is used.
No #theme hook may set a variable named 'type' as this immediately makes it impossible to ever implement a #type for this theme hook.
- #2010672: Rename 'type' variable of theme_mark to 'status'
- #1828536: Rename 'type' variable of theme_item_list() to 'list_type'
- #1985470: Remove theme_link()
Comments
Comment #0.0
thedavidmeister commentedUpdated issue summary.
Comment #0.1
thedavidmeister commentedUpdated issue summary.
Comment #0.2
thedavidmeister commentedUpdated issue summary.
Comment #0.3
thedavidmeister commentedUpdated issue summary.
Comment #0.4
thedavidmeister commentedUpdated issue summary.
Comment #0.5
thedavidmeister commentedUpdated issue summary.
Comment #0.6
thedavidmeister commentedUpdated issue summary.
Comment #0.7
thedavidmeister commentedUpdated issue summary.
Comment #0.8
thedavidmeister commentedUpdated issue summary.
Comment #0.9
thedavidmeister commentedUpdated issue summary.
Comment #0.10
thedavidmeister commentedUpdated issue summary.
Comment #0.11
thedavidmeister commentedUpdated issue summary.
Comment #0.12
thedavidmeister commentedUpdated issue summary.
Comment #0.13
thedavidmeister commentedUpdated issue summary.
Comment #0.14
thedavidmeister commentedUpdated issue summary.
Comment #0.15
thedavidmeister commentedUpdated issue summary.
Comment #0.16
thedavidmeister commentedUpdated issue summary.
Comment #0.17
thedavidmeister commentedUpdated issue summary.
Comment #0.18
thedavidmeister commentedUpdated issue summary.
Comment #0.19
thedavidmeister commentedUpdated issue summary.
Comment #0.20
thedavidmeister commentedUpdated issue summary.
Comment #0.21
thedavidmeister commentedUpdated issue summary.
Comment #0.22
thedavidmeister commentedUpdated issue summary.
Comment #0.23
thedavidmeister commentedUpdated issue summary.
Comment #0.24
thedavidmeister commentedUpdated issue summary.
Comment #0.25
thedavidmeister commentedUpdated issue summary.
Comment #0.26
thedavidmeister commentedUpdated issue summary.
Comment #0.27
thedavidmeister commentedUpdated issue summary.
Comment #0.28
thedavidmeister commentedUpdated issue summary.
Comment #0.29
thedavidmeister commentedUpdated issue summary.
Comment #0.30
thedavidmeister commentedUpdated issue summary.
Comment #0.31
thedavidmeister commentedUpdated issue summary.
Comment #0.32
thedavidmeister commentedUpdated issue summary.
Comment #0.33
thedavidmeister commentedUpdated issue summary.
Comment #0.34
thedavidmeister commentedUpdated issue summary.
Comment #0.35
thedavidmeister commentedUpdated issue summary.
Comment #0.36
thedavidmeister commentedUpdated issue summary.
Comment #0.37
thedavidmeister commentedUpdated issue summary.
Comment #0.38
thedavidmeister commentedUpdated issue summary.
Comment #0.39
thedavidmeister commentedUpdated issue summary.
Comment #0.40
thedavidmeister commentedUpdated issue summary.
Comment #0.41
thedavidmeister commentedUpdated issue summary.
Comment #0.42
thedavidmeister commentedUpdated issue summary.
Comment #0.43
thedavidmeister commentedUpdated issue summary.
Comment #0.44
thedavidmeister commentedUpdated issue summary.
Comment #1
thedavidmeister commentedRelated #2053671: [meta] Name all theme functions that are only compatible with drupal_render() when nested within #theme_wrappers "foo_wrapper"
Comment #1.0
thedavidmeister commentedUpdated issue summary.
Comment #2
webchickComing here from #2025661: Introduce #type equivalents for each theme hook in aggregator.module. I'm not sure I agree with this general movement. Was this run past one of the other core maintainers, and I'm just out of the loop?
hook_element_info() is meant for re-usable components that can be used across forms/pages/etc. #type => form. #type => textfield. #type => dropbutton, and so on.
#type => aggregator_block_item makes no sense as a re-usable component. No module outside of aggregator.module is ever going to use it. And bloating the values that come back from the element_info hook with these kind of one-offs feels like it makes it much more difficult to discover those elements that are meant to be used throughout the code base.
Comment #3
thedavidmeister commented@webchick - sure, happy to chat about it. It's rather late here so not right now, but I'm sure I'll see you on IRC sometime soon :)
Comment #4
thedavidmeister commented@webchick - FWIW, if #2005970: In renderable arrays, #type should provide a #theme suggestion, similar to how drupal_prepare_form() works lands, we don't need to bloat up hook_element_info() at all to get the basic conversion happening. The plan would be to immediately remove every unneeded #theme declaration in hook_element_info() throughout core in a followup to that issue.
Then, it doesn't matter if you use #type or #theme in the simple case, so we can simplify usage and improve learnability of the render API by saying "just use #type, unless you really need something custom".
I'm totally happy to wait on the linked issue before doing anything further here in an effort to avoid bloat and double handling.
Comment #5
catchwebchick just pointed out the aggregator patch and that raised an eyebrow for me as well.
I don't consider any of the aggregator theme hooks to be 'base' - most of them would ideally be removed in favour of using generic theme hooks, this goes for probably 80-90% of the theme functions in core. So doing this for actual core stuff might be fine, but optional core modules I'd rather see us focus on them re-using the core theme hooks than actually increasing all that code.
Comment #6
thedavidmeister commentedOh, absolutely. If we could increase the flexibility and re-usability of existing theme functions and do as much consolidation as possible, well that's the ultimate end-goal goal isn't it :)
Comment #7
thedavidmeister commentedAfter discussion with webchick in IRC it became very clear that the "lite" approach of simply duplicating #theme in #type and then looking for patterns in what we're left with to guide consolidation later is not going to fly with the core maintainers.
This is the best that I could summarise my thoughts/motivation behind opening this issue in the first place:
Which webchick agreed was a good outcome, but is firmly against the approach here because she believes that things will get much worse before they get better, and given where we are in the release cycle and within the context of other conversions happening elsewhere, we can't afford to make things any worse on a vague promise of things getting better "someday".
This means more high level work to identify patterns and new #types and implement them for a few related existing theme functions at a time (the sub-issues will end up looking more like #1595614: [meta] Remove all the theme functions and templates in core that simply output a link. Replace with #type 'link' render arrays), basically this issue got a lot harder and I don't think there'll be as much "chug and plug" novice work as I was hoping for, but that's life.
In light of that, I think we'll get a better end-result, but we probably want to wait for a lot of the existing, less useful theme functions and templates to die out - they're being killed off pretty quickly in theme cleanups/conversions elsewhere.
I've updated the title of this issue to make it clearer that this is less about blind conversion and more about strategic improvements to the render API as a whole. The issue summary will need an update to reflect this conceptual shift of our goals too.
I hope webchick doesn't mind me setting this back to "active" as I've provided her with all the information that she asked for in IRC, and I'm providing a summary report of the discussion as I understand it here.
Comment #7.0
thedavidmeister commentedUpdated issue summary.
Comment #7.1
thedavidmeister commentedUpdated issue summary.
Comment #8
webchickNope, that's great. Thanks, thedavidmeister!
Comment #8.0
webchickUpdated issue summary.
Comment #8.1
star-szrs/RAPI/Render API
Comment #8.2
thedavidmeister commentedUpdated issue summary.
Comment #9
sunComment #10
thedavidmeister commentedComment #11
thedavidmeister commentedI think it's interesting that webchick talks about extending a renderable thingy in #7 when really you can't do that at the moment, you can only copy and paste. Linking in a related issue #2272577: Make #base_type a standard way to extend #type in renderable arrays..
Comment #12
star-szrI don't have a strong opinion one way or another but I'd like to propose postponing the child issues until we have a clear plan or consensus here on the parent issue. The majority of them have been active for over a year with no activity. I would be happy to take care of the actual postponing.
Comment #13
thedavidmeister commentedsure thing
Comment #14
star-szrThanks @thedavidmeister, that makes the theme system queue a lot easier to triage!
Comment #28
catchI think this is a good overall goal, but it looks like it's adding a lot of extra #types, whereas I think we should try to remove the number of #theme first. Adding a related issue.
Comment #29
catchGoing to postpone on that issue.
I think we need to consolidate the theme hooks first, some like #theme links already have issues to switch to #type item_list with a theme suggestion, which would be cleaner than a new #type links element.
Comment #30
smustgrave commentedJust closed a bunch of the related issues for #3533198: [Meta] Make Drupal the first "design-system native" CMS + Unify & simplify render & theme systems
Should this be closed I want to make sure @thedavidmeister, @star-szr, and @joelpittet are credited somewhere since they organized all those tickets years back.