Problem/Motivation
From #1966704: In-place editing for taxonomy terms and custom blocks:
- Implement
hook_preprocess_HOOK()
for other entity types as well (currently only implemented for Node). Ideally, we'd have a single preprocess hook for all entity types, but that currently does not yet exist. Usinghook_entity_view_alter()
is also impossible, because$build['#attributes']
on the page level are never rendered, hence we're condemned to set$variables['attributes']
inhook_preprocess_HOOK()
. This is also what the RDFa module does since Drupal 7 (it implements 8 preprocess hooks).- As a consequence of the above, it is currently impossible to handle all entity types at once. Hence I chose to support the Comment, Custom Block and Taxonomy Term entity types in this patch.
This means code like this:
/**
* Implements hook_preprocess_HOOK() for node.tpl.php.
*/
function edit_preprocess_node(&$variables) {
$node = $variables['elements']['#node'];
$variables['attributes']['data-edit-entity'] = 'node/' . $node->nid;
}
/**
* Implements hook_preprocess_HOOK() for taxonomy-term.tpl.php.
*/
function edit_preprocess_taxonomy_term(&$variables) {
$term = $variables['elements']['#term'];
$variables['attributes']['data-edit-entity'] = 'taxonomy_term/' . $term->id();
}
/**
* Implements hook_preprocess_HOOK() for block.tpl.php.
*/
function edit_preprocess_block(&$variables) {
if (isset($variables['elements']['content']['#custom_block'])) {
$custom_block = $variables['elements']['content']['#custom_block'];
$variables['attributes']['data-edit-entity'] = 'custom_block/' . $custom_block->id();
}
}
// … and so on, for every entity type in core.
Instead of:
/**
* Implements hook_entity_view_alter().
*/
function edit_entity_view_alter(&$build, EntityInterface $entity, EntityDisplay $display) {
$build['#attributes']['data-edit-entity'] = $entity->entityType() . '/' . $entity->id();
}
Note: the above means it's IMPOSSIBLE for Edit.module to support entity types that are not in Drupal core, because it cannot know the names of custom entity types!
Proposed resolution
I talked to fubhy about this and there are apparently fundamental architectural constraints to provide hook_preprocess_entity()
. Fair enough. Then let's make the #attributes
defined in hook_entity_view_alter()
actually work?
Remaining tasks
(reviews needed, tests to be written or run, documentation to be written, etc.)
Simpletest failed in ThemeTest.php (line 57). Fix should be implemented and test again.
User interface changes
None.
API changes
None.
Related Issues
Comment | File | Size | Author |
---|---|---|---|
#46 | attributes_entity-1972514-46.patch | 9.22 KB | ekl1773 |
#42 | attributes_entity-1972514-42.patch | 8.83 KB | Gábor Hojtsy |
#37 | attributes_entity-1972514-37.patch | 9.76 KB | Wim Leers |
#37 | interdiff.txt | 2.26 KB | Wim Leers |
#36 | attributes_entity-1972514-36.patch | 10.31 KB | Wim Leers |
Comments
Comment #1
Wim LeersI'm stupid.
Comment #2
Wim LeersWorking on an initial patch for this has brought to light one very big deficiency in
\Drupal\Core\Template\Attribute
: its inability to merge!The patch that got committed at #1290694: Provide consistency for attributes and classes arrays provided by template_preprocess() sidestepped this elegantly AFAICT by simply not using
Attribute
everywhere, and only starting to use that at the last possible moment. I.e. build the list of attributes "the old school way", and then simply do$attributes = new Attribute($attributes);
. However, deeper in the theming layer, when the attributes are in an instance of the newAttribute
, you then run into this problem…So, instead of being able to simply do something like:
I now need to do this:
… repeated for every entity type (I'm only doing node/comment/taxonomy term in the attached patch).
Finally:
Attribute::value()
is broken, though it appears it shouldn't exist at all. I fixed it in this patch.Comment #3
Wim Leersd.o fail
Comment #4
Wim LeersThis will need to be rewritten once #1982024: Lazy-load Attribute objects later in the rendering process only if needed gets committed, which is probably soon — and all my complaints in #2 will go away :)
Comment #5
Fabianx CreditAttribution: Fabianx commentedOkay, #1982024: Lazy-load Attribute objects later in the rendering process only if needed is in. Have fun! :-)
Comment #6
Wim LeersMy suspicion was right, #1982024: Lazy-load Attribute objects later in the rendering process only if needed greatly simplifies this patch :)
Attached patch enables setting attributes on all entities via
hook_entity_view_alter()
. Only the first two hunks are for making this possible, the last hunk is to make edit.module leverage this :)Comment #7
Gábor HojtsyLooks superb, just applying the pattern of #attributes turning into useful things as found elsewhere in Drupal core.
Comment #8
effulgentsia CreditAttribution: effulgentsia commentedExcellent bug fix. Let's add a test.
We need a @todo here to fix this to use $variables['content_attributes']. That requires $variables['content'] to be a render array rather than a string, and that's being fixed in #1927608: Remove the tight coupling between Block Plugins and Block Entities.
Comment #9
Dave ReidThis made me go a little WTF, since obviously we need this same fix for title_attributes and content_attributes. Should we make separate related issues or try and fix them here as well?
Comment #10
aspilicious CreditAttribution: aspilicious commentedCan we write
'attributes' => isset($variables['elements']['#attributes']) ? $variables['elements']['#attributes'] : array(),
as
'attributes' => isset($variables['elements']['#attributes']) ?: array()
?
Comment #11
effulgentsia CreditAttribution: effulgentsia commentedJust a reroll for HEAD changes. Will follow up with a separate patch and interdiff that incorporates feedback.
Comment #12
effulgentsia CreditAttribution: effulgentsia commentedThis still needs a test added, but CNR for bot.
I don't think so. There are no core use cases of a #title_attributes or #content_attributes property on render elements. It's possible that in some cases, like for 'block' in this patch, that we want to merge the #attributes of a child element into $variables['title_attributes'] or $variables['content_attributes'], but I think that's always hook-specific, not something that can be done generically in template_preprocess().
In manual testing of this patch, the 'data-edit-entity' attribute is output correctly for custom blocks, but I don't get a "Quick Edit" contextual link for them.
Comment #14
Wim LeersThe patch in #12 makes a lot more sense than mine — thanks! :)
Sadly, your changes broke the blocks case. In my patch, I was setting
$variables['attributes']
. In your patch, that became$variables['content_attributes']
. A subtle, but very important difference.I wrote a test.
Comment #16
Wim LeersI forgot to add a new .tpl.php file… Ignore all attachments in #14, look at these instead.
Comment #18
Wim LeersThe changes in #12 broke
Drupal\language\Tests\LanguageSwitchingTest
. That's why #16's "PASS" patch still fails. Note how the "PASS" patch only failsDrupal\language\Tests\LanguageSwitchingTest
but passes the newly added test. For the "FAIL" test, it's the other way around. So all is good, we just need to make theDrupal\language\Tests\LanguageSwitchingTest
test pass again :)Comment #19
Wim LeersComment #21
Wim Leersblock.module had changed in between #16 and #19, hence patch didn't apply anymore.
Comment #23
Wim Leers#21: attributes_entity-1972514-21-PASS.patch queued for re-testing.
Comment #25
Damien Tournoud CreditAttribution: Damien Tournoud commentedPlease inject the
$info
into the preprocess function instead. This completely break encapsulation and is most likely very inefficient.I mean, transform the signature of those functions (preprocess, process) into:
Comment #26
Wim Leers#25: Are you sure you're posting to the right issue? There's no
$info
, there's no calling of additional functions.Comment #27
Damien Tournoud CreditAttribution: Damien Tournoud commented@Wim:
$info
is the name given to$hooks[$hook]
insidetheme()
. This should be passed to the preprocess/process functions bytheme()
, instead of those functions breaking encapsulation by getting them from the globaltheme_get_registry()
.Comment #28
Wim LeersI'm no theme system expert, so temporarily assigning to effulgentsia to resolve #25/#27.
Comment #29
effulgentsia CreditAttribution: effulgentsia commented@Damien Tournoud: I agree with you, but I think that's out of scope for this issue. This is copying the same pattern already being used in HEAD for contextual_preprocess(). Can we have a separate issue for changing the signature of preprocess functions?
Comment #30
Damien Tournoud CreditAttribution: Damien Tournoud commentedGiven that it's a simple and backward compatible change, we should do it in here. If you don't like the performance hit, contextual links you can disable,
template_preprocess()
you cannot.Comment #31
effulgentsia CreditAttribution: effulgentsia commentedOk. I also removed the cloning of $hook, because the reasoning in the code comment for it was faulty. I added that code and comment in D7 in a moment of paranoia, but we don't institutionalize that level of distrust about the functions we call in any other Drupal code, and I didn't want to expand that antipattern to $info or treat $hook and $info differently in that regard.
Comment #33
NnekaWorking on this at Drupalcon Portland contrib sprint. Filling out the Issue Summary.
Comment #34
Gábor Hojtsy#31: attributes_entity-1972514-31.patch queued for re-testing.
Comment #36
Wim LeersReroll to apply cleanly to HEAD again. It's almost certain that more is broken than before. It seems that in several related places things have changed, quite possibly due to Twig.
Comment #37
Wim LeersYay, Twig has actually simplified things for us a little bit :)
template_preprocess()
: it no longer adds default classes.LanguageSwitchingTest
hunk is no longer needed: it's already been made less brittle by Twig or elsewhere.This passes the relevant tests locally; let's see if testbot finds anything else that breaks.
Comment #38
Gábor HojtsyLooks nifty, thanks for the reroll. As far as I see this addresses concerns brought up above. Let's get it in!
Comment #39
Damien Tournoud CreditAttribution: Damien Tournoud commentedYep, looks sweet.
Comment #40
alexpottNeeds reroll
Comment #41
ekl1773Assigning to self to reroll patch for mentoring office hours.
Comment #42
Gábor HojtsyHere is a quick reroll. The patch still applied with some fuzz.
Comment #43
Gábor Hojtsy@ekl1773: ups, sorry for stepping on toes! Was not intended.
Comment #45
Wim Leers#42 lost the twig template it seems :) Easy fix!
Comment #46
ekl1773Added the twig template from patch at #37 to patch at #42. Maybe this works?
Comment #47
effulgentsia CreditAttribution: effulgentsia commentedThanks. Doing a diff of #37 vs. #46 shows no lines of code that differ, so back to RTBC.
By the way, no need for a "Needs review" tag, since we have that as a status. Tags are useful for things not captured by the other issue attributes.
Comment #48
alexpottCommitted 71a4ab1 and pushed to 8.x. Thanks!
I think requires a change notice to describe this functionality...
Comment #49
Wim LeersSure, will do! Thanks!
Comment #50
Wim LeersChange notice created: https://drupal.org/node/2018597.
Comment #51
Wim Leers.
Comment #53
star-szrSmall follow-up to fix call to template_preprocess() in theme():
#2030457: Warning: Missing argument 3 for template_preprocess() for theme functions overridden by templates
Comment #53.0
star-szrUpdated Issue Summary.