I'm facing this design issue regularly.

For example I've Jobs and Company node types. Both have one common taxonomy term reference field City.

Now when we go to a City term it will show both Jobs and Companies(I don't want this mixing).

I want that it show only Jobs or Companies(in different URL's)

One solution is to duplicate City vocabulary as City Jobs and second as City Companies. Now I get what I want. But in programming it'll complicate as same city in both Vocabularies will have different term id's.

What is the best way to achieve this?

  • 1
    i usually use some special modules around this use case, but I think for the most common use cases the views page solution by Dylan Tack is sufficient.
    – donquixote
    Commented Mar 10, 2014 at 5:06
  • I think Dylan's answer is totally fine, and he deserves the bounty. My own situation often has some more requirements, that is: (1) Different views for different vocabularies. (2) Different views for root-level terms than for lower-level terms (in a hierarchical vocabulary). (3) Having additional elements on the term page, e.g. the list of associated content plus some text field or image. (4) Having a special layout on the term page. (5) Having a similar behavior for nodes instead of terms. I would share this stuff, but I think it should go into a separate question.
    – donquixote
    Commented Mar 12, 2014 at 16:50

4 Answers 4


You can use the Views module to create two different pages:

  • "Jobs in City %1" at /jobs/%
  • "Companies in City %1" /companies/%

Your Views will need a filter for content type, and a contextual filter for taxonomy term. Next, use the Rabbit hole module to make the /taxonomy/term/NNN pages disappear.

  • But how to add all those urls at say jobs/% in the XML sitemap?
    – AgA
    Commented Mar 13, 2014 at 9:48
  1. You can create a view based on City term title

    Fields : Taxonomy term: Name -> Configure field: Taxonomy term: Name -> REWRITE RESULT -> Output this field as a link -> taxonomy/term/[tid]/job

  2. You can use the view module to create two different pages:

    a. view -> Page settings -> path -> taxonomy/term/%/job

    b. Contextual filters add Content: Has taxonomy term ID (with depth) and Content: Has taxonomy term ID depth modifier

    c. Content: Type (= job)

    a1. view -> Page settings -> path -> taxonomy/term/%/company

    b1. b. Contextual filters add Content: Has taxonomy term ID (with depth) and Content: Has taxonomy term ID depth modifier

    c1.Content: Type (= company)

    when You click Taxonomy term: Name (title) based on URL like taxonomy/term/1/job that redirect to taxonomy/term/%/job view page that return group of job content.

similarly group of company list


Dylan Tack's answer is the right and the easiest way to achieve this functionality; If you don't want to use Views module you can solve this by custom module, like this (I didn't test it, correct it, if something is wrong with it):

function myModule_menu() {
  $items = array();

  $items['jobs/%taxonomy_term'] = array(
    'title' => 'Jobs',
    'page callback' => 'custom_page_by_jobs',
    'page arguments' => array(1),
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,

  $items['companies/%taxonomy_term'] = array(
    'title' => 'Companies',
    'page callback' => 'custom_page_by_companies',
    'page arguments' => array(1),
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,

  return $items;

// Mimic of taxonomy_select_nodes() function;
function taxonomy_select_nodes_by_type($tid, $type, $pager = TRUE, $limit = FALSE, $order = array('t.sticky' => 'DESC', 't.created' => 'DESC')) {
  if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
    return array();
  $query = db_select('taxonomy_index', 't');
  $query->join('field_data_field_city', 'fdfc', 't.tid = fdfc.field_city_tid');
  $query->condition('t.tid', $tid);
  $query->condition('fdfc.bundle', $type, '=');
  if ($pager) {
    $count_query = clone $query;

    $query = $query->extend('PagerDefault');
    if ($limit !== FALSE) {
      $query = $query->limit($limit);
  else {
    if ($limit !== FALSE) {
      $query->range(0, $limit);
  $query->addField('t', 'nid');
  $query->addField('t', 'tid');
  foreach ($order as $field => $direction) {
    $query->orderBy($field, $direction);
    list($table_alias, $name) = explode('.', $field);
    $query->addField($table_alias, $name);
  return $query->execute()->fetchCol();

function custom_page_by_type($term, $type) {
//  drupal_set_title($term->name);
//  $current = (object) array(
//    'tid' => $term->tid,
//  );
//  $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);
//  $uri = entity_uri('taxonomy_term', $term);
//  drupal_add_html_head_link(array('rel' => 'canonical', 'href' => url($uri['path'], $uri['options'])), TRUE);
//  drupal_add_html_head_link(array('rel' => 'shortlink', 'href' => url($uri['path'], array_merge($uri['options'], array('alias' => TRUE)))), TRUE);

  $build['term_heading'] = array(
    '#prefix' => '<div class="term-listing-heading">',
    '#suffix' => '</div>',
    'term' => taxonomy_term_view($term, 'full'),

  if ($nids = taxonomy_select_nodes_by_type($term->tid, $type, TRUE, 20)) {
    $nodes = node_load_multiple($nids);
    $build += node_view_multiple($nodes);
    $build['pager'] = array(
      '#theme' => 'pager',
      '#weight' => 5,
  else {
    $build['no_content'] = array(
      '#prefix' => '<p>',
      '#markup' => t('There is currently no content classified with this term.'),
      '#suffix' => '</p>',
  return $build;

function custom_page_by_jobs($taxonomy_term) {
  return custom_page_by_type($taxonomy_term, 'jobs');

function custom_page_by_companies($taxonomy_term) {
  return custom_page_by_type($taxonomy_term, 'companies');


  • Go to Views administration page: admin/structure/views
  • Scroll down and clone Taxonomy term view.
  • Under Page Settings change path to: /taxonomy/term/%/%
  • Add new contextual filter under Advanced section
  • Select Content: type and apply default settings
  • Rearrange contextual filters so that the order is:
    1. Content: Has taxonomy term ID (with depth)
    2. Content: Type
    3. Content: Has taxonomy term ID depth modifier
  • That's it

If you visit the term page taxonomy/term/%term, you will still see all content types in a list. However, you can now filter this list with the name of the content type, for example:

  • taxonomy/term/%term/jobs: will only list the jobs tagged with this term
  • taxonomy/term/%term/company: will only list the companies tagged with this term.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.