So far the group module provides one context service, GroupRouteContext, which takes the context from the path.
The views groupPermission handler ONLY takes its context from the path.
However I would like contexts of:
- all the groups the current user is in (perhaps filtered by group type)
- all the groups the current content is in.
Does it make sense for contexts to return several groups?

CommentFileSizeAuthor
#52 group-context-2815971-52.patch7.76 KBbanoodle
#51 group-context-2815971-51.patch7.74 KBcamslice
#49 group-context-2815971-49.patch7.76 KBRuslan Piskarov
#48 interdiff-46-47.txt647 bytesbillywardrop
#48 group-context-2815971-47.patch7.81 KBbillywardrop
#46 interdiff-44-46.txt583 bytesphma
#46 group-context-2815971-46.patch7.8 KBphma
#45 group-context-2815971-44.patch7.81 KBscotwith1t
#42 group-context-2815971-42.patch7.57 KBkroh
#41 group-context-2815971-41.patch7.58 KBthatguy
#40 group-context-2815971-38.patch7.54 KBArtyom Hovasapyan
#39 group-context-2815971-38.patch7.54 KBArtyom Hovasapyan
#38 group-context-2815971-38.patch7.5 KBArtyom Hovasapyan
#37 group-context-2815971-37.patch7.51 KBle72
#36 group-context-2815971-36.patch7.49 KBle72
#35 Screen Shot 2022-04-28 at 21.51.41.png230.88 KBle72
#32 28-32-interdiff.patch2.05 KBChi
#32 group-context-2815971-32.patch7.45 KBChi
#31 28-31-interdiff.patch2.22 KBChi
#31 group-context-2815971-31.patch7.46 KBChi
#28 2815971-28.patch5.39 KBedysmp
#28 2815971--26-28-iterdiff.patch3.58 KBedysmp
#26 2815971-26.patch2.6 KBheddn
#26 interdiff_23-26.txt1.42 KBheddn
#23 group_context_on_group_content-2815971-23.patch2.64 KBChrisSnyder
#19 group_context_on_group_content-2815971-19.patch2.42 KBjastraat
#18 2815971-group_content_context-18.patch2.44 KBadamfranco
#15 2815971-group_content_context-15.patch1.82 KBakalata
#14 expand_context_to_nodes-2815971-14.patch2 KBtomasbarej
#13 expand_context_to_nodes-2815971-13.patch1.84 KBericras
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

matslats created an issue. See original summary.

matslats’s picture

I've created a new context, which returns all the groups of which the current user is a member.
I have modified the @ViewsAccess plugin group_permission so that you can choose to get the group context from the route or (the first group of) the current user.
Do you want this?
I would like to go further and specify in the @ViewsAccess plugin which grouptype in the current users's context we are interested in.
Do you want this?

matslats’s picture

Ok I've created a new GroupComboContext which returns an array of groups based on a cascade of possible contexts.
First of all is the route context, which would return only one group,
If the route doesn't indicate a group it falls back to a current user context, returning many groups
If the user isn't in any groups it falls back to the content being viewed, returning the groups it is in.

I also made a GroupComboSelection @EntityReferenceSelection plugin based on the GroupComboContext. It can be configured to select only groups that use certain plugins.

Shall I put all this in my own distro or shall I create a patch and post here?

rachel_norfolk’s picture

Absolutely yes - post it as a patch - it might be VERY useful!

I'm starting to think that it relates to my query in 2821513 where I'm trying to create a block view of other content in the same group. If I had a "group this content belongs to" context, that would be possible!

kristiaanvandeneynde’s picture

Contexts (as used for blocks etc.) preferably have a predictable outcome. "Grab the group from the route" should give you the result you expect. A context that asks you for the user's first group may be confusing, what is the person's first group? There's some ambiguity there.

I would love to see more contexts, though! But they have to produce predictable output. I would also love to see more Views plugins for contextual filters. If you have any ideas that are generic enough, please post them as patches!

matslats’s picture

I've made a module I'm calling group_exclusive.
It adds a boolean setting on the GroupContentEnabler when the entity cardinality is 1
When enabled the content MUST be added to one and only one group of that type.
I'm using this for users.
So the module then provides a context of the group of the current user.
I didn't mention it before because I supposed you wouldn't want this in the group module.

kristiaanvandeneynde’s picture

Well, we do have group cardinality for that purpose (only adding a node to a single group). But that is plugin-specific. So if another plugin were to allow you to add nodes, it could still lead to multiple parent groups per node.

You could try to make your module overrule the config for any node-serving plugin to enforce a group cardinality of 1.

matslats’s picture

Enforcing a cardinality of 1 has UI and DX consequences.
For example the user/add form needs to know, by the time the user entity is saved, which group it is in.
So I made a new module to keep all that stuff separate.

ericras’s picture

@matslats I'd like to see GroupComboContext if you could post a patch. That sounds like what Organic Groups does with OgContext::getGroup(). I previously used the Drupal 7 version of that to get the all the contexts/groups of the node being viewed.

ericras’s picture

Ambiguity is certainly an issue when something is assigned to multiple groups.

Here's an example: When viewing a node, I want to set the site title to the title/label of the group it is a part of. If it's just assigned to one group that is clean but if it's assigned to two or more groups then which is chosen?

OG's OgContext::getGroup() returns the "best candidate" based on its formula but its still just picking one. Its not very predictable because there's really no concept of the "main group" built into OG or Group. However, when there are multiple groups involved and you can only use one of them (e.g. to set the site title) then you just have to pick one somehow.

Possibly the solution is to name the proposed GroupComboContext something like GroupBestGuessContext. That way at least it indicates that it semi-arbitrarily returns one of many.

Edit: I just realized that this problem is similar to the ambiguity of having a delta-less [node:group] token in #2774827: Get a token of a node's parent group to create a pathauto pattern

matslats’s picture

@ericas sorry without any kind of go-ahead from @kristiaanvandeneynde I found another approach to my problem and I didn't have anywhere to retain that GroupCombo Context

mErilainen’s picture

I'm also interested on the topic of multiple groups per content. Should we create a canonical url per group? How can I display the link to the content in a list when the content has multiple groups, thus multiple contexts where it can be opened in. A clean url per group would look nice, but not sure how difficult it is to implement.

Another approach is to configure views to append a ?gid=x parameter to the content url depending on the currently active group context and then use some custom code to activate that group context when viewing content. Not sure if that's the right approach. Is it good for SEO when the content is the same but surrounding elements change depending on the parameter value.

ericras’s picture

I'm going to throw up a patch that I'm using as a starting point. It does a simplified version of what OG does with getBestCandidate(). If you're viewing a node it grabs all the groups that it is a part of and it returns one of them to set the context.

I'm using this patch because I want the "Group ID from URL" default value in a Views Contextual Filter to behave like the OG one ("Current OG group from context").

tomasbarej’s picture

I was using #13 patch successfully but I've run into errors when we enabled revision of nodes.

{node} parameter of node revision route was returned as int instead of node object in getBestCandidate:

$node = \Drupal::request()->attributes->get('node')
akalata’s picture

Here's an update to #14 using the currentRouteMatch service that is already being injected into the class.

SocialNicheGuru’s picture

Status: Active » Needs review
adamfranco’s picture

I have the situation of needing to display a view of a users Groups where each of the Groups is rendered using a display mode that in turn uses an attached EVA view to list all of nodes associated with this group. Something like this:

(Parent view of groups)
- Group A
  (EVA view of nodes in group)
  - Node 1
  - Node 2
- Group B
  (EVA view of nodes in group)
  - Node 3

I've set up the EVA view to use "GroupPermission" and this works fine when viewing the group directly, but found that it can't work when the group is in a view result because the Group Id is passed to the EVA view as an argument rather than being in the route context of the parent view. I don't want to unnecessarily hijack this issue, but I also don't want to pollute the queue with duplicates and think that this might be a very similar problem to those reported above -- a need to get the group from a different context than just the current route -- in this case a views argument.

In my particular use-case I can work around this GroupPermission failure by removing the access check in the EVA group since the groups listed are only those that the user is a member of and all members can view all nodes in the group. In other use-cases where group-roles have different view permissions checking the group permissions properly for each group would be necessary.

adamfranco’s picture

Please ignore my comment #17 -- I think that may be a distraction from the direction of this thread.

I found that patch #15 will fail if a block displayed on a node-view url uses the Group from Route context. This exception is caused by the GroupCacheContext which is still looking for the group in the route rather than using getBestCandidate() method like GroupRouteContext does in #15:

Error: Call to a member function bundle() on null in [...]/group/src/Cache/Context/GroupCacheContext.php on line 42

Attached is a patch which builds on #15 to unify the operation of GroupRouteContext and GroupCacheContext so that they both behave the same way.

jastraat’s picture

Rerolled patch from #18 to work with latest dev.

Example of where this change would be key - the group_content_menu module: https://www.drupal.org/project/group_content_menu

This patch allows nodes within the group to still return the context of their group so that the group menu displays across all the group pages, not just on the group itself.

Is there any chance of getting something like this committed? If so, does the patch need to be enhanced so that there's an administrative setting to enable the extended functionality so that it doesn't break existing implementations? (E.g. sites where a single node is associated with multiple groups and choosing a single group as the group context makes less sense.)

Status: Needs review » Needs work

The last submitted patch, 19: group_context_on_group_content-2815971-19.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

anruether’s picture

I just installed #18 and it works nicely! (I'm still on RC5)

I have a title block that is displayed on group pages only. Formerly it only displayed on the group pages itself, that was its purpose. With the patch it is also displayed on all group nodes. For our use case (apart from the title block..) this would be the expected behaviour. But we only ever add a node to one group, in other cases I'm not sure how you find out which group's context shall be used.

anruether’s picture

When using #19 with group 1.3 I run into this error when visiting e.g. /node/4/revisions/8/view

This does not happen when I limit a group views block to not appear on revision pages but only on node/*

<strong>The website encountered an unexpected error. Please try again later.
TypeError: Argument 1 passed to Drupal\group\Entity\GroupContent::loadByEntity() must implement interface Drupal\Core\Entity\ContentEntityInterface, string given, called in /var/www/html/web/modules/contrib/group/src/Context/GroupRouteContextTrait.php on line 99 in Drupal\group\Entity\GroupContent::loadByEntity() (line 122 of modules/contrib/group/src/Entity/GroupContent.php).

Drupal\group\Entity\GroupContent::loadByEntity('4') (Line: 99)
Drupal\group\Context\GroupRouteContext->getBestCandidate() (Line: 52)
Drupal\group\Context\GroupRouteContext->getRuntimeContexts(Array) (Line: 83)
Drupal\group\Plugin\views\access\GroupPermission->__construct(Array, 'group_permission', Array, Object, Object, Object) (Line: 98)
Drupal\group\Plugin\views\access\GroupPermission::create(Object, Array, 'group_permission', Array) (Line: 21)
Drupal\Core\Plugin\Factory\ContainerFactory->createInstance('group_permission', Array) (Line: 83)
Drupal\Component\Plugin\PluginManagerBase->createInstance('group_permission') (Line: 817)
Drupal\views\Plugin\views\display\DisplayPluginBase->getPlugin('access') (Line: 2317)
Drupal\views\Plugin\views\display\DisplayPluginBase->access(Object) (Line: 1766)
Drupal\views\ViewExecutable->access(Array) (Line: 93)
Drupal\views\Plugin\Block\ViewsBlockBase->blockAccess(Object) (Line: 120)
Drupal\Core\Block\BlockBase->access(Object, 1) (Line: 124)
Drupal\block\BlockAccessControlHandler->checkAccess(Object, 'view', Object) (Line: 105)
Drupal\Core\Entity\EntityAccessControlHandler->access(Object, 'view', Object, 1) (Line: 370)
Drupal\Core\Entity\EntityBase->access('view', NULL, 1) (Line: 56)
Drupal\block\BlockRepository->getVisibleBlocksPerRegion(Array) (Line: 137)
Drupal\block\Plugin\DisplayVariant\BlockPageVariant->build() (Line: 259)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 117)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object)
call_user_func(Array, Object, 'kernel.view', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.view', Object) (Line: 156)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 708)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
</strong>
ChrisSnyder’s picture

The following patch builds upon patch #19 to account for node revision issue @anruether experienced and to use the first group in array if there are multiple instead of last.

heddn’s picture

+++ b/src/Context/GroupRouteContextTrait.php
@@ -81,4 +83,28 @@ trait GroupRouteContextTrait {
+    elseif (in_array($this->getCurrentRouteMatch()->getRouteName(), ['entity.node.canonical', 'entity.node.revision'])) {

This should use the 3rd argument to in_array, as pass TRUE.

This also assumes that all group content are nodes. While a good starting place, it would be nice if that wasn't the only option. How can we make this extensible? Is there any way we can find out if the thing in the URL is a group content item? An event subscriber is one way, but are there other better ways?

kristiaanvandeneynde’s picture

Is there any way we can find out if the thing in the URL is a group content item?

Using the current route match's getParameters, you could grab said parameter and check if it's an instance of GroupContentInterface or call getEntityType() on it to find out that way.

heddn’s picture

Status: Needs review » Needs work

The last submitted patch, 26: 2815971-26.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

edysmp’s picture

anruether’s picture

Thanks for the work on this patch! After updating to core 9.1.5 I my local php server aborts in the following scenario:

Create a group views block (which creates a link to the group content overview page if users have permission)
Add an access check to the view, e.g. Access: Group permission | Access group node overview
Add block to group content nodes (via block layout)
Now when visiting a node where the block is active, my server hangs

When either removing the patch or the group access check of the view I don't get the error. The log has nothing. I tested #19, #26 and #28. With core 8.9 the exact same setup was working.

[Tue Mar 16 22:45:50 2021] 127.0.0.1:38910 [200]: GET /modules/contrib/admin_toolbar/js/admin_toolbar.js?qq30bi
[Tue Mar 16 22:45:50 2021] 127.0.0.1:38918 Accepted
[Tue Mar 16 22:45:50 2021] 127.0.0.1:38910 Closing
[Tue Mar 16 22:45:50 2021] 127.0.0.1:38914 [200]: GET /core/modules/toolbar/js/escapeAdmin.js?v=9.1.5
[Tue Mar 16 22:45:50 2021] 127.0.0.1:38914 Closing
[Tue Mar 16 22:45:50 2021] 127.0.0.1:38918 [200]: GET /core/modules/big_pipe/js/big_pipe.js?v=9.1.5
[Tue Mar 16 22:45:50 2021] 127.0.0.1:38918 Closing
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38922 Accepted
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38922 Closing
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38926 Accepted
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38930 Accepted
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38926 [200]: GET /core/modules/views/css/views.module.css?qq30bi
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38930 [200]: GET /core/themes/claro/css/components/views-exposed-form.css?qq30bi
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38926 Closing
[Tue Mar 16 22:46:00 2021] 127.0.0.1:38930 Closing
[Tue Mar 16 22:46:10 2021] 127.0.0.1:38934 Accepted
[Tue Mar 16 22:46:10 2021] 127.0.0.1:38938 Accepted

In Process.php line 428:
                                                  
  The process has been signaled with signal "9".  
scotwith1t’s picture

Component: Group (group) » Code

Using patch at #28 and works as advertised. Thanks!

Chi’s picture

The views groupPermission handler ONLY takes its context from the path.

The patch extends #28 to address this issue.

Chi’s picture

Made the patch compatible with PHP 7.3.

Chi’s picture

Status: Needs review » Needs work

Note that the current "getBestCandidate" approach does not handle ambigutiy issue discussed in #5-#12. Even though it works well on many projects it is not suitable for everyone. Consequently, there is nothing to review yet.

I think the only generic solution possible here is to invoke some hook or event subscriber wich would allow to provide correct group context from a custom module.

markdc’s picture

#32 working on PHP 7.4. Thanks

le72’s picture

I also faced this problem. Need a parent group context on a node page. Using Layout Builder.
Patch didn't help :-( Maybe I am doing something wrong.
I have a custom block defined as

/**
 * Provides a 'Event Details' block.
 *
 * @Block(
 *  id = "event_details",
 *  admin_label = @Translation("Event Details"),
 *  category = "Society Blocks",
 *   context_definitions = {
 *     "node" = @ContextDefinition("entity:node", required = FALSE, label = @Translation("Current Node")),
 *     "group" = @ContextDefinition("entity:group", required = FALSE, label = @Translation("Current Group")),
 *   }
 * )
 */
class EventDetails extends BlockBase {
  public function build() {
    ...some code here using "node" and "group".   
  }
}

When placing the block in a section region I don't see the second (group) context.
screen

More an easy step to reproduce the problem. Try to place "Group operations" block on a node page. Expectation: If the node belongs to a group, show that group's operations.

Any help?
Thank you in advance.

le72’s picture

If you are using group v3.x the patch will need some changes. I replaced "group_content" with "group_relationship" and it works fine on Drupal 9.4.x with Group 3.x

le72’s picture

Artyom Hovasapyan’s picture

Version: 8.x-1.x-dev » 3.0.0-beta6
FileSize
7.5 KB

Update.

Artyom Hovasapyan’s picture

FileSize
7.54 KB

When user group_member a lot of groups, #37 returned first element(if it user_page), I suggest patch which shows only for NodeInterface.
Update #37.

Artyom Hovasapyan’s picture

FileSize
7.54 KB

Fix bug.

thatguy’s picture

Re-rolled patch from #40 to work with dev-3.0.x version

kroh’s picture

Version: 3.0.0-beta6 » 2.0.0-rc1
FileSize
7.57 KB

Re-rolled patch from #40 to work with 2.0.x

gwvoigt’s picture

Thanks, patch from #41 working on 3.x for me

scotwith1t’s picture

Patch needs a re-roll for new 3.0.0 release.

scotwith1t’s picture

Taking a stab...this is NOT my strong point, apologies if this is all messed up.

phma’s picture

phma’s picture

Version: 2.0.0-rc1 » 3.1.x-dev
billywardrop’s picture

I patched groups 3.1 using the patch file in comment #46 but this stopped my theme running due to an error stating that group_content entity doesn't exist. Groups 3 now uses the group_relationship entity so I changed the entity type to group_relationship and the group nodes now show group blocks.

I have create a new patch and interdiff for this.

Ruslan Piskarov’s picture

Improved #48. Just removed "+ + " in diff.

heddn’s picture

+++ b/src/Context/GroupRouteContextTrait.php
@@ -81,4 +84,36 @@ trait GroupRouteContextTrait {
+      return $parameter instanceof NodeInterface;

Why are we focused on Nodes? Why not just entity interface instead? then it will work for anything that group itself supports.

camslice’s picture

Version: 3.1.x-dev » 2.2.0
FileSize
7.74 KB

Reroll #49 for 2.2.x — for people on the upgrade path. My first patch, sorry if I messed it up.

banoodle’s picture

Patch #51 applied OK for me, but throws these errors due to the inclusion of group_content.

Drupal\Component\Plugin\Exception\PluginNotFoundException: The "group_content" entity type does not exist. in Drupal\Core\Entity\EntityTypeManager->getDefinition() (line 139 of /code/web/core/lib/Drupal/Core/Entity/EntityTypeManager.php).

This patch I'm uploading just replaces "group_content" with "group_relationship".

le72’s picture

What is the state of Group v3 patch?
I did fresh Drupal 10 install with Layout builder and Group 3. The problem #35 is still there.