diff options
Diffstat (limited to 'modules/taxonomy')
-rw-r--r-- | modules/taxonomy/taxonomy-term.tpl.php | 4 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.api.php | 24 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.install | 2 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.module | 153 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.pages.inc | 17 | ||||
-rw-r--r-- | modules/taxonomy/taxonomy.test | 25 |
6 files changed, 190 insertions, 35 deletions
diff --git a/modules/taxonomy/taxonomy-term.tpl.php b/modules/taxonomy/taxonomy-term.tpl.php index b1ff20e3c..d410d1ef3 100644 --- a/modules/taxonomy/taxonomy-term.tpl.php +++ b/modules/taxonomy/taxonomy-term.tpl.php @@ -11,7 +11,7 @@ * such as render($content['field_example']). Use * hide($content['field_example']) to temporarily suppress the printing of a * given element. - * - $term_url: Direct url of the current term. + * - $term_url: Direct URL of the current term. * - $term_name: Name of the current term. * - $classes: String of classes that can be used to style contextually through * CSS. It can be manipulated through the variable $classes_array from @@ -36,6 +36,8 @@ * @see template_preprocess() * @see template_preprocess_taxonomy_term() * @see template_process() + * + * @ingroup themeable */ ?> <div id="taxonomy-term-<?php print $term->tid; ?>" class="<?php print $classes; ?>"> diff --git a/modules/taxonomy/taxonomy.api.php b/modules/taxonomy/taxonomy.api.php index cb778c9a7..10575c575 100644 --- a/modules/taxonomy/taxonomy.api.php +++ b/modules/taxonomy/taxonomy.api.php @@ -182,6 +182,30 @@ function hook_taxonomy_term_delete($term) { } /** + * Act on a taxonomy term that is being assembled before rendering. + * + * The module may add elements to $term->content prior to rendering. This hook + * will be called after hook_view(). The structure of $term->content is a + * renderable array as expected by drupal_render(). + * + * @param $term + * The term that is being assembled for rendering. + * @param $view_mode + * The $view_mode parameter from taxonomy_term_view(). + * @param $langcode + * The language code used for rendering. + * + * @see hook_entity_view() + */ +function hook_taxonomy_term_view($term, $view_mode, $langcode) { + $term->content['my_additional_field'] = array( + '#markup' => $additional_field, + '#weight' => 10, + '#theme' => 'mymodule_my_additional_field', + ); +} + +/** * Alter the results of taxonomy_term_view(). * * This hook is called after the content has been assembled in a structured diff --git a/modules/taxonomy/taxonomy.install b/modules/taxonomy/taxonomy.install index 711a0f983..c353c9c8c 100644 --- a/modules/taxonomy/taxonomy.install +++ b/modules/taxonomy/taxonomy.install @@ -266,7 +266,7 @@ function taxonomy_update_dependencies() { * * This function is valid for a database schema version 7002. * - * @ingroup update-api-6.x-to-7.x + * @ingroup update_api */ function _update_7002_taxonomy_get_vocabularies() { return db_query('SELECT v.* FROM {taxonomy_vocabulary} v ORDER BY v.weight, v.name')->fetchAllAssoc('vid', PDO::FETCH_OBJ); diff --git a/modules/taxonomy/taxonomy.module b/modules/taxonomy/taxonomy.module index d501282fe..dc3cf44bc 100644 --- a/modules/taxonomy/taxonomy.module +++ b/modules/taxonomy/taxonomy.module @@ -140,7 +140,7 @@ function taxonomy_entity_info() { } /** - * Entity uri callback. + * Entity URI callback. */ function taxonomy_term_uri($term) { return array( @@ -323,8 +323,8 @@ function taxonomy_menu() { ); $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name'] = array( - 'title callback' => 'taxonomy_admin_vocabulary_title_callback', - 'title arguments' => array(3), + 'title callback' => 'entity_label', + 'title arguments' => array('taxonomy_vocabulary', 3), 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_overview_terms', 3), 'access arguments' => array('administer taxonomy'), @@ -375,7 +375,13 @@ function taxonomy_term_edit_access($term) { } /** - * Return the vocabulary name given the vocabulary object. + * Returns the sanitized name of a vocabulary. + * + * Deprecated. This function was previously used as a menu item title callback + * but has been replaced by using entity_label() (which does not + * sanitize the title, since the menu system does that automatically). In + * Drupal 7, use that function for title callbacks, and call check_plain() + * directly if you need a sanitized title. */ function taxonomy_admin_vocabulary_title_callback($vocabulary) { return check_plain($vocabulary->name); @@ -386,7 +392,8 @@ function taxonomy_admin_vocabulary_title_callback($vocabulary) { * * @param $vocabulary * A vocabulary object with the following properties: - * - vid: The ID of the vocabulary. + * - vid: (optional) The ID of the vocabulary (omit if creating a new + * vocabulary; only use to update an existing vocabulary). * - name: The human-readable name of the vocabulary. * - machine_name: The machine name of the vocabulary. * - description: (optional) The vocabulary's description. @@ -401,7 +408,7 @@ function taxonomy_admin_vocabulary_title_callback($vocabulary) { * * @return * Status constant indicating whether the vocabulary was inserted (SAVED_NEW) - * or updated(SAVED_UPDATED). + * or updated (SAVED_UPDATED). */ function taxonomy_vocabulary_save($vocabulary) { // Prevent leading and trailing spaces in vocabulary names. @@ -736,6 +743,102 @@ function taxonomy_term_delete($tid) { } /** + * Generates an array which displays a term detail page. + * + * @param term + * A taxonomy term object. + * @return + * A $page element suitable for use by drupal_page_render(). + */ +function taxonomy_term_show($term) { + return taxonomy_term_view_multiple(array($term->tid => $term), 'full'); +} + +/** + * Constructs a drupal_render() style array from an array of loaded terms. + * + * @param $terms + * An array of taxonomy terms as returned by taxonomy_term_load_multiple(). + * @param $view_mode + * View mode, e.g. 'full', 'teaser'... + * @param $weight + * An integer representing the weight of the first node in the list. + * @param $langcode + * (optional) A language code to use for rendering. Defaults to the global + * content language of the current request. + * + * @return + * An array in the format expected by drupal_render(). + */ +function taxonomy_term_view_multiple($terms, $view_mode = 'teaser', $weight = 0, $langcode = NULL) { + field_attach_prepare_view('taxonomy_term', $terms, $view_mode, $langcode); + entity_prepare_view('taxonomy_term', $terms, $langcode); + $build = array(); + foreach ($terms as $term) { + $build['taxonomy_terms'][$term->tid] = taxonomy_term_view($term, $view_mode, $langcode); + $build['taxonomy_terms'][$term->tid]['#weight'] = $weight; + $weight++; + } + $build['taxonomy_terms']['#sorted'] = TRUE; + return $build; +} + +/** + * Builds a structured array representing the term's content. + * + * The content built for the taxonomy term (field values, file attachments or + * other term components) will vary depending on the $view_mode parameter. + * + * Drupal core defines the following view modes for terms, with the following + * default use cases: + * - full (default): term is displayed on its own page (taxonomy/term/123) + * Contributed modules might define additional view modes, or use existing + * view modes in additional contexts. + * + * @param $term + * A taxonomy term object. + * @param $view_mode + * View mode, e.g. 'full', 'teaser'... + * @param $langcode + * (optional) A language code to use for rendering. Defaults to the global + * content language of the current request. + */ +function taxonomy_term_build_content($term, $view_mode = 'full', $langcode = NULL) { + if (!isset($langcode)) { + $langcode = $GLOBALS['language_content']->language; + } + + // Remove previously built content, if exists. + $term->content = array(); + + // Try to add in the core taxonomy pieces like description and nodes. + $type = 'taxonomy_term'; + $entity_ids = entity_extract_ids($type, $term); + $settings = field_view_mode_settings($type, $entity_ids[2]); + $fields = field_extra_fields_get_display($type, $entity_ids[2], $view_mode); + if (!empty($term->description) && isset($fields['description']) && $fields['description']['visible']) { + $term->content['description'] = array( + '#markup' => check_markup($term->description, $term->format, '', TRUE), + '#weight' => $fields['description']['weight'], + '#prefix' => '<div class="taxonomy-term-description">', + '#suffix' => '</div>', + ); + } + + // Build fields content. + // In case of a multiple view, taxonomy_term_view_multiple() already ran the + // 'prepare_view' step. An internal flag prevents the operation from running + // twice. + field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode, $langcode); + entity_prepare_view('taxonomy_term', array($term->tid => $term), $langcode); + $term->content += field_attach_view('taxonomy_term', $term, $view_mode, $langcode); + + // Allow modules to make their own additions to the taxonomy term. + module_invoke_all('taxonomy_term_view', $term, $view_mode, $langcode); + module_invoke_all('entity_view', $term, 'taxonomy_term', $view_mode, $langcode); +} + +/** * Generate an array for rendering the given term. * * @param $term @@ -754,31 +857,31 @@ function taxonomy_term_view($term, $view_mode = 'full', $langcode = NULL) { $langcode = $GLOBALS['language_content']->language; } - field_attach_prepare_view('taxonomy_term', array($term->tid => $term), $view_mode, $langcode); - entity_prepare_view('taxonomy_term', array($term->tid => $term), $langcode); + // Allow modules to change the view mode. + $context = array( + 'entity_type' => 'taxonomy_term', + 'entity' => $term, + 'langcode' => $langcode, + ); + drupal_alter('entity_view_mode', $view_mode, $context); + + // Populate $node->content with a render() array. + taxonomy_term_build_content($term, $view_mode, $langcode); + $build = $term->content; + + // We don't need duplicate rendering info in $term->content. + unset($term->content); - $build = array( + $build += array( '#theme' => 'taxonomy_term', '#term' => $term, '#view_mode' => $view_mode, '#language' => $langcode, ); - $build += field_attach_view('taxonomy_term', $term, $view_mode, $langcode); - - // Add term description if the term has one. - if (!empty($term->description)) { - $build['description'] = array( - '#markup' => check_markup($term->description, $term->format, '', TRUE), - '#weight' => 0, - '#prefix' => '<div class="taxonomy-term-description">', - '#suffix' => '</div>', - ); - } - $build['#attached']['css'][] = drupal_get_path('module', 'taxonomy') . '/taxonomy.css'; - // Allow modules to modify the structured term. + // Allow modules to modify the structured taxonomy term. $type = 'taxonomy_term'; drupal_alter(array('taxonomy_term_view', 'entity_view'), $build, $type); @@ -1000,8 +1103,8 @@ function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities $parents = &drupal_static(__FUNCTION__ . ':parents', array()); $terms = &drupal_static(__FUNCTION__ . ':terms', array()); - // We cache trees, so it's not CPU-intensive to call get_tree() on a term - // and its children, too. + // We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a + // term and its children, too. if (!isset($children[$vid])) { $children[$vid] = array(); $parents[$vid] = array(); @@ -1914,7 +2017,7 @@ function taxonomy_taxonomy_term_delete($term) { * Converts EntityFieldQuery instances on taxonomy terms that have an entity * condition on term bundles (vocabulary machine names). Since the vocabulary * machine name is not present in the {taxonomy_term_data} table itself, we have - * to convert the bundle condition into a proprety condition of vocabulary IDs + * to convert the bundle condition into a property condition of vocabulary IDs * to match against {taxonomy_term_data}.vid. */ function taxonomy_entity_query_alter($query) { diff --git a/modules/taxonomy/taxonomy.pages.inc b/modules/taxonomy/taxonomy.pages.inc index 501ebbe10..4d2c4e6fc 100644 --- a/modules/taxonomy/taxonomy.pages.inc +++ b/modules/taxonomy/taxonomy.pages.inc @@ -33,21 +33,24 @@ function taxonomy_term_page($term) { drupal_set_breadcrumb($breadcrumb); drupal_add_feed('taxonomy/term/' . $term->tid . '/feed', 'RSS - ' . $term->name); - $build = array(); + // 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); - $build['term_heading'] = array( - '#prefix' => '<div class="term-listing-heading">', - '#suffix' => '</div>', - 'term' => taxonomy_term_view($term, 'full'), - ); + // 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); if ($nids = taxonomy_select_nodes($term->tid, TRUE, variable_get('default_nodes_main', 10))) { $nodes = node_load_multiple($nids); $build += node_view_multiple($nodes); $build['pager'] = array( '#theme' => 'pager', '#weight' => 5, - ); + ); } else { $build['no_content'] = array( diff --git a/modules/taxonomy/taxonomy.test b/modules/taxonomy/taxonomy.test index 32ae84d66..4cfb81b28 100644 --- a/modules/taxonomy/taxonomy.test +++ b/modules/taxonomy/taxonomy.test @@ -98,6 +98,18 @@ class TaxonomyVocabularyFunctionalTest extends TaxonomyWebTestCase { $edit['machine_name'] = '!&^%'; $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save')); $this->assertText(t('The machine-readable name must contain only lowercase letters, numbers, and underscores.')); + + // Ensure that vocabulary titles are escaped properly. + $edit = array(); + $edit['name'] = 'Don\'t Panic'; + $edit['description'] = $this->randomName(); + $edit['machine_name'] = 'don_t_panic'; + $this->drupalPost('admin/structure/taxonomy/add', $edit, t('Save')); + + $site_name = variable_get('site_name', 'Drupal'); + $this->drupalGet('admin/structure/taxonomy/don_t_panic'); + $this->assertTitle(t('Don\'t Panic | @site-name', array('@site-name' => $site_name))); + $this->assertNoTitle(t('Don't Panic | @site-name', array('@site-name' => $site_name))); } /** @@ -1378,12 +1390,16 @@ class TaxonomyHooksTestCase extends TaxonomyWebTestCase { function setUp() { parent::setUp('taxonomy', 'taxonomy_test'); + module_load_include('inc', 'taxonomy', 'taxonomy.pages'); $taxonomy_admin = $this->drupalCreateUser(array('administer taxonomy')); $this->drupalLogin($taxonomy_admin); } /** - * Test that hooks are run correctly on creating, editing and deleting a term. + * Test that hooks are run correctly on creating, editing, viewing, + * and deleting a term. + * + * @see taxonomy_test.module */ function testTaxonomyTermHooks() { $vocabulary = $this->createVocabulary(); @@ -1408,6 +1424,13 @@ class TaxonomyHooksTestCase extends TaxonomyWebTestCase { $term = taxonomy_term_load($term->tid); $this->assertEqual($edit['antonym'], $term->antonym, 'Antonym was successfully edited.'); + // View the term and ensure that hook_taxonomy_term_view() and + // hook_entity_view() are invoked. + $term = taxonomy_term_load($term->tid); + $term_build = taxonomy_term_page($term); + $this->assertFalse(empty($term_build['taxonomy_terms'][$term->tid]['taxonomy_test_term_view_check']), 'hook_taxonomy_term_view() was invoked when viewing the term.'); + $this->assertFalse(empty($term_build['taxonomy_terms'][$term->tid]['taxonomy_test_entity_view_check']), 'hook_entity_view() was invoked when viewing the term.'); + // Delete the term. taxonomy_term_delete($term->tid); $antonym = db_query('SELECT tid FROM {taxonomy_term_antonym} WHERE tid = :tid', array(':tid' => $term->tid))->fetchField(); |