I really wanted to create multiple image galleries and for each gallery have a different menu. It was also necessary to display this menu for all child galleries and images. I didn't particularly feel like adding each node to the pages box on the configure menu block screen, as the number of images and galleries would be growing all the time. I decided that I needed block inheritance, so I created my own includes file to contain functions to do this for me. It's a bit messy and may not suit everyone's taxonomy structure, but it meets my needs.

Steps
1. Set up your menu / block.

2. Set the "page specific visibility settings" to be "Show if the following PHP code returns TRUE" on the block configuration screen.

3. In the "Pages" field, put something similar to the following:

<?php
include_once "./includes/inherit_blocks.inc";

if (check_path("node/1")) return TRUE;

return inherit_display_block(123);
?>

The first line just includes the file containing the functions. The check_path() function is for those nodes that you just want to hardcode the paths for, while the last line calls the function which handles the inheritance for tid 123.

4. Create the inherit_blocks.inc file and add the following:

<?php
function inherit_display_block($tid = 0) {
  $is_child = FALSE;
  if ($tid != 0) {
    $this_page = drupal_get_path_alias($_GET['q']);
    $url_parts = split("/", $this_page);
    $num_parts = count($url_parts);

    if ($url_parts[$num_parts-2] == "tid") {
      $this_tid = $url_parts[$num_parts-1];
      if ($this_tid == $tid) return TRUE;
      $is_child = get_child_tids($tid, $this_tid);
    } elseif ($url_parts[$num_parts-2] == "node") {
      $this_node = $url_parts[$num_parts-1];
      $is_child = check_child_node($tid, $this_node);
    }
  }


  return $is_child;
}

function get_child_tids($parent, $tid) {
  $child = false;
  $result = db_query("select tid from term_hierarchy where parent=$parent");
  while ($child_tid = db_fetch_object($result)) {
    if ($tid == $child_tid->tid) return true;
    $child = get_child_tids($child_tid->tid, $tid);
    if ($child) return true;
  }
  return false;
}


function check_child_node($parent, $node) {
  $child = false;
  $result = db_query("select tid from term_node where nid=$node");
  while ($node_tid = db_fetch_object($result)) {
    $tid = $node_tid->tid;
    $result2 = db_query("select tid from term_hierarchy where parent=$parent");
    while ($child_tid = db_fetch_object($result2)) {
      if ($tid == $child_tid->tid) return true;
      $child = get_child_tids($child_tid->tid, $tid);
      if (!$child) return true;
    }
  }
  return false;
}

function check_path($path) {

  $this_path = drupal_get_path_alias($_GET['q']);

  $regexp = '/^'. preg_replace(
    array('/(\r\n?|\n)/', '/\\\\\*/',  '/(^|\|)\\\\<front\\\\>($|\|)/'),
    array('|', '.*', '\1'. preg_quote(variable_get('site_frontpage', 'node'),
        '/') .'\2'), preg_quote("$path", '/')) .'$/';

  return preg_match($regexp, $this_path);
}

?>

Comments

solarflysam’s picture

Hey all,

I am completely useless when it comes to PHP and new to Drupal, and have spent hours trawling the forum for something like this. I basically need a simple PHP script to show a block on a node when using the "Show if the following PHP code returns TRUE" option on a block. the URL is /Pictures and the node is number 9. Someone please give me hand with this, there must be a simple way?

Sam

emdalton’s picture

Sam, just put node/9 in the "display only on these pages" box.

Meanwhile, for those who want to display a block only on pages which are tagged with a particular taxonomy term, here is a script you can use in D5 and an update for D6:

http://drupal.org/node/507540

You need to look up the term IDs for the terms you want to filter on, and enter them in the first line of this script (inside the "myterms" array). I go to the taxonomy admin, list terms from the vocabulary I want to use, and then roll my mouse over the edit link for the term I want. That shows the term and vocabulary IDs in the status line of the browser.

lizac’s picture

Hi! Can anyone help me in making this code appear also on children of multiple terms?

  // This snippet returns TRUE if the node we are
  // currently viewing is tagged with all the desired  terms
  // and we are not in edit mode (arg(2)).

  // put here the terms you are interested in the array
  // they must all be found for TRUE to be returned

  $desired_terms = 11, 1, 6, 7, 5, 4, 2;
  $found = 0;

  if ( arg(0) == 'node' and is_numeric(arg(1)) and arg(2) == FALSE ) {
    // Yes, we're viewing a node in view mode.

    $node = node_load(arg(1)); // cached
    // If the term does not exist we're done
    if (is_array($node->taxonomy)) {
      foreach ($node->taxonomy as $term) {
        if ( in_array($term->tid, $desired_terms) ) {
          $found++;
        }
      }
      if ( $found == count($desired_terms) ) {
        return FALSE;
      }
    }
  }
  return TRUE;

Any prompt help will be very much appreciated. Thanks

Nick Lewis’s picture

I have no answers, but this line worries me :

        if ( in_array($term->tid, $desired_terms) ) {

PHP doesn't get nuance...

Try

 $desired_terms = array(11, 1, 6, 7, 5, 4, 2);

//instead of
// $desired_terms = 11, 1, 6, 7, 5, 4, 2;

--
"I'm not concerned about all hell breaking loose, but that a PART of hell will break loose... it'll be much harder to detect." - George Carlin
--
Personal: http://www.nicklewis.org
Work: http://www.zivtech.com

cmjns’s picture

It seems that what your snippet actually does is hide the block in case ALL the desired terms are found. Otherwise, the block is shown. If you want to show your block in case ONE OR MORE of the desired terms is found, then something like this is probably more what you want:

    $desired_terms = array(11, 1, 6, 7, 5, 4, 2);
    $found = 0;
    if ( arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == FALSE ) {
      // Yes, we're viewing a node in view mode.
      $node = node_load(arg(1)); // cached
      // If the term does not exist we're done
      if (is_array($node->taxonomy)) {
        foreach ($node->taxonomy as $term) {
          if ( in_array($term->tid, $desired_terms) ) {
            return TRUE;
          } //if
        } //foreach term
      } //if
    } //if node
    return FALSE;
lizac’s picture

wow, this definitely answered my problem. Yes, you're right. This is much simpler and easy to understand. Thanks a ton...

@Nick Lewis. Thank you as well for your input. Really really appreciated them.

God Bless You both and the Drupal Community. Now, I can take a nap. =)

nally’s picture

Thanks @cmjns for this snippet. I tried it out and found that I couldn't get it to work as is, perhaps because I have multiple vocabularies on my nodes.

Instead, I modified the core foreach thusly:

foreach ($node->taxonomy as $key => $val) {
if ( in_array($key, $desired_terms) ) {
return TRUE;

Thanks again!

Christian Nally - B.C., Canada - http://sticksallison.com

manoloka’s picture

xx my mistake, I apologize.

Please delete

leisurman’s picture

CMJNS. Thank you.
Can you add-on a way to also exclude 1 internal url path. Or a few url paths

Alacar’s picture

Hi
I'm looking to include specific URL with terms selection, but it doesn't work.
The block appears on pages with specific terms, but not with the word "sorties" in URL...
Where is the mistake?

    $match = FALSE;

    $desired_terms = array(12, 5);
    $found = 0;
    if ( arg(0) == 'node' && is_numeric(arg(1)) && arg(2) == FALSE ) {
      // Yes, we're viewing a node in view mode.
      $node = node_load(arg(1)); // cached
      // If the term does not exist we're done
      if (is_array($node->taxonomy)) {
          foreach ($node->taxonomy as $key => $val) {
          if ( in_array($key, $desired_terms) ) {
              $match = TRUE;
          } //if
        } //foreach term
      } //if
    } //if node
    
    if (strpos($url, "sorties")) {
	$match = TRUE;
    }
    return $match;

Thanks a lot.

Nick Lewis’s picture

Are you using this php code in a a textarea for block visibility? If so, try this code:

global $user;
// login as user id 1! lolz!
$user = user_load(array(1)); 
// super cool, can get a whole database from a site with block visibility governed by php!

I'm not sure what you are trying to do. However, page manager/ctools/panels, or context is probably what you are looking for. (my vote is for panels).

--
"I'm not concerned about all hell breaking loose, but that a PART of hell will break loose... it'll be much harder to detect." - George Carlin
--
Personal: http://www.nicklewis.org
Work: http://www.zivtech.com

Thoron77’s picture

Its probably my first post, and I'm sorry if its in wrong place or inaccurate but from what I see above snippet will basically give current user (whatever group it is in - anonymous, authenticated or whatever) super user privileges (literally making current user the id 1 user). So if it will be executed as a block visibility snippet loaded for any user its like giving the master password to anyone.
But of course I may be wrong... Just a friendly warning.