Group actions with ECA VBO¶
Version v1
You can apply this model as a recipe (Drupal 10.3 or later) to your own Drupal site:
1 2 3 4 5 6 7 8 9 10 11 | |
Purpose¶
Add selected nodes to a group straight from a view, and only let people who belong to that group do it.
The technique comes from a writeup by liberatr answering someone who could not work out how Group Actions and Views Bulk Operations fit together. The answer stalled on one objection, which this model exists to remove.
The objection, and the answer¶
liberatr's model hard-coded the group ID, and Mike Anello pointed out what that costs:
> your model is limited in that the group name/id cannot be passed into it - it must be hard-coded as part of the model. Which means, if I have 120 terms, then I need 120 models
He was right, and the thread concluded that ECA could not do better. It can. The group is not configured here at all: it arrives as the view's contextual filter, read by "VBO: Get Views argument". One model serves every group, and adding a group never means touching the model.
The membership lookup avoids the same trap a second time. It matches on the relationship's plugin_id — group_membership — rather than on the bundle a specific group type produces, so nothing in this model names a group type either.
Access and execution ask different questions¶
The model reacts to two events, and the split between them is the part worth studying.
The custom access event decides whether the operation appears in the list at all. It runs while the view is being built, before anyone has chosen anything, and it deliberately asks a coarse question: does this user hold a membership in any group? It has to be coarse, because the access event carries no view arguments — "VBO: Get Views argument" only works on execution and form events — so the group in the URL is not knowable at that moment.
The execution event then asks the precise question. It reads the group from the argument, loads the membership for that exact group, and only adds the node when that membership exists.
That is the right shape regardless of the limitation. An access check decorates the interface; it is not a security boundary, because nothing stops a determined visitor from submitting the form anyway. The check that protects data is the one at execution time, and this model has both.
Access starts by denying. "VBO: Set custom access" assigns to the event, so the last write wins, and a later grant overrides the earlier deny. Denying first means any unexpected break in the chain leaves the operation hidden rather than exposed.
The permissions are part of the model, not a footnote¶
Two group permissions are load-bearing, and the recipe grants both to the member role:
- View own membership. "Entity: load" checks access on what it loads, so a member who cannot view their own membership relationship fails the lookup, and the access branch treats them exactly like a non-member. The operation never appears and nothing says why.
- Create the content relationship. Without it the add is refused at the last step, after every condition has already passed.
Both failures are silent. Neither logs an error, neither shows a message, and both look identical to "the model did not match". If this model appears to do nothing on a site of your own, check these two permissions before checking anything else.
This model needs a patch on Group Actions¶
group_add_content promotes its "Group ID / UUID" field to an entity autocomplete, and an autocomplete element cannot hold a token. With the released module the action's configuration form throws as soon as that field contains anything, [target_group] included, so the model works but its form cannot be rendered or edited.
The fix is merge request 6 against issue #3619954. Apply it until a release carries it:
1 2 3 4 5 6 7 | |
Nothing else in the recipe depends on it, and the operation itself runs correctly either way. Only the form does not.
Adapting it¶
The recipe ships its own view at /eca/group/{group}/content so that the demonstration works the moment the recipe is applied. To run the operation from a view of your own, the requirements are only these: a contextual filter carrying the group ID as the first argument, the "ECA bulk operations" field, and the operation enabled inside that field. The operation name must match on both events exactly.
Group Node's own /group/{group}/nodes view satisfies the first requirement already, so adding the ECA bulk operations field to it is enough. The recipe deliberately does not do that for you: the only configuration action available for a view replaces its whole display, which would overwrite whatever Group Node ships next and discard any customization you had made.
The group relationship for the node bundles in your view has to exist before the operation can add anything. The recipe installs the article relationship for its own group type; other bundles and other group types need their own.
Dependencies¶
- module
- eca_base
- eca_content
- eca_user
- eca_vbo
- group_action
- modeler_api
- views_bulk_operations
Used plugins¶
Events¶
- VBO: Execute Views bulk operation (one by one) (Add selected content to group)
- VBO: Custom access for Views bulk operation (Add selected content to group)