4

I am setting up a relatively simple website using Drupal 8. There are several different content types. Within each content type I would like some content to be available to anonymous users and some only available to authenticated users (i.e. 'member only' content).

I would like to add a simple tick box field that would control whether the content was publicly available or not. i.e. if the field is ticked then it is available to anyone but if it isn't ticked then it is only available to members.

I have managed to get some way to achieving this by using Node View Permissions and creating a duplicate of each content type - both have the same fields but one is visible to anonymous users and the other is only visible to authenticated users. This works, but isn't very satisfactory because it requires duplicate content types. I would prefer to have a single content type with a field that controls view permissions.

Do you have any suggestions?

3 Answers 3

7

You could use a programmatically solution using hook_node_access(), in this example the field_YOURFIELD is a checkbox.

/**
 * Implements hook_node_access().
 */
function MYMODULE_node_access(\Drupal\node\NodeInterface $node, $op, \Drupal\Core\Session\AccountInterface $account) {
  $access = new \Drupal\Core\Access\AccessResultNeutral();
  if ($node->hasField('field_YOURFIELD')) {
    $field = $node->get('field_YOURFIELD')->getString();
    if (empty($field) && $account->id() != $node->getOwnerId()) {
      $access = new \Drupal\Core\Access\AccessResultForbidden();
    }
  }
  $access->addCacheableDependency($field);
  $access->addCacheableDependency($node);
  return $access;
}
2

There are a few options.

If it's really just that checkbox and won't get more complicated over time and writing code is an option, then you can write a custom views filter plugin that only adds a condition if the user is not a member.

Such a plugin would do something like this in the query method and extend from the one that is used by default, and then you use hook_views_data_alter() to use your plugin on your field instead of that one, or add your own views data definition.

/**
 * {@inheritdoc}
 */
public function query() {
  // Only add the condition if the current user is not authenticated.
  if (\Drupal::currentUser()->isAnonymous()) {
    parent::query();
  }
}

The other option is to rely on a node access module like https://www.drupal.org/project/content_access. That has a development release for Drupal 8, I'm not sure how usable it is already. There might also be alternative modules that do something, or you can implement one yourself. Drupal core has a fairly simple node_access_test test module that makes nodes private based on a "private" field, you could base yours on that.

2

After further research I opted for the following approach.

  • Install Taxonomy Access Control Lite
  • Create a new vocabulary in taxonomy - e.g. 'Access control'
  • Create a new term in this vocabulary - e.g. 'Member only'
  • Configure Taxonomy Access Control Lite to make content tagged with this term viewable to the roles you want (e.g. authenticated users)
  • Add a taxonomy field with this vocabulary to each content type that you want to restrict access to

After following these steps I have a simple select field called 'Access control' which can be set to ' - None - ' or 'Member only'. The content will be displayed publicly or only to members depending on the option chosen.

Notes

  1. I looked at another module that works in a similar way: Permissions by Term. This looks like a good alternative.
  2. I opted to display the 'Access control' field as a select list as I only needed one selection. It would be easy enough to use tick boxes instead if you allowed multiple selections for this field.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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