yorkshirepudding's picture

I'm thinking of using hidden paths to have content aimed at site editors and to avoid using a content access module.  However, I wouldn't want the hidden paths message ("Only people with the View hidden paths permission will be able to view this page. Everyone else will receive a "Page not found" error")  to show up on each page.  Is there a way to write a custom module that would disable it for particular content types?

The function it is set is /core/modules/node/node.module > node_page_view()

 

 

Accepted answer

I would write a custom module that implements hook_node_view_alter().

Because of the way Backdrop/D7 handle system messages, the only way to remove ONLY the info message related to the hidden path is a bit hacky. It requires you to unset a specific array item in the $_SESSION array. See below

function MYMODULE_node_view_alter($build) {
  $type = node_type_get_type($build['#node']);

  if ($type->settings['hidden_path']) {
    $message = t('Only people with the View hidden paths permission will be able to view this page. Everyone else will receive a "Page not found" error.');
    $info_messages = !empty($_SESSION['messages']['info']) ? $_SESSION['messages']['info'] : array();
    foreach ($info_messages as $delta => $info_message) {
      if (strpos($info_message, $message) !== FALSE) {
        unset($_SESSION['messages']['info'][$delta]);
      }
    }
    if (empty($_SESSION['messages']['info'])) {
      unset($_SESSION['messages']['info']);
    }
  }
}
 

Comments

I would write a custom module that implements hook_node_view_alter().

Because of the way Backdrop/D7 handle system messages, the only way to remove ONLY the info message related to the hidden path is a bit hacky. It requires you to unset a specific array item in the $_SESSION array. See below

function MYMODULE_node_view_alter($build) {
  $type = node_type_get_type($build['#node']);

  if ($type->settings['hidden_path']) {
    $message = t('Only people with the View hidden paths permission will be able to view this page. Everyone else will receive a "Page not found" error.');
    $info_messages = !empty($_SESSION['messages']['info']) ? $_SESSION['messages']['info'] : array();
    foreach ($info_messages as $delta => $info_message) {
      if (strpos($info_message, $message) !== FALSE) {
        unset($_SESSION['messages']['info'][$delta]);
      }
    }
    if (empty($_SESSION['messages']['info'])) {
      unset($_SESSION['messages']['info']);
    }
  }
}
 

Another idea.

Could you create a custom layout for this Hidden Path content type and remove the system notifications block from the layout for that page?

Of course, this would hide all notifications on those pages, but it might work.

EDIT: Nevermind, this does not work. I tested it and these notifications show up anyway, even without a block.

Thank you @argiepiano - that is perfect

Anyone else following this, note that the forum content editor takes the <em> and </em> around the "View hidden paths" and turns it into formatting so you'll need to put that back into your code.

I added an if ($type->type === 'content_type') {} around it so it only applied to one content type.

Seems to be an awkward ways to avoid using a content access module :).

Seems to be an awkward ways to avoid using a content access module :).

I don't follow. This doesn't in any way restrict or grant access. It simply removes an info message.

To add to @argiepiano's point; 

I've been following the discussion in #5634 on possible/probable performance impacts of content access modules :

https://github.com/backdrop/backdrop-issues/issues/5634#issuecomment-125...

In this particular use case, the content type is not sensitive (user guide for editors) and I don't need fine grain control over viewing own/any.

Hidden path by itself in theory does the job but the users would get confused by the message and it's not necessary. @argiepiano's solution just hides that message. 

@argiepiano I was referring to the main goal of restricting access to a content type. I was thinking that if the solution is to write a custom module there's a more direct way to implement access control. Though the solution does work so feel free to ignore me!

@yorkshirepudding, Nate's comment about performance is mostly relevant to having a default way of applying access grants to nodes in core (I think). For simple solutions one can create a custom module to restrict content to a particular role without involving access grants. For example, one could just use hook_node_view_alter() and check a custom permission there, which is basically how hidden_path does it. With little impact on performance.

The benefit of using your hidden path approach though would be that we've already also dealt with excluding those content types from core search results and in views.

Thanks for explaining @herb

I was actually thinking along the same lines and have created a simple module that gives the 'view any content_type content' permission and restricts just by checking the permission.  I think hook_node_grants only seems to be needed for node level access control, which includes the 'view own content_type content' type permissions or specific node access requirements.

As you refer to in your comment this doesn't by default sort out the issues with views, layout (not sure what this one affects) and search results.  Also menus are not dealt with.   In my use case, I can easily work around this by excluding the entire content type from search and only including in views that are restricted.