Last updated January 8, 2009. Created on May 17, 2006.
Edited by Michelle, Shai, NancyDru, sepeck. Log in to edit this page.

As of Drupal 5.x you can specify what roles can see a block through the block admin UI, but using PHP still gives you extra flexibility.

If you are going to set visibility on a lot of blocks, see Block Page Visibility

Review of how the role visibility works in Drupal 5

  • If no role check boxes are checked, block is visible to all roles.
  • If "authenticated user" is checked, all logged in users will see the block, checking any of the other role boxes (other than anonymous user) is meaningless.
  • Checking anonymous users means that logged-in users, unless they belong to another role that is also checked, will not see the block.

Basics of setting visability via PHP:

  1. Go to administer >> access control and ensure “administer blocks “ and “use PHP for block visibility” are checked for your role.
  2. Go to administer >> blocks and find the block you want to set the visibility for.
  3. Click “configure” next to that block.
  4. Under the section entitled, “Page specific visibility settings”, click the radio button for “Show if the following PHP code returns TRUE”
  5. In the text box provided, enter whichever of the following snippets meets your needs:

Sample Snippets

Show block only to logged in users:

(In Drupal 5 this is done by simply checking the "authenticated user" box.)

<?php
global $user;
if ($user->uid){
  return TRUE;
} else {
  return FALSE;
}
?>

Variation: “if (!$user->uid){“ will show block only to anonymous users.

Show block only to a particular role:

(In Drupal 5 this is done by simply checking the box of the desired role.)

<?php
global $user;
if (in_array('Approved Role',$user->roles)) {
  return TRUE;
} else {
  return FALSE;
}
?>

Variations: Replace "Approved Role" with whichever role you want to view it. Or use !in_array to hide it for that role.

Show block set of roles:

(Thanks Chris Herberte). (In Drupal 5 this is done by checking role checkboxes.)

global $user;
$allowed = array('moderator','administrator');
$valid=FALSE;
foreach($user->roles as $role){
  if(in_array($role, $allowed)) {
    $valid=TRUE;
  }
}
return $valid;

Don't show block set of roles:

(This snippet is quite helpful in Drupal 5. If you want to show the block to authenticated users who have no other role but not to other authenticated users who do have a role, the checkboxes will be of no help.)

global $user;
// These are the roles who should not see this block
$notallowed = array('anonymous user','artist','GoZabo Administrator', 'SuperAdmin');

// Assume they can see it to start
$valid=TRUE;

// Go through each role the user is in and, if we hit a role that is not allowed to see it, set valid to false
foreach($user->roles as $role){
  if(in_array($role, $notallowed)) {
    $valid=FALSE;
  }
}

// If no roles were hit that aren't allowed, this will still be true. Otherwise it will be false.
return $valid;

Show block only to a particular user:

<?php
global $user;
if ($user->uid == 1){
  return TRUE;
} else {
  return FALSE;
}
?>

Variations: Replace the “1” with any UID.

Show block only for specific content type:

<?php
$match = FALSE;
$types = array('story' => 1, 'page' => 1);
if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
  $node = node_load(array('nid' => $nid));
  $type = $node->type;
  if (isset($types[$type])) {
    $match = TRUE;
  }
}
return $match;
?>

Variations: This example would show the block on all 'story' and 'page' type nodes. Just change line 2 - the $types array - to indicate which node types you want your block to appear on. Use the format 'nodetype' => 1 for each type you need. And yes, the array can hold single type only.

Combining PHP visibility control with specific page visibility:

When you choose the option to control visibility by PHP, you lose the ability to have Drupal automatically show/not show a block based on path. The following workaround is a bit complex and clunky, but it works.

  1. On the page administer >> blocks, hover over the configure link for the block you want to control in order to view the URL. Most of the URLs will end in “configure/sometext/somenumberortext”. Make a note of the “sometext” and the “somenumberortext”.
  2. Set the region for this block to "None". From now on let's call this block "Original Block."
  3. Go to administer >> blocks >> add block (tab) . In the block description field (what shows up on the admin/build/block page) write something like "Original Block Name Visible".
  4. Set the block body input type to PHP.
  5. What we do here, in the body (not in the visibility settings) is that we set the non page orientated visibility settings with php code. If the visability settings we set are TRUE -- then the code calls to output the actual content of our now disabled, original block. Pretty tricky huh! As an example, we are going to use a simple visability snippet. Start out with this shell in the block body text area:
  6. <?php
    global $user;
    $output = '';
    
    return $output;
    ?>
    
  7. Paste in just the “if” part from one of the snippets above. We’ll use the first snippet as an example. You should have something like this:
  8. <?php
    global $user;
    $output = '';
    
    if ($user->uid){
    }
    
    return $output;
    ?>
    
  9. Add in the block calling code so it looks like this:
  10. <?php
    global $user;
    $output = '';
    
    if ($user->uid){
    $block = SOMETEXT_block('view', SOMENUMBER);
    $output =  $block['content'];
    }
    
    return $output;
    ?>
    
  11. Replace with the “SOMETEXT” and “SOMENUMBER” that you noted in step 1.
  12. The final result should look something like this:
  13. <?php
    global $user;
    $output = '';
    
    if ($user->uid){
    $block = menu_block('view', 10);
    $output =  $block['content'];
    }
    
    return $output;
    ?>
    
  14. That takes care of showing the block only to logged in users (or whatever snippet you used). Next go to the “Page specific visibility settings” (you are still in this new block, not the original block) section and set one of the first two radio buttons as normal. Add the page specific setting in the usual place
  15. Enable and place this new block and check to see that the original one has its region set to "none". Make sure you don't delete the original one. That's where the content is coming from. Examine the block descriptions for both of them and describe them in a way that, hopefully, won't confuse you later. It's a good idea to add commenting to the php snippet explaining exactly what you've done.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

v1nce’s picture

I needed to show a block for specific content type as well as specific url aliases.

I believe I read the arg(0) function doesn't work correctly for all content types so I combined this with $_SERVER['REQUEST_URI'] that works well:

if (arg(0) == 'faceted_search' || $_SERVER['REQUEST_URI'] == '/collections') {
  $match = TRUE;
}

Here is the combined snippet:

<?php
$match = FALSE;
$types = array('collection_item' => 1);
if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
  $node = node_load(array('nid' => $nid));
  $type = $node->type;
  if (isset($types[$type])) {
    $match = TRUE;
  }
}

if (arg(0) == 'faceted_search' || $_SERVER['REQUEST_URI'] == '/collections') {
  $match = TRUE;
}
return $match;
?>

-----------------------------------------------------------------
Petafoo - We Love Animals

zuk0’s picture

The following code is just slightly modified v1nce's snippet.

Changes:
I use Drupal request_uri() function instead of $_SERVER['REQUEST_URI'] to get URL of current page and strpos() to show block when this URL contains specified word ("blog" in this case; you can change it on line 13).

$match = FALSE;
$types = array('blog' => 1);
if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
  $node = node_load(array('nid' => $nid));
  $type = $node->type;
  if (isset($types[$type])) {
    $match = TRUE;
  }
}
$url = request_uri();
if (strpos($url, "blog")) {
  $match = TRUE;
}
return $match;
Shai’s picture

Here is another snippet cut and paste. This one combines the need to make a block visible based on a node's taxonomy term OR the presence of a string in part of the URL. I have a topic area of a site which includes nodes and views and I needed the block to show both the nodes (based on taxonomy term) and views (based on a portion of the path).

Note: I'm a relatively new coder. Not only do I like comments in code, but I also like verbose semantically oriented names for variables. I know a lot of coders like to use short variable names. Here the variable names are long and verbose and hopefully make the code easier to understand.

  //code snippet for causing block to show based on a node's taxonomy term OR on a designated string in the url.
  $make_block_visible = FALSE;
  $term_id_to_trigger_show_block = 21; // replace '21' your term id.

  if ((arg(0) == 'node') && is_numeric(arg(1))) {
    $terms = taxonomy_node_get_terms(arg(1));
    foreach($terms as $term) {
      if ($term->tid == $term_id_to_trigger_show_block) {
         $make_block_visible = TRUE;
      }
    }
  }
  // The following code will cause block to show on the designated term's built-in "view" page such as:
  // example.com/taxonomy/term/21
  if ((arg(0) == 'taxonomy') && (arg(1) == 'term') && (arg(2) == $term_id_to_trigger_show_block)) {
    $make_block_visible = TRUE;
  }

  // the following code causes the block to show any time the designated string 
  //(replace 'panim' with your string) appears in the url
	$url = request_uri();
	if (strpos($url, 'panim')) {
	  $make_block_visible = TRUE;
	}
	return $make_block_visible;
 

Shai Gluskin
content2zero.com

sliiiiiide’s picture

modified for D6:

  //code snippet for causing block to show based on a node's taxonomy term OR on a designated string in the url.
  $make_block_visible = FALSE;
  $term_id_to_trigger_show_block = 21; // replace '21' your term id.

  if ((arg(0) == 'node') && is_numeric(arg(1))) {
    $node = node_load(arg(1));
    $terms = taxonomy_node_get_terms($node);
    foreach($terms as $term) {
      if ($term->tid == $term_id_to_trigger_show_block) {
         $make_block_visible = TRUE;
      }
    }
  }
  // The following code will cause block to show on the designated term's built-in "view" page such as:
  // example.com/taxonomy/term/21
  if ((arg(0) == 'taxonomy') && (arg(1) == 'term') && (arg(2) == $term_id_to_trigger_show_block)) {
    $make_block_visible = TRUE;
  }

  // the following code causes the block to show any time the designated string 
  //(replace 'panim' with your string) appears in the url
    $url = request_uri();
    if (strpos($url, 'panim')) {
      $make_block_visible = TRUE;
    }
    return $make_block_visible;

waltercat’s picture

This works great for Terms. How would I alter it to work for and entire vocabulary? The initial one posted at the top isn't working for me in Version 6.

Also how do I alter it so that it works for multiple term ids. The one you posted only works for 1 term.

WisTex’s picture

Here is a variation of the code posted above. This time it prevents the block from being shown for specific node types, in this case story and page.

<?php
$match = TRUE;
$types = array('story' => 1, 'page' => 1);
if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
  $node = node_load(array('nid' => $nid));
  $type = $node->type;
  if (isset($types[$type])) {
    $match = FALSE;
  }
}
return $match;
?>

--
Scott M. Stolz
http://www.wistex.com/

goldschmidt.a’s picture

Combining a couple of methods shown above and using the conditional statement if ($user->uid == $node->uid), I created this code to only show a block when the node is a certain content type (page) AND the viewer is also the author of the node.


<?php
global $user;
$match = FALSE;
$types = array('page' => 1);
if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
  $node = node_load(array('nid' => $nid));
  $type = $node->type;
  if (isset($types[$type])) {
    if ($user->uid == $node->uid) {
        $match = TRUE;
    }
  }
}
return $match;
?>

Sincerely,
Andrew G

dadderley’s picture

This will works in panels when you want to show a pane only to the author of the post.
Thanks

esllou’s picture

user/1, user/2, user/3, etc. Block shows
user/1/edit. Block doesn't show because arg(2) exists
user/register. Block doesn't show because arg(1) isn't numeric.

<?php
/* this block will show on user/2 but not on user/register or user/2/edit. First arg must be "user", second arg must be a number, third arg must be empty. */
if ((arg(0) == 'user') && is_numeric(arg(1)) && (arg(2) == NULL)) {
   return TRUE;
}
else {
   return FALSE;
}
?>
anawillem’s picture

i created a nodetype that is associated with a user's profile vis a vis the Content Profile module. i want to limit a block's visibility based on whether or not they have created that piece of content. so, for example, i have a nodetype called 'am_registration' which is associated to the user who created it. if they have already filled out this content type once, i do not want the block to show. because i only want this block to show up on one page, i have the code for it in the body section:

<?php
global $user;
if ($user->uid) {
  if ($user->am_registration) {}
?>
<div id="register-button">
<p><h5>Congratulations! You are logged into the site!</h5></p><p><h4><a href="/node/add/am-registration">To proceed in your registration, please click here.</a></h4></p><p>&nbsp;</p><p>&nbsp;</p>
</div>
<?php
}
?>

it works in terms of becoming invisible when the user is not logged in (if ($user->uid)) but the next embedded if statement doesn't seem to be doing a damn thing...

ideas?

--
anawillem
http://jellobrain.com

valderama’s picture

if ($node = menu_get_object()) {
return($node->type=='agent' || $node->type=='exhibition')
}

--

keine zeit für spielkonsolen mein leben ist jump n run!

valderama.net

sja1’s picture

Hi, thanks for the 6x snippet above, it's working great for me. The only snag I hit was that the "return" line is missing a semi-colon at the very end of the line. After adding the semicolon it started working.

Funkwarrior’s picture

Any clue about testing visibilty on site-wide contact page?

merco’s picture

I did exactly what you said. İt worked great. Guys you are just awsome :)

Surf New Media’s picture

We need to figure out a way to combine these two php codes for block visibility, which so far we haven't been able to figure it out. Can anyone help? We need a block to show on the profile page for author (shown below), but not have that block on the edit page for that same user's profile.

This one shows a block on the profile page only if the profile belongs to the logged in user:

<?php
global $user;
if (arg(0) == 'user' && $user->uid == arg(1)){
return TRUE;
}
else {
return FALSE;
}

This one will show a block on the profile page, but not the profile subpages, like user/1/xxx:

<?php
  $args = arg();
  if (count($args) > 2) return FALSE;
  if (($args[0] == 'user') || ($args[0] == 'users')) {
    if (count($args) == 1) return TRUE;
    if ((($args[0] == 'user') && is_numeric($arg[1])) || ($args[0] == 'users')) {
      return TRUE;
    }
  }
  return FALSE;
?>

We tried this and it doesn't work. It makes the block not show at all:

<?php
$args = arg();

// Make sure we're on a user or users page, if not then hide the blocks
if (($args[0] == 'user') || ($args[0] == 'users')) {

// If there is only one arg, we're on the logged
// in user's page so return TRUE
if (count($args) == 1) {
return TRUE;
} else {

// Make sure we're on the logged in user's user page
if ($user->uid == arg(1)){

// If we're too deep, then don't show the blocks
if (count($args) > 2) {
return FALSE;
} else {

// We're on the logged in user's profile
// page and we're not too deep, so return
// true
return TRUE;
}
} else {
return FALSE;
}
}
} else {
return FALSE;
}
?>
Surf New Media’s picture

Here is the code that works:

<?php
       global $user;
       $args = arg();
 
	// Make sure we're on a user or users page, if not then hide the blocks  
	if (($args[0] == 'user') || ($args[0] == 'users')) {
	
		// If there is only one arg, we're on the logged in user's page so return TRUE
		if (count($args) == 1) {
			return TRUE;
		} else {
		
			// Make sure we're on the logged in user's user page
			if ($user->uid == arg(1)){
			
			    //  If we're too deep, then don't show the blocks
			    if (count($args) > 2) {
			    	return FALSE;
			  	} else {  	
			  	
			  		// We're on the logged in user's profile page and we're not too deep, so return true
					return TRUE;
				}
			} else {
				return FALSE;
			}
		}
	} else {
		return FALSE;
	}
?>
Sagar Ramgade’s picture

Block visible only on the profile page not on user/*/edit and user/*/register.
I feel really happy to help because even i needed this and was able to achieve this, Try this :

global $user;
if (arg(0) == 'user' && $user->uid == arg(1) && is_numeric(arg(1)) && (arg(2) == NULL) )
{
  return TRUE;
}

else {
  return FALSE;
}

Acquia certified Developer, Back end and Front specialist
Need help? Please use my contact form

boogsbobo’s picture

Trying to display one thing to the author of the node and something different to everyone else viewing it:

global $user;
if ($user->uid == $node->uid) 
{ print t('you are THE AUTHOR'); }
else {
print t('you are NOT the author'); 
} 

but I get the negative NOT message in all cases, even when the author of the node is the currently logged in user.

The possible catch is that I am trying to use this functionality for the "empty text" of a view.

This should be easy... is there something wrong with my php? Thanks

Lbob’s picture

I have the same issue: I want to display a block (http://drupal.org/project/authorcontact) for every user, except for the author of the node.
I used this code:

<?php
global $user;
if ($user->uid == $node->uid)
{return FALSE; }
else {
return TRUE;
}
?>

But :
- the block is still displayed for every logged user, including the node's author
- the block is not displayed for anonymous users

Any solution?

cossme’s picture

I think you have to load the $node before you can access its uid.

So it should be something like

global $user;
if (arg(0) == 'node' && is_numeric(arg(1))) {
  $nid = arg(1);
  $node = node_load(array('nid' => $nid));
  return !($user->uid == $node->uid);
}

hope it helps, cossme

Lbob’s picture

Thanks a lot Cossme, it works perfectly!

lesbi’s picture

Hi some1 can say me what is the code pour the block visibility by screen size ?
thank for you help

CardinalFang’s picture

If you had a profile field to store a favorite color, you could use this to display a block if the favorite color matches one of the items in the array.

<?php
global $user;
profile_load_profile($user);
$allowed = array('Blue', 'Yellow');
  if(in_array($user->profile_color, $allowed)) {
    return TRUE;
  }
  else {
    return FALSE;
  }
?>

uasport’s picture

Any ideas? Looking to only show a block when a "Special Alert" node type is published and not show the block when the "Special Alert" node type is unpublished or deleted.

superxain’s picture

Any idea to show a block only when the page title containing some string?

subadmin’s picture

these all information is very well for visibility of block but i have an problem where anonymous user does not see block please help me..

tinny’s picture

D6

Administer > Blocks > Configure > Show if the following PHP code returns TRUE

Add block for specific content type:


	// do not show on edit pages
	// $args[2] would be edit: www. example.com/node/46/edit where 46 is the node id
	$args = arg();
	if (count($args) > 2) {
		return FALSE;
	}

	$match = FALSE;
	
	// add content types here
	$types = array('news' => 1, 'product' => 1);

	// if url is www .example.com/node/46
	if (($args[0] == 'node') && is_numeric($args[1])) {
		$node = node_load($args[1]);
		// true if matches content type
		$match = isset($types[$node->type]);
	}

	return $match;

Show block only on user profile

  // dont display on edit pages
  $args = arg();
    if (count($args) > 2) {
  	return FALSE;
    }
  
  // display if the url is www .example.com/user/2 where 2 is the user id
  if ($args[0] == 'user') {
    return TRUE;
  }

madaxe’s picture

That's awesome tinny. Thanks.

What about if one wanted it to appear only on one specific page like 'user' but not appear on 'user/2'

Sagar Ramgade’s picture

Hi, Here is the one you are looking for :

<?php
$bool = FALSE;
$args = arg();
// return true on when the page is profile page
if(args[0] == 'user'){
 $bool = TRUE;
}

// return false when the page is edit or something else except the profile page
if (count($args) > 2){
 $bool = FALSE;
}

//return false when user uid is '2'
elseif(args[1] == 2){
 $bool = FALSE;
}
return $bool;
?>

Hope this helps

Regards
Sagar

Acquia certified Developer, Back end and Front specialist
Need help? Please use my contact form

madaxe’s picture

Cheers Sagar. In the end I got it working by simply changing the first arg to being greater than 1.

  // dont display on www.example.com/user/* pages
  $args = arg();
    if (count($args) > 1) {
      return FALSE;
    }
  
  // display if the url is www .example.com/user 
  if ($args[0] == 'user') {
    return TRUE;
  }
amcoms’s picture

Is there any code that will identify panel types? or custome pages. The easiest way would be for taxonomy but the codes I have tried just ignore the taxonomy altogether :(

TIA
Andrew

nerdydragon’s picture

This is very helpful, thank you for posting it.

I was able to quickly display a block for a particular content type, and focus my time on other elements of the site.

Thanks for the post.

mrigank’s picture

Hi all,

My URL hierarchy is like 1/2/3/4/5/6

I have a block which I want to show only for 1/2/3 and 1/2/3/*
but not for 1/2/3/*/* or 1/2/3/*/*/*.

I tried the following using the option
Show on only the listed pages
1/2/3
1/2/3/*

This does not work. It shows for all 4 types, 1/2/3, 1/2/3/*, 1/2/3/*/* and 1/2/3/*/*/*.

Show on only the listed pages
1/2/3
1/2/3/*/

This also does not work. This shows only for 1/2/3 only.

Can you please help me out?

Thanks,
Mrigank.

mrigank’s picture

Stacy Prendeville’s picture

Can anyone tell me how to amend the code below so that the block also appears on

if(arg(0) == "node" && is_numeric(arg(1)))
{
 $node = node_load(arg(1));
 //list all node types where this should appear
 $array = array("activity_location_page");
 if(in_array($node->type,$array))
   return TRUE;
}
Sagar Ramgade’s picture

Hi,

You need to add this code under page specific visiblity settings and select "Show if the following PHP code returns TRUE (PHP-mode, experts only)" and hit save block.Hope this helps.

Regards
Sagar

Acquia certified Developer, Back end and Front specialist
Need help? Please use my contact form

Steve -cc’s picture

Hi
I am having a weird problem with Block Visibility. I enabled the Who's Online block for just one User Role. It shows correctly when someone in that role logs in but does not show when I am logged in as User 1.

Any ideas?

Louis Bob’s picture

I was wondering if it was possible at all to display a block on the preview page only. I have tried using this:
if ($node->in_preview == TRUE)
However, it's not working.
Would there be a solution with the "form_state()" function? Since I am not a programmer, any advice would be greatly appreciated :)

HS’s picture

Can someone please tell me how to combine the snippet 'Don't show block set of roles' with 'Combining PHP visibility control with specific page visibility'?

I've done this, but nothing shows up:

<?php
global $user;
$output = '';

// These are the roles who should not see this block
$notallowed = array('anonymous user','Staff +1','Staff','Content creator', 'SuperAdmin');

// Assume they can see it to start
$valid=TRUE;

// Go through each role the user is in and, if we hit a role that is not allowed to see it, set valid to false
foreach($user->roles as $role){
  if(in_array($role, $notallowed)) {
    $valid=FALSE;
    $block = block_block('view', 172);
    $output =  $block['content'];
  }
}

// If no roles were hit that aren't allowed, this will still be true. Otherwise it will be false.
return $valid;

return $output;
?>