/[drupal]/contributions/modules/taxonomy_menu/adv_taxonomy_menu/adv_taxonomy_menu.module
ViewVC logotype

Contents of /contributions/modules/taxonomy_menu/adv_taxonomy_menu/adv_taxonomy_menu.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.1 - (show annotations) (download) (as text)
Sun May 3 02:57:41 2009 UTC (6 months, 3 weeks ago) by newzeal
Branch: MAIN
CVS Tags: DRUPAL-5--1-04, DRUPAL-5--1-05, HEAD
File MIME type: text/x-php
First commit
1 <?php
2 /**
3 * $Id: adv_taxonomy_menu.module,v 1.17.2.1.2.12 2008/01/31 16:23:34 brmassa Exp $
4 * @file adv_taxonomy_menu.module
5 * @author Jonathan Chaffer <jchaffer@structureinteractive.com> original taxonomy_menu.module
6 * @author Bruno Massa <http://drupal.org/user/67164> original taxonomy_menu.module
7 * @author Kent Parker <kent@webdev.passingphase.co.nz> adv_taxonomy_menu.module
8 * It Generates menu links for all taxonomy terms using one single level vocabulary for each level
9 * TODO validate that at least two levels have been selected
10 */
11
12 // Some "magic numbers" mastered
13 define('ADV_TAXONOMY_MENU_NONE', 0);
14 define('ADV_TAXONOMY_MENU_NORMAL', 1);
15 define('ADV_TAXONOMY_MENU_VIEW', 2);
16 define('ADV_TAXONOMY_MENU_DEFAULT_TAX', 3);
17
18 /**
19 * Admin area. Configure the module, setting which
20 * vocabularies will be converted into menus items
21 *
22 * @return
23 * Array. The form fields.
24 */
25 function __adv_taxonomy_menu_admin($op) {
26 require_once(drupal_get_path('module', 'adv_taxonomy_menu') .'/adv_taxonomy_menu.inc');
27 return _adv_taxonomy_menu_admin($op);
28 }
29
30 /**
31 * Admin area. validate form
32 *
33 */
34 function __adv_taxonomy_menu_admin_validate(&$form_id, &$form_values) {
35 if($form_values['op']!= 'Delete') {
36 if ($form_values['adv_taxonomy_menu_name'] == '') {
37 form_set_error('', t('You must select a name for this menu system.'));
38 }
39 if ($form_values['adv_taxonomy_menu_display_page'] == '') {
40 form_set_error('', t('You must select a label for the url.'));
41 }
42 }
43 }
44 /**
45 * Admin area. Configure the module, setting which
46 * vocabularies will be converted into menu items
47 */
48 function __adv_taxonomy_menu_admin_submit(&$form_id, &$form) {
49 $order = array();
50 $show = array();
51 $show_views = array();
52 foreach (taxonomy_get_vocabularies() as $vocab) {
53 $order[$vocab->vid] = $form['adv_taxonomy_menu_vocab_order_'. $vocab->vid];
54 }
55 $order = serialize($order);
56 // either update or add depending on whether a tmid is supplied
57 if($form['adv_taxonomy_menu_tmid']>0) {
58 $mid = db_result(db_query("SELECT mid FROM {menu} WHERE pid=0 AND path='' AND title = '%s'", $form['adv_taxonomy_menu_name']));
59 db_query("UPDATE {adv_taxonomy_menu} SET mid=%d, name='%s', display_page='%s', display_num=%d, hide_empty=%d, display_descendants=%d, vocab_order='%s', show_normal='%s', show_views='%s' WHERE tmid=%d", $mid, $form['adv_taxonomy_menu_name'], $form['adv_taxonomy_menu_display_page'], $form['adv_taxonomy_menu_display_num'], $form['adv_taxonomy_menu_hide_empty'], $form['adv_taxonomy_menu_display_descendants'], $order, $form['adv_taxonomy_menu_show'], $form['adv_taxonomy_menu_show_view'], $form['adv_taxonomy_menu_tmid']);
60 drupal_set_message('Menu system updated successfully');
61 }
62 elseif(arg(3) == 'delete') {
63 $tmid = arg(4);
64 if($tmid>0) {
65 db_query("DELETE FROM {adv_taxonomy_menu} WHERE tmid=%d", $tmid);
66 drupal_set_message('Menu system deleted');
67 drupal_goto('admin/settings/adv_taxonomy_menu');
68 }
69 }
70 else {
71 // Create menu system and link to menu system
72 $item = array('mid' => 0, 'pid' => 0, 'path' => '', 'weight' => 0, 'type' => MENU_CUSTOM_MENU, 'title' => $form['adv_taxonomy_menu_name']);
73 menu_edit_item_save($item);
74 $mid = db_result(db_query("SELECT mid FROM {menu} WHERE pid=0 AND path='' AND title = '%s'", $form['adv_taxonomy_menu_name']));
75 $tmid = db_next_id('{adv_taxonomy_menu}_tmid');
76 db_query("INSERT INTO {adv_taxonomy_menu} SET tmid=%d, mid=%d, name='%s', display_page='%s', display_num=%d, hide_empty=%d, display_descendants=%d, vocab_order='%s', show_normal='%s', show_views='%s' ", $tmid, $mid, $form['adv_taxonomy_menu_name'], $form['adv_taxonomy_menu_display_page'], $form['adv_taxonomy_menu_display_num'], $form['adv_taxonomy_menu_hide_empty'], $form['adv_taxonomy_menu_display_descendants'], $order, $show, $show_views);
77 drupal_set_message('New menu system created');
78 }
79 // Rebuild the menu to include these features - Now done manually
80 // menu_rebuild();
81 drupal_goto('admin/settings/adv_taxonomy_menu');
82 }
83
84 function adv_taxonomy_menu_get_settings($tmid = '') {
85 static $result;
86 if($tmid) {
87 return db_query('SELECT * FROM {adv_taxonomy_menu} WHERE tmid = %d', $tmid);
88 }
89 else $result = db_query('SELECT * FROM {adv_taxonomy_menu}');
90 return $result;
91 }
92
93
94 /**
95 * Implementation of hook_help().
96 */
97 function adv_taxonomy_menu_help($section) {
98 switch ($section) {
99 case 'admin/help#adv_taxonomy_menu':
100 $output = '<p>'. t('The advanced taxonomy menu module is similar to the taxonomy_menu module exept that it creates a heirarchy from a set of single level vocabularies rather than from a standard taxonomy heirarchy. This is useful for heirarchies in which subcategories share the same terms, for instance clothing might consist of first level items such as shirts, trousers, shoes, second level items such as male, female, third level items such as size and fourth level items such as colour. Such heirarchies can get complex and unwieldy if created using the taxonomy sub-level system.') .'</p>'.
101 '<p>'. t('To configure go to admin/settings/adv_taxonomy_menu and create a menu system. You can create any number of menus and each is generated as a block which you can place where you like. A breadcrumb is generated showing your position in the heirarchy.') .'</p>'.
102 t('<p>You can</p>
103 <ul>
104 <li>view a list of taxonomies in <a href="@admin-taxonomy">Administer &gt;&gt; Content management &gt;&gt; Categories</a>.</li>
105 <li>create a new vocabulary at <a href="@admin-taxonomy-add-vocabulary">Administer &gt;&gt; Content management &gt;&gt; Categories &gt;&gt; Add vocabulary</a>.</li>
106 </ul>', array('@admin-taxonomy' => url('admin/content/taxonomy'), '@admin-taxonomy-add-vocabulary' => url('admin/content/taxonomy/add/vocabulary'))).
107 '<p>'. t('For more information please read the configuration and customization handbook <a href="@adv_taxonomy_menu">Taxonomy menu page</a>.', array('@adv_taxonomy_menu' => 'http://www.drupal.org/handbook/modules/adv_taxonomy_menu/')) .'</p>';
108 return $output;
109 }
110 }
111
112
113 /**
114 * Implementation of hook_menu().
115 * (moved from the .inc file to make main engine accessible to other modules)
116 * Its the main function for this module.
117 */
118 function adv_taxonomy_menu_menu($may_cache) {
119 if ($may_cache) {
120 $items['admin/settings/adv_taxonomy_menu'] = array(
121 'access' => user_access('administer site configuration'),
122 'callback' => '__adv_taxonomy_menu_admin',
123 'callback arguments' => array('main'),
124 'file' => 'adv_taxonomy_menu.inc',
125 'description' => t('Global configuration of advanced taxonomy menu functionality.'),
126 'path' => 'admin/settings/adv_taxonomy_menu',
127 'title' => t('Advanced Taxonomy Menu'),
128 'type' => MENU_NORMAL_ITEM
129 );
130 $items['admin/settings/adv_taxonomy_menu/list'] = array(
131 'access' => user_access('administer site configuration'),
132 'callback' => '__adv_taxonomy_menu_admin',
133 'callback arguments' => array('main'),
134 'file' => 'adv_taxonomy_menu.inc',
135 'description' => t('Global configuration of advanced taxonomy menu functionality.'),
136 'path' => 'admin/settings/adv_taxonomy_menu/list',
137 'title' => t('List'),
138 'type' => MENU_DEFAULT_LOCAL_TASK,
139 'weight' => 0,
140 );
141 $items['admin/settings/adv_taxonomy_menu/edit'] = array(
142 'access' => user_access('administer site configuration'),
143 'callback' => 'drupal_get_form',
144 'callback arguments' => array('__adv_taxonomy_menu_admin', 'edit'),
145 'file' => 'adv_taxonomy_menu.inc',
146 'description' => t('Edit a taxonomy menu.'),
147 'path' => 'admin/settings/adv_taxonomy_menu/edit',
148 'title' => t('Edit'),
149 'type' => MENU_CALLBACK,
150 );
151 $items['admin/settings/adv_taxonomy_menu/delete'] = array(
152 'access' => user_access('administer site configuration'),
153 'callback' => 'drupal_get_form',
154 'callback arguments' => array('__adv_taxonomy_menu_admin', 'delete'),
155 'file' => 'adv_taxonomy_menu.inc',
156 'description' => t('Edit a taxonomy menu.'),
157 'path' => 'admin/settings/adv_taxonomy_menu/delete',
158 'title' => t('Delete'),
159 'type' => MENU_CALLBACK,
160 );
161 $items['admin/settings/adv_taxonomy_menu/add'] = array(
162 'access' => user_access('administer site configuration'),
163 'callback' => 'drupal_get_form',
164 'callback arguments' => array('__adv_taxonomy_menu_admin', 'add'),
165 'file' => 'adv_taxonomy_menu.inc',
166 'description' => t('Add a taxonomy menu.'),
167 'path' => 'admin/settings/adv_taxonomy_menu/add',
168 'title' => t('Add'),
169 'type' => MENU_LOCAL_TASK,
170 'weight' => 1,
171 );
172 // This user access function will be used for
173 // all menu items
174 $access = user_access('access content');
175 if($result = adv_taxonomy_menu_get_settings()) {
176 while ($settings = db_fetch_object($result)) {
177 $name[$settings->tmid] = $settings->name;
178 $display_page[$settings->tmid] = $settings->display_page;
179 $display_num[$settings->tmid] = $settings->display_num;
180 $hide_empty[$settings->tmid] = $settings->hide_empty;
181 $display_descendants[$settings->tmid] = $settings->display_descendants;
182 $order[$settings->tmid] = unserialize($settings->vocab_order);
183 $pid[$settings->tmid] = $settings->mid;
184 }
185 if(is_array($name)) {
186 foreach($name as $k => $tmenu) {
187 $items = array_merge($items, adv_taxonomy_menu_process_menu($k, $display_page[$k], $display_num[$k], $hide_empty[$k], $display_descendants[$k], $order[$k], $pid[$k]));
188 }
189 }
190 }
191 }
192 else {
193 if($bc = adv_taxonomy_menu_breadcrumb()) drupal_set_breadcrumb($bc);
194 }
195
196 return $items;
197 }
198
199 function adv_taxonomy_menu_process_menu($k, $display_page, $display_num, $hide_empty, $display_descendants, $order, $pid, $on_the_fly=FALSE) {
200 $vocabs = array();
201 foreach(taxonomy_get_vocabularies() as $vocab) {
202 if($order[$vocab->vid] >0 ) {
203 $key = $order[$vocab->vid];
204 $vocabs[$key] = $vocab->vid;
205 }
206 }
207 // sort vocabs and create ordered keys starting at 1 which will be used to define the current $level later on
208 ksort($vocabs);
209 $vlist = array();
210 $c = 1;
211 foreach($vocabs as $value) {
212 $vlist[$c] = $value;
213 $c++;
214 }
215 $vocabulary = taxonomy_get_vocabulary($vlist[1]);
216 $root_path = $display_page .'/'. $vocabulary->vid;
217 $level = 1;
218 $items = adv_taxonomy_menu_recurse_levels($k, $level, $vlist, $root_path, $display_num, $access, $tids=array(), $display_descendants, $pid, $on_the_fly);
219 return $items;
220
221 }
222
223 /**
224 * Recurse through the list of vocabularies, creating a menu tree from sub-vacabularies
225 *
226 * The main engine for this module.
227 */
228 function adv_taxonomy_menu_recurse_levels($k, $level, $vlist, $root_path, $display_num, $access, $tids, $display_desc, $pid, $on_the_fly=FALSE) {
229 $items = array();
230 $v_id = "vid_".$level;
231 $tree = "tree_".$level;
232 $term = "term_".$level;
233 $$v_id = $vlist[$level];
234 $$tree = taxonomy_get_tree($$v_id,0,-1,1); // get terms of top level only, ignore any subterms that exist
235 foreach($$tree as $$term) {
236 // go through each item of each vocab and generate a tree from the other vocabs below it
237 $t = array_pop($tids);
238 $tids[] = $$term->tid;
239 // Calculate the numbers of children nodes
240 // If this menu is being created on the fly, invoke any existing hooks
241 if($on_the_fly) {
242 foreach (module_implements('adv_taxonomy_menu_sql_alter') AS $module) {
243 $function = $module .'_adv_taxonomy_menu_sql_alter';
244 $result = $function($settings, $tids, 'and', variable_get('adv_taxonomy_menu_display_descendants', TRUE) ? 'all' : 0, FALSE);
245 break;
246 }
247 if(isset($result)) $num = db_num_rows($result);
248 }
249 else $num = db_num_rows(adv_taxonomy_menu_select_nodes($tids, 'and', $display_desc ? 'all' : 0, FALSE)); // get nodes with this first level term
250 if($num) {
251 $path = $root_path;
252 foreach($tids as $tid) {
253 $path .= "/".$tid;
254 }
255 $items[$path] = adv_taxonomy_menu_item($k, $path, $$term, $tids, $num, $display_num, $access, $level, $pid);
256 // if we haven't reached the full number of levels go to next level
257 if(count($vlist) > $level) {
258 $keep_level = $level;
259 $keep_tids = $tids;
260 $level++;
261 $tids[] = 0; // add a dummy item to end of tids array which gets popped off
262 $items = array_merge($items, adv_taxonomy_menu_recurse_levels($k, $level, $vlist, $root_path, $display_num, $access, $tids, $display_desc, $pid));
263 $level = $keep_level;
264 $tids = $keep_tids;
265 }
266 }
267 }
268 return $items;
269 }
270
271
272 function adv_taxonomy_menu_item($k, $path, $term, $tids, $num, $display_num, $access, $level, $pid) {
273 // Calculate the numbers of children nodes
274 // If the number of children nodes of this term is
275 // zero and the Hide Empty Terms option is enabled,
276 // dont create the menu item
277
278 $name = t($term->name);
279 if ($display_num == TRUE) {
280 $name .= ' ('. $num .')';
281 }
282 $items['path'] = array(
283 'access' => user_access('access content'),
284 'callback' => '__adv_taxonomy_menu_page',
285 'callback arguments' => array($term->description),
286 'description' => t($term->description),
287 'file' => 'adv_taxonomy_menu.inc',
288 'page callback' => '__adv_taxonomy_menu_page',
289 'path' => $path,
290 'title' => $name,
291 'weight' => $term->weight
292 );
293 // Top level items are added directly to the menu that was created when this system was first added
294 if($level==1) $items['path']['pid'] = $pid;
295 return $items['path'];
296 }
297
298
299 /**
300 * Implementation of hook_nodeapi().
301 *
302 * This hook enables the menu to be displayed in context during node views.
303 */
304 function adv_taxonomy_menu_nodeapi(&$node, $op, $a3, $a4) {
305 static $vocabs = array();
306 if (empty($vocabs) and is_array($vocabs)) {
307 if($terms = taxonomy_node_get_terms($node->nid)) {
308 $bc = adv_taxonomy_menu_node_breadcrumb($terms);
309 // if the node carries terms currently part of the taxonomy menu
310 if($bc['bc']) {
311 if($op=='view') {
312 drupal_set_breadcrumb($bc['bc']);
313 }
314 elseif ($op == 'update' || $op == 'insert' || $op == 'delete') {
315 menu_rebuild();
316 }
317 }
318 }
319 }
320 }
321 // helper function for breadcrumb that can be used by other modules
322 function adv_taxonomy_menu_node_breadcrumb($terms) {
323 static $output = array();
324 if(empty($bc) && is_array($terms)) {
325 if($result = adv_taxonomy_menu_get_settings()) {
326 while ($settings = db_fetch_object($result)) {
327 $vids = array_flip(unserialize($settings->vocab_order));
328 unset($vids[0]); // this is not needed, keys are now the levels, level 0 is not included
329 //drupal_set_message('vids '.print_r($vids,1));
330 $found = FALSE;
331 // loop in the order of the heirarchy
332 $found = FALSE;
333 foreach($vids as $vid) {
334 $params = '/'.$vid;
335 $display_page = $settings->display_page;
336 foreach ($terms as $term) {
337 if ($term->vid == $vid) {
338 //drupal_set_message(print_r($term,1).' '.$settings->display_page);
339 $params .= '/'.$term->tid;
340 if(!$found) {
341 $q = $settings->display_page.$params;
342 $found = TRUE;
343 }
344 $bc[] = l($term->name, $settings->display_page.$params);
345 }
346 }
347 }
348 //break; // we've got what we want so let's go
349 }
350 $output['bc'] = $bc;
351 $output['q'] = $q;
352 }
353 }
354 //drupal_set_message(' d '.$display_page.$params);
355 return $output;
356 }
357 // Can be used by other modules to generate a breadcrumb for taxonomy menu pages
358 function adv_taxonomy_menu_breadcrumb() {
359 static $bc = array();
360 if(empty($bc)) {
361 if($result = adv_taxonomy_menu_get_settings()) {
362 while ($settings = db_fetch_object($result)) {
363 $len = strlen($settings->display_page);
364 if(substr($_GET['q'], 0, $len) == $settings->display_page) {
365 $args = substr($_GET['q'],$len+1);
366 $parts = explode("/", $args);
367 // need to get page name
368 $vid = array_shift($parts);
369 $params = '/'.$vid;
370 foreach($parts as $part) {
371 $params .= '/'.$part;
372 $term = taxonomy_get_term($part);
373 $bc[] = l($term->name, $settings->display_page.$params);
374 }
375 }
376 }
377 }
378 }
379 return $bc;
380 }
381 // taxonomy_select_nodes() only returns 10 items which is no good for counting above 10
382 function adv_taxonomy_menu_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE, $order = 'n.sticky DESC, n.created DESC') {
383 if (count($tids) > 0) {
384 // For each term ID, generate an array of descendant term IDs to the right depth.
385 $descendant_tids = array();
386 if ($depth === 'all') {
387 $depth = NULL;
388 }
389 foreach ($tids as $index => $tid) {
390 $term = taxonomy_get_term($tid);
391 $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth);
392 $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
393 }
394
395 if ($operator == 'or') {
396 $args = call_user_func_array('array_merge', $descendant_tids);
397 $placeholders = implode(',', array_fill(0, count($args), '%d'));
398 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1 ORDER BY '. $order;
399 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.nid = tn.nid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1';
400 }
401 else {
402 $joins = '';
403 $wheres = '';
404 $args = array();
405 foreach ($descendant_tids as $index => $tids) {
406 $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.nid = tn'. $index .'.nid';
407 $placeholders = implode(',', array_fill(0, count($tids), '%d'));
408 $wheres .= ' AND tn'. $index .'.tid IN ('. $placeholders .')';
409 $args = array_merge($args, $tids);
410 }
411 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order;
412 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres;
413 }
414 $sql = db_rewrite_sql($sql);
415 $sql_count = db_rewrite_sql($sql_count);
416 if ($pager) {
417 $result = pager_query($sql, variable_get('default_nodes_main', 10), 0, $sql_count, $args);
418 }
419 else {
420 $result = db_query($sql, $args);
421 }
422 }
423
424 return $result;
425 }
426
427 /**
428 * Page callback that renders a node listing for the selected term.
429 */
430 function __adv_taxonomy_menu_page() {
431 require_once(drupal_get_path('module', 'adv_taxonomy_menu') .'/adv_taxonomy_menu.inc');
432 return _adv_taxonomy_menu_page();
433 }
434
435 /**
436 * Implementation of hook_taxonomy().
437 *
438 * Invalidates the menu cache on taxonomy changes.
439 */
440 function adv_taxonomy_menu_taxonomy() {
441 menu_rebuild();
442 }
443
444 function adv_taxonomy_menu_term_path(&$term) {
445 return 'asdf';
446 }

  ViewVC Help
Powered by ViewVC 1.1.2