chacadwa.com

Technical blog and writings by Micah Webner.

Override Drupal 7 taxonomy display by vocabulary

I've had a couple of cases recently where I've wanted to use views to override the output of taxonomy/term/%taxonomy_term on a site, but this can be tricky if you want to use different views for one or more specific vocabularies. Normally, you'd just enable the delivered Taxonomy Term view and modify it as needed for the site, and presumably that's how Drupal 8 will work by default with Views in Core. I've looked briefly at the Taxonomy Views Integrator module, but quite frankly, this task falls under customization for a specific site, so why not just customize for the site?

I looked around a little, and determined that the code I want to override is near the bottom of taxonomy_term_page(), starting where taxonomy_select_nodes() is called to build the contents. For this project, I really wanted to leave everything else alone (although I may come back and disable the RSS feeds, since I don't really need those, either.)

We start by overriding the page callback for taxonomy/term/%taxonomy_term to pass through a custom page callback function:

/**
 * Implements hook_menu_alter().
 */

function mysite_menu_alter(&$items) {
  $items['taxonomy/term/%taxonomy_term']['page callback'] = 'mysite_taxonomy_term_page';
}

Now we create our custom callback page. In this example, we'll use switch() to choose our output based on the term vocabulary, leaving core taxonomy_term_page() as the default for vocabularies we don't want to override.

/**
 * Page callback for taxonomy terms.
 *
 * Redirect selected vocabularies to custom functions, defaulting to the core
 * taxonomy_term_page() function for all remaining terms.
 */

function mysite_taxonomy_term_page($term) {
  switch($term->vocabulary_machine_name) {
    case 'teams':
      return mysite_taxonomy_term_teams_page($term);
    default:
      return taxonomy_term_page($term);
  }
}

Now we create our custom page contents by copying taxonomy_term_page() into a new function and changing the parts we want to override. In this example, I've created a view named team_members, which I'll inject as content by calling views_embed_view() in place of the core default code:

/**
 * Page callback for taxonomy teams vocabulary.
 *
 * Rewrite only the content portion of this page using views.
 * The rest of the code here is a direct copy of the core function
 * taxonomy_term_page() function.
 */

function mysite_taxonomy_term_teams_page($term) {
  // Assign the term name as the page title.
  drupal_set_title($term->name);

  // Build breadcrumb based on the hierarchy of the term.
  $current = (object) array(
    'tid' => $term->tid,
  );
  // @todo This overrides any other possible breadcrumb and is a pure hard-coded
  //   presumption. Make this behavior configurable per vocabulary or term.
  $breadcrumb = array();
  while ($parents = taxonomy_get_parents($current->tid)) {
    $current = array_shift($parents);
    $breadcrumb[] = l($current->name, 'taxonomy/term/' . $current->tid);
  }
  $breadcrumb[] = l(t('Home'), NULL);
  $breadcrumb = array_reverse($breadcrumb);
  drupal_set_breadcrumb($breadcrumb);
  drupal_add_feed('taxonomy/term/' . $term->tid . '/feed', 'RSS - ' . $term->name);

  // If there is a menu link to this term, the link becomes the last part of
  // the active trail, and the link name becomes the page title. Thus, we must
  // explicitly set the page title to be the node title.
  $uri = entity_uri('taxonomy_term', $term);

  // Set the term path as the canonical URL to prevent duplicate content.
  drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
  // Set the non-aliased path as a default shortlink.
  drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);

  $build = taxonomy_term_show($term);
  // This is the only deviation from the core function.
  $build['members'] = array('#markup' => views_embed_view('team_members', 'block', $term->tid));
  return $build;
}

If different outputs are desired for each vocabulary, we can simply add additional cases to our page callback and replicate the output function.

Topics: