What's the best way to create variables that are available to every single URL on my site, based on node id or taxonomy id? On Drupal site A we have a bunch of links to non-Drupal site B. For marketing and tracking purposes all these links have a different URL variable appended to them, so that when a user registers on site B we can determine where on site A they came from.

At the moment I use page.tpl.php to create the variable ($forceCode) but it now transpires I need this variable to be available to node.tpl.php too, and I feel like there must be a less hacky and more universal way of doing this, probably using a preprocess function in template.php that right now seems beyond my comprehension level.

PLAIN LANGUAGE EXPLANATION

$specialPages is an array of node IDs that need a special code.
$specialFolders is an array of taxonomy IDs that need a special code.


If the current node ID matches any in the nid array, I set the variable accordingly.
If not then I get the category (taxonomy) of the current node, or if the current page is a taxonomy term itself then use its own tid.

Then using this taxonomy ID I get all other tids that are parents of that tid.
Then I look for matches of any of these taxonomy IDs in my array of special tids in order to set the variable.

If the current page has not matched any of my special nodes or taxonomies, the variable remains its default value.


ACTUAL CODE

// we later restrict our parent taxonomy search to certain types but it's not strictly necessary
$contentTypes = array("article","advpoll","event");

$specialFolders = array(
    276 =&gt; "events",
    292 =&gt; "free-dating",
    498 =&gt; "date-explorer"
);
$specialPages = array(
    22 =&gt; "reviews",
    86 =&gt; "texting"
);

$forceCode = "default";

// check for specific page first
if (@array_key_exists($node-&gt;nid,$specialPages)){
    $forceCode = $specialPages[$node-&gt;nid];
} else {
    // there was no entry for this nid, let's check parent terms
    $parentTerms = array();
    $hasParents = false;
    if (arg(0) == "taxonomy") $hasParents = arg(2);
    if (@in_array($node-&gt;type,$contentTypes)) {
        $category = field_view_field('node', node_load($node-&gt;nid), 'field_category');
        $hasParents = $category['#items'][0]['tid'];
    }
    if ($hasParents !== false) {
        $parents = taxonomy_get_parents_all($hasParents);
        foreach ($parents as $term){
            $parentTerms[] = $term-&gt;tid;
        }
    }

    foreach ($parentTerms as $tid){
        if (array_key_exists($tid,$specialFolders)){
            $forceCode = $specialFolders[$tid];
            continue;
        }
    }
}
I've found a very satisfactory solution using function matchtheme_preprocess(&amp;$variables, $hook) which will always supply variables to page and node templates.

The more complicated bit was finding an appropriate way to get this function to collect the data I need (nid or tid) properly regardless of whether it was the page or node template making the call.

Essentially (this is the cut down version) I just did this:

if ($hook == "page"){
    // supplies variables to page.tpl.php
    // the page template can cover anything, including a node and taxonomy
    if (arg(0) == "node"){
        $nidToCheck = arg(1);           
    } else if (arg(0) == "taxonomy"){
        // already a taxonomy page, the term id is the category
        $hasParents = arg(2);
    }
} else if ($hook == "node"){
    // supplies variables to node.tpl.php
    $nidToCheck = $variables['elements']['#node']-&gt;nid;
}


From there if ($nidToCheck) allows me to use the nid to generate $hasParents for nodes, and then I can move on handling all nodes and taxonomy terms to do what I want (all this bit is essentially the same as in my question).

Finally I feed back to the template an array of variables in much the same way as they were set before.

So glad to have this sorted as it caused quite a headache. Would love to hear whether or not this is an efficient or clever way of dealing with it. The most obvious issue to me is that the array of variables (and of course the whole function) will get run twice on node pages - once for the page template and once for the node template - which is a touch inefficent. I guess I could contain the whole thing in an if (!isset...