'Taxonomy Tools', 'description' => 'Taxonomy Tools configuration', 'page callback' => 'system_admin_menu_block_page', 'access arguments' => array('access administration pages'), 'file' => 'system.admin.inc', 'file path' => drupal_get_path('module', 'system'), ); $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/overview'] = array( 'title' => 'Overview', 'description' => 'Vocabulary overview table', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_tools_overview', 3, 5), 'file' => 'taxonomy_tools.admin.inc', 'file path' => drupal_get_path('module', 'taxonomy_tools'), 'type' => MENU_LOCAL_TASK, 'weight' => 50, 'access callback' => 'taxonomy_tools_overview_access', 'access arguments' => array(3), ); $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/overview/%/add'] = array( 'title' => 'Add term', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_form_term', array(), 3), 'file path' => drupal_get_path('module', 'taxonomy'), 'file' => 'taxonomy.admin.inc', 'access callback' => 'taxonomy_tools_overview_access', 'access arguments' => array(3, TRUE), ); $items['admin/structure/taxonomy/%taxonomy_vocabulary_machine_name/overview/add'] = array( 'title' => 'Add term', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_form_term', array(), 3), 'file path' => drupal_get_path('module', 'taxonomy'), 'file' => 'taxonomy.admin.inc', 'access callback' => 'taxonomy_tools_overview_access', 'access arguments' => array(3, TRUE), ); $items['taxonomy/term/%taxonomy_term/overview'] = array( 'title' => 'Subtree', 'description' => 'Subtree overview table', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_tools_overview', NULL, 2), 'file' => 'taxonomy_tools.admin.inc', 'file path' => drupal_get_path('module', 'taxonomy_tools'), 'access arguments' => array('use taxonomy tools'), 'weight' => 50, 'type' => MENU_LOCAL_TASK, ); $items['taxonomy/term/%taxonomy_term/overview/add/%taxonomy_vocabulary_machine_name'] = array( 'title' => 'Add term', 'page callback' => 'drupal_get_form', 'page arguments' => array('taxonomy_form_term', array(), 5), 'file path' => drupal_get_path('module', 'taxonomy'), 'file' => 'taxonomy.admin.inc', 'access callback' => 'taxonomy_tools_overview_access', 'access arguments' => array(5, TRUE), ); return $items; } /** * Implements hook_theme(). */ function taxonomy_tools_theme() { return array( 'taxonomy_tools_overview' => array( 'render element' => 'form', ), ); } /** * Implements hook_form_FORM_ID_alter(). */ function taxonomy_tools_form_taxonomy_form_term_alter(&$form, &$form_state) { // Preset default parent term. if (arg(4) && arg(4) == 'overview' && is_numeric(arg(5))) { $form['relations']['parent']['#default_value'] = array(arg(5) => arg(5)); } if (arg(3) && arg(3) == 'overview' && is_numeric(arg(2))) { $form['relations']['parent']['#default_value'] = array(arg(2) => arg(2)); } } /** * Implements hook_menu_alter(). */ function taxonomy_tools_menu_alter(&$items) { $use_view = FALSE; if (module_exists('views')) { $views = views_get_enabled_views(); foreach ($views as $view) { foreach ($view->display as $display) { if (isset($display->display_options['path']) && $display->display_options['path'] == 'taxonomy/term/%') { // If term page path is used by a view. $items['taxonomy/term/%views_arg']['access callback'] = 'taxonomy_tools_taxonomy_term_access'; $items['taxonomy/term/%views_arg']['access arguments'] = array(2); $use_view = TRUE; break 2; } } } } if (!$use_view) { $items['taxonomy/term/%taxonomy_term']['access callback'] = 'taxonomy_tools_taxonomy_term_access'; $items['taxonomy/term/%taxonomy_term']['access arguments'] = array(2); } } /** * Controls the access to the taxonomy term. * * If the taxonomy term is from a vocabulary that uses Taxonoomy Publisher * functionality, it's status will checked to determine whether the user is * allowed to access it. * * @param stdClass $term * A taxonomy term object or a string containing taxonomy term ID. * * @return bool * TRUE if user is allowed to access the taxonomy term, and FALSE if isn't. */ function taxonomy_tools_taxonomy_term_access($term) { $access = user_access('access content'); // In case only term ID is passed as parameter we must load the term object. if (is_numeric($term)) { $term = taxonomy_term_load($term); } if (is_object($term)) { if (module_exists('taxonomy_tools_publisher') && $access) { // If Taxonomy Publisher is enabled and term is available to the user. $config = variable_get('taxonomy_tools_publisher_config', array()); if (!empty($config) && in_array($term->vid, $config)) { // We must check the whole hierarchy branch up to the top level. $result = taxonomy_tools_publisher_check_branch($term->tid); if (!user_access('bypass taxonomy publisher') && $result == 0) { // User isn't allowed to access the term, // because the term (or it's parent term) is not published // and user doesn't have permission to view unpublished terms. $access = FALSE; } } } if (module_exists('taxonomy_tools_role_access') && $access && !user_access('bypass taxonomy role access')) { // If Taxonomy Role Access is enabled and term is still available to // the user and user doesn't have permissions to bypass settings. $access = FALSE; global $user; $roles = $user->roles; // User role "authenticated user" is not used when other custom // created user roles exist. if (sizeof($roles) > 1) { unset($roles[2]); } $config = variable_get('taxonomy_tools_role_access_role_config', array()); foreach ($roles as $rid => $role) { if (in_array($rid, $config)) { // User role is controlled by Taxonomy Role Access. $role_access = taxonomy_tools_role_access_get_access($term->tid, $rid); if ($role_access) { // Term is available to the user role. $access = TRUE; break; } } else { // One of the user roles is not controlled by Taxonomy Role Access // term is available to the user. $access = TRUE; break; } } } } else { // Something is wrong with the passed parameter - deny access. $access = FALSE; } return $access; } /** * Implements hook_node_grants(). */ function taxonomy_tools_node_grants($account, $op) { $node_grants = array(); $roles = $account->roles; // User role "authenticated user" is not used when other custom // created user roles exist. if (sizeof($roles) > 1) { unset($roles[2]); } $node_grants = array('taxonomy_tools' => array_keys($roles)); return $node_grants; } /** * Implements hook_node_access_records(). */ function taxonomy_tools_node_access_records($node) { $grants = array(); $grants = taxonomy_tools_build_grants($node); return $grants; } /** * Builds node access grants for all user roles. * * @param stdClass $node * A node object. * * @return array * An array containing node access grants. */ function taxonomy_tools_build_grants($node) { $grants = array(); // Get all terms associated with this node. $query = db_select('taxonomy_index', 'foo'); $query->addField('foo', 'tid'); $query->condition('foo.nid', $node->nid); $query->leftJoin('taxonomy_term_data', 'bar', 'foo.tid = bar.tid'); $query->addField('bar', 'vid'); $result = $query->execute()->fetchAll(); // Get all user roles. $roles = user_roles(); // User role "authenticated user" is not used when other custom // created user roles exist. if (sizeof($roles) > 2) { unset($roles[2]); } $roles = array_keys($roles); // Create node access grants for each user role. foreach ($roles as $rid) { $view = TRUE; if (!empty($result)) { // There are terms associated with this node. $permissions = taxonomy_tools_role_permissions_all($rid); if (module_exists('taxonomy_tools_publisher') && $view) { // If Taxonomy Publisher is enabled and node is visible to user role. $view = FALSE; $config = variable_get('taxonomy_tools_publisher_config', array()); foreach ($result as $term_data) { if (!in_array($term_data->vid, $config) || (in_array($term_data->vid, $config) && taxonomy_tools_publisher_check_branch($term_data->tid))) { // One of terms is not controlled by Taxonomy Publisher // or is controlled but is seen by user. $view = TRUE; break; } } if (!$view && in_array('bypass taxonomy publisher', $permissions)) { // None of associated terms is available to the user, // but user is allowed to see nodes from unpublished terms. $view = TRUE; } } if (module_exists('taxonomy_tools_role_access') && $view) { // If Taxonomy Role Access is enabled and node is visible to user role. $v_config = variable_get('taxonomy_tools_role_access_vocab_config', array()); $r_config = variable_get('taxonomy_tools_role_access_role_config', array()); if (in_array($rid, $r_config)) { $view = FALSE; // Only if user role is controlled by Taxonomy Role Access. foreach ($result as $term_data) { if (!in_array($term_data->vid, $v_config) || (in_array($term_data->vid, $v_config) && taxonomy_tools_role_access_get_access($term_data->tid, $rid))) { // One of terms is not controlled by Taxonomy Role Access // or is controlled but is available to this user role. $view = TRUE; break; } } if (!$view && in_array('bypass taxonomy role access', $permissions)) { // None of associated terms is available to the user, // but user is allowed to see nodes from restricted terms. $view = TRUE; } } } } $grants[] = array( 'realm' => 'taxonomy_tools', 'gid' => $rid, 'grant_view' => $view ? 1 : 0, 'grant_update' => 0, 'grant_delete' => 0, 'priority' => 0, ); } return $grants; } /** * Collects all permissions (also inherited) specific to a user role. * * @param string $rid * A string containing user role ID. * * @return array * An array of user permissions. */ function taxonomy_tools_role_permissions_all($rid) { $user_roles = array(); $user_roles[$rid] = $rid; if ($rid != 1) { // All other roles than anonymous user inherit permissions from // authenticated user. $user_roles[2] = 2; } $permissions = user_role_permissions($user_roles); $permissions_all = array(); // Merge all permissions. foreach ($permissions as $data) { $permissions_all = array_merge($permissions_all, array_keys($data)); } // Remove duplicate values. $permissions_all = array_unique($permissions_all); return $permissions_all; } /** * Fetches ID's of all nodes associated with specific taxonomy term. * * @param string $tid * A string containing taxonomy term ID. * * @return array * An array containing all associated node ID's. */ function taxonomy_tools_associated_nodes($tid) { $nids = array(); // Get all associated node ID's. $query = db_select('taxonomy_index', 'foo'); $query->addField('foo', 'nid'); $query->condition('foo.tid', $tid); $query->execute(); $result = $query->execute()->fetchAll(); foreach ($result as $data) { $nids[] = $data->nid; } // Check if this term has any children. $query = db_select('taxonomy_term_hierarchy', 'foo'); $query->addField('foo', 'tid'); $query->condition('foo.parent', $tid); $result = $query->execute()->fetchAll(); foreach ($result as $data) { // Nodes associated with children terms could also be affected; // fetch those nids also. $nids = array_merge($nids, taxonomy_tools_associated_nodes($data->tid)); } return $nids; } /** * Builds new access grants for nodes associated with specific taxonomy term. * * @param stdClass $term * A taxonomy term object */ function taxonomy_tools_rebuild_access_grants($term) { if (is_numeric($term)) { $term = taxonomy_term_load($term); } $rebuild = FALSE; if (module_exists('taxonomy_tools_publisher') && !$rebuild) { // Whether Taxonomy Publisher module is enabled. $config = variable_get('taxonomy_tools_publisher_config', array()); // Only if the vocabulary uses Taxonomy Publisher. if (!empty($config) && in_array($term->vid, $config)) { $rebuild = TRUE; } } if (module_exists('taxonomy_tools_role_access') && !$rebuild) { // Whether Taxonomy Publisher module is enabled. $config = variable_get('taxonomy_tools_role_access_vocab_config', array()); // Only if the vocabulary uses Taxonomy Publisher. if (!empty($config) && in_array($term->vid, $config)) { $rebuild = TRUE; } } if ($rebuild) { // Get all associated nodes. $nids = taxonomy_tools_associated_nodes($term->tid); foreach ($nids as $nid) { // Rewrite node access grants. $node = node_load($nid); node_access_acquire_grants($node); // Allow other modules to act on node access grants rebuild. module_invoke_all('taxonomy_tools_node_access_grants_rebuild', $node); } } } /** * Implements hook_taxonomy_term_update(). */ function taxonomy_tools_taxonomy_term_update($term) { taxonomy_tools_rebuild_access_grants($term); } /** * Implements hook_taxonomy_term_delete(). */ function taxonomy_tools_taxonomy_term_delete($term) { taxonomy_tools_rebuild_access_grants($term); } /** * Returns full parent hierarchy of taxonomy term. * * @param string $tid * Taxonomy term identificator. * * @return array * An array representing full hierarchy of taxonomy term. */ function taxonomy_tools_term_path($tid, $return = TRUE) { $path = array(); $query = db_select('taxonomy_term_data', 'foo'); $query->addField('foo', 'name'); $query->condition('foo.tid', $tid); $query->leftJoin('taxonomy_term_hierarchy', 'bar', 'foo.tid = bar.tid'); $query->addField('bar', 'parent'); $result = $query->execute()->fetchObject(); if ($return) { $path[] = array( 'tid' => $tid, 'name' => $result->name, ); } if ($result->parent > 0) { $path = array_merge($path, taxonomy_tools_term_path($result->parent)); } return $path; } /** * Implements hook_permission(). */ function taxonomy_tools_permission() { return array( 'use taxonomy tools' => array( 'title' => t('Use Taxonomy Tools'), 'description' => t('Allows the user to access Taxonomy Tools overview page.'), ), ); } /** * Controls access to Taxonomy Tools overview page. * * @return bool * TRUE if the vocabulary uses at least one of Taxonomy Tools * sub-modules and user has permission to access * Taxonomy Tools overview page; * FALSE otherwise. */ function taxonomy_tools_overview_access($vocabulary, $add = NULL) { $access = FALSE; $access = user_access('use taxonomy tools'); if ($access && $add && !(user_access('administer taxonomy') || user_access('edit terms in ' . $vocabulary->vid))) { $access = FALSE; } return $access; } /** * Implements hook_admin_paths(). */ function taxonomy_tools_admin_paths() { $paths = array( 'taxonomy-tools/*/order/*' => TRUE, ); return $paths; } /** * Implements hook_taxonomy_term_presave(). */ function taxonomy_tools_taxonomy_term_presave($term) { if (arg(4) == 'overview' || arg(3) == 'overview') { $count = array(); // Take in account that term can have more than one parent. foreach ($term->parent as $tid) { $query = db_select('taxonomy_term_hierarchy', 'foo'); $query->addField('foo', 'tid'); $query->condition('foo.parent', $tid); $query->join('taxonomy_term_data', 'bar', 'foo.tid = bar.tid'); $query->condition('bar.vid', $term->vid); $count[] = $query->countQuery()->execute()->fetchField(); } // Set term weight to siblings count + 1. // We use the biggest siblings count. $term->weight = max($count) + 1; } } /** * Implements hook_modules_enabled(). */ function taxonomy_tools_modules_enabled($modules) { if (in_array('views', $modules)) { // Set the module weight bigger than Views. $query = db_select('system', 's'); $query->addField('s', 'weight'); $query->condition('s.name', 'views'); $weight = $query->execute()->fetchField(); $query = db_update('system'); $query->fields(array( 'weight' => $weight + 1, )); $query->condition('name', 'taxonomy_tools'); $query->execute(); } } /** * Implements hook_preprocess_HOOK(). */ function taxonomy_tools_preprocess_page(&$variables) { if (arg(4) == 'overview' && arg(5) != 'add' && arg(6) != 'add') { // Proper breadcrumb for vocabulary overview page. $breadcrumb = array(); $options = array('html' => TRUE); $step = l(t('Home'), '', $options); array_push($breadcrumb, $step); $step = l(t('Administration'), 'admin', $options); array_push($breadcrumb, $step); $step = l(t('Structure'), 'admin/structure', $options); array_push($breadcrumb, $step); $step = l(t('Taxonomy'), 'admin/structure/taxonomy', $options); array_push($breadcrumb, $step); if (is_numeric(arg(5))) { $query = db_select('taxonomy_vocabulary', 'foo'); $query->addField('foo', 'name'); $query->condition('foo.machine_name', arg(3)); $vocabulary_name = $query->execute()->fetchField(); $step = l($vocabulary_name, 'admin/structure/taxonomy/' . arg(3) . '/overview', $options); array_push($breadcrumb, $step); $path = array_reverse(taxonomy_tools_term_path(arg(5), FALSE)); if (!empty($path)) { foreach ($path as $term) { $step = l($term['name'], 'admin/structure/taxonomy/' . arg(3) . '/overview/' . $term['tid'], $options); array_push($breadcrumb, $step); } } } drupal_set_breadcrumb($breadcrumb); } if (arg(4) == 'overview' && (arg(5) == 'add' || arg(6) == 'add')) { // Proper breadcrumb when adding new term through vocabulary // overview page. $breadcrumb = array(); $options = array('html' => TRUE); $step = l(t('Home'), '', $options); array_push($breadcrumb, $step); $step = l(t('Administration'), 'admin', $options); array_push($breadcrumb, $step); $step = l(t('Structure'), 'admin/structure', $options); array_push($breadcrumb, $step); $step = l(t('Taxonomy'), 'admin/structure/taxonomy', $options); array_push($breadcrumb, $step); $query = db_select('taxonomy_vocabulary', 'foo'); $query->addField('foo', 'name'); $query->condition('foo.machine_name', arg(3)); $vocabulary_name = $query->execute()->fetchField(); $step = l($vocabulary_name, 'admin/structure/taxonomy/' . arg(3) . '/overview', $options); array_push($breadcrumb, $step); if (is_numeric(arg(5))) { $path = array_reverse(taxonomy_tools_term_path(arg(5))); if (!empty($path)) { foreach ($path as $term) { $step = l($term['name'], 'admin/structure/taxonomy/' . arg(3) . '/overview/' . $term['tid'], $options); array_push($breadcrumb, $step); } } } drupal_set_breadcrumb($breadcrumb); } if (arg(3) == 'overview' && arg(4) == 'add' && is_numeric(arg(2))) { // Proper breadcrumb when adding new term through vocabulary // overview page which is opened through term page. $breadcrumb = array(); $options = array('html' => TRUE); $step = l(t('Home'), '', $options); array_push($breadcrumb, $step); $path = array_reverse(taxonomy_tools_term_path(arg(2))); if (!empty($path)) { foreach ($path as $term) { $step = l($term['name'], 'taxonomy/term/' . $term['tid'] . '/overview', $options); array_push($breadcrumb, $step); } } drupal_set_breadcrumb($breadcrumb); } } /** * Returns the title of a taxonomy term. * * @param string $tid * The taxonomy term title. */ function taxonomy_tools_term_title($tid) { $title = ''; $query = db_select('taxonomy_term_data', 'foo'); $query->addField('foo', 'name'); $query->condition('foo.tid', $tid); $title = $query->execute()->fetchField(); return $title; } /** * Implements hook_module_implements_alter(). */ function taxonomy_tools_module_implements_alter(&$implementations, $hook) { if ($hook == 'menu_alter' && module_exists('views')) { // Implementation of hook_menu_alter() of this module is called last. $group = $implementations['taxonomy_tools']; unset($implementations['taxonomy_tools']); $implementations['taxonomy_tools'] = $group; } }