You are here

taxonomy_breadcrumb.module in Taxonomy Breadcrumb 5

The taxonomy_breadcrumb module generates taxonomy based breadcrumbs on node pages and taxonomy/term pages. The breadcrumb trail takes on the form: [HOME] >> [VOCABULARY] >> TERM >> [TERM] ...

  • The HOME breadcrumb (if present) links to the homepage. The text displayed for HOME is administrator configurable. If the HOME breadcrumb is not defined by the administrator, it will not appear in the breadcrumb trail.
  • The VOCABULARY breadcrumb (if present) will link to an administrator defined page. If the VOCABULARY does not have an administrator defined page, it will not appear in the breadcrumb trail.
  • Each TERM breadcrumb will link to either (1) taxonomy/term/tid by default, or (2) an administrator defined page if one is defined for the term.
  • These administrator defined "breadcrumb links" for VOCABULARIES and TERMS are controlled from the add/edit vocabulary and add/edit term administrator pages.

Examples: home >> term >> term mysite >> term >> term home >> vocabulary >> term >> term vocabulary >> term >> term

Issues:

  • use of db_rewrite_sql?
  • This module is not expected to be compatible with other modules that call drupal_set_breadcrumb, such as taxonomy_context.
  • With multi-parent terms, all parent terms seem to show up, look into taxonomy_get_parents_all.

File

taxonomy_breadcrumb.module
View source
<?php

/**
 * @file
 * The taxonomy_breadcrumb module generates taxonomy based breadcrumbs on node
 * pages and taxonomy/term pages.  The breadcrumb trail takes on the form:
 *   [HOME] >> [VOCABULARY] >> TERM >> [TERM] ...
 *
 *   - The HOME breadcrumb (if present) links to the homepage.  The text
 *     displayed for HOME is administrator configurable.  If the HOME
 *     breadcrumb is not defined by the administrator, it will not appear
 *     in the breadcrumb trail.
 *   - The VOCABULARY breadcrumb (if present) will link to an administrator
 *     defined page.  If the VOCABULARY does not have an administrator
 *     defined page, it will not appear in the breadcrumb trail.
 *   - Each TERM breadcrumb will link to either
 *     (1) taxonomy/term/tid by default, or
 *     (2) an administrator defined page if one is defined for the term.
 *   - These administrator defined "breadcrumb links" for VOCABULARIES and TERMS
 *     are controlled from the add/edit vocabulary and add/edit term
 *     administrator pages.
 *
 * Examples:
 *   home >> term >> term
 *   mysite >> term >> term
 *   home >> vocabulary >> term >> term
 *   vocabulary >> term >> term
 *
 * Issues:
 *   - use of db_rewrite_sql?
 *   - This module is not expected to be compatible with other modules that call
 *     drupal_set_breadcrumb, such as taxonomy_context.
 *   - With multi-parent terms, all parent terms seem to show up, look into
 *     taxonomy_get_parents_all. 
 */

// default value for Advanced Settings, Node Types
define('TAXONOMY_BREADCRUMB_NODE_TYPES_DEFAULT', 'book');

/**
 * Return lightest term for given node ($nid).
 * Similar to taxonomy_node_get_terms, but only return the lightest term in the
 * lightest vocab for the node.
 */
function taxonomy_breadcrumb_node_get_lightest_term($nid) {

  // We only want the first row of the result--this is the lightest term of the
  // lightest vocab.  This query should be the same as the query found in
  // taxonomy_node_get_terms.
  $result = db_query(db_rewrite_sql('SELECT t.* FROM {term_node} r INNER JOIN {term_data} t ON r.tid = t.tid INNER JOIN {vocabulary} v ON t.vid = v.vid WHERE r.nid = %d ORDER BY v.weight, t.weight, t.name', 't', 'tid'), $nid);
  $term = db_fetch_object($result);

  // extract first row of query
  return $term;
}

/**
 * Return the administrator defined vocabulary path for a given vocabulary
 * ($vid).  If a path doesn't exist, NULL is returned.
 */
function taxonomy_breadcrumb_get_vocabulary_path($vid) {
  $result = db_query("SELECT path FROM {taxonomy_breadcrumb_vocabulary} WHERE vid = %d", $vid);
  $path = NULL;
  if ($row = db_fetch_array($result)) {
    $path = $row['path'];
  }
  return $path;
}

/**
 * Return the administrator defined term path for a given term ($tid).
 * If a path doesn't exist, NULL is returned.
 */
function taxonomy_breadcrumb_get_term_path($tid) {
  $result = db_query("SELECT path FROM {taxonomy_breadcrumb_term} WHERE tid = %d", $tid);
  $path = NULL;
  if ($row = db_fetch_array($result)) {
    $path = $row['path'];
  }
  return $path;
}

/**
 * If the current drupal path (q=) is /node/nid, generate the breadcrumb trail
 * based on nid.
 */
function taxonomy_breadcrumb_generate_breadcrumb($tid, $is_term_page = FALSE) {
  $term = taxonomy_get_term($tid);

  // HOME breadcrumb generation
  $home_text = variable_get('taxonomy_breadcrumb_home', '');
  if ($home_text != '') {
    $breadcrumb[] = l($home_text, NULL);
  }

  // VOCABULARY breadcrumb generation
  $vocabulary_path = taxonomy_breadcrumb_get_vocabulary_path($term->vid);
  if ($vocabulary_path != NULL) {
    $vocabulary = taxonomy_get_vocabulary($term->vid);
    $breadcrumb[] = l($vocabulary->name, $vocabulary_path);
  }

  // TERM breadcrumb generation
  $parent_terms = array_reverse(taxonomy_get_parents_all($tid));
  foreach ($parent_terms as $parent_term) {
    $term_path = taxonomy_breadcrumb_get_term_path($parent_term->tid);
    if ($term_path == NULL) {
      $term_path = taxonomy_term_path(taxonomy_get_term($parent_term->tid));
    }

    // Do not create links to own self if we are on a taxonomy/term page.
    if ($is_term_page && $parent_term->tid == $tid) {
      $breadcrumb[] = check_plain($parent_term->name);
    }
    else {
      $breadcrumb[] = l($parent_term->name, $term_path);
    }
  }

  // Remove current TERM from end of breadcrumb trail
  if (!variable_get('taxonomy_breadcrumb_show_current_term', TRUE) && !is_null($breadcrumb)) {
    array_pop($breadcrumb);
  }
  return $breadcrumb;
}

/**
 * Implementation of hook_menu().
 */
function taxonomy_breadcrumb_menu($may_cache) {
  $items = array();
  if ($may_cache) {
    $items[] = array(
      'path' => 'admin/settings/taxonomy-breadcrumb',
      'title' => t('Taxonomy Breadcrumb'),
      'description' => t('Configure how taxonomy based breadcrumbs are displayed.'),
      'callback' => 'drupal_get_form',
      'callback arguments' => array(
        'taxonomy_breadcrumb_admin_settings',
      ),
      'access' => user_access('administer site configuration'),
      'type' => MENU_NORMAL_ITEM,
    );

    // Similiar to core menu item in taxonomy_menu, except callback is different
    $items[] = array(
      'path' => 'taxonomy/term',
      'title' => t('Taxonomy term'),
      'callback' => 'taxonomy_breadcrumb_term_page',
      'access' => user_access('access content'),
      'type' => MENU_CALLBACK,
    );
  }
  return $items;
}

/**
 * Settings page for module.
 */
function taxonomy_breadcrumb_admin_settings() {
  $form['settings'] = array(
    '#type' => 'fieldset',
    '#title' => t('Basic Settings'),
    '#collapsible' => TRUE,
  );
  $form['settings']['taxonomy_breadcrumb_home'] = array(
    '#type' => 'textfield',
    '#title' => t('Home breadcrumb text'),
    '#default_value' => variable_get('taxonomy_breadcrumb_home', ''),
    '#description' => t('Text to display at top of breadcrumb trail.  Typically home or your site name.  Leave blank to have no home breadcrumb.'),
  );
  $form['settings']['taxonomy_breadcrumb_show_current_term'] = array(
    '#type' => 'checkbox',
    '#title' => t('Show current term in breadcrumb trail?'),
    '#default_value' => variable_get('taxonomy_breadcrumb_show_current_term', TRUE),
    '#description' => t('When enabled, the lightest term associated with node is shown as the last breadcrumb in the breadcrumb trail.  When disabled, the only terms shown in the breadcrumb trail are parent terms (if any parents exist).  The recommended setting is enabled.'),
  );
  $form['advanced'] = array(
    '#type' => 'fieldset',
    '#description' => 'Use these advanced settings to control which node types taxonomy based breadcrumbs will be generated for.  This allows taxonomy_breadcrumb to peacefully coexist with modules that define their own breadcrumbs, such as the book module.  For typical drupal configurations, administrators will not need to modify these settings; however, if user contributed modules are enabled you may need to fine tune taxonomy_breadcrumb here.',
    '#title' => t('Advanced Settings'),
    '#collapsible' => TRUE,
    '#collapsed' => TRUE,
  );
  $form['advanced']['taxonomy_breadcrumb_include_nodes'] = array(
    '#type' => 'radios',
    '#title' => t('Include or exclude the following node types'),
    '#default_value' => variable_get('taxonomy_breadcrumb_include_nodes', FALSE),
    '#options' => array(
      TRUE => t('Include'),
      FALSE => t('Exclude'),
    ),
    '#weight' => 10,
  );
  $tb_types = (array) variable_get('taxonomy_breadcrumb_node_types', TAXONOMY_BREADCRUMB_NODE_TYPES_DEFAULT);
  $default = array();
  foreach ($tb_types as $index => $value) {
    if ($value) {
      $default[] = $index;
    }
  }
  $form['advanced']['taxonomy_breadcrumb_node_types'] = array(
    '#type' => 'checkboxes',
    '#multiple' => TRUE,
    '#title' => t('Node types to include or exclude'),
    '#default_value' => $default,
    '#options' => array_map('check_plain', node_get_types('names')),
    '#description' => t('A list of node types to include or exclude applying taxonomy based breadcrumbs to.'),
    '#weight' => 20,
  );
  return system_settings_form($form);
}

/**
 * Implementation of hook_nodeapi().
 */
function taxonomy_breadcrumb_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

  // If we are on a page view (not just a teaser), set the breadcrumb
  // $a4 contains TRUE if we are on a page view
  if ($op == 'view' && $a4 && !drupal_is_front_page() && arg(1) == $node->nid) {

    // See if the node type of the current node is part of the node types listed on the advanced settings page.
    $array_of_types = array_filter((array) variable_get('taxonomy_breadcrumb_node_types', TAXONOMY_BREADCRUMB_NODE_TYPES_DEFAULT));
    $in_list = in_array($node->type, $array_of_types);

    // if the node type IS IN     the node types list and the list IS     inclusive OR
    // if the node type IS NOT IN the node types list and the list IS NOT inclusive (e.g. exclusive)
    // THEN modify the breadcrumb trail.
    if ($in_list == variable_get('taxonomy_breadcrumb_include_nodes', FALSE)) {

      // Extract lightest term from lightest vocabulary associated with node.
      $term = taxonomy_breadcrumb_node_get_lightest_term($node->nid);
      $breadcrumb = taxonomy_breadcrumb_generate_breadcrumb($term->tid);
      drupal_set_breadcrumb($breadcrumb);
    }
  }
}

/**
 * This function overrides the core taxonomy_term_page.  First, call the core
 * taxonomy_term_page.  Then, alter the breadcrumb trail.  This module's 
 * hook_menu and a module weight greater than taxonomy's ensure this 
 * function gets called for the taxonomy/term path (the module weight is
 * in the system table and is set in taxonomy_breadcrumb.install).
 */
function taxonomy_breadcrumb_term_page($str_tids = '', $depth = 0, $op = 'page') {

  // Call the core taxonomy_term_page function
  $output = taxonomy_term_page($str_tids, $depth, $op);

  // Use first term to generate breadcrumb trail
  $terms = taxonomy_terms_parse_string($str_tids);
  $breadcrumb = taxonomy_breadcrumb_generate_breadcrumb($terms['tids'][0], TRUE);
  drupal_set_breadcrumb($breadcrumb);
  return $output;
}

/**
 * Implementation of hook_help().
 */
function taxonomy_breadcrumb_help($section) {
  switch ($section) {
    case 'admin/help#taxonomy_breadcrumb':
      $output .= t('<p>See %link.</p>', array(
        '%link' => l('admin/settings/taxonomy-breadcrumb', 'admin/settings/taxonomy-breadcrumb'),
      ));
      break;
    case 'admin/settings/taxonomy-breadcrumb':
      $output .= t('The taxonomy_breadcrumb module generates taxonomy based breadcrumbs on node pages and taxonomy/term pages.  The breadcrumb trail takes on the form:
                    <ul>[HOME] >> [VOCABULARY] >> TERM >> [TERM] ...</ul>
                    <ul>
                    <li>The text displayed for HOME is configurable below.  The <em>HOME </em>breadcrumb (if present) links to the homepage.  The text displayed for HOME is administrator configurable.  If the HOME breadcrumb is not defined by the administrator, it will not appear in the breadcrumb trail.</li>
                    <li>The <em>VOCABULARY </em>breadcrumb (if present) will link to an administrator defined page.  If the VOCABULARY does not have an administrator defined page, it will not appear in the breadcrumb trail. This can be configured on the add/edit vocabulary pages within !tax_link (taxonomy).</li>
                    <li>Each <em>TERM </em>breadcrumb will link to either (1) taxonomy/term/tid by default, or (2) an administrator defined page if one is defined for the term. This can be configured on the add/edit term pages within !tax_link (taxonomy).</li>
                    </ul>
                    <br>
                    <p>Examples:
                    <ul>
                    <li>home >> term >> term</li>
                    <li>mysite >> term >> term</li>
                    <li>home >> vocabulary >> term >> term</li>
                    <li>vocabulary >> term >> term</li>
                    </ul>', array(
        '!tax_link' => l('administer >> categories', 'admin/content/taxonomy'),
      ));
      break;
  }
  return $output;
}

/**
 * Implementation of hook_form_alter().  This must be used over hook_taxonomy to
 * add the Breadcrumb Path fields to the vocabulary and term forms.  The
 * hook_taxonomy function does not provide a way to obtain the vid or tid
 * of the vocabulary or term.
 */
function taxonomy_breadcrumb_form_alter($form_id, &$form) {
  if ($form_id == 'taxonomy_form_vocabulary') {
    $form['taxonomy_breadcrumb_path'] = array(
      '#type' => 'textfield',
      '#title' => t('Breadcrumb path (taxonomy_breadcrumb)'),
      '#default_value' => taxonomy_breadcrumb_get_vocabulary_path($form['vid']['#value']),
      '#maxlength' => 128,
      '#description' => t('Specify the path this vocabulary links to as a breadcrumb.  If blank, the breadcrumb will not appear.  Use a relative path and don\'t add a trailing slash.  For example: node/42 or my/path/alias.'),
      '#weight' => 0,
    );
  }
  elseif ($form_id == 'taxonomy_form_term') {
    $form['taxonomy_breadcrumb_path'] = array(
      '#type' => 'textfield',
      '#title' => t('Breadcrumb path (taxonomy_breadcrumb)'),
      '#default_value' => taxonomy_breadcrumb_get_term_path($form['tid']['#value']),
      '#maxlength' => 128,
      '#description' => t('Specify the path this term links to as a breadcrumb.  If blank, the breadcrumb links to the default taxonomy page.  Use a relative path and don\'t add a trailing slash.  For example: node/42 or my/path/alias.'),
      '#weight' => 0,
    );
  }
}

/**
 * Implementation of hook_taxonomy().  This implementation checks to see if a
 * vocabulary or term is being updated and makes the necessary changes in
 * the taxonomy_breadcrumb database tables.
 */
function taxonomy_breadcrumb_taxonomy($op, $type, $object = NULL) {

  // if (after a vocabulary or term is updated)
  // called by module_invoke_all('taxonomy', 'update', 'term', $edit);  in taxonomy.module
  if ($op == 'update' && ($type == 'vocabulary' || $type == 'term')) {

    // Set variables to used in SQL query to reflect if vocabulary or term is
    // being updated.
    if ($type == 'vocabulary') {
      $table = '{taxonomy_breadcrumb_vocabulary}';
      $key_type = 'vid';
      $old_path = taxonomy_breadcrumb_get_vocabulary_path($object['vid']);
    }
    elseif ($type == 'term') {
      $table = '{taxonomy_breadcrumb_term}';
      $key_type = 'tid';
      $old_path = taxonomy_breadcrumb_get_term_path($object['tid']);
    }
    $key = $object[$key_type];
    $new_path = $object['taxonomy_breadcrumb_path'];

    // Delete record from taxonomy_breadcrumb_vocabulary or taxonomy_breadcrumb_term
    if (strlen($new_path) == 0 && $old_path !== NULL) {
      db_query("DELETE FROM {$table} WHERE {$key_type} = %d", $key);
    }
    elseif (strlen($new_path) != 0 && $old_path != NULL) {
      db_query("UPDATE {$table} SET path = '%s' WHERE {$key_type} = %d", $new_path, $key);
    }
    elseif (strlen($new_path) != 0 && $old_path == NULL) {
      db_query("INSERT INTO {$table} ({$key_type}, path) VALUES (%d, '%s')", $key, $new_path);
    }
  }
}

Functions

Namesort descending Description
taxonomy_breadcrumb_admin_settings Settings page for module.
taxonomy_breadcrumb_form_alter Implementation of hook_form_alter(). This must be used over hook_taxonomy to add the Breadcrumb Path fields to the vocabulary and term forms. The hook_taxonomy function does not provide a way to obtain the vid or tid of the vocabulary or term.
taxonomy_breadcrumb_generate_breadcrumb If the current drupal path (q=) is /node/nid, generate the breadcrumb trail based on nid.
taxonomy_breadcrumb_get_term_path Return the administrator defined term path for a given term ($tid). If a path doesn't exist, NULL is returned.
taxonomy_breadcrumb_get_vocabulary_path Return the administrator defined vocabulary path for a given vocabulary ($vid). If a path doesn't exist, NULL is returned.
taxonomy_breadcrumb_help Implementation of hook_help().
taxonomy_breadcrumb_menu Implementation of hook_menu().
taxonomy_breadcrumb_nodeapi Implementation of hook_nodeapi().
taxonomy_breadcrumb_node_get_lightest_term Return lightest term for given node ($nid). Similar to taxonomy_node_get_terms, but only return the lightest term in the lightest vocab for the node.
taxonomy_breadcrumb_taxonomy Implementation of hook_taxonomy(). This implementation checks to see if a vocabulary or term is being updated and makes the necessary changes in the taxonomy_breadcrumb database tables.
taxonomy_breadcrumb_term_page This function overrides the core taxonomy_term_page. First, call the core taxonomy_term_page. Then, alter the breadcrumb trail. This module's hook_menu and a module weight greater than taxonomy's ensure this function gets called for the…

Constants