content_taxonomy.module 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. <?php
  2. /**
  3. * Implements hook_form_ID_alter().
  4. */
  5. function content_taxonomy_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
  6. $field = $form['#field'];
  7. $instance = $form['#instance'];
  8. // Add parent selector to term reference fields, except to the autocomplete
  9. // widget, as it ignores the parent setting.
  10. if ($field['type'] == 'taxonomy_term_reference'
  11. && $instance['widget']['type'] != 'taxonomy_autocomplete'
  12. && $instance['widget']['type'] != 'autocomplete_deluxe_taxonomy'
  13. && $instance['widget']['type'] != 'entityreference_autocomplete'
  14. && $instance['widget']['type'] != 'entityreference_autocomplete_tags') {
  15. // Add parent form.
  16. foreach ($field['settings']['allowed_values'] as $delta => $tree) {
  17. $options[0] = '---';
  18. // todo this might break with huge vocs
  19. $voc = taxonomy_vocabulary_machine_name_load($tree['vocabulary']);
  20. foreach (taxonomy_get_tree($voc->vid) as $term) {
  21. $options[$term->tid] = str_repeat('- ', $term->depth) . $term->name;
  22. }
  23. $form['field']['settings']['allowed_values'][$delta]['parent'] = array(
  24. '#type' => 'select',
  25. '#title' => t('Parent'),
  26. '#options' => $options,
  27. '#default_value' => isset($tree['parent']) ? $tree['parent'] : 0,
  28. );
  29. $form['field']['settings']['allowed_values'][$delta]['depth'] = array(
  30. '#type' => 'textfield',
  31. '#title' => t('Tree depth'),
  32. '#default_value' => isset($tree['depth']) ? $tree['depth'] : '',
  33. '#description' => t('Set the depth of the tree. Leave empty to load all terms.'),
  34. '#element_validate' => array('_element_validate_integer_positive'),
  35. );
  36. }
  37. }
  38. // Add opt group setting.
  39. if ($field['type'] == 'taxonomy_term_reference' && $instance['widget']['type'] == 'options_select') {
  40. $form['instance']['widget']['settings']['content_taxonomy_opt_groups'] = array(
  41. '#type' => 'checkbox',
  42. '#title' => t('Render parent terms as opt-groups'),
  43. '#default_value' => isset($instance['widget']['settings']['content_taxonomy_opt_groups']) ? $instance['widget']['settings']['content_taxonomy_opt_groups'] : FALSE,
  44. '#description' => t('This option only works if you have a 2-level hierarchy in your vocabulary. Then the parents in the first level get opt-groups and the child terms will be selectable.'),
  45. );
  46. }
  47. }
  48. /**
  49. * Implements hook_field_info_alter().
  50. */
  51. function content_taxonomy_field_info_alter(&$info) {
  52. // Use own options callback for handling additional configuration options.
  53. $info['taxonomy_term_reference']['settings']['options_list_callback'] = 'content_taxonomy_allowed_values';
  54. // Add depth option.
  55. foreach ($info['taxonomy_term_reference']['settings']['allowed_values'] as $key => $values) {
  56. $info['taxonomy_term_reference']['settings']['allowed_values'][$key]['depth'] = 0;
  57. }
  58. }
  59. /**
  60. * Returns the set of valid terms for a taxonomy field.
  61. * Extends taxonomy_allowed_values() with the tree depth option.
  62. *
  63. * @param $field
  64. * The field definition.
  65. * @return
  66. * The array of valid terms for this field, keyed by term id.
  67. */
  68. function content_taxonomy_allowed_values($field) {
  69. $options = array();
  70. foreach ($field['settings']['allowed_values'] as $tree) {
  71. if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
  72. $max_depth = (isset($tree['depth']) && !empty($tree['depth'])) ? $tree['depth'] : NULL;
  73. $terms = content_taxonomy_get_terms($field, $vocabulary, $tree['parent'], $max_depth);
  74. if (!empty($terms) && is_array($terms)) {
  75. foreach ($terms as $term) {
  76. $options[$term->tid] = str_repeat('- ', $term->depth) . $term->name;
  77. }
  78. }
  79. }
  80. }
  81. return $options;
  82. }
  83. /**
  84. * Returns an array of terms that can be used in an options list.
  85. *
  86. * By default taxonomy_get_tree is used to retrieve the list of terms, but an
  87. * alteration via hook_content_taxonomy_tree_callback_alter() is possible. It
  88. * is important that any provided tree callback must have the same function
  89. * signature as hook_content_taxonomy_tree_callback_alter().
  90. * For example this hook can be used to exchange the callback with a language
  91. * specific tree function.
  92. *
  93. * Although we could change the options list callback via the field definitions,
  94. * it is easier to do this via the alteration hook provided by this function.
  95. *
  96. * @param $field
  97. * The term reference field info array.
  98. * @param $vocabulary
  99. * The vocabulary object for which the term list should be retrieved. One
  100. * field can have multiple vocabularies attached, which leads to multiple
  101. * invocations of this function.
  102. * @param $parent
  103. * The parent term id. Use 0 for the root level.
  104. * @param $max_depth
  105. * The maximum depth. Use NULL for non limitation.
  106. *
  107. * @return array
  108. */
  109. function content_taxonomy_get_terms($field, $vocabulary, $parent, $max_depth) {
  110. $terms = array();
  111. $tree_callback = 'taxonomy_get_tree';
  112. drupal_alter('content_taxonomy_tree_callback', $tree_callback, $field, $vocabulary);
  113. if (function_exists($tree_callback)) {
  114. $terms = $tree_callback($vocabulary->vid, $parent, $max_depth, FALSE);
  115. }
  116. return $terms;
  117. }
  118. /**
  119. * Implements hook_field_widget_info_alter().
  120. */
  121. function content_taxonomy_field_widget_info_alter(&$info) {
  122. if (isset($info['options_select']['settings'])) {
  123. $info['options_select']['settings'] += array(
  124. 'content_taxonomy_opt_groups' => FALSE,
  125. );
  126. }
  127. }
  128. /**
  129. * Implements hook_field_widget_form_alter().
  130. */
  131. function content_taxonomy_field_widget_form_alter(&$element, &$form_state, $context) {
  132. $field = $context['field'];
  133. $instance = $context['instance'];
  134. if (!empty($instance['widget']['settings']['content_taxonomy_opt_groups'])) {
  135. $options = content_taxonomy_allowed_values_opt_groups($field);
  136. if (isset($element['#options']['_none'])) {
  137. $options = array('_none' => $element['#options']['_none']) + $options;
  138. }
  139. $element['#options'] = $options;
  140. }
  141. }
  142. /**
  143. * Helper function for generating opt groups.
  144. *
  145. * Similar to content_taxonomy_allowed_values(), but unfortunately we cannot
  146. * directly change content_taxonomy_allowed_values() as it only has the field
  147. * variable and opt groups are settings on the instance level. Still, this is
  148. * not a big performance issue, as taxonomy_get_tree statically caches some
  149. * data.
  150. */
  151. function content_taxonomy_allowed_values_opt_groups($field) {
  152. $options = array();
  153. foreach ($field['settings']['allowed_values'] as $tree) {
  154. if ($vocabulary = taxonomy_vocabulary_machine_name_load($tree['vocabulary'])) {
  155. $terms = content_taxonomy_get_terms($field, $vocabulary, 0, 2);
  156. if (!empty($terms) && is_array($terms)) {
  157. $current_group_term = NULL;
  158. foreach ($terms as $term) {
  159. if ($term->depth == 0) {
  160. $current_group_term = $term;
  161. }
  162. elseif ($term->depth == 1 && !is_null($current_group_term)) {
  163. $options[$current_group_term->name][$term->tid] = $term->name;
  164. }
  165. }
  166. }
  167. }
  168. }
  169. return $options;
  170. }