This is a few years old but I thought I would throw in an answer on how to do this with a very light weight custom module. This answer would be applicable to Drupal 8, 9, and 10.
I am using Drupal 8 and I am a little bit confused that there is no
core functionality to restrict the access to some nodes based on roles
or users.
Yes, welcome to the world of Drupal! Drupal doesn't have an out of the box UI for restricting access to nodes based on roles.
I found PageAccess, which is marked as unsecure and ACL/Access Control
which are both dev and not working on my system.
No comment on these modules. I find contributed modules end up giving you more than you need. If you are not comfortable with coding than a good module that does what you want is encouraged.
Isn't there any option to do so? I need the private sector on my site
and can't believe there is no way in Drupal.
Hope you can help me, because if not I have to redo the whole site
with another wcms.
You have likely found a solution that works for you but for someone looking in the future here is how you can do it with a custom module.
- Name and place your module
- Let Drupal know about it
- Create a .module file
Create a .module file
Within your custom module root folder, the same place your .info
file is, create a new file with your module name ending with .module
. i.e. custom-module/custom-module.module
)
Within that file add the following code:
<?php
/**
* @file
* Contains custom_module.module
*/
// Allows you to load the node's info
use Drupal\node\NodeInterface;
// Allows you to load and change access attributes
use Drupal\Core\Access\AccessResult;
/**
* Implements hook_ENTITY_TYPE_access().
*/
function custom_module_node_access(NodeInterface $node, $op, AccountInterface $account) {
/**
* The $node argument can be either a $node object or a machine name of
* node's content type. It is called multiple times during a page load, so
* it is enough if you perform the check once you get the object.
*
* If $node is an object, is a custom_content_type, and the operation is
* view get the role continue processing or return access neutral. If the
* current user does not have the paid_user role and the node is published
* return access forbidden.
*/
if (is_object($node) && $node->getType() == 'custom_content_type' && $op == 'view' ) {
// Get the roles of the current user.
$roles = \Drupal::currentUser()->getRoles();
// If the current user does not have the paid_user role deny access.
if (!in_array('paid_user', $roles)) {
return AccessResult::forbidden();
}
}
// Return a neutral opinion otherwise.
return AccessResult::neutral();
}
About the code... The comments in the code already explain quite a bit but there are a few things that I intentionally left out of the comments as they aren't really comment worthy.
Drupal has a standard way of doing things. Either a node is a draft or published. Published for the most part means it is viewable by the public and draft means that it isn't. Using the hook_ENTITY_TYPE_access() function I can change that functionality.
By checking if the node is an object it only triggers the code on the page once. Likely, you only want to limit viewer to a specific content type. That is why I am checking for custom_content_type
. That would be replaced with the machine name of your content type. I am also want the $op
or operation the be view to continue processing. These checks narrow down the scope to what access I want to affect.
The return AccessResult::neutral();
at the end is best practice if there is no change to the access results.