---
title: "Custom taxonomy term pages · Appnovation"
url: "https://www.appnovation.com/insights/custom-taxonomy-term-pages"
description: "Customize what Drupal displays on taxonomy term pages instead of the default node list, using Views and theming techniques."
---

Article

# Custom taxonomy term pages

[![](https://cdn.sanity.io/images/ey850001/production/36eb314260fb474cacc1b3a473d7e8402d997898-68x68.png?w=68&auto=format) Appno Blogger Appnovation Coop](/people/appno-blogger.md) Aug 10, 2011  
 5 min read 

![Appnovation Blog Default Header](https://cdn.sanity.io/images/ey850001/production/9efe1c26d9584ecfb3dfef5a63e698bf4567d305-1440x600.jpg?w=1400&auto=format) 

Although Drupal's taxonomy module very thoughtfully provides a term page which lists all nodes tagged with that term, site builders often want to customize what is displayed on the term page. Of course, you could just ignore the default term page at taxonomy/term/% and build your own page, but then the term links so nicely provided on node pages and through views fields will not be the ones you want to use and you will have to output all term links yourself. Here are three ways to override the default term page. The first way simply uses a view. The second uses a hook provided by the taxonomy module to alter term page paths. The third uses [hook\_menu\_alter() (opens in new window)](http://api.drupal.org/api/drupal/modules--system--system.api.php/function/hook_menu_alter/7) to take over the whole menu callback for term pages.

**1\. Override the callback for the term path using views** (Drupal 6 and 7) Because the views module has a weight of 10, its hooks get called later than core and many contrib modules. This means views can override the callback for existing paths. If I build a view with a page display and give it a path of taxonomy/term/%, my views display will show up when I navigate to taxonomy/term/%, not the default term page. Given that I can access template files for my view and use views headers, footers, attachments, etc.. this option could fulfill many custom requirements.

Building Rich Internet Apps with Drupal & HTML5 Learn the power of combining Drupal + HTML5 + CSS3 + JS **2\. Use** [**hook\_term\_path()** (opens in new window)](http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_term_path/6) **to link terms to a different path** (Drupal 6 only) I can also have my module change the default path for term pages. (For example, in one case the term page was meant to link to a corresponding node page.) The taxonomy module provides a hook for this: [hook\_term\_path() (opens in new window)](http://api.drupal.org/api/drupal/developer--hooks--core.php/function/hook_term_path/6) will allow my module to override the default taxonomy term path *only for vocabularies which have my module declared in the module column of the vocabulary table*. So if I want hook\_term\_path() to be called I must update the vocabulary table to give my module responsibility, so to speak, for any specific vocabularies whose term path I want to control.

/\*\* \* Implementation of hook\_term\_path(). \*/ function mymodule\_term\_path($term) { // Return the term path. return 'somepath/' . $term->tid; } 

Now, anywhere taxonomy terms are output as links by Drupal (eg. in views, on node pages, on the taxonomy admin pages, ...), the user will be directed to the term pages provided by my module. The correct path for each term is returned by the function [taxonomy\_term\_path() (opens in new window)](http://api.drupal.org/api/drupal/modules--taxonomy--taxonomy.module/function/taxonomy_term_path/6), which checks to see which module is responsible for the term's vocabulary. If outputting the links myself, I also use taxonomy\_term\_path().

$keyword\[\] = l($term->name, taxonomy\_term\_path($term)); 

Note for Drupal 7: taxonomy\_term\_path() is replaced by [taxonomy\_term\_uri() (opens in new window)](http://api.drupal.org/api/drupal/modules--taxonomy--taxonomy.module/function/taxonomy_term_uri/7) which returns an array containing the term path.

**3\. Override the page callback and/or access callback for taxonomy/term/%** (Drupal 6 and 7) Another option is to override the page callback for term pages using [hook\_menu\_alter() (opens in new window)](http://api.drupal.org/api/drupal/modules--system--system.api.php/function/hook_menu_alter/7). This gives me unlimited freedom to display whatever I want when the default taxonomy term path (taxonomy/term/%) is called. I can also override the access callback if I want to set some custom limits on who can see the term pages.

/\*\* \* Implementation of hook\_menu\_alter(). \*/ function mymodule\_menu\_alter(&$menu) { if (isset($menu\['taxonomy/term/%'\])) { $menu\['taxonomy/term/%'\]\['page callback'\] = 'mymodule\_term\_page'; $menu\['taxonomy/term/%'\]\['access callback'\] = 'mymodule\_access\_term\_pages'; $menu\['taxonomy/term/%'\]\['access arguments'\] = array(2); } } 

In my callback function, I can check the term's vocabulary and return something different for each vocabulary. I can also return the default term page provided by the taxonomy module for vocabularies whose term pages I don't want to alter.

/\*\* \* Callback function for taxonomy/term/%. \* \* @param $tid \* The term id. \* \* @return \* Themed page for a taxonomy term, specific to the term's vocabulary. \*/ function mymodule\_taxonomy\_term\_page($tid) { $term = taxonomy\_get\_term($tid); $vocabulary = taxonomy\_vocabulary\_load($term->vid); switch($vocabulary->name) { case 'Keyword': // Returns a custom view. return views\_embed\_view('projects', 'term\_block', $tid); case 'Subject': // Returns a page themed by mymodule. return mymodule\_subject\_page($tid); default: // Returns the default term page provided by taxonomy module. module\_load\_include('inc', 'taxonomy', 'taxonomy.pages'); return taxonomy\_term\_page($tid); } } 

In granting users access to term pages, as with the page callback, I can treat each vocabulary differently if requirements demand it.

/\*\* \* Access callback function for taxonomy/term/%. \* \* @param $tid \* The term id. \* \* @return \* True if current user is granted access, FALSE otherwise. \*/ function mymodule\_access\_term\_pages($tid) { $term = taxonomy\_get\_term($tid); $vocabulary = taxonomy\_vocabulary\_load($term->vid); switch($vocabulary->name) { case 'Keyword': case 'Subject': return user\_access('access content'); default: return user\_access('administer taxonomy'); } } 

As an example of taxonomy term information which may be available, here is a helper function which I used to return term details. (Drupal 6)

/\*\* \* Helper function to get term details ready for term pages. \* \* @param $tid \* The term id. \* \* @return \* An array of term details. \*/ function \_my\_module\_get\_term\_details($tid) { $term = taxonomy\_get\_term($tid); $vars\['description'\] = $term->description; $vars\['synonyms'\] = implode(', ', taxonomy\_get\_synonyms($tid)); $related = taxonomy\_get\_related($tid); foreach ($related as $related\_term) { $related\_terms\[\] = $related\_term->name; } $vars\['related\_terms'\] = implode(', ', $related\_terms); if (user\_access('administer taxonomy')) { $vars\['edit\_link'\] = l('Edit term', 'admin/content/taxonomy/edit/term/' . $tid); } return $vars; } 

Please add your ideas on customizing term pages, if you feel so inclined, especially if you have experience working with taxonomy in Drupal 7.

[![](https://cdn.sanity.io/images/ey850001/production/36eb314260fb474cacc1b3a473d7e8402d997898-68x68.png?w=68&auto=format) Appno Blogger Appnovation Coop · Appnovation](/people/appno-blogger.md) 

## Keep reading

[![What is Sovereign AI](https://cdn.sanity.io/images/ey850001/production/a5889abdd5e80376912546622e046e3fbef234b4-2496x1664.png?w=640&auto=format)](/insights/what-is-open-source-sovereign-ai.md)

 Article · 7 min AI 

### [What Is Open Source, Sovereign AI?](/insights/what-is-open-source-sovereign-ai.md)

Every company is encouraging more AI, and almost every AI bill is climbing. Sovereign AI is about two kinds of control: over your data and over your costs. Here's why open source sits at its foundation.

[Iain MacNeil](/people/iain-macneil.md) Article 

[![AI-first experience design](https://cdn.sanity.io/images/ey850001/production/8bbc2418e87924ef10f36115478a2e10d5bed95e-1584x624.jpg?w=640&auto=format)](/insights/how-build-ai-first-experience-without-throwing-out-everything-youve-already-built.md)

 Article · 6 min AI Sep 10, 2026 

### [How to Build an AI-First Experience Without Throwing Out Everything You've Already Built](/insights/how-build-ai-first-experience-without-throwing-out-everything-youve-already-built.md)

Users now expect a direct answer, not a list of links to click through. Here's how organizations can layer an AI-First experience onto their existing website or app, in weeks rather than years.

[Andrew Douglas](/people/andrew-douglas.md) Article 

[![What Becomes Possible When AI Can Read All the Data](https://cdn.sanity.io/images/ey850001/production/c28ab0bd26753421ee42937e13adc7a7f19b47f0-1296x510.jpg?w=640&auto=format)](/insights/what-becomes-possible-when-ai-can-read-all-data.md)

 Article · 4 min AI Sep 09, 2026 

### [What Becomes Possible When AI Can Read All the Data](/insights/what-becomes-possible-when-ai-can-read-all-data.md)

Most of the world's data has never been analyzed, only sampled. AI changes that. How AI-ready data platforms unlock questions no one could ask before.

[Appnovation](/people/appnovation.md) Article 

## Get the thinking,  
*before everyone else.*

One considered email a month. New essays, field notes from live engagements, and the occasional strong opinion. No noise.
