Some sites want to show node teasers on the front page while restricting body access to authorized users. The idea is to encourage anonymous users to log in or to encourage authorized users to subscribe. Out of the box Drupal node access is all or nothing.

There are several ways to accomplish this:

Disabling SQL rewriting in a view

Create a view that uses the fields you wish to display for the teaser. Then, under Query settings, select the Disable SQL rewriting checkbox. (Views 3)

Views Ignore Node Permissions

See Views Ignore Node Permissions for the module details.

See Creating a Node View Which Bypasses Access Restrictions for an explanation of how this works. Note that it runs the SQL query twice, so is a little inefficient.

Code your own access with PHP

PHP Solution 1

  1. Navigate to Home > Administer > User management .
  2. Find the node module section and click the check boxes for anonymous user and authorized user. This grants access to all nodes for all users.
  3. Make sure to enable PHP filter in the Core-optional section at Home > Administer > Site building > Modules.
  4. Add code to each node you want to protect. It might look something like:

*html and text here accessible to anonymous*

global $user;
$privileged_roles = array ('authenticated user');
if (count (array_intersect ($privileged_roles, $user->roles)) > 0) :

*here we write text and html accessible only to authenticated users*

endif;

Pros: This technique allows you to display text customized for different roles in many ways

Cons: This technique can be error prone and would be hard to manage if protecting lots of nodes. It is only useful to people who know a bit of PHP.

PHP Solution 2

In this case we will create our own security check and will make all content initially available to everyone. The reason for this is because Drupal Security system uses a YES or NO access mode, and there is no, SHOW JUST A BIT.

What this does is checks access to the node using you own test, and then, if access is restricted changes the FULL BODY for the TEASER using HOOK_nodeapi()

  1. Create you own module (or use one you already created)
  2. implement HOOK_nodeapi()
  3. Create your own access rule, there are many ways of doing it, the result for the test should be a BOOLEAN. in my case I have a CCK field which stores the profiles that have access to the node, I then compare the current user profiles againts the ones on the CCK filed. I store the result in a variable called $access, and this is used in the HOOK_nodeapi implementation.

This is how my implementation looks like

function HOOK_nodeapi(&$node, $op, $a3 = NULL, $a4  = NULL){
...
  switch ($op) {
  ...
    case 'view':
      $access = YOUR ACCESS TEST;
      if($access == 0){
        $node->content['body']['#value']=check_markup($node->teaser, $node->format, FALSE);
        break;
      }
  ...
  }
...
}

It is important to use check_markup(), otherwise you will get the unfiltered HTML that could break you page. Or if the content includes PHP, it wouldn't get parsed.

You can also hide any other field by changing the access property in $node

$node->content['FIELD_TO_HIDE']['#access']=0;

The good things about this module

  • It is a set and forget module. Once it is installed it will work forever and ever.
  • SEO friendly: THIS IS A BIG PLUS: Google (and well, Yahoo and Bing) will see your snippet, and will index it, and people will be able to find it (ONLY YOUR SNIPPET), so be happy knowing that you can be found!
  • Server response will be 200, which to me is good because I want Google knowing about the page. You can change this by sending a different response (403: Forbidden) you will have to research that by yourself (sorry)
  • Views using "node" row style will follow this rule.

Considerations with this solution

  • You are bypassing Drupal Access Control, which means that technically users have access to the content, they just won't be able to see it
  • Your internal search index will change depending on your cron settings. If you run cron as an anonymous user, content accessible by anonymous user will be indexed. If you run cron as X user, content accessible by X user will be indexed. I recommend you set cron to be run as a super admin, this way your search results will be more accurate, and it is safe, users won't see anything they are not allowed to.
    • This applies to default Search module, not tested with other modules
    • If you change your cron user, you will have to re-index you site for changes to take effext.
    • You can use DRUSH to run cron with a specific user (e.g. "drush -u 1 cron" will run cron as super admin)
  • Views using "field" row style will not follow this rule.

Use the Premium module

Check out Premium for details. I haven't tried this out yet. Feel free to edit this section and/or add more sections that describe other modules that solve this problem.

From HawkDrupal: As of early January 2010, Premium by itself does not do the job. There's been no official release for Drupal 6, and the module has seemed to be abandoned for months. Premium as patched by "liquidcms" (http://drupal.org/node/642392) gets much closer but it is still incomplete. So it's not clear if or when some version of Premium will be the content management solution that so many Drupal users need.

Using Views and Nodequeue

This technique was discovered accidentally while using Nodequeue to put nodes in a specific order. If you have relatively stable front page content, want the teasers presented in a fixed order and want most of your site inaccessible to anonymous users this is a pretty easy solution.

  1. Navigate to Home > Administer > User management
  2. Find the node module section and click the check boxes for authorized user. Make sure anonymous user is NOT checked. This prohibits anonymous users from accessing any node.
  3. Download, install and enable the Views and Nodequeue modules.
  4. Create a Nodequeue, add the pages that have the teasers you want on the front page.
  5. Views comes with a view named frontpage, edit it ( Home > Administer > Site building > Views ) to use Relationships Nodequeue: Queue, Sort criteria (queue) Nodequeue Position asc and Filters Node: Promoted to front page Yes, Node: Published: Yes
  6. Home > Administer > Site configuration > Site-information was edited so the default front page refers to the frontpage view's path: frontpage

Pros: It is easy, especially if you want to use Nodequeue anyway to order the teasers on your home page.

Cons: It seems limited in its ability to control other pages, blocks and so on.

This technique was tested using Drupal v 6.14 with only the modules Views 6.x-2.6 and Nodequeue 6.x-2.4. Test website: http://wohlforth.com/DrupalViewNQ/

Comments

hixster’s picture

I'm very grateful to have found this page as I'd been searching for a solution to this for ages.

I wanted to contribute another solution. In another thread I someone suggested using CCK redirection field.

http://drupal.org/project/cck_redirection

1) You can create a new node type called 'redirection_url' and add a CCK redirection field to it.
a) The CCK redirection field has a number of options , to redirect, divert etc..
2) The new 'redirection_url' node can be have permissions set so all users can view it. ( i'm using the access control module to set permissions in a per node or content type basis)
3) These 'redirection_url' nodes can be added to views as teasers and menus (which is what i required) or whatever you want.
4) So, back to adding info the the 'redirection_url' node.In the redirection field enter the URL of the node you redirect to which is protected by regular permissions.
5) when someone visit the link or teaser created in a view or menu they get redirected to the protected page
6) I use loginTobogan to display a login page instead of an 'unauthorised page'

Needs a bit of setting up but it works.

Wouldn't it be nice if Drupal would provided a switch in a node with these options..

O Users can view this node but require xRole to view node body - Will Display's teasers and links to node.
O Users with the following permission cannot view this node at all.

Drupal Web Designers Surrey South East England www.lightflows.co.uk

Yuri’s picture

http://drupal.org/project/cck_teaser_field (or Views node Field http://drupal.org/project/viewsnodefield )
in combination with: http://drupal.org/project/cck_field_perms
Add the fields to Ubercart product nodes and install the uc_roles module.
Safe and flexible.

intrafusion’s picture

You can also use the node template files to accomplish this, create a new template file for your node type i.e. node-type.tpl.php

  global $user;
  $privileged_roles = array('authenticated user');
  if ($page && count(array_intersect($privileged_roles, $user->roles)) == 0) {
    // Your denied code/message goes here.
  } else {
    // The standard node.tpl.php code goes here
  }
jm.federico’s picture

It is safer to do it via hook_nodapi. That way you make sure that content won't be passed anywhere, not only to the final screen display. For instance when search results are being shown, your node-type.tpl.php won't be used, hence you could end up giving away content you do not want to show.

jm.federico’s picture

If you want to see a real live example fo PHP solution #2, go to www.intermedium.com.au

It uses PHP solution #2.

It also uses Ubercart to allow users buy a PDF version of the article if they don't have access to it.

Sborsody’s picture

These two solutions are essentially the same thing. Premium uses hook_nodeapi.

lgb’s picture

I was able to use PHP Solution #1 in conjunction with Content Templates to simplify things. This turned out to be a great and easy solution...many thanks!

I'm curious (since it wasn't mentioned in the write-up) if there are any SEO snags with this? The teaser output looks exposed and fine in the SEO tool, but...I'm definitely not an SEO expert. Thanks in advance for any input.

gberm’s picture

Can this work with Drupal 7?

jm.federico’s picture

What exactly are you asking about?
There are different ways of doing it, so, some may work, some may not!

PHP options will work!

mpoulsen’s picture

Here is my solution:

/**
 * Implementation of hook_node_access().
 */
function YOUR_MODULE_node_access($node, $op, $account) {
  if (isset($node->nid) && arg(0) == 'node' && is_numeric(arg(1)) && $node->nid == arg(1)) {

    // Deny anonymous access to certain node types.
    $deny_for = array('YOUR_CONTENT_TYPES');
    if (in_array($node->type, $deny_for) && user_is_anonymous()) {
      return NODE_ACCESS_DENY;
    }
  }
}
Hadi Farnoud’s picture

thanks for this. actually I was looking for something like Premium module.

xoomalec’s picture

thanks .
i am happy for this .

----------------------------
سایت ساز
فروشگاه ساز
اپلیکیشن ساز
سایت ساز پوپش یکی از بهترین نمونه ای طراحی سایت به روش درگ اند دارپ میباشد.