taxonomy_access.create.inc in Taxonomy Access Control 7
Implements the Add Tag (create) grant on editing forms.
These functions need to be included in three circumstances:
- Form building for forms with taxonomy fields.
- Form validation for forms with taxonomy fields.
- Taxonomy autocomplete AJAX requests.
File
taxonomy_access.create.incView source
<?php
/**
* @file
* Implements the Add Tag (create) grant on editing forms.
*
* These functions need to be included in three circumstances:
* - Form building for forms with taxonomy fields.
* - taxonomy_access_field_widget_form_alter()
* - taxonomy_access_field_widget_taxonomy_autocomplete_form_alter()
* - Form validation for forms with taxonomy fields.
* - taxonomy_access_autocomplete_validate()
* - taxonomy_access_options_validate()
* - taxonomy_access_field_attach_validate()
* - Taxonomy autocomplete AJAX requests.
* - taxonomy_access_autocomplete()
*/
/**
* @defgroup tac_create Taxonomy Access Control: Add tag (create) permission
* @{
* Implement access control for taxonomy terms on node editing forms.
*/
/**
* Implements the create grant for autocomplete fields.
*
* - Denies access if the user cannot alter the field values.
* - Determines whether the user can autocreate new terms for the field.
* - Removes default values disallowed by create.
* - Adds information on autocreate and disallowed defaults to the element so
* it is available to the validator.
* - Adds the custom validator.
* - Sets a custom autocomplete path to filter autocomplete by create.
*
* Some of the logic here is borrowed from taxonomy_autocomplete_validate().
*
* @see taxonomy_access_field_widget_taxonomy_autocomplete_form_alter()
*/
function _taxonomy_access_autocomplete_alter(&$element, &$form_state, $context) {
// Collect a list of terms and filter out those disallowed by create.
$filtered = array();
foreach ($context['items'] as $item) {
$filtered[$item['tid']] = $item;
}
$disallowed_defaults = taxonomy_access_create_disallowed(array_keys($filtered));
foreach ($disallowed_defaults as $tid) {
unset($filtered[$tid]);
}
// Assemble a list of all vocabularies for the field.
$vids = array();
foreach ($context['field']['settings']['allowed_values'] as $tree) {
if ($vocab = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
$vids[] = $vocab->vid;
}
}
// Determine whether the user has create for any terms in the given vocabs.
$allowed_terms = FALSE;
foreach ($vids as $vid) {
$terms = taxonomy_access_user_create_terms_by_vocab($vid);
if (!empty($terms)) {
$allowed_terms = TRUE;
break;
}
}
// Filter the vids to vocabs in which the user may create new terms.
$allowed_vids = taxonomy_access_create_default_allowed($vids);
// If the field already has the maximum number of values, and all of these
// values are disallowed, deny access to the field.
if ($context['field']['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
if (sizeof($disallowed_defaults) >= $context['field']['cardinality']) {
$element['#access'] = FALSE;
}
}
// If the user may not create any terms on this field, deny access.
if (empty($allowed_vids) && !$allowed_terms) {
$element['#access'] = FALSE;
}
// Set the default value from the filtered item list.
$element['#default_value'] = taxonomy_access_autocomplete_default_value($filtered);
// Custom validation. Set values for the validator indicating:
// 1. Whether the user can autocreate terms in this field (vocab. default).
// 2. Which tids were removed due to create restrictions.
$element['#allow_autocreate'] = empty($allowed_vids) ? FALSE : TRUE;
$element['#disallowed_defaults'] = $disallowed_defaults;
$element['#element_validate'] = array(
'taxonomy_access_autocomplete_validate',
);
// Use a custom autocomplete path to filter by create rather than list.
$element['#autocomplete_path'] = 'taxonomy_access/autocomplete/' . $context['field']['field_name'];
unset($context);
}
/**
* Implements the create grant for options widgets.
*
* - Denies access if the user cannot alter the field values.
* - Attaches jQuery to disable values disallowed by create.
* - Adds the disallowed values from the element so they are available to the
* custom validator.
* - Adds the custom validator.
*
* We use jQuery to disable the options because of FAPI limitations:
* @see http://drupal.org/node/284917
* @see http://drupal.org/node/342316
* @see http://drupal.org/node/12089
*
* @see taxonomy_access_field_widget_form_alter()
*/
function _taxonomy_access_options_alter(&$element, &$form_state, $context) {
// Check for an existing entity ID.
$entity_id = 0;
if (!empty($form_state['build_info']['args'][0])) {
$info = entity_get_info($context['instance']['entity_type']);
$pseudo_entity = (object) $form_state['build_info']['args'][0];
if (isset($pseudo_entity->{$info['entity keys']['id']})) {
$entity_id = $pseudo_entity->{$info['entity keys']['id']};
}
}
// Collect a list of terms and determine which are allowed
$tids = array_keys($element['#options']);
// Ignore the "none" option if present.
$key = array_search('_none', $tids);
if ($key !== FALSE) {
unset($tids[$key]);
}
$allowed_tids = taxonomy_access_create_allowed($tids);
$disallowed_tids = taxonomy_access_create_disallowed($tids);
// If no options are allowed, deny access to the field.
if (empty($allowed_tids)) {
$element['#access'] = FALSE;
}
// On node creation, simply remove disallowed default values.
if (!$entity_id) {
$disallowed_defaults = array();
if (is_array($element['#default_value'])) {
foreach ($element['#default_value'] as $key => $value) {
if (in_array($value, $disallowed_tids)) {
unset($element['#default_value'][0]);
}
}
}
elseif (in_array($element['#default_value'], $disallowed_tids)) {
unset($element['#default_value']);
}
}
else {
$defaults = is_array($element['#default_value']) ? $element['#default_value'] : array(
$element['#default_value'],
);
$disallowed_defaults = array_intersect($defaults, $disallowed_tids);
if ($context['field']['cardinality'] != FIELD_CARDINALITY_UNLIMITED) {
if (sizeof($disallowed_defaults) >= $context['field']['cardinality']) {
$element['#access'] = FALSE;
}
}
}
// If there are disallowed, terms, add CSS and JS for jQuery.
// We use jQuery because FAPI does not currently support attributes
// for individual options.
if (!empty($disallowed_tids)) {
// Add a css class to the field that we can use in jQuery.
$class_name = 'tac_' . $element['#field_name'];
$element['#attributes']['class'][] = $class_name;
// Add js for disabling create options.
$settings[] = array(
'field' => $class_name,
'disallowed_tids' => $disallowed_tids,
'disallowed_defaults' => $disallowed_defaults,
);
$element['#attached']['js'][] = drupal_get_path('module', 'taxonomy_access') . '/tac_create.js';
$element['#attached']['js'][] = array(
'data' => array(
'taxonomy_access' => $settings,
),
'type' => 'setting',
);
}
$element['#disallowed_defaults'] = $disallowed_defaults;
$element['#element_validate'] = array(
'taxonomy_access_options_validate',
);
}
/**
* Retrieve terms that the current user may create.
*
* @return array|true
* An array of term IDs, or TRUE if the user may create all terms.
*
* @see taxonomy_access_user_create_terms_by_vocab()
* @see _taxonomy_access_user_term_grants()
*/
function taxonomy_access_user_create_terms() {
// Cache the terms the current user can create.
$terms =& drupal_static(__FUNCTION__, NULL);
if (is_null($terms)) {
$terms = _taxonomy_access_user_term_grants(TRUE);
}
return $terms;
}
/**
* Retrieve terms that the current user may create in specific vocabularies.
*
* @param int $vid
* A vid to use as a filter.
*
* @return array|true
* An array of term IDs, or TRUE if the user may create all terms.
*
* @see taxonomy_access_user_create_terms()
* @see _taxonomy_access_user_term_grants()
*/
function taxonomy_access_user_create_terms_by_vocab($vid) {
// Cache the terms the current user can create per vocabulary.
static $terms = array();
if (!isset($terms[$vid])) {
$terms[$vid] = _taxonomy_access_user_term_grants(TRUE, array(
$vid,
));
}
return $terms[$vid];
}
/**
* Retrieve terms that the current user may create.
*
* @return array|true
* An array of term IDs, or TRUE if the user may create all terms.
*
* @see _taxonomy_access_create_defaults()
*/
function taxonomy_access_user_create_defaults() {
// Cache the terms the current user can create.
static $vids = NULL;
if (is_null($vids)) {
$vids = _taxonomy_access_create_defaults();
}
return $vids;
}
/**
* Check a list of term IDs for terms the user may not create.
*
* @param array $tids
* The array of term IDs.
*
* @return array
* An array of disallowed term IDs.
*/
function taxonomy_access_create_disallowed(array $tids) {
$all_allowed = taxonomy_access_user_create_terms();
// If the user's create grant info is exactly TRUE, no terms are disallowed.
if ($all_allowed === TRUE) {
return array();
}
return array_diff($tids, $all_allowed);
}
/**
* Filter a list of term IDs to terms the user may create.
*
* @param array $tids
* The array of term IDs.
*
* @return array
* An array of disallowed term IDs.
*/
function taxonomy_access_create_allowed(array $tids) {
$all_allowed = taxonomy_access_user_create_terms();
// If the user's create grant info is exactly TRUE, all terms are allowed.
if ($all_allowed === TRUE) {
return $tids;
}
return array_intersect($tids, $all_allowed);
}
/**
* Filter a list of vocab IDs to those in which the user may create by default.
*
* @param array $vids
* The array of vocabulary IDs.
*
* @return array
* An array of disallowed vocabulary IDs.
*/
function taxonomy_access_create_default_allowed(array $vids) {
$all_allowed = taxonomy_access_user_create_defaults();
// If the user's create grant info is exactly TRUE, all terms are allowed.
if ($all_allowed === TRUE) {
return $vids;
}
return array_intersect($vids, $all_allowed);
}
/**
* Retrieve vocabularies in which the current user may create terms.
*
* @param object|null $account
* (optional) The account for which to retrieve grants. If no account is
* passed, the current user will be used. Defaults to NULL.
*
* @return array
* An array of term IDs, or TRUE if the user has the grant for all terms.
*/
function _taxonomy_access_create_defaults($account = NULL) {
// If the user can administer taxonomy, return TRUE for a global grant.
if (user_access('administer taxonomy', $account)) {
return TRUE;
}
// Build a term grant query.
$query = _taxonomy_access_grant_query(array(
'create',
), TRUE);
// Select term grants for the current user's roles.
if (is_null($account)) {
global $user;
$account = $user;
}
$query
->fields('td', array(
'vid',
))
->groupBy('td.vid')
->condition('tadg.rid', array_keys($account->roles), 'IN');
// Fetch term IDs.
$r = $query
->execute()
->fetchAll();
$vids = array();
// If there are results, initialize a flag to test whether the user
// has the grant for all terms.
$grants_for_all_vocabs = empty($r) ? FALSE : TRUE;
foreach ($r as $record) {
// If the user has the grant, add the term to the array.
if ($record->grant_create) {
$vids[] = $record->vid;
}
else {
$grants_for_all_vocabs = FALSE;
}
}
// If the user has the grant for all terms, return TRUE for a global grant.
if ($grants_for_all_vocabs) {
return TRUE;
}
return $vids;
}
/**
* Autocomplete menu callback: filter allowed terms by create, not list.
*
* For now we essentially duplicate the code from taxonomy.module, because
* it calls drupal_json_output without providing the logic separately.
*
* @see http://drupal.org/node/1169964
* @see taxonomy_autocomplete()
*/
function taxonomy_access_autocomplete($field_name, $tags_typed = '') {
// Enforce that list grants do not filter the autocomplete.
taxonomy_access_disable_list();
$field = field_info_field($field_name);
// The user enters a comma-separated list of tags. We only autocomplete the last tag.
$tags_typed = drupal_explode_tags($tags_typed);
$tag_last = drupal_strtolower(array_pop($tags_typed));
$matches = array();
if ($tag_last != '') {
// Part of the criteria for the query come from the field's own settings.
$vids = array();
$vocabularies = taxonomy_vocabulary_get_names();
foreach ($field['settings']['allowed_values'] as $tree) {
$vids[] = $vocabularies[$tree['vocabulary']]->vid;
}
$query = db_select('taxonomy_term_data', 't');
$query
->addTag('translatable');
$query
->addTag('term_access');
// Do not select already entered terms.
if (!empty($tags_typed)) {
$query
->condition('t.name', $tags_typed, 'NOT IN');
}
// Select rows that match by term name.
$tags_return = $query
->fields('t', array(
'tid',
'name',
))
->condition('t.vid', $vids)
->condition('t.name', '%' . db_like($tag_last) . '%', 'LIKE')
->range(0, 10)
->execute()
->fetchAllKeyed();
// Unset suggestions disallowed by create grants.
$disallowed = taxonomy_access_create_disallowed(array_keys($tags_return));
foreach ($disallowed as $tid) {
unset($tags_return[$tid]);
}
$prefix = count($tags_typed) ? drupal_implode_tags($tags_typed) . ', ' : '';
$term_matches = array();
foreach ($tags_return as $tid => $name) {
$n = $name;
// Term names containing commas or quotes must be wrapped in quotes.
if (strpos($name, ',') !== FALSE || strpos($name, '"') !== FALSE) {
$n = '"' . str_replace('"', '""', $name) . '"';
}
$term_matches[$prefix . $n] = check_plain($name);
}
}
drupal_json_output($term_matches);
}
/**
* Validates taxonomy autocomplete values for create grants.
*
* For now we essentially duplicate the code from taxonomy.module, because
* it calls form_set_value() without providing the logic separately.
*
* We use two properties set in hook_field_widget_form_alter():
* - $element['#allow_autocreate']
* - $element['#disallowed_defaults']
*
* @todo
* Specify autocreate per vocabulary?
*
* @see taxonomy_autocomplete_validate()
* @see taxonomy_access_autocomplete()
* @see taxonomy_access_field_widget_taxonomy_autocomplete_form_alter()
*/
function _taxonomy_access_autocomplete_validate($element, &$form_state) {
// Autocomplete widgets do not send their tids in the form, so we must detect
// them here and process them independently.
$value = array();
if ($tags = $element['#value']) {
// Collect candidate vocabularies.
$field = field_widget_field($element, $form_state);
$vocabularies = array();
foreach ($field['settings']['allowed_values'] as $tree) {
if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
$vocabularies[$vocabulary->vid] = $vocabulary;
}
}
// Translate term names into actual terms.
$typed_terms = drupal_explode_tags($tags);
foreach ($typed_terms as $typed_term) {
// See if the term exists in the chosen vocabulary and return the tid;
// otherwise, create a new 'autocreate' term for insert/update.
if ($possibilities = taxonomy_term_load_multiple(array(), array(
'name' => trim($typed_term),
'vid' => array_keys($vocabularies),
))) {
$term = array_pop($possibilities);
}
elseif ($element['#allow_autocreate']) {
$vocabulary = reset($vocabularies);
$term = array(
'tid' => 'autocreate',
'vid' => $vocabulary->vid,
'name' => $typed_term,
'vocabulary_machine_name' => $vocabulary->machine_name,
);
}
else {
form_error($element, t('You may not create new tags in %name.', array(
'%name' => t($element['#title']),
)));
}
if ($term) {
$value[] = (array) $term;
}
}
}
// Add in the terms that were disallowed.
// taxonomy.module expects arrays, not objects.
$disallowed = taxonomy_term_load_multiple($element['#disallowed_defaults']);
foreach ($disallowed as $key => $term) {
$disallowed[$key] = (array) $term;
}
$value = array_merge($value, $disallowed);
// Subsequent validation will be handled by hook_field_attach_validate().
// Set the value in the form.
form_set_value($element, $value, $form_state);
}
/**
* Form element validation handler for taxonomy option fields.
*
* We use a property set in hook_field_widget_form_alter():
* - $element['#disallowed_defaults']
*
* @see options_field_widget_validate()
* @see taxonomy_access_field_widget_form_alter()
*/
function _taxonomy_access_options_validate($element, &$form_state) {
if ($element['#required'] && $element['#value'] == '_none') {
form_error($element, t('!name field is required.', array(
'!name' => $element['#title'],
)));
}
// Clone the element and add in disallowed defaults.
$el = $element;
if (!empty($element['#disallowed_defaults'])) {
if (empty($el['#value'])) {
$el['#value'] = $element['#disallowed_defaults'];
}
elseif (is_array($el['#value'])) {
$el['#value'] = array_unique(array_merge($el['#value'], $element['#disallowed_defaults']));
}
else {
$el['#value'] = array_unique(array_merge(array(
$el['#value'],
), $element['#disallowed_defaults']));
}
}
// Transpose selections from field => delta to delta => field, turning
// multiple selected options into multiple parent elements.
$items = _options_form_to_storage($el);
// Subsequent validation will be handled by hook_field_attach_validate().
// Set the value in the form.
form_set_value($element, $items, $form_state);
}
/**
* Default value re-generation for autocomplete fields.
*
* @param array $items
* An array of values from form build info, filtered by create grants.
*
* @return string
* Field default value.
*
* @see taxonomy_field_widget_form()
*/
function taxonomy_access_autocomplete_default_value(array $items) {
// Preserve the original state of the list flag.
$flag_state = taxonomy_access_list_enabled();
// Enforce that list grants do not filter the options list.
taxonomy_access_disable_list();
// Assemble list of tags.
$tags = array();
foreach ($items as $item) {
$tags[$item['tid']] = isset($item['taxonomy_term']) ? $item['taxonomy_term'] : taxonomy_term_load($item['tid']);
}
// Assemble the default value using taxonomy.module.
$tags = taxonomy_implode_tags($tags);
// Restore list flag to previous state.
if ($flag_state) {
taxonomy_access_enable_list();
}
return $tags;
}
/**
* Validates form submissions of taxonomy fields for create grants.
*
* @todo
* Use field label and term names in errors rather than field name and tids.
*
* @see http://drupal.org/node/1220212
* @see entity_form_field_validate()
*/
function _taxonomy_access_field_validate($entity_type, $entity, &$errors) {
// Check for a pre-existing entity (i.e., the entity is being updated).
$old_fields = FALSE;
// The entity is actually a "pseudo-entity," and the user profile form
// neglects to include the uid. So, we need to load it manually.
if ($entity_type == 'user') {
// Some modules which extend the user profile form cause additional
// validation to happen with "pseudo-entities" that do not include the
// name. So, check if it exists.
if (isset($entity->name)) {
if ($account = user_load_by_name($entity->name)) {
$entity->uid = $account->uid;
}
}
}
list($entity_id, , $bundle) = entity_extract_ids($entity_type, $entity);
if ($entity_id) {
// Load the entity.
$old_entity = entity_load($entity_type, array(
$entity_id,
));
$old_entity = $old_entity[$entity_id];
// Fetch the original entity's taxonomy fields.
$old_fields = _taxonomy_access_entity_fields($entity_type, $old_entity, $bundle);
}
// Fetch the updated entity's taxonomy fields.
$new_fields = _taxonomy_access_entity_fields($entity_type, $entity, $bundle);
// Set errors if there are any disallowed changes.
$changes = _taxonomy_access_compare_fields($new_fields, $old_fields);
// We care about the overall value list, so delta is not important.
$delta = 0;
// Check each field and langcode for disallowed changes.
foreach ($changes as $field_name => $langcodes) {
foreach ($langcodes as $langcode => $disallowed) {
if ($disallowed) {
if (!empty($disallowed['added'])) {
$text = 'You may not add the following tags to %field: %tids';
$errors[$field_name][$langcode][$delta][] = array(
'error' => 'taxonomy_access_disallowed_added',
'message' => t($text, array(
'%field' => $field_name,
'%tids' => implode(', ', $disallowed['added']),
)),
);
}
if (!empty($disallowed['removed'])) {
$text = 'You may not remove the following tags from %field: %tids';
$errors[$field_name][$langcode][$delta][] = array(
'error' => 'taxonomy_access_disallowed_removed',
'message' => t($text, array(
'%field' => $field_name,
'%tids' => implode(', ', $disallowed['removed']),
)),
);
}
}
}
}
}
/**
* Helper function to extract the taxonomy fields from an entity.
*
* @param object $entity
* The entity object.
*
* @return array
* An associative array of field information, containing:
* - field_list: A flat array of all this entity's taxonomy fields, with the
* format $field_name => $field_name.
* - langcodes: A flat array of all langcodes in this entity's fields, with
* the format $langcode => $langcode.
* - data: An associative array of non-empty fields:
* - $field_name: An associative array keyed by langcode.
* - $langcode: Array of field values for this field name and langcode.
*
* @see http://drupal.org/node/1220168
*/
function _taxonomy_access_entity_fields($entity_type, $entity, $bundle) {
// Maintain separate lists of field names and langcodes for quick comparison.
$fields = array();
$fields['field_list'] = array();
$fields['langcodes'] = array();
$fields['data'] = array();
// If there is no entity, return the empty structure.
if (!$entity) {
return $fields;
}
// Get a list of possible fields for the bundle.
// The bundle does not contain the field type (see #122016), so our only use
// for it is the field names.
$possible = array_keys(field_info_instances($entity_type, $bundle));
// Sort through the entity for relevant field data.
foreach ($entity as $field_name => $field) {
// Only proceed if this element is a valid field for the bundle.
if (in_array($field_name, $possible, TRUE)) {
// Check whether each entity field is a taxonomy field.
$info = field_info_field($field_name);
if ($info['type'] == 'taxonomy_term_reference') {
foreach ($field as $langcode => $values) {
// Add non-empty fields to the lists.
if (!empty($values)) {
$fields['langcodes'][$langcode] = $langcode;
$fields['field_list'][$field_name] = $field_name;
$fields['data'][$field_name][$langcode] = $values;
}
unset($values);
}
}
}
unset($info);
unset($field);
}
unset($entity);
return $fields;
}
/**
* Helper function to compare field values and look for disallowed changes.
*
* @param array $new
* An associative array of the updated field information as returned by
* _taxonomy_access_entity_fields().
* @param array $old
* (optional) An associative array of the original field information,
* or FALSE if there is no original field data. Defaults to FALSE.
*
* @return array
* An array of disallowed changes, with the structure:
* - $field_name: An associative array keyed by langcode.
* - $langcode: Disallowed changes for this field name and langcode,
* or FALSE if none.
* - 'added' => An array of added terms that are disallowed.
* - 'removed' => An array of removed termss that are disallowed.
*
* @see _taxonomy_access_entity_fields()
* @see _taxonomy_access_disallowed_changes()
*/
function _taxonomy_access_compare_fields($new, $old = FALSE) {
$disallowed_changes = array();
// If there are no original fields, simply process new.
if (!$old) {
foreach ($new['data'] as $field_name => $langcodes) {
foreach ($langcodes as $langcode => $values) {
$changes = _taxonomy_access_disallowed_changes($values, array());
if ($changes) {
if (!isset($disallowed_changes[$field_name])) {
$disallowed_changes[$field_name] = array();
}
$disallowed_changes[$field_name][$langcode] = $changes;
}
}
}
}
else {
$all_fields = $new['field_list'] + $old['field_list'];
$all_langcodes = $new['langcodes'] + $old['langcodes'];
foreach ($all_fields as $field_name) {
foreach ($all_langcodes as $langcode) {
$new_values = array();
if (isset($new['field_list'][$field_name]) && isset($new['data'][$field_name][$langcode])) {
$new_values = $new['data'][$field_name][$langcode];
}
$old_values = array();
if (isset($old['field_list'][$field_name]) && isset($old['data'][$field_name][$langcode])) {
$old_values = $old['data'][$field_name][$langcode];
}
$changes = _taxonomy_access_disallowed_changes($new_values, $old_values);
if ($changes) {
if (!isset($disallowed_changes[$field_name])) {
$disallowed_changes[$field_name] = array();
}
$disallowed_changes[$field_name][$langcode] = $changes;
}
}
}
}
unset($old);
unset($new);
return $disallowed_changes;
}
/**
* Helper function to check for term reference changes disallowed by create.
*
* @param array $new_field
* The entity or form values of the updated field.
* @param array $old_field
* The entity or form values of the original field.
*
* @return array|false
* Returns FALSE if there are no disallowed changes. Otherwise, an array:
* - 'added' => An array of added terms that are disallowed.
* - 'removed' => An array of removed termss that are disallowed.
*/
function _taxonomy_access_disallowed_changes(array $new_field, array $old_field) {
// Assemble a list of term IDs from the original entity, if any.
$old_tids = array();
foreach ($old_field as $old_item) {
// Some things are NULL for some reason.
if ($old_item['tid']) {
$old_tids[] = $old_item['tid'];
}
}
// Assemble a list of term IDs from the updated entity.
$new_tids = array();
foreach ($new_field as $delta => $new_item) {
// Some things are NULL for some reason.
// Allow the special tid "autocreate" so users can create new terms.
if ($new_item['tid'] && $new_item['tid'] != 'autocreate') {
$new_tids[$delta] = $new_item['tid'];
}
}
// Check for added tids, and unset ones the user may not add.
$added = array_diff($new_tids, $old_tids);
$may_not_add = taxonomy_access_create_disallowed($added);
// Check for removed tids, and restore ones the user may not remove.
$removed = array_diff($old_tids, $new_tids);
$may_not_remove = taxonomy_access_create_disallowed($removed);
// If there were any disallowed changes, return them.
if (!empty($may_not_add) || !empty($may_not_remove)) {
return array(
'added' => $may_not_add,
'removed' => $may_not_remove,
);
}
// Return FALSE if all changes were valid.
return FALSE;
}
/**
* End of "defgroup tac_create".
* @}
*/
Functions
Name | Description |
---|---|
taxonomy_access_autocomplete | Autocomplete menu callback: filter allowed terms by create, not list. |
taxonomy_access_autocomplete_default_value | Default value re-generation for autocomplete fields. |
taxonomy_access_create_allowed | Filter a list of term IDs to terms the user may create. |
taxonomy_access_create_default_allowed | Filter a list of vocab IDs to those in which the user may create by default. |
taxonomy_access_create_disallowed | Check a list of term IDs for terms the user may not create. |
taxonomy_access_user_create_defaults | Retrieve terms that the current user may create. |
taxonomy_access_user_create_terms | Retrieve terms that the current user may create. |
taxonomy_access_user_create_terms_by_vocab | Retrieve terms that the current user may create in specific vocabularies. |
_taxonomy_access_autocomplete_alter | Implements the create grant for autocomplete fields. |
_taxonomy_access_autocomplete_validate | Validates taxonomy autocomplete values for create grants. |
_taxonomy_access_compare_fields | Helper function to compare field values and look for disallowed changes. |
_taxonomy_access_create_defaults | Retrieve vocabularies in which the current user may create terms. |
_taxonomy_access_disallowed_changes | Helper function to check for term reference changes disallowed by create. |
_taxonomy_access_entity_fields | Helper function to extract the taxonomy fields from an entity. |
_taxonomy_access_field_validate | Validates form submissions of taxonomy fields for create grants. |
_taxonomy_access_options_alter | Implements the create grant for options widgets. |
_taxonomy_access_options_validate | Form element validation handler for taxonomy option fields. |