Spinoff from #1889790: [Meta] Allow modules to register links for menus, breadcrumbs and tabs (if not with hook_menu):

We rip action links out of hook_menu entirely, using essentially the model from #1889790-9: [Meta] Allow modules to register links for menus, breadcrumbs and tabs (if not with hook_menu). To wit, action links become their own object unto themselves that reference to a route they point TO, and to routes they should appear ON. They are then removed from hook_menu entirely. We then build a block that looks at the current route (which may need to be passed as a literal string, not pulled from the request, TBD), grabs the action links that should be on that route, and displays them. Want to change the L&F? It's a block. Enjoy.

Benefit: Action links get separated from hook_menu, where they didn't belong in the first place.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

tim.plunkett’s picture

Priority: Major » Normal

The meta issue is major, we don't need this to be as well.

mtift’s picture

Assigned: Unassigned » mtift

I'll take this one

tim.plunkett’s picture

Title: Separate Action Links from hook_menu() » Separate Action Links (MENU_LOCAL_ACTION) from hook_menu()
mtift’s picture

Assigned: mtift » Unassigned

So I'm really not sure where to go with this one. For example, I don't even know where MENU_LOCAL_ACTION will go when we rip it out, or what interface/class to implement/extend. Sorry...

Crell’s picture

It's all new classes, likely culminating in a block is my guess. The idea is that MENU_LOCAL_ACTION ceases to exist. See the linked comment for background.

tim.plunkett’s picture

Assigned: Unassigned » tim.plunkett

I just spent a good amount of time with local actions thanks to #1938960: _menu_translate() doesn't care about new routes, going to take a look

tim.plunkett’s picture

Status: Active » Needs review
Issue tags: +Needs tests
FileSize
14.23 KB
4.8 KB

Views UI is the only hook_menu() whose MENU_LOCAL_ACTIONs are routes that reference other paths that are routes. More conversions will have to follow.

To do this, I had to clean up _menu_router_merge_route().
It has been tweaked over time, and currently takes a $path and discards it directly.
Also, the entire point of the function is to populate the path from a route name.
So I've renamed it and repurposed it for just that.

This contains #1938960: _menu_translate() doesn't care about new routes.

Crell’s picture

At a quick glance, this seems like a reasonable start. I'm sad that it's a hook, but not sure what the alternative is. :-(

I'm a bit concerned about using the target route name as the key; I've a gut feeling (no data at the moment) that it's going to end up biting us somehow. Also, the "route" key in the array should probably be more descriptive. "Appears_On" wouldn't fit any known standard, but something more like that so that it's more self-documenting, perhaps?

tim.plunkett’s picture

It's so sad, I've worked so hard to kill off info hooks this cycle, yet this would mark the third new info hook I'm responsible for...

I'll mull over the naming while I write a test.

Status: Needs review » Needs work

The last submitted patch, local-actions-1908756-7-combined.patch, failed testing.

tim.plunkett’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
FileSize
8.75 KB
3.92 KB

Okay, made the switch to 'appears_on', and here's a test.

larowlan’s picture

I can only see nitpicks here

+++ b/core/includes/menu.incundefined
@@ -2215,6 +2215,19 @@ function menu_secondary_local_tasks() {
+  foreach (module_invoke_all('local_actions_info') as $route_name => $route_info) {

module_invoke_all deprecated?

+++ b/core/modules/system/tests/modules/menu_test/menu_test.moduleundefined
@@ -416,10 +416,36 @@ function menu_test_menu() {
+ * Implments hook_local_actions_info().

Implements

tim.plunkett’s picture

Good catch!
Converted picture and aggregator since there were move conversions committed.

Status: Needs review » Needs work

The last submitted patch, local-actions-1908756-13.patch, failed testing.

tim.plunkett’s picture

dawehner’s picture

+++ b/core/includes/menu.incundefined
@@ -2215,6 +2215,19 @@ function menu_secondary_local_tasks() {
 function menu_local_actions() {
   $links = menu_local_tasks();
+  $router_item = menu_get_item();
+  foreach (Drupal::moduleHandler()->invokeAll('local_actions_info') as $route_name => $route_info) {
+    if (in_array($router_item['route_name'], $route_info['appears_on'])) {
+      $route_path = _menu_router_translate_route($route_name);
+      $links['actions'][$route_path] = array(
+        '#theme' => 'menu_local_action',
+        '#link' => array(
+          'title' => $route_info['title'],
+          'href' => $route_path,
+        ),
+      );
+    }
+  }
   return $links['actions'];
 }

There is just a single place there this function is used so we maybe can move this into some kind of object already?

tim.plunkett’s picture

Status: Postponed » Needs review
FileSize
2.89 KB
11.77 KB

Okay. MENU_LOCAL_ACTION does two things.

  1. When on the parent page, the action link is displayed
  2. When on the action page, the tabs of the sibling pages are displayed

This issue is just about the former. It does not let us remove the hook_menu() definition.

But to better differentiate these two things, we *can* start converting now, and just have an identical bitmask menu type with a different name.

Introducing MENU_SIBLING_LOCAL_TASK.
Let's see how it fares.
---
@dawehner, I'm not sure what that would look like, especially with the menu_get_item() and menu_local_tasks() calls.

tim.plunkett’s picture

Here is my reasoning for introducing a duplicated constant (MENU_SIBLING_LOCAL_TASK and MENU_LOCAL_ACTION have the same value):

We are attempting to replace the display of menu local actions on their parent page (the functionality of menu_local_actions())

We are NOT attempting to rewrite _menu_router_build(), where it checks hook_menu() in order to build the breadcrumbs and decide what tabs to show on the action's page itself.

Once this issue is in, and all existing MENU_LOCAL_ACTIONs are converted, we will still be left with a hook_menu() entry for that. Yet it will not be for anything action-related, just about its behavior as a pseudo-local-task. Hence MENU_SIBLING_LOCAL_TASK.

The added benefit will be knowing which actions remain (since they will have the old constant).

Crell’s picture

+++ b/core/modules/system/system.api.php
@@ -865,6 +865,29 @@ function hook_menu() {
+ * @return array
+ *   An associative array keyed by the local action's route name, containing:
+ *   - title: The title of the local action.
+ *   - routes: An array of route names for this action to be display on.
+ */
+function hook_local_actions_info() {
+  return array(
+    'mymodule.route.action' => array(
+      'title' => 'Perform local action',
+      'appears_on' => array(
+        'mymodule.other_route',
+        'mymodule.other_other_route',

Docblock is out of date. Should say "appears_on", not "routes".

Tim's explanation of the new/renamed constant makes sense. It's basically just there for breadcrumbs/tabs while viewing the route that is the local action. I am not convinced MENU_SIBLING_LOCAL_TASK is the best name for it, but... hard problems.

Otherwise this works for me.

tim.plunkett’s picture

Fixed the docs, and added another conversion.

dawehner’s picture

Status: Needs review » Needs work
+++ b/core/includes/menu.incundefined
@@ -2215,6 +2223,19 @@ function menu_secondary_local_tasks() {
+  foreach (Drupal::moduleHandler()->invokeAll('local_actions_info') as $route_name => $route_info) {
+    if (in_array($router_item['route_name'], $route_info['appears_on'])) {

Maybe we should come later here, as this maybe not scale if there are a lot of local actions defined.

+++ b/core/includes/menu.incundefined
@@ -2215,6 +2223,19 @@ function menu_secondary_local_tasks() {
+      $route_path = _menu_router_translate_route($route_name);
+      $links['actions'][$route_path] = array(
+        '#theme' => 'menu_local_action',

maybe it would be nice to have some access checking on there ...

+++ b/core/includes/menu.incundefined
@@ -2215,6 +2223,19 @@ function menu_secondary_local_tasks() {
+          'title' => $route_info['title'],

... We want to be able to translate the title ...

+++ b/core/modules/picture/picture.moduleundefined
@@ -48,6 +48,20 @@ function picture_permission() {
+    'picture_mapping_page_add' => array(

Let's move the route_name to the definition, as it's for example more consistent to the way hook_menu looks at the moment.

tim.plunkett’s picture

Status: Needs work » Needs review
FileSize
4.14 KB
10.49 KB

Fixed all of those but the first, where I added a @todo to consider adding static caching later.

dawehner’s picture

Status: Needs review » Reviewed & tested by the community
+++ b/core/includes/theme.incundefined
@@ -2900,7 +2900,7 @@ function template_preprocess_page(&$variables) {
+  $variables['action_links']      = menu_get_local_actions();

I will not bitch about silly spaces!

+++ b/core/modules/system/tests/modules/menu_test/menu_test.moduleundefined
@@ -432,13 +432,13 @@ function menu_test_menu() {
- * Implements hook_local_actions_info().
+ * Implements hook_local_actions().

Good idea!

tim.plunkett’s picture

#26: local-action-1908756-26.patch queued for re-testing.

alexpott’s picture

Title: Separate Action Links (MENU_LOCAL_ACTION) from hook_menu() » Change notice: Separate Action Links (MENU_LOCAL_ACTION) from hook_menu()
Priority: Normal » Critical
Status: Reviewed & tested by the community » Active

Committed 00fdcd3 and pushed to 8.x. Thanks!

tstoeckler’s picture

+++ b/core/modules/system/tests/modules/menu_test/menu_test.module
@@ -416,10 +416,37 @@ function menu_test_menu() {
+ * Implements hook_local_actions().

Any specific reason why this was changed from hook_local_action_info()? It seems the latter is a standard throughout core, that would make sense following here, IMO.

tim.plunkett’s picture

We're actually in the midst of killing info hooks. In the above patches it was named that, I was asked to rename it at Drupalcon.

tstoeckler’s picture

Hmm... still seems strange to not apply an existing pattern just because the whole concept is sort of deprecated-ish. Not a big deal, either way, though, so I'll shut up.

tim.plunkett’s picture

tim.plunkett’s picture

Assigned: tim.plunkett » Unassigned
Status: Active » Needs review
jibran’s picture

Title: Change notice: Separate Action Links (MENU_LOCAL_ACTION) from hook_menu() » Separate Action Links (MENU_LOCAL_ACTION) from hook_menu()
Priority: Critical » Normal
Status: Needs review » Fixed

Change notice looks good.

Automatically closed -- issue fixed for 2 weeks with no activity.