taxonomy_menu.module in Taxonomy menu 8
Same filename and directory in other branches
Generates menu links for all selected taxonomy terms.
File
taxonomy_menu.moduleView source
<?php
/**
* @file
* Generates menu links for all selected taxonomy terms.
*/
use Drupal\Core\Language\Language;
use Drupal\Core\Entity\EntityInterface;
use Drupal\taxonomy\Entity\Term;
use Drupal\taxonomy\Entity\Vocabulary;
// Include the database layer.
module_load_include('inc', 'taxonomy_menu', 'taxonomy_menu.database');
// Include the batch functions.
module_load_include('inc', 'taxonomy_menu', 'taxonomy_menu.batch');
// Include the admin functions. Submit function on the confirmation page of the
// taxonomy overview page cannot be found if inc file is included on form alter
// only.
module_load_include('inc', 'taxonomy_menu', 'taxonomy_menu.admin');
/**
* Implements hook_help().
*/
function taxonomy_menu_help($path, $arg) {
// @TODO Implement the hook. Make documentation available to the user.
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function taxonomy_menu_form_taxonomy_vocabulary_form_alter(&$form, &$form_state) {
taxonomy_menu_form_taxonomy_form_vocabulary($form, $form_state);
}
/**
* Rebuilds all the menu items.
*
* @param $vid
* The vocabulary ID of the taxonomy terms from which to rebuild the menu links.
*/
function taxonomy_menu_items_rebuild($vid) {
// Get the name of the menu from the administration settings.
$menu_exists = taxonomy_menu_variable_get('vocab_menu', $vid, FALSE);
// Delete the menu links associated to this vocabulary.
taxonomy_menu_menu_links_delete($vid);
// Re-create the menu links if a menu is set.
if ($menu_exists) {
taxonomy_menu_menu_links_insert($vid);
}
}
/**
* Inserts menu links associated to a vocabulary.
*
* @param $vid
* The ID of the vocabulary.
*/
function taxonomy_menu_menu_links_insert($vid) {
// Get a list of all the taxonomy terms for that vocabulary and process them
// using the bacth API.
$menu_name = taxonomy_menu_variable_get('vocab_menu', $vid, FALSE);
$terms = taxonomy_get_tree($vid, 0, NULL, TRUE);
_taxonomy_menu_save_menu_links_batch($terms, $menu_name);
menu_cache_clear_all($menu_name);
drupal_set_message(t('The Taxonomy menu has been created.'), 'status');
}
/**
* Updates menu links associated to a vocabulary.
*
* @param $vid
* The ID of the vocabulary.
*/
function taxonomy_menu_menu_links_update($vid) {
// Get a list of all the existing taxonomy terms for that vocabulary and
// process them using the bacth API.
$menu_name = taxonomy_menu_variable_get('vocab_menu', $vid, FALSE);
$tm_menu_links = _taxonomy_menu_get_menu_items($vid);
$term_ids = array_values($tm_menu_links);
$terms = entity_load_multiple('taxonomy_term', $term_ids);
_taxonomy_menu_save_menu_links_batch($terms, $menu_name);
menu_cache_clear_all($menu_name);
drupal_set_message(t('The Taxonomy menu has been updated.'), 'status');
}
/**
* Deletes all the menu links associated to a vocabulary.
*
* @param $vid
* The vocabulary ID from which to delete the menu items.
*/
function taxonomy_menu_menu_links_delete($vid) {
// Get a list of all the taxonomy terms for this vocabulary and delete them.
// Deleting means that the menu links are deleted and their respective
// associations in {taxonomy_menu} table as well.
$menu_items = _taxonomy_menu_get_menu_items($vid);
$mlids = array_keys($menu_items);
foreach ($mlids as $mlid) {
menu_link_delete($mlid);
}
_taxonomy_menu_delete_all($vid);
// Remove orphaned links.
$menu_items = _taxonomy_menu_get_orphaned_menu_items($vid);
if (!empty($menu_items)) {
$mlids = array_values($menu_items);
foreach ($mlids as $mlid) {
menu_link_delete($mlid);
}
}
drupal_set_message(t('The Taxonomy menu has been removed.'), 'status');
}
/**
* Prepares a taxonomy item to be saved as a menu link.
*
* A menu item has the following properties:
* - link_path: (required)
* - link_title: (required)
* - router_path: (required)
* - menu_name: (optional)
* - weight: (optional)
* - expanded: (optional)
* - options: (optional)
* - mlid: (optional)
* - plid: (optional)
*
* @param $term
* A taxonomy term used to save a respective menu item.
* @param $menu_name
* The machine name of the menu in which the menu link should be saved.
*
* @return
* A menu link built upon a taxonomy term, to be saved in the menu.
*/
function taxonomy_menu_menu_link_prepare($term, $menu_name) {
static $weight = 0;
$langcode = isset($term
->language()->id) ? $term
->language()->id : Language::LANGCODE_NOT_SPECIFIED;
$recursive_count = FALSE;
// Count nodes attached to a taxonomy term if the settings require it.
// TODO Make the recursivity of node count optional.
$display_count = taxonomy_menu_variable_get('display_num', $term
->bundle(), FALSE);
$hide_term = taxonomy_menu_variable_get('hide_empty_terms', $term
->bundle(), FALSE);
if ($hide_term || $display_count) {
$nodes_count = taxonomy_menu_term_count_nodes($term
->id(), $recursive_count);
$is_hidden = $hide_term && (!$nodes_count || $nodes_count == 0) ? 1 : 0;
}
// Load or create a menu link corresponding the taxonomy term being processed.
$menu_link = taxonomy_menu_existing_menu_link_load($term, $langcode);
// Menu to be attached to.
$menu_link['menu_name'] = $menu_name;
// Expanded.
$menu_link['expanded'] = taxonomy_menu_variable_get('expanded', $term
->bundle(), 0);
// Has children.
$has_children = taxonomy_term_load_children($term
->id(), $term
->bundle());
$menu_link['has_children'] = empty($has_children) ? 0 : 1;
// Flatten.
$flatten_menu = taxonomy_menu_variable_get('flat', $term
->bundle(), 0);
if ($flatten_menu) {
$menu_link['weight'] = $weight++;
$menu_link['has_children'] = 0;
$menu_link['plid'] = taxonomy_menu_variable_get('vocab_parent', $term
->bundle(), NULL);
$menu_link['expanded'] = 0;
}
else {
$menu_link['weight'] = $term->weight->value;
$menu_link['plid'] = taxonomy_menu_term_get_plid($term, $langcode);
}
// Empty terms.
$menu_link['hidden'] = isset($is_hidden) ? $is_hidden : 0;
// Menu link title.
$menu_link['link_title'] = $term->name->value;
if ($display_count && $nodes_count > 0) {
$menu_link['link_title'] .= " (" . $nodes_count . ")";
}
// HTML title attribute.
if (taxonomy_menu_variable_get('display_title_attr', $term
->bundle(), TRUE)) {
$term_description = taxonomy_menu_variable_get('term_item_description', $term
->bundle(), 0);
}
$menu_link['options']['attributes']['title'] = isset($term_description) && $term_description == 1 ? trim($term->description->value) : '';
// Path.
$link_path = taxonomy_menu_path_get($term);
$menu_link['link_path'] = \Drupal::service('path.alias_manager.cached')
->getSystemPath($link_path, $langcode);
return $menu_link;
}
/**
* Loads an existing menu link or creates an initialized one from a taxonomy
* term.
*
* @param array $term
* A taxonomy term to be used to load or create its corresponding menu link.
* @param string $langcode
* The language code corresponding to the menu link to be loaded.
*
* @return array
* A menu link corresponding to the taxonomy term.
*/
function taxonomy_menu_existing_menu_link_load($term, $langcode) {
$menu_link = array();
// Try to get an existing menu link, else initialize a new one with the right
// settings.
$mlid = _taxonomy_menu_get_mlid($term
->id(), $term
->bundle(), $langcode);
if ($mlid) {
$menu_link = menu_link_load($mlid);
// Flag that we want to update a reference in {taxonomy_menu} table later.
$menu_link['taxonomy_menu']['update'] = TRUE;
}
else {
// Only use the term's weight for menu links to be created, else you will
// reset weights that may have been changed by other processes than
// Taxonomy Menu.
$menu_link = entity_create('menu_link', array(
'module' => 'taxonomy_menu',
'hidden' => 0,
'weight' => $term->weight->value,
'has_children' => 1,
'language' => $langcode,
'taxonomy_menu' => array(
'update' => FALSE,
),
));
}
return $menu_link;
}
/**
* Helper function to determine a parent mlid for a specific taxonomy term, in
* function of the settings of the administration pages.
*
* @param $term
* The term, which we want to find the parent mlid.
* @param $langcode
* The language of the term.
*
* @return $plid
* The corresponding parent mlid.
*/
function taxonomy_menu_term_get_plid($term, $langcode) {
$plid = 0;
$parents = taxonomy_term_load_parents($term
->id());
if (empty($parents)) {
// Try to get the vocabulary parent from the settings
// Returns for example:
// - "0:0" : DISABLED
// - "main-menu:0" : MENU ROOT
// - "main-menu:123" : MENU ITEM ROOT
$vocab_parent = taxonomy_menu_variable_get('vocab_parent', $term
->bundle(), NULL);
if ($vocab_parent) {
// "main-menu:123" case
$plid = $vocab_parent;
}
else {
// "main-menu:0" OR "0:0" cases
$plid = 0;
}
}
else {
// We have parents for this taxonomy term. Only get the first one, we don't
// support multiple parents yet.
// @TODO Support multiple parents.
foreach ($parents as $parent) {
$plid = _taxonomy_menu_get_mlid($parent
->id(), $term
->bundle(), $langcode);
break;
}
if ($plid == FALSE) {
$plid = 0;
}
}
return $plid;
}
/**
* Saves a menu link in a menu, based on a taxonomy term.
*
* @param $term
* A taxonomy term used to save a respective menu item.
* @param $menu_name
* The machine name of the menu in which the menu link should be saved.
*
* @return
* The menu link ID of the menu item that has been saved. FALSE, if no item
* could be saved.
*/
function taxonomy_menu_menu_link_save($term, $menu_name) {
$mlid = FALSE;
// Prepare a menu link based on the settings of the vocabulary edit page and
// save it.
$menu_link = taxonomy_menu_menu_link_prepare($term, $menu_name);
drupal_alter('taxonomy_menu_link', $menu_link, $term, $menu_name);
if (menu_link_save($menu_link)) {
$mlid = entity_load_by_uuid('menu_link', $menu_link->uuid)->mlid;
// Let other modules perform actions after the menu item has been saved.
foreach (\Drupal::moduleHandler()
->getImplementations('taxonomy_menu_save') as $module) {
$function = $module . '_taxonomy_menu_save';
$function($term, $menu_link, $mlid);
}
}
return $mlid;
}
/**
* Implements hook_taxonomy_menu_save().
*
* Updates {taxonomy_menu} table using the newly created menu item.
*/
function taxonomy_menu_taxonomy_menu_save($term, $menu_link, $mlid) {
if ($menu_link->taxonomy_menu['update'] == FALSE) {
_taxonomy_menu_insert_menu_item($mlid, $term
->id(), $term
->bundle(), $menu_link->language);
}
}
/**
* Implements hook_taxonomy_vocabulary_delete().
*/
function taxonomy_menu_taxonomy_vocabulary_delete(Vocabulary $vocabulary) {
taxonomy_menu_menu_links_delete($vocabulary
->id());
}
/**
* Implements hook_taxonomy_term_insert($term).
*/
function taxonomy_menu_taxonomy_term_insert(Term $term) {
_taxonomy_menu_termapi_helper($term, 'insert');
}
/**
* Implements hook_taxonomy_term_update().
*/
function taxonomy_menu_taxonomy_term_update(Term $term) {
_taxonomy_menu_termapi_helper($term, 'update');
}
/**
* Implements hook_taxonomy_term_delete().
*/
function taxonomy_menu_taxonomy_term_delete(Term $term) {
_taxonomy_menu_termapi_helper($term, 'delete');
}
/**
* Implements hook_node_insert().
*
* @TODO Update the menu items count, empty terms.
*/
function taxonomy_menu_node_insert(EntityInterface $node) {
}
/**
* Implements hook_node_update().
*
* @TODO Update the menu items count, empty terms.
*/
function taxonomy_menu_node_update(EntityInterface $node) {
}
/**
* Implements hook_node_presave().
*
* @TODO Update the menu items count, empty terms.
*/
function taxonomy_menu_node_presave(EntityInterface $node) {
}
/**
* Implements hook_node_delete().
*
* @TODO Update the menu items count, empty terms.
*/
function taxonomy_menu_node_delete(EntityInterface $node) {
}
/**
* Abstraction of hook_node_<op>().
*
* @param $node
* The node to process.
* @param $operation
* A string of the operation to be performed [update|insert|delete].
*
* @TODO Rebuild the function.
*/
function _taxonomy_menu_nodeapi_helper($node, $operation) {
$terms = array();
// Update the taxonomy menu for each terms
foreach ($terms as $key => $tid) {
$menu_name = taxonomy_menu_variable_get('vocab_menu', $term->vid, FALSE);
$sync = taxonomy_menu_variable_get('sync', $term->vid, TRUE);
$display_num = taxonomy_menu_variable_get('display_num', $term->vid, TRUE);
$hide_empty_terms = taxonomy_menu_variable_get('hide_empty_terms', $term->vid, FALSE);
$term = entity_load('taxonomy_term', $tid);
// taxonomy_term_load($tid) return FALSE if the term was not found
// if taxonomy $term is false, then go to the next $term
if (!$term) {
continue;
}
if ($term && $menu_name && $sync && ($display_num || $hide_empty)) {
switch ($operation) {
case 'insert':
break;
case 'update':
if ($hide_empty_terms) {
_taxonomy_menu_update_all_parents($term, $menu_name);
}
break;
case 'delete':
break;
}
}
// Report status.
//drupal_set_message($message, 'status');
// Rebuild the menu.
\Drupal::state()
->set('menu_rebuild_needed', TRUE);
}
}
/**
* Abstraction of hook_termapi_<op>().
*
* @param $term
* The term to process.
* @param $operation
* A string of the operation to be performed [update|insert|delete].
*/
function _taxonomy_menu_termapi_helper($term, $operation) {
// Only sync if taxonomy_menu is enabled for this vocab and the 'sync'
// option has been checked.
$menu_name = taxonomy_menu_variable_get('vocab_menu', $term
->bundle(), 0);
$sync = taxonomy_menu_variable_get('sync', $term
->bundle(), 0);
if ($menu_name && $sync) {
switch ($operation) {
case 'insert':
$text = 'Added term %term to taxonomy menu %menu_name.';
break;
case 'update':
$text = 'Updated term %term in taxonomy menu %menu_name.';
break;
case 'delete':
$text = 'Deleted term %term from taxonomy menu %menu_name.';
break;
}
$message = t($text, array(
'%term' => $term->name->value,
'%menu_name' => $menu_name,
));
if ($operation == 'delete') {
$mlid = _taxonomy_menu_get_mlid($term
->id(), $term
->bundle());
_taxonomy_menu_delete_item($term
->bundle(), $term
->id());
menu_link_delete($mlid);
}
else {
taxonomy_menu_menu_link_save($term, $menu_name);
}
drupal_set_message($message, 'status');
\Drupal::state()
->set('menu_rebuild_needed', TRUE);
}
}
/**
* Update all parent items.
*
* @param $term
* The taxonomy term from which to update the parents.
* @param $menu_name
* The menu name of the resulting menu links.
*/
function _taxonomy_menu_update_all_parents($term, $menu_name) {
$parents = taxonomy_term_load_parents($term
->id());
if ($parents) {
_taxonomy_menu_save_menu_links_batch($parents, $menu_name);
}
}
/**
* Helper function to see if any of the children have any nodes.
*
* @param $tid
* @param $vid
*
* @return boolean
*/
function _taxonomy_menu_children_has_nodes($tid, $vid, $return = FALSE) {
$children = taxonomy_term_load_children($tid, $vid);
foreach ($children as $tid => $term) {
if (_taxonomy_menu_term_count($tid) > 0) {
$return = TRUE;
}
else {
$return = _taxonomy_menu_children_has_nodes($tid, $vid, $return);
}
}
return $return;
}
/**
* Calculates the number of nodes linked to a term. It can be either recursive
* and process all the children or just for this very term.
*
* This is inspired by taxonomy_select_nodes from taxonomy.module.
*
* @param $tid
* The term ID.
* @param $recursive
* Process all the children or not. Default is FALSE according to Drupal standard.
*
* @return int
* The number of nodes attached to a term and optionally its children.
*
* @TODO Make function recursive.
*/
function taxonomy_menu_term_count_nodes($tid, $recursive = FALSE) {
if ($tid == 0 || !\Drupal::config('taxonomy.settings')
->get('maintain_index_table') ?: TRUE) {
return FALSE;
}
if ($recursive) {
//@TODO Make it recursive.
}
else {
$query = db_select('taxonomy_index', 't');
$query
->condition('tid', $tid);
$query
->addField('t', 'nid');
$query
->addField('t', 'tid');
$count = $query
->countQuery()
->execute()
->fetchField();
}
return $count;
}
/**
* Creates the path for the vid/tid combination.
*
* @param $vid
* @param $tid
*
* @return string
*/
function taxonomy_menu_path_get($term) {
// Get the path function for this vocabulary and run it.
$function = taxonomy_menu_variable_get('path', $term
->bundle(), 'taxonomy_menu_path_default');
return $function($term);
}
/**
* Implements hook_taxonomy_menu_path().
*
* Invoked from taxonomy_menu_get_paths.
*
* @return array
* An array composed of the name of the function to be run to build the path
* (key) and a description (value).
*/
function taxonomy_menu_taxonomy_menu_path() {
$output = array(
'taxonomy_menu_path_default' => t('Default (taxonomy/term/tid)'),
'taxonomy_menu_path_multiple_terms' => t('Multiple terms (taxonomy/term/tid1+tid2+tid3...)'),
);
return $output;
}
/**
* Callback for hook_taxonomy_menu_path.
*/
function taxonomy_menu_path_default($term) {
// When tid equals 0, we are dealing with a vocabulary item. We cannot use
// default path with vocabulary items.
if ($term
->id() == 0) {
return FALSE;
}
else {
$path = 'taxonomy/term/' . $term
->id();
}
return $path;
}
/**
* Callback for hook_taxonomy_menu_path.
*/
function taxonomy_menu_path_multiple_terms($term) {
// When tid equals 0, we are dealing with a vocabulary item. We want the path
// to be a mulitple term path.
if ($term
->id() == 0) {
$tids = _taxonomy_menu_get_tids($term
->bundle());
}
else {
$tids = array(
$term
->id(),
);
$terms = taxonomy_get_tree($term
->bundle(), $term
->id());
foreach ($terms as $term) {
$tids[] = $term->tid;
}
}
// Build the path.
if ($tids) {
$path = 'taxonomy/term/' . implode('+', $tids);
}
else {
$uri = $term
->uri();
$path = !empty($uri['path']) ? $uri['path'] : 'taxonomy/term/' . $term->tid;
}
return $path;
}
/**
* Creates the path to use in a menu item.
*
* @return array
* An array of paths' selections.
*/
function taxonomy_menu_get_paths() {
return \Drupal::moduleHandler()
->invokeAll('taxonomy_menu_path');
}
/**
* Builds a variable from the supplied name and machine name of the vocabulary.
*
* @param $name
* The name of the variable.
* @param $vid
* The vocabulary id from which the machine name will be taken.
*
* @return
* A variable name if a vocabulary could be found from the vid, FALSE otherwise.
*/
function _taxonomy_menu_build_variable($name, $vid) {
if ($vocabulary = entity_load('taxonomy_vocabulary', $vid)) {
return 'taxonomy_menu_' . $name . '_' . $vocabulary->vid;
}
else {
return FALSE;
}
}
/**
* Helper function to replace Drupal's config for Taxonomy menu.
* Gets a value per vocabulary.
*/
function taxonomy_menu_variable_get($key, $vid, $default) {
$config = \Drupal::config('taxonomy_menu.settings')
->get(_taxonomy_menu_build_variable($key, $vid));
if (isset($config)) {
return $config;
}
return $default;
}
/**
* Helper function to replace Drupal's config for Taxonomy menu.
* Sets a value per vocabulary.
*/
function taxonomy_menu_variable_set($key, $vid, $value) {
Drupal::config('taxonomy_menu.settings')
->set(_taxonomy_menu_build_variable($key, $vid), $value)
->save();
}
Functions
Name | Description |
---|---|
taxonomy_menu_existing_menu_link_load | Loads an existing menu link or creates an initialized one from a taxonomy term. |
taxonomy_menu_form_taxonomy_vocabulary_form_alter | Implements hook_form_FORM_ID_alter(). |
taxonomy_menu_get_paths | Creates the path to use in a menu item. |
taxonomy_menu_help | Implements hook_help(). |
taxonomy_menu_items_rebuild | Rebuilds all the menu items. |
taxonomy_menu_menu_links_delete | Deletes all the menu links associated to a vocabulary. |
taxonomy_menu_menu_links_insert | Inserts menu links associated to a vocabulary. |
taxonomy_menu_menu_links_update | Updates menu links associated to a vocabulary. |
taxonomy_menu_menu_link_prepare | Prepares a taxonomy item to be saved as a menu link. |
taxonomy_menu_menu_link_save | Saves a menu link in a menu, based on a taxonomy term. |
taxonomy_menu_node_delete | Implements hook_node_delete(). |
taxonomy_menu_node_insert | Implements hook_node_insert(). |
taxonomy_menu_node_presave | Implements hook_node_presave(). |
taxonomy_menu_node_update | Implements hook_node_update(). |
taxonomy_menu_path_default | Callback for hook_taxonomy_menu_path. |
taxonomy_menu_path_get | Creates the path for the vid/tid combination. |
taxonomy_menu_path_multiple_terms | Callback for hook_taxonomy_menu_path. |
taxonomy_menu_taxonomy_menu_path | Implements hook_taxonomy_menu_path(). |
taxonomy_menu_taxonomy_menu_save | Implements hook_taxonomy_menu_save(). |
taxonomy_menu_taxonomy_term_delete | Implements hook_taxonomy_term_delete(). |
taxonomy_menu_taxonomy_term_insert | Implements hook_taxonomy_term_insert($term). |
taxonomy_menu_taxonomy_term_update | Implements hook_taxonomy_term_update(). |
taxonomy_menu_taxonomy_vocabulary_delete | Implements hook_taxonomy_vocabulary_delete(). |
taxonomy_menu_term_count_nodes | Calculates the number of nodes linked to a term. It can be either recursive and process all the children or just for this very term. |
taxonomy_menu_term_get_plid | Helper function to determine a parent mlid for a specific taxonomy term, in function of the settings of the administration pages. |
taxonomy_menu_variable_get | Helper function to replace Drupal's config for Taxonomy menu. Gets a value per vocabulary. |
taxonomy_menu_variable_set | Helper function to replace Drupal's config for Taxonomy menu. Sets a value per vocabulary. |
_taxonomy_menu_build_variable | Builds a variable from the supplied name and machine name of the vocabulary. |
_taxonomy_menu_children_has_nodes | Helper function to see if any of the children have any nodes. |
_taxonomy_menu_nodeapi_helper | Abstraction of hook_node_<op>(). |
_taxonomy_menu_termapi_helper | Abstraction of hook_termapi_<op>(). |
_taxonomy_menu_update_all_parents | Update all parent items. |