taxonomy | Eric's Drupal Blog

Content tagged with: taxonomy

Eric's picture

Using AHAH to dynamically generate form elements (and integration with multi-tiered taxonomy)

For some time now I've wanted to write a blog entry about using AHAH to create dynamically generated form elements. After a recent conversation at work regarding usability, I now had a real world example to create: how to use tiered taxonomy to dynamically generate a form. This code snippet will show you how to create a form that creates child select dropdowns based on the parent taxonomy term the user selects.

First I established a multi-tier taxonomy called "AHAH":

For this example I created a menu callback to display my initial form:

<?php
function helper_menu() {
 
 
$items = array();
 
 
$items['ahah-form'] = array(
   
'title' => 'AHAH Form',
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('_helper_callback_ahah_form'),
   
'type' => MENU_CALLBACK,
   
'access callback' => 'user_access',
   
'access arguments' => array('access content'),
  );
 
  return
$items;
 
}
?>

I then defined the page callback to show the initial form:

<?php
function _helper_callback_ahah_form() {

 
// define an array to contain form elements
 
$form = array();
 
 
// define the top level vid
 
$vid = 2;
 
 
// fetch a tree of taxonomy elements
 
$tree = taxonomy_get_tree($vid, 0, -1, 1);
 
 
// loop though taxonomy and collect elements
 
$options = array();
  foreach (
$tree as $key => $value) {
   
$options[$value->tid] = $value->name;
  }
 
 
// create the first select dropdown input
 
$form['select_1'] = array(
   
'#type' => 'select',
   
'#options' => $options,
   
'#title' => t('Select 1'),
   
'#size' => 5,
   
'#multiple' => false,
   
'#ahah' => array(
     
'event' => 'change',
     
'path' => 'ahah-form-callback',
     
'wrapper' => 'wrapper-1',
     
'method' => 'replace',
    ),
  );
 
 
// pass the top level vid in the form
 
$form['ahah_vid'] = array(
   
'#type' => 'hidden',
   
'#value' => $vid,
  );
 
 
// create an empty form element to contain the second taxonomy dropdown
 
$form['wrapper_1'] = array(
   
'#prefix' => '<div id="wrapper-1">',
   
'#suffix' => '</div>',
   
'#value' => '&nbsp;',
  );
 
 
// add a form submit button
 
$form['submit'] = array(
   
'#value' => 'Submit',
   
'#type' => 'submit'
 
);
 
  return
$form;
 
}
?>

The above form callback produces the following:

Next, I defined a callback to handle the AHAH page request:

<?php
// new menu item:
function helper_menu() {
 
 
// ...
 
 
$items['ahah-form-callback'] = array(
   
'title' => 'AHAH Form Callback',
   
'page callback' => '_helper_callback_ahah_form_callback',
   
'type' => MENU_CALLBACK,
   
'access callback' => 'user_access',
   
'access arguments' => array('access content'),
  );
 
 
// ...

 
return $items;
 
}

// and, here's the AHAH callback used to create the new form elements:
function _helper_callback_ahah_form_callback() {
 
 
// define a string variable to contain callback output
 
$output = "";
 
 
// pull the top level vid from the $_POST data
 
$vid = $_POST['ahah_vid'];
 
 
// pull the selected dropdown from the $_PODT data
 
$parentVid = $_POST['select_1'];
 
 
// loop through the taxonomy tree and fetch child taxonomies
 
$options = array();
 
$tree = taxonomy_get_tree($vid, $parentVid, -1, 1);  
  foreach (
$tree as $key => $value) {
   
$options[$value->tid] = $value->name;
  }
 
 
// define the second tier select dropdown element
 
$form['select_2'] = array(
   
'#type' => 'select',
   
'#options' => $options,
   
'#title' => t('Select 2'),
   
'#size' => 5,
   
'#multiple' => false,
  );
 
 
// rebuild form object and output new form elements
 
$output .= ahah_render($form, 'select_2');
 
 
// render form output as JSON
 
print drupal_to_js(array('data' => $output, 'status' => true));
 
 
// exit to avoid rendering the theme layer
 
exit();
 
}

// Lastly, here's a help function pulled from Nick Lewis's blog to alter the form
// see: http://www.nicklewis.org/node/967
// NOTE: based on poll module, see: poll_choice_js() function in poll.module
function ahah_render($fields, $name) {
 
$form_state = array('submitted' => FALSE);
 
$form_build_id = $_POST['form_build_id'];
 
// Add the new element to the stored form. Without adding the element to the
  // form, Drupal is not aware of this new elements existence and will not
  // process it. We retreive the cached form, add the element, and resave.
 
$form = form_get_cache($form_build_id, $form_state);
 
$form[$name] = $fields;
 
form_set_cache($form_build_id, $form, $form_state);
 
$form += array(
   
'#post' => $_POST,
   
'#programmed' => FALSE,
  );
 
// Rebuild the form.
 
$form = form_builder($_POST['form_id'], $form, $form_state);

 
// Render the new output.
 
$new_form = $form[$name];
  return
drupal_render($new_form);
}
?>

The above code allows the user to select an option from the top level tier of taxonomy and the AHAH callback will generate the a select dropdown of the child taxonomies as shown below:

On form submission, you'll see that the options the user selected as stored in $form_state['values']['select_1'] and $form_state['values']['select_2']

gradient spacer
Eric's picture

Changing the title of the taxonomy landing pages

If someone clicks on a taxonomy term they land on a page showing all the content tagged with that term. The title on those pages is simply the taxonomy term. I thought it would be more usable if I changed the verbiage of the title to let the user know what they are viewing. This code snippet shows how you can change the title for the taxonomy term landing pages:

<?php
function MYTHEME_preprocess_page(&$variables) {
  if (
arg(0)=='taxonomy' && arg(1)=='term') {
   
$variables['title'] = "Content tagged with: " . $variables['title'];
  }
}
?>

gradient spacer
Eric's picture

Automatically generate meta keywords from a node's taxonomy terms

Most SEO tutorials claim that meta keywords are not very important to search engines. But, if you insist on inserting meta keywords for each node's taxonomy terms, this tutorial will show you how to accomplish this. I added the following function to my template.php file in my theme.

<?php
function _phptemplate_variables($hook, $vars) {
 
// check for page scope
 
if ($hook == 'page') {
   
// ensure this page is a node view
   
if (is_object($vars['node'])) {
     
// get a list of taxonomy terms for this node
     
$terms = taxonomy_node_get_terms($vars['node']->nid);
           
     
// ensure terms exist
     
if (is_array($terms)) {

       
// loop through terms, and collect the names
       
$t = array();
        foreach (
$terms as $k => $v) {
         
$t[] = $v->name;   
        }
               
       
// ensure names exist
       
if (is_array($t)) {
         
// implode the terms into a string and add to the head variable
         
$vars['head'] .= "<meta name='keywords' content='" . implode(",", $t) . "'>";
        }

      }

    }
       
  }
  return
$vars;
}
?>

To verify this code is working, check out the tags I used on this page and then view the source. Hopefully, they match!

(NOTE: my homepage is a view, so there show not be any meta keywords.)


NOTE: when I upgraded my theme to Drupal 6, I had to update this above code:

<?php
function MYTHEME_preprocess_page(&$variables) {
  if (
is_object($variables['node']) && is_array($variables['node']->taxonomy)) {
   
$tags = array();
    foreach (
$variables['node']->taxonomy as $tid => $term) {
      if (!
in_array($term->name, $tags)) $tags[] = $term->name;
    }
       
    if (
count($tags)) {
     
sort($tags);
     
$variables['head'] .= "<meta name='keywords' content='" . implode(",", $tags) . "'>";
    }
  }
}
?>

gradient spacer
Eric's picture

Creating custom breadcrumbs for a certain node type

Here's a quick code snippet that shows you how you can create custom breadcrumbs for a certain node type. This code would reside in your template.php theme file.

<?php
function MYTHEME_preprocess_page(&$variables) {
  if (
$variables['node']->type == 'MYNODETYPE') {
       
   
$links = array();

   
// creating a link to the home page
   
$links[] = l('Home', '<front>');

   
// here's how you could add a link to a taxonomy page
   
$vid = 2;
    foreach (
$variables['node']->taxonomy as $k => $v) {
      if (
$v->vid = $vid) {  
       
$links[] = l($v->name, 'taxonomy/term/' . $v->tid);
        break;
      }
    }
       
   
// yet another link
   
$links[] = l('Some Other Link', 'SOMEOTHERLINK');

   
// lastly, overwrite the contents of the breadcrumbs variable in the page scope
   
$variables['breadcrumb'] = theme('breadcrumb', $links);
  }
}
?>

NOTE: if you were adding this code to a module, you could use the drupal_set_breadcrumb() function to do the same functionality.

gradient spacer
Eric's picture

Displaying the taxonomy term description

When using views to handle the taxonomy term pages, you may not have the taxonomy term description available in your page variable scope (either page.tpl.php or page-taxonomy.tpl.php). If you'd like to display it at the top of the page, you can add a preprocess function in your theme to add the variable:

<?php
function MYTHEME_preprocess_page(&$variables) {
 
// check to see if this is a taxonomy term page
 
if (arg(0)=='taxonomy' && arg(1)=='term') {
   
// load the taxonomy term object
   
$term = taxonomy_get_term(arg(2));

   
// add the taxonomy term description to the variables
   
$variables['taxonomy_term_description'] = $term->description;
  }   
}
?>

Now in your page.tpl.php (or page-taxonomy.tpl.php) file, you can add the following line of PHP to output the description. NOTE: I enclosed it in a div with a class so I can add necessary CSS easily.

<?php
if ($taxonomy_term_description) print "<div class='taxonomy_term_description'>$taxonomy_term_description</div>";
?>

gradient spacer Syndicate content