Page Manager in Drupal 7 allows you to configure a menu link for a page, this can be either a Tab (Local Task/Default Local Task), a Menu Item or a Local Action.

I suggest we look at how views provides this functionality a use that.

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

tim.plunkett’s picture

Title: Add menu link options » Add ability to provide local actions and tasks

Local tasks and actions are plugins, and have stable APIs.
Menu links are currently entities, but are in flux: #2227441: New plan, Phase 1:Review the architecture and overall implementation proposal for menu links as plugins

I think they should be split to another issue.

rlmumford’s picture

Assigned: Unassigned » rlmumford

I've started working on this, hopefully will have a patch up this evening.

rlmumford’s picture

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

Here's a patch. No tests yet, but both local actions and local tasks should work work.

rlmumford’s picture

FileSize
13.61 KB
2.21 KB

Rerolled against head.

tim.plunkett’s picture

  1. +++ b/page_manager.module
    @@ -15,3 +18,21 @@ function page_manager_permission() {
    +/**
    + * Implements hook_local_tasks_alter().
    + */
    +function page_manager_local_tasks_alter(&$local_tasks) {
    +  $container = \Drupal::getContainer();
    +  $local_task = PageManagerLocalTask::create($container, 'page_manager_page');
    +  $local_task->alterLocalTasks($local_tasks);
    +}
    +
    +/**
    + * Implements hook_menu_local_actions_alter().
    + */
    +function page_manager_menu_local_actions_alter(&$local_actions) {
    +  $container = \Drupal::getContainer();
    +  $local_action = PageManagerLocalAction::create($container, 'page_manager_page');
    +  $local_action->alterLocalActions($local_actions);
    +}
    

    Ughhhh I *hate* that we have to do this. /me shakes fist at core

  2. +++ b/src/Entity/Page.php
    @@ -70,6 +70,13 @@ class Page extends ConfigEntityBase implements PageInterface {
    +  protected $menu = array();
    
    @@ -167,6 +185,13 @@ class Page extends ConfigEntityBase implements PageInterface {
    +      $this->menu = array(
    +        'type' => 'none',
    +      );
    

    Couldn't these be combined?

  3. +++ b/src/Plugin/Derivative/PageManagerLocalAction.php
    @@ -0,0 +1,117 @@
    +        $route_name = "page_manager.page_view_$entity_id";
    +        // @todo: Add a routeName method to the page entity?
    

    Yeahhhh this is tricky. If you look at PageManagerRoutes, we do work to ensure that existing pages are properly taken over.

  4. +++ b/src/Plugin/Derivative/PageManagerLocalAction.php
    @@ -0,0 +1,117 @@
    +        $pattern = str_replace('%', '{}', $path);
    

    Do we actually need to do this? In RouteParamContext I have $routes = $this->routeProvider->getRoutesByPattern($page->getPath())->all();

  5. +++ b/src/Plugin/Derivative/PageManagerLocalTask.php
    @@ -0,0 +1,121 @@
    +    foreach ($this->entityStorage->loadMultiple() as $entity_id => $entity) {
    ...
    +    foreach ($this->entityStorage->loadMultiple() as $entity_id => $entity) {
    

    I think we should mimic Views' RouteSubscriber and encapsulate this in a protected method, storing them between the two methods.

Let's go with tests next, it will help clarify what we have covered and what we still need.

@rlmumford++

rlmumford’s picture

FileSize
23.55 KB

Here's a patch with some tests. I think they're going to fail, but the tests already in 8.x-1.x fail on my local.

tim.plunkett’s picture

Assigned: rlmumford » Unassigned
Status: Needs review » Needs work
Issue tags: -Needs tests

This still needs to address my comments from #5. Unassigning for now since there is a sprint coming up, but @rlmumford if you want it back, assign it back.

blueminds’s picture

Assigned: Unassigned » blueminds

Going to work on this issue as part of the layout sprint https://groups.drupal.org/node/423448

blueminds’s picture

Status: Needs work » Needs review
FileSize
23.7 KB
5.74 KB

Addressed #5.2/4/5 Not sure what to do with #5.3

cgalli’s picture

Status: Needs review » Needs work

Installed and tested.

Works well, based on url/paths. Can be applied on own default paths (pm/; pm/tab1; pm/tab2) or on existing ones (admin/tab1). It also works with wildcards /node/%/local1).

For local actions it should be possible to attach them to several paths (analog to the local_action.yml) . This could be achieved by adding a path list or pattern list to the menu definition.

And it needs some help text/documentation to be understood by the user.

blueminds’s picture

Status: Needs work » Needs review
FileSize
26.06 KB
4.8 KB

Implemented the ability to attach an action link to multiple pages. See screenshot for the UX details.

blueminds’s picture

rlmumford’s picture

FileSize
26.73 KB

Rerolled against head. (Patch no longer applied)

rlmumford’s picture

FileSize
26.05 KB
1.34 KB

Remove some things that got muddled in the re-base.

rlmumford’s picture

FileSize
28.77 KB
7.66 KB

Here's a patch that stores the route names in a state variable so that they can be reused in the the Local Task and Local Action derivatives. This is how views solves the same problem.

Status: Needs review » Needs work

The last submitted patch, 15: 2273531-15.patch, failed testing.

rlmumford’s picture

This is weird. The tests passed locally for me.

rlmumford’s picture

FileSize
30.02 KB
1.24 KB

Try this

rlmumford’s picture

Status: Needs work » Needs review
tim.plunkett’s picture

Status: Needs review » Needs work

Really sorry for letting this sit. It needs a reroll now, unfortunately.

sylus’s picture

+++ b/config/schema/page_manager.schema.yml
index 66724f2..a3eef8a 100644
--- a/page_manager.local_actions.yml

--- a/page_manager.local_actions.yml
+++ b/page_manager.local_actions.yml

+++ b/page_manager.local_actions.yml
+++ b/page_manager.local_actions.yml
@@ -3,3 +3,6 @@ page_manager.page_add:

@@ -3,3 +3,6 @@ page_manager.page_add:
+page_manager_page:
+  class: Drupal\Core\Menu\LocalActionDefault
+  derivative: \Drupal\page_manager\Plugin\Derivative\PageManagerLocalAction

+++ b/page_manager.module
@@ -15,3 +18,21 @@ function page_manager_permission() {
+ * Implements hook_local_tasks_alter().
+ */
+function page_manager_local_tasks_alter(&$local_tasks) {
+  $container = \Drupal::getContainer();
+  $local_task = PageManagerLocalTask::create($container, 'page_manager_page');
+  $local_task->alterLocalTasks($local_tasks);
+}
+
+/**
+ * Implements hook_menu_local_actions_alter().
+ */
+function page_manager_menu_local_actions_alter(&$local_actions) {
+  $container = \Drupal::getContainer();
+  $local_action = PageManagerLocalAction::create($container, 'page_manager_page');
+  $local_action->alterLocalActions($local_actions);
+}

Does the following code still looks like this with all the event subscriber work? Looking around core I still don't see a better way?

I'd love to tackle this issue but would need some instruction on how best to approach this given the codebase is entirely different since this was last looked at.

lucas.constantino’s picture

Any news on this? This is something badly needed :) I also tried to figure out how to reroll, but code base is completely different :(

cosolom’s picture

Version: 8.x-1.x-dev » 8.x-4.x-dev
saemideluxe’s picture

I am also looking for news on this. Any progress?

Christopher Riley’s picture

Is this a feature that we can just not look forward to having or is it possible to get it functional?

joel_osc’s picture

Is there anyone looking into this for 8.7? IMHO this is quite an important piece of functionality.

manuel.adan’s picture

Assigned: blueminds » Unassigned

I'm with you that it is a really required feature. I trying to convince my boss of spending more time in contrib, but no case by now ;)

In the mean time, menu links can be added in a custom module as follows:

"your_module.links.menu.yml":

your_module.you_menu_link_id:
  title: 'Menu item'
  description: 'An example menu item.'
  menu_name: some_menu
  route_name: page_manager.page_id-variant_id
  weight: 10

Drupal Console can be used to get a list of the available page manager pages in your system:

$ console debug:router | grep "page_manager.page"

joel_osc’s picture

Thanks @manuel.adan! I was just looking into how to do this. Appreciate the help.

joel_osc’s picture

Actually, my menu requirements are a bit different as I am trying to add a tabs (menu local tasks) to a node view (example /node/43/my-tab). Any advice is appreciated.

joel_osc’s picture

If anyone else runs into this, you need to create a dynamic local task... I used entity_clone as an example and then trimmer it down to what I needed. I would recommend reading this: https://www.drupal.org/docs/8/api/menu-api/providing-module-defined-loca... and then create a mymodule.links.task.yml file to generate the local tasks in the derivative class placed at src/Plugin/Derivative/DynamicLocalTasks.php as follows:

mymodule.local_tasks:
  deriver: 'Drupal\mymodule\Plugin\Derivative\DynamicLocalTasks'
  weight: 100

And then create the deriver something like as follows:

/**
 * Defines dynamic local tasks.
 */
class DynamicLocalTasks extends DeriverBase implements ContainerDeriverInterface {

  /**
   * The entity type manager.
   *
   * @var \Drupal\Core\Entity\EntityTypeManagerInterface
   */
  protected $entityTypeManager;

  /**
   * The translation manager.
   *
   * @var \Drupal\Core\StringTranslation\TranslationManager
   */
  protected $translationManager;

  /**
   * Constructs a new DynamicLocalTasks.
   *
   * @param \Drupal\Core\Entity\EntityTypeManagerInterface $entity_type_manager
   *   The entity type manager.
   * @param \Drupal\Core\StringTranslation\TranslationManager $string_translation
   *   The translation manager.
   */
  public function __construct(EntityTypeManagerInterface $entity_type_manager, TranslationManager $string_translation) {
    $this->entityTypeManager = $entity_type_manager;
    $this->translationManager = $string_translation;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container, $base_plugin_id) {
    return new static(
      $container->get('entity_type.manager'),
      $container->get('string_translation')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getDerivativeDefinitions($base_plugin_definition) {
    $this->derivatives = [];

    $this->derivatives["node.example_tab"] = [
      'route_name' => "page_manager.page_view_example_tab_example_tab-panels_variant-0",
      'title' => $this->translationManager->translate('My tab'),
      'base_route' => "entity.node.canonical",
      'weight' => 100,
    ];

    return $this->derivatives;
  }

}
geek-merlin’s picture

Status: Needs work » Needs review
FileSize
21.22 KB

Patch flying in with a brain-dead reroll of #18. I'm quite impressed that this is even possible after 6 years. Let's see what breaks.

TODO: Port the simpletests from #18.

Status: Needs review » Needs work

The last submitted patch, 31: page_manager-2273531-31-local-tasks.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

geek-merlin’s picture

FileSize
22.33 KB

Missed some API runaways.

geek-merlin’s picture

Status: Needs work » Needs review
andypost’s picture

Nice to see this resurrected)

geek-merlin’s picture

Status: Needs review » Needs work

I tested this locally and besides showing the config form it's not yet useful. So NW.

andypost’s picture

dsnopek’s picture

Status: Needs work » Closed (duplicate)
Related issues: +#2620036: Allow pages to have menu items

I'm closing this one as a duplicate of #2620036: Allow pages to have menu items.

That issue also provides support for local tasks and actions (in addition to normal menu items), and it has an up-to-date, working patch.

Looking at the latest patch on this issue, there are some small features here than aren't implemented there, for example, setting additional visibility paths on local actions. However, I think it'd be easier to add those into the patch on the other issue (or in a follow-up) rather than trying to resurrect this one.