5

I have a node type 'faq'. For node type 'faq' I need to remove the tab 'node clone'.

For that I have done the following codes. In node_clone.routing.yml I have the following code

      
node_clone.prepopulate_node:  
  path: '/node/{node}/clone/prepopulate'  
  defaults:  
    _title: 'Clone content'  
    _controller: 'node_clone.form_controller:getContentResult'  
  requirements:  
    _custom_access: 'node_clone.form_controller:access'  
    #_node_add_access: 'node:{node_type}'  
    node: '\d+'  
  options:  
    _node_operation_route: TRUE  
    parameters:  
      node:  
        type: 'entity:node'  

In my controller file

public function access(AccountInterface $account, NodeInterface $node) {

      $node_type = ($node->getType());
      if($node_type=="faq")
      {
          $access = new AccessResultForbidden();

      }

    if ($account->hasPermission('clone node') || ($node->uid->value === $account->id() && $account->hasPermission('clone own nodes'))) {
      $access = new AccessResultAllowed();
    }

    else {
      $access = new AccessResultForbidden();
    }
    $access->addCacheableDependency($node);
    $access->cachePerPermissions();
    if ($access->isAllowed()) {
      $access = $access->andIf($node->access('view', $account, TRUE));
    }
    if ($access->isAllowed()) {
      $node_type = NodeType::load($node->getType());
      $access = $access->andIf($this->nodeAddAccessCheck->access($account, $node_type));
    }
    return $access;
  }

Please help me to find out what's wrong with my code? Is this enough or I should do something else?

10

To completely remove the tab from all pages you can use hook_local_tasks_alter().

function mymodule_local_tasks_alter(&$local_tasks) {
  unset($local_tasks['local_task_to_remove']);
}

Where local_task_to_remove is the tab you want to remove.

To have it removed from some pages you could use hook_menu_local_tasks_alter() instead. Something like:

function mymodule_menu_local_tasks_alter(&$data, $route_name) {
  $routes = ['entity.entity_view_display.node.default', ...]; // put other routes in place of '...'
  if (in_array($route_name, $routes)) {
    unset($data['tabs'][0]['local_task_to_remove']); 
  }
}
  • Since 8.5, hook_menu_local_tasks_alter() gives you &$cacheability metadata as a third-parameter, so it's a good idea to check you have the correct cache contexts etc. – William Turrell Oct 31 '18 at 12:22
1

Your $access variable is overwritten with the original Node Clone logic that looks at whether the user has the permission. Hence, it will never return an AccessResultForbidden object on the faq content type and deny access to the route.

You should avoid hacking the Node Clone module, the module has incomplete feature to add/exclude node types (the project is still in the dev phase). Looking at the project, it looks like all that's needed is update the setting form (to update the per-node type settings) and _custom_access function to read in those settings. You should utilize that and create a patch for the project if you're going down that that route.

However, if you're insistent on overriding Node Clone's route permissions, you can override it's access permission using a RouteSubscriber:

  // see link for an example RouteSubscriber.php & example.services.yml

  /**
   * Inside your module's RouteSubscriber::alterRoutes method
   */
  public function alterRoutes(RouteCollection $collection) {
    if ($route = $collection->get('node_clone.prepopulate_node')) {
      $route->setRequirement('_custom_access', '\Drupal\example\Routing\RouteSubscriber::nodeCloneAccessOverride');
    }
  }

  /**
   * An example override _custom_access override.
   */
  public static function nodeCloneAccessOverride(AccountInterface $account, NodeInterface $node) {
    if ($node->getType() == 'faq') {
      return new AccessResultForbidden();
    }
    else {
      return new AccessResultAllowed();
    }
  }
  • Thanks for this - there aren't a lot of examples of overriding permissions in another module where you also need to do so based on user role/permissions. (Note, if you first attempt to use \Drupal::currentUser() directly within alterRoutes, it doesn't throw an error, it'll return an anonymous user regardless of who's actually logged in.) – William Turrell Sep 21 '18 at 9:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.