Newer
Older
/**
* @file
* Enables the organization of content into categories.
*/
use Drupal\Component\Utility\Tags;
catch
committed
use Drupal\Core\Entity\ContentEntityDatabaseStorage;
use Drupal\Core\Entity\EntityInterface;
Angie Byron
committed
use Drupal\Core\Render\Element;
Angie Byron
committed
use Drupal\Core\Url;
use Drupal\file\FileInterface;
use Drupal\node\Entity\Node;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
use Drupal\taxonomy\VocabularyInterface;
Alex Pott
committed
use Drupal\Component\Utility\String;
/**
* Denotes that no term in the vocabulary has a parent.
*/
const TAXONOMY_HIERARCHY_DISABLED = 0;
/**
* Denotes that one or more terms in the vocabulary has a single parent.
*/
const TAXONOMY_HIERARCHY_SINGLE = 1;
/**
* Denotes that one or more terms in the vocabulary have multiple parents.
*/
const TAXONOMY_HIERARCHY_MULTIPLE = 2;
/**
* Users can create new terms in a free-tagging vocabulary when
* submitting a taxonomy_autocomplete_widget. We store a term object
* whose tid is 'autocreate' as a field data item during widget
* validation and then actually create the term if/when that field
* data item makes it to taxonomy_field_insert/update().
*/
/**
Dries Buytaert
committed
* Implements hook_help().
*/
function taxonomy_help($path, $arg) {
switch ($path) {
case 'admin/help#taxonomy':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Taxonomy module allows you to classify the content of your website. To classify content, you define <em>vocabularies</em> that contain related <em>terms</em>, and then assign the vocabularies to content types. For more information, see the online handbook entry for the <a href="@taxonomy">Taxonomy module</a>.', array('@taxonomy' => 'http://drupal.org/documentation/modules/taxonomy')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Creating vocabularies') . '</dt>';
Angie Byron
committed
$output .= '<dd>' . t('Users with sufficient <a href="@perm">permissions</a> can create <em>vocabularies</em> and <em>terms</em> through the <a href="@taxo">Taxonomy page</a>. The page listing the terms provides a drag-and-drop interface for controlling the order of the terms and sub-terms within a vocabulary, in a hierarchical fashion. A <em>controlled vocabulary</em> classifying music by genre with terms and sub-terms could look as follows:', array('@taxo' => url('admin/structure/taxonomy'), '@perm' => url('admin/people/permissions', array('fragment'=>'module-taxonomy'))));
$output .= '<ul><li>' . t('<em>vocabulary</em>: Music') . '</li>';
$output .= '<ul><li>' . t('<em>term</em>: Jazz') . '</li>';
$output .= '<ul><li>' . t('<em>sub-term</em>: Swing') . '</li>';
$output .= '<li>' . t('<em>sub-term</em>: Fusion') . '</li></ul></ul>';
$output .= '<ul><li>' . t('<em>term</em>: Rock') . '</li>';
$output .= '<ul><li>' . t('<em>sub-term</em>: Country rock') . '</li>';
$output .= '<li>' . t('<em>sub-term</em>: Hard rock') . '</li></ul></ul></ul>';
$output .= t('You can assign a sub-term to multiple parent terms. For example, <em>fusion</em> can be assigned to both <em>rock</em> and <em>jazz</em>.') . '</dd>';
$output .= '<dd>' . t('Terms in a <em>free-tagging vocabulary</em> can be built gradually as you create or edit content. This is often done used for blogs or photo management applications.') . '</dd>';
$output .= '<dt>' . t('Assigning vocabularies to content types') . '</dt>';
Dries Buytaert
committed
$output .= '<dd>' . t('Before you can use a new vocabulary to classify your content, a new Taxonomy term field must be added to a <a href="@ctedit">content type</a> on its <em>manage fields</em> page. When adding a taxonomy field, you choose a <em>widget</em> to use to enter the taxonomy information on the content editing page: a select list, checkboxes, radio buttons, or an auto-complete field (to build a free-tagging vocabulary). After choosing the field type and widget, on the subsequent <em>field settings</em> page you can choose the desired vocabulary, whether one or multiple terms can be chosen from the vocabulary, and other settings. The same vocabulary can be added to multiple content types, by using the "Re-use existing field" section on the manage fields page.', array('@ctedit' => url('admin/structure/types'))) . '</dd>';
$output .= '<dt>' . t('Classifying content') . '</dt>';
Angie Byron
committed
$output .= '<dd>' . t('After the vocabulary is assigned to the content type, you can start classifying content. The field with terms will appear on the content editing screen when you edit or <a href="@addnode">add new content</a>.', array('@addnode' => url('node/add'))) . '</dd>';
$output .= '<dt>' . t('Viewing listings and RSS feeds by term') . '</dt>';
$output .= '<dd>' . t("Each taxonomy term automatically provides a page listing content that has its classification, and a corresponding RSS feed. For example, if the taxonomy term <em>country rock</em> has the ID 123 (you can see this by looking at the URL when hovering on the linked term, which you can click to navigate to the listing page), then you will find this list at the path <em>taxonomy/term/123</em>. The RSS feed will use the path <em>taxonomy/term/123/feed</em> (the RSS icon for this term's listing will automatically display in your browser's address bar when viewing the listing page).") . '</dd>';
$output .= '<dt>' . t('Extending Taxonomy module') . '</dt>';
$output .= '<dd>' . t('There are <a href="@taxcontrib">many contributed modules</a> that extend the behavior of the Taxonomy module for both display and organization of terms.', array('@taxcontrib' => 'http://drupal.org/project/modules?filters=tid:71&solrsort=sis_project_release_usage%20desc'));
$output .= '</dl>';
return $output;
case 'admin/structure/taxonomy':
Angie Byron
committed
$output = '<p>' . t('Taxonomy is for categorizing content. Terms are grouped into vocabularies. For example, a vocabulary called "Fruit" would contain the terms "Apple" and "Banana".') . '</p>';
return $output;
case 'admin/structure/taxonomy/manage/%':
$vocabulary = entity_load('taxonomy_vocabulary', $arg[4]);
switch ($vocabulary->hierarchy) {
case TAXONOMY_HIERARCHY_DISABLED:
return '<p>' . t('You can reorganize the terms in %capital_name using their drag-and-drop handles, and group terms under a parent term by sliding them under and to the right of the parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . '</p>';
case TAXONOMY_HIERARCHY_SINGLE:
return '<p>' . t('%capital_name contains terms grouped under parent terms. You can reorganize the terms in %capital_name using their drag-and-drop handles.', array('%capital_name' => drupal_ucfirst($vocabulary->name), '%name' => $vocabulary->name)) . '</p>';
case TAXONOMY_HIERARCHY_MULTIPLE:
return '<p>' . t('%capital_name contains terms with multiple parents. Drag and drop of terms with multiple parents is not supported, but you can re-enable drag-and-drop support by editing each term to include only a single parent.', array('%capital_name' => drupal_ucfirst($vocabulary->name))) . '</p>';
}
}
}
Dries Buytaert
committed
* Implements hook_permission().
function taxonomy_permission() {
Dries Buytaert
committed
$permissions = array(
Angie Byron
committed
'administer taxonomy' => array(
'title' => t('Administer vocabularies and terms'),
Angie Byron
committed
),
);
foreach (entity_load_multiple('taxonomy_vocabulary') as $vocabulary) {
Dries Buytaert
committed
$permissions += array(
'edit terms in ' . $vocabulary->id() => array(
Dries Buytaert
committed
'title' => t('Edit terms in %vocabulary', array('%vocabulary' => $vocabulary->name)),
),
);
$permissions += array(
'delete terms in ' . $vocabulary->id() => array(
'title' => t('Delete terms from %vocabulary', array('%vocabulary' => $vocabulary->name)),
Dries Buytaert
committed
),
);
}
return $permissions;
Dries Buytaert
committed
/**
* Implements hook_entity_bundle_info().
*/
function taxonomy_entity_bundle_info() {
$bundles = array();
foreach (taxonomy_vocabulary_get_names() as $id) {
$config = \Drupal::config('taxonomy.vocabulary.' . $id);
Alex Pott
committed
$bundles['taxonomy_term'][$id]['label'] = $config->get('name');
}
Dries Buytaert
committed
return $bundles;
Dries Buytaert
committed
}
Angie Byron
committed
/**
Angie Byron
committed
* Entity URI callback.
Angie Byron
committed
*/
Angie Byron
committed
function taxonomy_term_uri($term) {
Angie Byron
committed
return new Url('taxonomy.term_page', array(
'taxonomy_term' => $term->id(),
));
Angie Byron
committed
}
Angie Byron
committed
/**
* Return nodes attached to a term across all field instances.
*
* This function requires taxonomy module to be maintaining its own tables,
* and will return an empty array if it is not. If using other field storage
* methods alternatives methods for listing terms will need to be used.
*
* @param $tid
* The term ID.
Angie Byron
committed
* @param $pager
* Boolean to indicate whether a pager should be used.
* @param $limit
* Integer. The maximum number of nodes to find.
* Set to FALSE for no limit.
Dries Buytaert
committed
* @param $order
Angie Byron
committed
* An array of fields and directions.
*
* @return
* An array of nids matching the query.
*/
function taxonomy_select_nodes($tid, $pager = TRUE, $limit = FALSE, $order = array('t.sticky' => 'DESC', 't.created' => 'DESC')) {
if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
Angie Byron
committed
return array();
}
$query = db_select('taxonomy_index', 't');
$query->addTag('node_access');
Dries Buytaert
committed
$query->addMetaData('base_table', 'taxonomy_index');
Dries Buytaert
committed
$query->condition('tid', $tid);
Angie Byron
committed
if ($pager) {
$count_query = clone $query;
$count_query->addExpression('COUNT(t.nid)');
catch
committed
$query = $query->extend('Drupal\Core\Database\Query\PagerSelectExtender');
if ($limit !== FALSE) {
$query = $query->limit($limit);
}
Angie Byron
committed
$query->setCountQuery($count_query);
}
else {
if ($limit !== FALSE) {
$query->range(0, $limit);
}
Angie Byron
committed
}
$query->addField('t', 'nid');
$query->addField('t', 'tid');
foreach ($order as $field => $direction) {
$query->orderBy($field, $direction);
// ORDER BY fields need to be loaded too, assume they are in the form
// table_alias.name
list($table_alias, $name) = explode('.', $field);
$query->addField($table_alias, $name);
}
return $query->execute()->fetchCol();
}
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implements hook_theme().
Dries Buytaert
committed
*/
function taxonomy_theme() {
return array(
'taxonomy_term' => array(
'render element' => 'elements',
'template' => 'taxonomy-term',
),
Dries Buytaert
committed
);
}
* Checks and updates the hierarchy flag of a vocabulary.
* Checks the current parents of all terms in a vocabulary and updates the
* vocabulary's hierarchy setting to the lowest possible level. If no term
* has parent terms then the vocabulary will be given a hierarchy of
* TAXONOMY_HIERARCHY_DISABLED. If any term has a single parent then the
* vocabulary will be given a hierarchy of TAXONOMY_HIERARCHY_SINGLE. If any
* term has multiple parents then the vocabulary will be given a hierarchy of
* TAXONOMY_HIERARCHY_MULTIPLE.
Alex Pott
committed
* @param \Drupal\taxonomy\VocabularyInterface $vocabulary
* A taxonomy vocabulary entity.
* @param $changed_term
* An array of the term structure that was updated.
*
* @return
* An integer that represents the level of the vocabulary's hierarchy.
Alex Pott
committed
function taxonomy_check_vocabulary_hierarchy(VocabularyInterface $vocabulary, $changed_term) {
$tree = taxonomy_get_tree($vocabulary->id());
$hierarchy = TAXONOMY_HIERARCHY_DISABLED;
foreach ($tree as $term) {
// Update the changed term with the new parent value before comparison.
if ($term->tid == $changed_term['tid']) {
$term = (object) $changed_term;
$term->parents = $term->parent;
}
// Check this term's parent count.
if (count($term->parents) > 1) {
$hierarchy = TAXONOMY_HIERARCHY_MULTIPLE;
break;
}
elseif (count($term->parents) == 1 && !isset($term->parents[0])) {
$hierarchy = TAXONOMY_HIERARCHY_SINGLE;
Dries Buytaert
committed
if ($hierarchy != $vocabulary->hierarchy) {
$vocabulary->hierarchy = $hierarchy;
Alex Pott
committed
$vocabulary->save();
}
return $hierarchy;
}
Angie Byron
committed
* Generates an array which displays a term detail page.
Alex Pott
committed
* @param \Drupal\taxonomy\Entity\Term $term
Angie Byron
committed
* A taxonomy term object.
* @param string $view_mode
* View mode, e.g. 'full', 'teaser'...
Angie Byron
committed
* @param string $langcode
Dries Buytaert
committed
* (optional) A language code to use for rendering. Defaults to the global
* content language of the current request.
Angie Byron
committed
* @return array
Jennifer Hodgdon
committed
* A $page element suitable for use by drupal_render().
Angie Byron
committed
*/
Angie Byron
committed
function taxonomy_term_view(Term $term, $view_mode = 'full', $langcode = NULL) {
return entity_view($term, $view_mode, $langcode);
Angie Byron
committed
}
Dries Buytaert
committed
/**
Angie Byron
committed
* Constructs a drupal_render() style array from an array of loaded terms.
Angie Byron
committed
*
Angie Byron
committed
* @param array $terms
* An array of taxonomy terms as returned by entity_load_multiple('taxonomy_term').
Angie Byron
committed
* @param string $view_mode
* View mode, e.g. 'full', 'teaser'...
* @param string $langcode
* (optional) A language code to use for rendering. Defaults to the global
* content language of the current request.
*
Angie Byron
committed
* @return array
* An array in the format expected by drupal_render().
Angie Byron
committed
*/
Angie Byron
committed
function taxonomy_term_view_multiple(array $terms, $view_mode = 'full', $langcode = NULL) {
return entity_view_multiple($terms, $view_mode, $langcode);
/**
* Implements hook_theme_suggestions_HOOK().
*/
function taxonomy_theme_suggestions_taxonomy_term(array $variables) {
$suggestions = array();
/** @var \Drupal\taxonomy\TermInterface $term */
$term = $variables['elements']['#taxonomy_term'];
$suggestions[] = 'taxonomy_term__' . $term->bundle();
$suggestions[] = 'taxonomy_term__' . $term->id();
return $suggestions;
}
* Prepares variables for taxonomy term templates.
*
* Default template: taxonomy-term.html.twig.
*
* @param array $variables
* An associative array containing:
* - elements: An associative array containing the taxonomy term and any
* fields attached to the term. Properties used:
* - #taxonomy_term: A \Drupal\taxonomy\TermInterface object.
* - #view_mode: The current view mode for this taxonomy term, e.g.
* 'full' or 'teaser'.
* - attributes: HTML attributes for the containing element.
*/
function template_preprocess_taxonomy_term(&$variables) {
$variables['view_mode'] = $variables['elements']['#view_mode'];
$variables['term'] = $variables['elements']['#taxonomy_term'];
/** @var \Drupal\taxonomy\TermInterface $term */
$term = $variables['term'];
Alex Pott
committed
$variables['url'] = $term->url();
// We use name here because that is what appears in the UI.
$variables['name'] = $variables['elements']['name'];
unset($variables['elements']['name']);
$variables['page'] = $variables['view_mode'] == 'full' && taxonomy_term_is_page($term);
// Helpful $content variable for templates.
Dries Buytaert
committed
$variables['content'] = array();
Angie Byron
committed
foreach (Element::children($variables['elements']) as $key) {
$variables['content'][$key] = $variables['elements'][$key];
}
Dries Buytaert
committed
// Gather classes, and clean up name so there are no underscores.
Dries Buytaert
committed
$variables['attributes']['class'][] = 'taxonomy-term';
$vocabulary_name_css = str_replace('_', '-', $term->bundle());
Dries Buytaert
committed
$variables['attributes']['class'][] = 'vocabulary-' . $vocabulary_name_css;
}
/**
Dries Buytaert
committed
* Returns whether the current page is the page of the passed-in term.
Alex Pott
committed
* @param \Drupal\taxonomy\Entity\Term $term
* A taxonomy term entity.
Dries Buytaert
committed
function taxonomy_term_is_page(Term $term) {
Angie Byron
committed
$request = \Drupal::request();
if ($request->attributes->has('taxonomy_term')) {
$page_term = $request->attributes->get('taxonomy_term');
return $page_term->id() == $term->id();
}
return FALSE;
Dries Buytaert
committed
/**
* Clear all static cache variables for terms.
Dries Buytaert
committed
*/
function taxonomy_terms_static_reset() {
catch
committed
\Drupal::entityManager()->getStorage('taxonomy_term')->resetCache();
Dries Buytaert
committed
}
/**
* Clear all static cache variables for vocabularies.
*
* @param $ids
* An array of ids to reset in entity controller cache.
*/
function taxonomy_vocabulary_static_reset(array $ids = NULL) {
catch
committed
\Drupal::entityManager()->getStorage('taxonomy_vocabulary')->resetCache($ids);
}
Dries Buytaert
committed
/**
* Get names for all taxonomy vocabularies.
*
* @return array
* A list of existing vocabulary IDs.
Dries Buytaert
committed
*/
function taxonomy_vocabulary_get_names() {
$names = &drupal_static(__FUNCTION__);
if (!isset($names)) {
$names = array();
$config_names = \Drupal::configFactory()->listAll('taxonomy.vocabulary.');
foreach ($config_names as $config_name) {
$id = substr($config_name, strlen('taxonomy.vocabulary.'));
$names[$id] = $id;
}
Dries Buytaert
committed
return $names;
}
* Finds all parents of a given term ID.
*
* @param $tid
* A taxonomy term ID.
*
* @return
Dries Buytaert
committed
* An array of term objects which are the parents of the term $tid, or an
* empty array if parents are not found.
function taxonomy_term_load_parents($tid) {
$parents = &drupal_static(__FUNCTION__, array());
if ($tid && !isset($parents[$tid])) {
catch
committed
$tids = \Drupal::entityManager()->getStorage('taxonomy_term')->loadParents($tid);
$parents[$tid] = entity_load_multiple('taxonomy_term', $tids);
return isset($parents[$tid]) ? $parents[$tid] : array();
function taxonomy_term_load_parents_all($tid) {
Dries Buytaert
committed
$cache = &drupal_static(__FUNCTION__, array());
if (isset($cache[$tid])) {
return $cache[$tid];
}
if ($term = entity_load('taxonomy_term', $tid)) {
Angie Byron
committed
$parents[] = $term;
while ($parent = taxonomy_term_load_parents($parents[$n]->id())) {
Dries Buytaert
committed
$cache[$tid] = $parents;
* Finds all children of a term ID.
*
* @param $tid
* A taxonomy term ID.
*
* @return
Angie Byron
committed
* An array of term objects that are the children of the term $tid, or an
* empty array when no children exist.
function taxonomy_term_load_children($tid) {
$children = &drupal_static(__FUNCTION__, array());
if ($tid && !isset($children[$tid])) {
catch
committed
$tids = \Drupal::entityManager()->getStorage('taxonomy_term')->loadChildren($tid);
$children[$tid] = entity_load_multiple('taxonomy_term', $tids);
return isset($children[$tid]) ? $children[$tid] : array();
/**
* Create a hierarchical representation of a vocabulary.
*
* @param $vid
* The vocabulary ID to generate the tree for.
* @param $parent
* The term ID under which to generate the tree. If 0, generate the tree
* for the entire vocabulary.
* @param $max_depth
* The number of levels of the tree to return. Leave NULL to return all levels.
Angie Byron
committed
* @param $load_entities
* If TRUE, a full entity load will occur on the term objects. Otherwise they
* are partial objects queried directly from the {taxonomy_term_data} table to
* save execution time and memory consumption when listing large numbers of
* terms. Defaults to FALSE.
* @return
* An array of all term objects in the tree. Each term object is extended
* to have "depth" and "parents" attributes in addition to its normal ones.
Angie Byron
committed
* Results are statically cached. Term objects will be partial or complete
* depending on the $load_entities parameter.
Angie Byron
committed
function taxonomy_get_tree($vid, $parent = 0, $max_depth = NULL, $load_entities = FALSE) {
Dries Buytaert
committed
$children = &drupal_static(__FUNCTION__, array());
$parents = &drupal_static(__FUNCTION__ . ':parents', array());
$terms = &drupal_static(__FUNCTION__ . ':terms', array());
// We cache trees, so it's not CPU-intensive to call taxonomy_get_tree() on a
// term and its children, too.
Dries Buytaert
committed
$parents[$vid] = array();
$terms[$vid] = array();
catch
committed
$result = \Drupal::entityManager()->getStorage('taxonomy_term')->loadTree($vid);
Angie Byron
committed
foreach ($result as $term) {
$children[$vid][$term->parent][] = $term->tid;
$parents[$vid][$term->tid][] = $term->parent;
$terms[$vid][$term->tid] = $term;
Angie Byron
committed
// Load full entities, if necessary. The entity controller statically
// caches the results.
if ($load_entities) {
$term_entities = entity_load_multiple('taxonomy_term', array_keys($terms[$vid]));
Angie Byron
committed
}
$max_depth = (!isset($max_depth)) ? count($children[$vid]) : $max_depth;
Dries Buytaert
committed
$tree = array();
Angie Byron
committed
// Keeps track of the parents we have to process, the last entry is used
// for the next processing step.
$process_parents = array();
$process_parents[] = $parent;
// Loops over the parent terms and adds its children to the tree array.
// Uses a loop instead of a recursion, because it's more efficient.
while (count($process_parents)) {
$parent = array_pop($process_parents);
// The number of parents determines the current depth.
$depth = count($process_parents);
if ($max_depth > $depth && !empty($children[$vid][$parent])) {
$has_children = FALSE;
$child = current($children[$vid][$parent]);
do {
if (empty($child)) {
break;
}
$term = $load_entities ? $term_entities[$child] : $terms[$vid][$child];
if (isset($parents[$vid][$load_entities ? $term->id() : $term->tid])) {
Dries Buytaert
committed
// Clone the term so that the depth attribute remains correct
// in the event of multiple parents.
Angie Byron
committed
$term = clone $term;
}
$term->depth = $depth;
unset($term->parent);
$tid = $load_entities ? $term->id() : $term->tid;
$term->parents = $parents[$vid][$tid];
Angie Byron
committed
$tree[] = $term;
if (!empty($children[$vid][$tid])) {
Angie Byron
committed
$has_children = TRUE;
// We have to continue with this parent later.
$process_parents[] = $parent;
// Use the current term as parent for the next iteration.
$process_parents[] = $tid;
Angie Byron
committed
// Reset pointers for child lists because we step in there more often
// with multi parents.
reset($children[$vid][$tid]);
Angie Byron
committed
// Move pointer so that we get the correct term the next time.
next($children[$vid][$parent]);
break;
}
} while ($child = next($children[$vid][$parent]));
if (!$has_children) {
// We processed all terms in this hierarchy-level, reset pointer
// so that this function works the next time it gets called.
reset($children[$vid][$parent]);
Dries Buytaert
committed
return $tree;
* Provides a case-insensitive and trimmed mapping, to maximize the
* likelihood of a successful match.
*
* @param $name
* @param $vocabulary
* (optional) Vocabulary machine name to limit the search. Defaults to NULL.
function taxonomy_term_load_multiple_by_name($name, $vocabulary = NULL) {
$values = array('name' => trim($name));
if (isset($vocabulary)) {
$vocabularies = taxonomy_vocabulary_get_names();
if (isset($vocabularies[$vocabulary])){
$values['vid'] = $vocabulary;
}
else {
// Return an empty array when filtering by a non-existing vocabulary.
return array();
}
}
return entity_load_multiple_by_properties('taxonomy_term', $values);
/**
* Load multiple taxonomy terms based on certain conditions.
*
* This function should be used whenever you need to load more than one term
* from the database. Terms are loaded into memory and will not require
* database access if loaded again during the same page request.
*
* @see entity_load_multiple()
Alex Pott
committed
* @see \Drupal\Core\Entity\Query\EntityQueryInterface
Dries Buytaert
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use entity_load_multiple('taxonomy_term', $tids).
* @param array $tids
* (optional) An array of entity IDs. If omitted, all entities are loaded.
*
* @return array
* An array of taxonomy term entities, indexed by tid. When no results are
* found, an empty array is returned.
*/
function taxonomy_term_load_multiple(array $tids = NULL) {
return entity_load_multiple('taxonomy_term', $tids);
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Loads multiple taxonomy vocabularies based on certain conditions.
Dries Buytaert
committed
*
* This function should be used whenever you need to load more than one
* vocabulary from the database. Terms are loaded into memory and will not
* require database access if loaded again during the same page request.
*
* @see entity_load_multiple()
Dries Buytaert
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use entity_load_multiple('taxonomy_vocabulary', $vids).
* @param array $vids
* (optional) An array of entity IDs. If omitted, all entities are loaded.
Dries Buytaert
committed
*
* @return array
Dries Buytaert
committed
* An array of vocabulary objects, indexed by vid.
*/
function taxonomy_vocabulary_load_multiple(array $vids = NULL) {
return entity_load_multiple('taxonomy_vocabulary', $vids);
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Return the taxonomy vocabulary entity matching a vocabulary ID.
Dries Buytaert
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use entity_load('taxonomy_vocabulary', $vid).
* @param int $vid
* The vocabulary's ID.
Dries Buytaert
committed
*
* @return \Drupal\taxonomy\Entity\Vocabulary|null
Dries Buytaert
committed
* The taxonomy vocabulary entity, if exists, NULL otherwise. Results are
* statically cached.
Dries Buytaert
committed
*/
function taxonomy_vocabulary_load($vid) {
return entity_load('taxonomy_vocabulary', $vid);
Dries Buytaert
committed
}
* Return the taxonomy term entity matching a term ID.
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use entity_load('taxonomy_term', $tid).
* @param $tid
* A term's ID
*
* @return \Drupal\taxonomy\Entity\Term|null
Dries Buytaert
committed
* A taxonomy term entity, or NULL if the term was not found. Results are
Jennifer Hodgdon
committed
* statically cached.
Dries Buytaert
committed
function taxonomy_term_load($tid) {
Dries Buytaert
committed
if (!is_numeric($tid)) {
Dries Buytaert
committed
return NULL;
Dries Buytaert
committed
}
return entity_load('taxonomy_term', $tid);
}
/**
* Implements hook_file_download_access().
*/
function taxonomy_file_download_access($field, EntityInterface $entity, FileInterface $file) {
if ($entity->getEntityTypeId() == 'taxonomy_term') {
return $entity->access('view');
}
}
/**
Dries Buytaert
committed
* Implodes a list of tags of a certain vocabulary into a string.
* @see \Drupal\Component\Utility\Tags::explode()
*/
function taxonomy_implode_tags($tags, $vid = NULL) {
$typed_tags = array();
foreach ($tags as $tag) {
// Extract terms belonging to the vocabulary in question.
if (!isset($vid) || $tag->bundle() == $vid) {
Dries Buytaert
committed
// Make sure we have a completed loaded taxonomy term.
Angie Byron
committed
if ($tag instanceof EntityInterface && $label = $tag->label()) {
Dries Buytaert
committed
// Commas and quotes in tag names are special cases, so encode 'em.
$typed_tags[] = Tags::encode($label);
}
}
}
Dries Buytaert
committed
return implode(', ', $typed_tags);
}
Dries Buytaert
committed
/**
Dries Buytaert
committed
* Implements hook_field_widget_info_alter().
Dries Buytaert
committed
*/
function taxonomy_field_widget_info_alter(&$info) {
catch
committed
$info['options_select']['field_types'][] = 'taxonomy_term_reference';
$info['options_buttons']['field_types'][] = 'taxonomy_term_reference';
Dries Buytaert
committed
}
Dries Buytaert
committed
/**
* Title callback for term pages.
*
Alex Pott
committed
* @param \Drupal\taxonomy\Entity\Term $term
* A taxonomy term entity.
Dries Buytaert
committed
*
Dries Buytaert
committed
* @return
* The term name to be used as the page title.
*/
Dries Buytaert
committed
function taxonomy_term_title(Term $term) {
Alex Pott
committed
return $term->getName();
Dries Buytaert
committed
}
Angie Byron
committed
/**
Dries Buytaert
committed
* Form element validate handler for taxonomy term autocomplete element.
Angie Byron
committed
*/
function taxonomy_autocomplete_validate($element, &$form_state) {
Angie Byron
committed
// Split the values into an array.
Alex Pott
committed
// @see \Drupal\taxonomy\Plugin\Field\FieldWidget\TaxonomyAutocompleteWidget:massageFormValues()
Angie Byron
committed
$typed_terms = array();
Dries Buytaert
committed
if ($tags = $element['#value']) {
$typed_terms = Tags::explode($tags);
Angie Byron
committed
}
Angie Byron
committed
form_set_value($element, $typed_terms, $form_state);
Angie Byron
committed
}
Angie Byron
committed
/**
* @defgroup taxonomy_index Taxonomy indexing
* @{
* Functions to maintain taxonomy indexing.
Angie Byron
committed
*
* Taxonomy uses default field storage to store canonical relationships
* between terms and fieldable entities. However its most common use case
* requires listing all content associated with a term or group of terms
* sorted by creation date. To avoid slow queries due to joining across
* multiple node and field tables with various conditions and order by criteria,
* we maintain a denormalized table with all relationships between terms,
* published nodes and common sort criteria such as sticky and created.
* This is used as a lookup table by taxonomy_select_nodes(). When using other
* field storage engines or alternative methods of denormalizing this data
* you should set the taxonomy.settings:maintain_index_table to '0' to avoid
* unnecessary writes in SQL.
Angie Byron
committed
*/
/**
* Implements hook_node_insert().
Angie Byron
committed
*/
Angie Byron
committed
function taxonomy_node_insert(EntityInterface $node) {
// Add taxonomy index entries for the node.
taxonomy_build_node_index($node);
Angie Byron
committed
}
/**
* Builds and inserts taxonomy index entries for a given node.
*
* The index lists all terms that are related to a given node entity, and is
* therefore maintained at the entity level.
*
* @param \Drupal\node\Entity\Node $node
* The node entity.
Angie Byron
committed
*/
function taxonomy_build_node_index($node) {
// We maintain a denormalized table of term/node relationships, containing
// only data for current, published nodes.
catch
committed
if (!\Drupal::config('taxonomy.settings')->get('maintain_index_table') || !(\Drupal::entityManager()->getStorage('node') instanceof ContentEntityDatabaseStorage)) {
return;
}
$status = $node->isPublished();
$sticky = (int) $node->isSticky();
// We only maintain the taxonomy index for published nodes.
Angie Byron
committed
if ($status && $node->isDefaultRevision()) {
// Collect a unique list of all the term IDs from all node fields.
$tid_all = array();
foreach ($node->getFieldDefinitions() as $field) {
Alex Pott
committed
$field_name = $field->getName();
if ($field->getType() == 'taxonomy_term_reference') {
catch
committed
foreach ($node->getTranslationLanguages() as $language) {
foreach ($node->getTranslation($language->id)->$field_name as $item) {
if (!$item->isEmpty()) {
$tid_all[$item->target_id] = $item->target_id;
}
}
}
}
}
// Insert index entries for all the node's terms.
if (!empty($tid_all)) {
foreach ($tid_all as $tid) {
db_merge('taxonomy_index')
->key(array('nid' => $node->id(), 'tid' => $tid))
->fields(array('sticky' => $sticky, 'created' => $node->getCreatedTime()))
->execute();
Angie Byron
committed
}
}
}
}
/**
* Implements hook_node_update().
*/
Angie Byron
committed
function taxonomy_node_update(EntityInterface $node) {
// Always rebuild the node's taxonomy index entries on node save.
taxonomy_delete_node_index($node);
taxonomy_build_node_index($node);
}
Angie Byron
committed
/**
catch
committed
* Implements hook_node_predelete().
Angie Byron
committed
*/
Angie Byron
committed
function taxonomy_node_predelete(EntityInterface $node) {
// Clean up the {taxonomy_index} table when nodes are deleted.
taxonomy_delete_node_index($node);
}
/**
* Deletes taxonomy index entries for a given node.
*
Angie Byron
committed
* @param \Drupal\Core\Entity\EntityInterface $node
* The node entity.
*/
Angie Byron
committed
function taxonomy_delete_node_index(EntityInterface $node) {
if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
db_delete('taxonomy_index')->condition('nid', $node->id())->execute();
Angie Byron
committed
}
}
/**
Dries Buytaert
committed
* Implements hook_taxonomy_term_delete().
Angie Byron
committed
*/
Dries Buytaert
committed
function taxonomy_taxonomy_term_delete(Term $term) {
if (\Drupal::config('taxonomy.settings')->get('maintain_index_table')) {
Angie Byron
committed
// Clean up the {taxonomy_index} table when terms are deleted.
db_delete('taxonomy_index')->condition('tid', $term->id())->execute();
Angie Byron
committed
}
}
/**
* @} End of "defgroup taxonomy_index".