/[drupal]/contributions/modules/taxonomy_filter/taxonomy_filter.module
ViewVC logotype

Contents of /contributions/modules/taxonomy_filter/taxonomy_filter.module

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


Revision 1.21 - (show annotations) (download) (as text)
Tue Nov 3 14:41:15 2009 UTC (3 weeks, 3 days ago) by solotandem
Branch: MAIN
CVS Tags: DRUPAL-6--1-1, HEAD
Changes since 1.20: +5 -5 lines
File MIME type: text/x-php
#622006: Add check_clean and filter_xss_admin to appropriate places.
1 <?php
2 // $Id: taxonomy_filter.module,v 1.20 2009/07/25 23:39:02 solotandem Exp $
3
4 /**
5 * @file
6 * The core Taxonomy Filter module containing the API bits.
7 */
8
9 /*
10 TODO - Overall tasks before release:
11 Refactor data structures etc - weed out redundancies
12 Investigate block caching when n_a modules installed
13 Depth handling - both on the outgoing links and on term selection
14 Check for unused functions
15 Add back some sql_rewrite wrappers on database queries for sites that use access control on terms
16 Documentation and commenting
17 Add explanation text to admin UI
18 Add Drupal 5 upgrade code
19 Implement tests (maybe later once I understand it)
20 */
21
22
23
24 // Define constants for variable defaults
25 define('TAXONOMY_FILTER_INPUT', 'taxonomy/term/%tids/%depth!feed'); // 'taxonomy/term/%tids/%depth/!feed'
26 define('TAXONOMY_FILTER_OUTPUT', 'taxonomy/term/%tids/%depth');
27 define('TAXONOMY_FILTER_CURRENT_BLOCK_TITLE', 'Search results');
28 define('TAXONOMY_FILTER_REFINE_BLOCK_TITLE', 'Refine your search');
29
30 module_load_include('inc', 'taxonomy_filter', 'taxonomy_filter.base');
31
32 /**
33 * Implementation of hook_menu().
34 */
35 function taxonomy_filter_menu() {
36 $items = array();
37 $items['admin/settings/taxonomy_filter'] = array(
38 'title' => 'Taxonomy filter',
39 'description' => 'Configure the taxonomy filter module.',
40 'page callback' => 'taxonomy_filter_admin_list',
41 'access arguments' => array('administer site configuration'),
42 'file' => 'taxonomy_filter.admin.inc',
43 );
44 $items['admin/settings/taxonomy_filter/menus'] = array(
45 'title' => 'Menus',
46 'weight' => -5,
47 'type' => MENU_DEFAULT_LOCAL_TASK,
48 );
49 $items['admin/settings/taxonomy_filter/general'] = array(
50 'title' => 'General',
51 'weight' => 0,
52 'description' => 'General settings.',
53 'page callback' => 'drupal_get_form',
54 'page arguments' => array('taxonomy_filter_admin_general'),
55 'access arguments' => array('administer site configuration'),
56 'file' => 'taxonomy_filter.admin.inc',
57 'type' => MENU_LOCAL_TASK,
58 );
59 $items['admin/settings/taxonomy_filter/mappings'] = array(
60 'title' => 'Mappings',
61 'weight' => 7,
62 'description' => 'Map menus to vocabs.',
63 'page callback' => 'taxonomy_filter_admin_mappings',
64 'access arguments' => array('administer site configuration'),
65 'parent' => 'admin/settings/taxonomy_filter/',
66 'file' => 'taxonomy_filter.admin.inc',
67 'type' => MENU_LOCAL_TASK,
68 );
69 $items['admin/settings/taxonomy_filter/advanced'] = array(
70 'title' => 'Advanced',
71 'weight' => 10,
72 'description' => 'Advanced settings.',
73 'page callback' => 'drupal_get_form',
74 'page arguments' => array('taxonomy_filter_admin_advanced'),
75 'access arguments' => array('administer site configuration'),
76 'file' => 'taxonomy_filter.admin.inc',
77 'type' => MENU_LOCAL_TASK,
78 );
79 $items['admin/settings/taxonomy_filter/%/edit'] = array(
80 // TODO - fix breadcrumb for this page
81 'title' => 'Edit Taxonomy Filter menu',
82 'page callback' => 'drupal_get_form',
83 'page arguments' => array('taxonomy_filter_admin_menu_edit_form', 3),
84 'access arguments' => array('administer site configuration'),
85 'file' => 'taxonomy_filter.admin.inc',
86 'type' => MENU_CALLBACK,
87 );
88 $items['admin/settings/taxonomy_filter/%/delete'] = array(
89 'title' => 'Delete Taxonomy Filter menu',
90 'page callback' => 'drupal_get_form',
91 'page arguments' => array('taxonomy_filter_admin_menu_delete_confirm', 3),
92 'access arguments' => array('administer site configuration'),
93 'file' => 'taxonomy_filter.admin.inc',
94 'type' => MENU_CALLBACK,
95 );
96 $items['admin/settings/taxonomy_filter/mappings/%/edit'] = array(
97 'title' => 'Edit Taxonomy Filter mappings',
98 'page callback' => 'drupal_get_form',
99 'page arguments' => array('taxonomy_filter_admin_mappings_edit_form', 4),
100 'access arguments' => array('administer site configuration'),
101 'parent' => 'admin/settings/taxonomy_filter/mappings',
102 'file' => 'taxonomy_filter.admin.inc',
103 'type' => MENU_CALLBACK,
104 );
105 return $items;
106 }
107
108 /**
109 * Implementation of hook_taxonomy().
110 */
111 function taxonomy_filter_taxonomy($op, $type, $object = NULL) {
112 // TODO: when manual block caching is implemented, the cache will need to be flushed
113 // after taxonomy changes.
114 if ($type == 'vocabulary') {
115 taxonomy_filter_update_mappings();
116 }
117 }
118
119 /**
120 * Implementation of hook_enable().
121 */
122 function taxonomy_filter_enable() {
123 $filters = variable_get('taxonomy_filter_input', TAXONOMY_FILTER_INPUT);
124 taxonomy_filter_parse_input_filters($filters);
125 taxonomy_filter_update_mappings();
126 }
127
128 /**
129 * Implementation of hook_help().
130 */
131 function taxonomy_filter_help() {
132 // TODO?
133 }
134
135 /**
136 * Implementation of hook_forms().
137 */
138 function taxonomy_filter_forms() {
139 // use this for building menu settings forms?
140 }
141
142 /**
143 * Implementation of hook_theme().
144 */
145 function taxonomy_filter_theme($existing, $type, $theme, $path) {
146 return array(
147 'taxonomy_filter_admin_list_form_templates' => array(
148 'arguments' => array('form' => array()),
149 'file' => 'taxonomy_filter.theme.inc',
150 ),
151 'taxonomy_filter_admin_list_form_menus' => array(
152 'arguments' => array('form' => array()),
153 'file' => 'taxonomy_filter.theme.inc',
154 ),
155 'taxonomy_filter_admin_mappings_table' => array(
156 'arguments' => array('form' => array()),
157 'file' => 'taxonomy_filter.theme.inc',
158 ),
159 // Current criteria
160 'taxonomy_filter_block_current_content' => array(
161 'arguments' => array('terms' => NULL, 'block_info' => NULL),
162 'file' => 'taxonomy_filter.theme.inc',
163 ),
164 'taxonomy_filter_current_item' => array(
165 'arguments' => array('item' => NULL, 'block_info' => NULL),
166 'file' => 'taxonomy_filter.theme.inc',
167 'template' => 'taxonomy-filter-item',
168 ),
169 // Refine criteria
170 'taxonomy_filter_block_content' => array(
171 'arguments' => array('sections' => NULL, 'block_info' => NULL),
172 'file' => 'taxonomy_filter.theme.inc',
173 ),
174 'taxonomy_filter_section' => array(
175 'arguments' => array('section' => NULL, 'block_info' => NULL),
176 'file' => 'taxonomy_filter.theme.inc',
177 'template' => 'taxonomy-filter-section',
178 ),
179 'taxonomy_filter_item' => array(
180 'arguments' => array('item' => NULL, 'section_info' => NULL, 'block_info' => NULL),
181 'file' => 'taxonomy_filter.theme.inc',
182 'template' => 'taxonomy-filter-item',
183 ),
184 'taxonomy_filter_link' => array(
185 'arguments' => array('name' => NULL, 'attributes' => NULL),
186 'file' => 'taxonomy_filter.theme.inc',
187 ),
188 );
189 }
190
191 /**
192 * Implementation of hook_block().
193 */
194 function taxonomy_filter_block($op = 'list', $delta = 0, $edit = array()) {
195 if ($op == 'list') {
196 $blocks = array();
197 $blocks[0] = array(
198 'info' => t('Taxonomy filter - refine criteria'),
199 // cache per page as menu is different for each url
200 // no point also caching per user or role - it would only vary if a node
201 // access module is installed and that bypasses block caching anyway.
202 // See: http://drupal.org/node/80951 and http://drupal.org/node/186636
203 // TODO: (later) implement manual per user or role caching
204 'cache' => BLOCK_CACHE_PER_PAGE,
205 );
206 $blocks[1] = array(
207 'info' => t('Taxonomy filter - current criteria'),
208 'cache' => BLOCK_CACHE_PER_PAGE,
209 'weight' => -20,
210 );
211 return $blocks;
212 }
213 elseif ($op == 'view') {
214 $block = array();
215 // Check url to see if we should display on this page.
216 $url_tokens = taxonomy_filter_get_url_tokens();
217 if ($url_tokens['tids'] && $url_tokens['op'] != 'feed') {
218 // TODO Depth returns as '3!feed' - parsing is incorrect - what happened in 5.x??? Same thing!
219 $depth = _taxonomy_filter_validate_depth($url_tokens['depth']);
220 $tids = _taxonomy_filter_validate_tids($url_tokens['tids']);
221 switch($delta) {
222 case 0:
223 // Refine search criteria block.
224 if (count($tids) > 0) {
225 $block_data = taxonomy_filter_block_refine($tids, $depth);
226 $block = array(
227 'subject' => filter_xss_admin($block_data['title']),
228 'content' => theme('taxonomy_filter_block_content', $block_data['sections'], $block_data['info']),
229 );
230 }
231 break;
232
233 case 1:
234 // Current search criteria block.
235 $block_data = taxonomy_filter_block_current_NEW($tids, $depth);
236 $block = array(
237 'subject' => filter_xss_admin($block_data['title']),
238 'content' => theme('taxonomy_filter_block_content', $block_data['sections'], $block_data['info']),
239 );
240 break;
241 }
242 return $block;
243 }
244 }
245 }
246
247 function taxonomy_filter_block_current($url_tids, $url_depth = NULL) {
248 // drupal_set_title('Search results'); // User-setting or based on url alias or content?
249 $terms = array();
250 foreach ($url_tids as $tid) {
251 $terms[] = taxonomy_get_term($tid);
252 }
253 foreach ($terms as $term) {
254 $term->vocab_name = taxonomy_vocabulary_load($term->vid)->name;
255 }
256 $block['title'] = t('Search results'); // TODO Use caption in settings.
257 $block['terms'] = $terms;
258 $block['info'] = array(
259 'url_tids' => $url_tids,
260 'url_depth' => $url_depth,
261 );
262 return $block;
263 }
264
265 /**
266 * Return array for current search results block.
267 *
268 * @param array $url_tids Term IDs.
269 * @param integer $url_depth Depth of taxonomy terms to display (NA).
270 * @return array Block content.
271 */
272 function taxonomy_filter_block_current_NEW($url_tids, $url_depth = NULL) {
273 $terms = array();
274 foreach ($url_tids as $tid) {
275 $terms[] = taxonomy_get_term($tid);
276 }
277 $block['sections'] = array();
278 $block['info'] = array(
279 'url_tids' => $url_tids,
280 'url_depth' => $url_depth,
281 );
282 $sections_info = taxonomy_filter_sections_info_NEW($block['info']);
283 if (!$sections_info) {
284 return $block;
285 }
286 foreach ($sections_info as $section_info) {
287 $module = $section_info['module']; // TODO Implement other menu templates?
288 // TODO Context menu is not implemented for the current search block.
289 $section_info['module'] = $module == 'tf_context' ? 'taxonomy_filter' : $module;
290 $section_terms = array();
291 foreach ($terms as $term) {
292 if ($term->vid == $section_info['vid']) {
293 $section_terms[] = $term;
294 }
295 }
296 $items = array();
297 if (count($section_terms) > 0) {
298 $items = taxonomy_filter_section_items($section_terms, $section_info, $block['info']);
299 }
300
301 if (!count($items)) {
302 continue;
303 }
304 $section = array(
305 'title' => $section_info['section_title'],
306 'items' => $items,
307 'info' => $section_info,
308 );
309 drupal_alter('tf_section', $section, $block['info']);
310 $block['sections'][] = $section;
311 }
312 drupal_alter('tf_block', $block);
313 $settings = variable_get('taxonomy_filter_general', array());
314 $block['title'] = isset($settings['current_block_title']) ? t($settings['current_block_title']) : t(TAXONOMY_FILTER_CURRENT_BLOCK_TITLE); // JB NEW Override tf_multi
315 return $block;
316 }
317
318 function taxonomy_filter_sections_info_NEW($block_info) {
319 $all_mappings = variable_get('taxonomy_filter_mappings', array());
320 $menus = variable_get('taxonomy_filter_menus', array());
321
322 $sections = array();
323 $url_tids = $block_info['url_tids'];
324 $sql = "SELECT DISTINCT(vid) FROM {term_data} WHERE tid IN (". db_placeholders($url_tids) .")";
325 $result = db_query($sql, $url_tids);
326 while ($row = db_fetch_object($result)) {
327 $vid = $row->vid;
328
329 $menu_id = $all_mappings[$vid]['current_menu'] ? $all_mappings[$vid]['current_menu'] : $all_mappings[$vid]['refine_menu'];
330 $menu = $menus[$menu_id];
331 $section = array(
332 // TODO - this needs some refactoring / clean up
333 'section_title' => check_plain($all_mappings[$vid]['vocab']),
334 'vid' => $vid,
335 'menu_id' => $menu_id,
336 'module' => $menu['module'], // use $module_tf_section to get data
337 'section_settings' => $menu,
338 'class' => array('section', $menu['module']), // TODO - should we use template name instead of module name?
339 );
340 $sections[] = $section;
341 }
342 return $sections;
343 }
344
345 // Rename from taxonomy_filter_block_data
346
347 /**
348 * Block builder.
349 *
350 * @param array $url_tids Term ids in page URL.
351 * @param integer $url_depth Depth of terms to display.
352 * @return array Block content.
353 */
354 function taxonomy_filter_block_refine($url_tids, $url_depth = NULL) {
355 // drupal_set_title('Search results');
356
357 $first_term = taxonomy_get_term($url_tids[0]);
358 // TODO Do we want to offer this option???
359 $block['title'] = t('Select topics tagged with \'@term\' and:', array('@term' => $first_term->name));
360
361 $settings = variable_get('taxonomy_filter_general', array());
362 $block['title'] = isset($settings['refine_block_title']) ? t($settings['refine_block_title']) : t(TAXONOMY_FILTER_REFINE_BLOCK_TITLE); // JB NEW Override tf_multi
363
364 $block['sections'] = array();
365 $block['info'] = array(
366 'url_tids' => $url_tids,
367 'url_depth' => $url_depth,
368 );
369 $sections_info = taxonomy_filter_sections_info($block['info']);
370 if (!$sections_info) {
371 return $block;
372 }
373 foreach ($sections_info as $section_info) {
374 $module = $section_info['module'];
375 $items = taxonomy_filter_invoke($module, 'tf_section', $section_info, $block['info']);
376 if (!count($items)) {
377 continue;
378 }
379 $section = array(
380 'title' => $section_info['section_title'],
381 'items' => $items,
382 'info' => $section_info,
383 );
384 drupal_alter('tf_section', $section, $block['info']);
385 $block['sections'][] = $section;
386 }
387 drupal_alter('tf_block', $block);
388 return $block;
389 }
390
391 /**
392 * Section builder (where section is a vocabulary).
393 *
394 * @param array $block_info Block information.
395 * @return array $sections
396 * Section information - title, menu id, module that renders this menu template, etc.
397 */
398 function taxonomy_filter_sections_info($block_info) {
399 $sections = array();
400 $url_tids = $block_info['url_tids'];
401 $sql = "SELECT DISTINCT(vid) FROM {term_data} WHERE tid IN (". db_placeholders($url_tids) .")";
402 $result = db_query($sql, $url_tids);
403 while ($row = db_fetch_object($result)) {
404 $term_vids[] = $row->vid;
405 }
406 $all_mappings = variable_get('taxonomy_filter_mappings', array());
407 $menus = variable_get('taxonomy_filter_menus', array());
408 foreach ($all_mappings as $vid => $vid_mapping) {
409 $menu_id = $vid_mapping['refine_menu'];
410 // array_intersect is not strict enough; we need a subset relationship
411 if (!array_diff($term_vids, $vid_mapping['mappings']) && $menu_id != 0) {
412 $menu = $menus[$menu_id];
413 $section = array(
414 // TODO - this needs some refactoring / clean up
415 'section_title' => $vid_mapping['vocab'],
416 'vid' => $vid,
417 'menu_id' => $menu_id,
418 'module' => $menu['module'], // use $module_tf_section to get data
419 'section_settings' => $menu,
420 'class' => array('section', $menu['module']), // TODO - should we use template name instead of module name?
421 );
422 $sections[] = $section;
423 }
424 }
425 return $sections;
426 }
427
428 /**
429 * Return list of terms to display in this section.
430 *
431 * @param array $section_info Section information.
432 * @param array $block_info Block information.
433 * @return array Section items.
434 */
435 function taxonomy_filter_tf_section($section_info, $block_info) {
436 // Should we use taxonomy_get_tree for these functions?
437 $context = NULL;
438 $terms = array();
439 $vid = $section_info['vid'];
440 $tids = $block_info['url_tids'];
441 // $menu_id = $section_info['menu_id']; // Not used
442
443 $select = "SELECT td.vid, td.tid, td.name, COUNT(DISTINCT(n.nid)) AS count" .
444 " FROM {term_data} td" .
445 " INNER JOIN {term_node} tn ON tn.tid = td.tid";
446
447 $joins = '';
448 // By replacing %d with multiple %d's we could run this query at one time (from another function above)
449 $wheres = ' WHERE td.vid IN (%d)';
450 foreach ($tids as $index => $tid) {
451 $joins .= ' INNER JOIN {term_node} tn' . $index . ' ON tn.nid = tn' . $index . '.nid';
452 $wheres .= ' AND tn' . $index . '.tid IN ('. $tid .')';
453 }
454 $joins .= " INNER JOIN {node} n ON tn.nid = n.nid";
455 $wheres .= ' AND n.status = 1 AND n.moderate = 0';
456 $group = ' GROUP BY td.vid, td.tid, td.name, td.weight';
457 $order = ' ORDER BY vid, weight, name';
458
459 $sql = $select . $joins . $wheres . $group . $order;
460 $sql = db_rewrite_sql($sql);
461
462 $result = db_query($sql, $vid);
463 while ($term = db_fetch_object($result)) {
464 $terms[] = $term;
465 }
466 // If only one term, then the section is not needed as all existing nodes have this one term value.
467 // Unset the section in the calling routine.
468 $items = array();
469 if (count($terms) > 0) {
470 $items = taxonomy_filter_section_items($terms, $section_info, $block_info, $context);
471 }
472 return $items;
473 }
474
475 /**
476 * Item builder.
477 *
478 * @param array $terms Term objects to produce items for.
479 * @param array $section_info Section information.
480 * @param array $block_info Block information.
481 * @param unknown_type $context
482 * @return array $items Item information.
483 */
484 function taxonomy_filter_section_items($terms, $section_info, $block_info, $context = NULL) {
485 $items = array();
486 $module = $section_info['module'];
487 foreach ($terms as $term) {
488 $item_tid = $term->tid;
489 $link_tids = taxonomy_filter_get_link_tids($block_info['url_tids'], $item_tid, $context);
490 $item = array(
491 'title' => check_plain($term->name),
492 'item_attributes' => array(),
493 'link_attributes' => array(),
494 'info' => array(
495 'item_tid' => $item_tid,
496 'link_tids' => $link_tids,
497 ),
498 );
499 if (isset($term->count)) {
500 $item['info']['tf_count'] = $term->count;
501 }
502 // if ($term->template_settings) {
503 // TODO - should this be template name not module name?
504 $item['info'][$module] = ''; // $term->template_settings;
505 // }
506 drupal_alter('tf_item', $item, $section_info, $block_info, $context);
507 // TODO Combine this with above alter after stabilizing module with tests.
508 drupal_alter('tf_item_2', $item, $section_info, $block_info, $term, $context);
509 $items[] = $item;
510 }
511 return $items;
512 }
513
514 function taxonomy_filter_get_link_tids($url_tids, $item_tid, $context = NULL) {
515 $link_tids = array();
516 if (!in_array($item_tid, $url_tids)) {
517 // only return link tids for unselected items
518 // $link_tids = array_merge($url_tids, array($item_tid)); // TEMP Code change made on 2009-04-28.
519 $link_tids = array($url_tids[0], $item_tid); // TEMP Revert to code prior to 2009-04-28.
520 }
521 drupal_alter('tf_link_tids', $link_tids, $item_tid, $context);
522 return $link_tids;
523 }
524
525 /**
526 * generates paths for items.
527 */
528 function _taxonomy_filter_format_path($tids, $depth, $op = NULL) {
529 // if no tids return empty path (TODO do we need this check?)
530 if (!$tids) return '';
531 $template = variable_get('taxonomy_filter_output', TAXONOMY_FILTER_OUTPUT);
532 $tid_str = implode(',', $tids);
533 $depth_str = ($depth) ? $depth : '';
534 $op_str = ($op) ? $op : '';
535
536 $raw_url = str_replace('%tids', $tid_str, $template);
537 $raw_url = str_replace('%depth', $depth_str, $raw_url);
538 $raw_url = str_replace('%op', $op_str, $raw_url);
539 $raw_url = str_replace('//', '/', $raw_url);
540 $raw_url = trim($raw_url, '/');
541
542 $url = drupal_get_path_alias(str_replace('%2C', ',', url($raw_url)));
543 return $url;
544 }
545
546 /**
547 * Check the current url against the list of urls to listen on.
548 *
549 * @return array Matched or unmatched tokens.
550 */
551 function taxonomy_filter_get_url_tokens() {
552 static $tokens;
553
554 if (!is_null($tokens)) {
555 return $tokens;
556 }
557
558 // TODO: make this extensible by other modules?
559 $filter_array = variable_get('taxonomy_filter_input_parsed', array());
560 $args = array();
561 $argnum = 0;
562 // create an array from arg(0), arg(1) etc
563 while ($arg = arg($argnum)) {
564 $args[] = $arg;
565 $argnum++;
566 }
567 foreach ($filter_array as $filter_line) {
568 $tids = NULL; // reset url variables
569 $depth = NULL;
570 $op = NULL;
571 $min = min(count($args), count($filter_line)); // TODO - this needs rethinking for checking against extra params
572 for ($i = 0; $i < $min; $i++) {
573 $filter_bit = $filter_line[$i];
574 $filter_bit_prefix = (strpos('/*%!', $filter_bit{0})) ? $filter_bit{0} : '' ; // uses a dummy '/' as pos 0
575 if ($filter_bit_prefix == '') {
576 if ($filter_bit != $args[$i]) {
577 break;
578 }
579 }
580 elseif ($filter_bit_prefix == '!') {
581 if ($filter_bit == '!'. $args[$i]) {
582 break;
583 }
584 }
585 if ($filter_bit == '%tids') {
586 $tids = $args[$i];
587 }
588 elseif ($filter_bit == '%depth') {
589 $depth = $args[$i];
590 }
591 elseif ($filter_bit == '%op') {
592 $op = $args[$i];
593 }
594 }
595 if ($tids) {
596 $tokens = array('tids' => $tids, 'depth' => $depth, 'op' => $op);
597 return $tokens;
598 }
599 }
600 $tokens = array('tids' => NULL, 'depth' => NULL, 'op' => NULL);
601 return $tokens;
602 }
603
604 /**
605 * Validate and convert the term ids in the url to an array.
606 */
607 function _taxonomy_filter_validate_tids($raw_tids) {
608 $tids = array();
609 foreach (preg_split('/[+ ,]/', $raw_tids) as $tid) {
610 if (is_numeric($tid) && (int) $tid > 0) {
611 $tids[] = (int) $tid;
612 }
613 }
614 return $tids;
615 }
616
617 /**
618 * Validate the depth parameter in the current path.
619 */
620 function _taxonomy_filter_validate_depth($raw_depth) {
621 if (is_numeric($raw_depth)) {
622 $depth = ($raw_depth > 0) ? min(9, (int) $raw_depth): 0;
623 }
624 else {
625 $depth = ($raw_depth == 'all') ? 'all' : NULL;
626 }
627 return $depth;
628 }
629
630 function _taxonomy_filter_get_vocabs() {
631 // TODO: use static array for performance?
632 // TODO: supply vocab weight for further calcs?
633 // TODO: use taxonomy_get_vocabularies?
634 $vocabs = array();
635 $result = db_query('SELECT v.vid, v.name FROM {vocabulary} v ORDER BY v.weight, v.name');
636 while ($voc = db_fetch_object($result)) {
637 $vocabs[$voc->vid] = $voc->name;
638 }
639 return $vocabs;
640 }
641
642 /**
643 * Update mappings variable for vocabulary changes.
644 */
645 function taxonomy_filter_update_mappings() {
646 $vocabs = _taxonomy_filter_get_vocabs();
647 $old_mappings = variable_get('taxonomy_filter_mappings', array());
648
649 // Check for any deleted vocabularies.
650 $vids = array_keys($vocabs);
651 foreach ($old_mappings as $vid => &$old_mapping) {
652 if (!array_key_exists($vid, $vocabs)) {
653 // Delete the mapping variable entry for the deleted vocabulary.
654 unset($old_mappings[$vid]);
655 }
656 elseif ($deleted_vids = array_diff($old_mapping['mappings'], $vids)) {
657 // Delete any mappings pointing to the deleted vocabulary.
658 foreach ($deleted_vids as $index => $deleted_vid) {
659 $key = array_search($deleted_vid, $old_mapping['mappings']);
660 unset($old_mapping['mappings'][$key]);
661 }
662 }
663 }
664
665 // Recreate the entire variable to synchronize the filter menu "display"
666 // order to a vocabulary weight change.
667 $new_mappings = array();
668 foreach ($vocabs as $vid => $name) {
669 if (array_key_exists($vid, $old_mappings)) {
670 // For existing mappings:
671 // - store the current vocabulary name (it may have changed).
672 // - create a mappings item if not present.
673 $new_mappings[$vid] = array(
674 'vocab' => $name,
675 'refine_menu' => $old_mappings[$vid]['refine_menu'],
676 'current_menu' => $old_mappings[$vid]['current_menu'],
677 'mappings' => isset($old_mappings[$vid]['mappings']) ? $old_mappings[$vid]['mappings'] : array(),
678 );
679 }
680 else {
681 // For missing mappings, add default values.
682 $new_mappings[$vid] = array(
683 'vocab' => $name,
684 'refine_menu' => 0,
685 'current_menu' => 0,
686 'mappings' => array(),
687 );
688 }
689 }
690
691 // Save the mappings.
692 variable_set('taxonomy_filter_mappings', $new_mappings);
693 }
694
695 /**
696 * Breaks the input filter patterns into component pieces.
697 */
698 function taxonomy_filter_parse_input_filters($filters) {
699 $input_bits = array();
700 $lines = preg_split('/[\n\r]+/', trim($filters));
701 foreach ($lines as $line) {
702 $temp = array();
703 $bits = explode('/', trim($line, '/'));
704 foreach ($bits as $bit) {
705 $temp[] = $bit;
706 }
707 $input_bits[] = $temp;
708 }
709 variable_set('taxonomy_filter_input_parsed', $input_bits);
710 }
711
712 function taxonomy_filter_invoke() {
713 // Just like module_invoke() but falls back on base menu template implementation.
714 $args = func_get_args();
715 $module = $args[0];
716 $hook = $args[1];
717 unset($args[0], $args[1]);
718 $function = $module .'_'. $hook;
719 if (module_hook($module, $hook)) {
720 return call_user_func_array($function, $args);
721 }
722 elseif (module_hook('taxonomy_filter', $hook)) {
723 return call_user_func_array('taxonomy_filter_'. $hook, $args);
724 }
725 }
726
727 /**
728 * Get all tids in the url up to and including the current tid based on the
729 * order selected by the user.
730 *
731 * @param array $tids
732 * @param integer $this_tid
733 * @return array
734 */
735 function _taxonomy_filter_tids_upto($tids, $this_tid) {
736 $length = 1;
737 foreach ($tids as $tid) {
738 if ($tid == $this_tid) {
739 break;
740 }
741 $length++;
742 }
743 /*
744 * On the last url tid omit a link to select all tids up to this tid as this
745 * content is already being displayed.
746 */
747 if ($length == count($tids)) {
748 return null;
749 }
750 return array_slice($tids, 0, $length);
751 }
752
753 /**
754 * Return variables table entries for the 'taxonomy_filter_menus' key.
755 *
756 * TODO Is this useful?
757 *
758 * @param integer $menu_id First level index.
759 * @param string $key Second level index.
760 * @return array Values.
761 */
762 function taxonomy_filter_menu_settings($menu_id, $key) {
763 $menus = variable_get('taxonomy_filter_menus', array());
764 $settings = array();
765 if (isset($menus[$menu_id]) && isset($menus[$menu_id][$key])) {
766 $settings = $menus[$menu_id][$key];
767 }
768 return $settings;
769 }
770
771 /**
772 * Process variables for page.tpl.php.
773 *
774 * This preprocess function works because the page hook is in a template.
775 * If the page hook was in a theme function then this would not be possible.
776 */
777 function taxonomy_filter_preprocess_page(&$variables) {
778 // Check url to see if we should display on this page.
779 $url_tokens = taxonomy_filter_get_url_tokens();
780 if ($url_tokens['tids'] && $url_tokens['op'] != 'feed') {
781 $settings = variable_get('taxonomy_filter_general', array());
782 if (isset($settings['display_current_atop_content']) && $settings['display_current_atop_content']) {
783 $variables['title'] = isset($settings['current_block_title']) ? t($settings['current_block_title']) : t(TAXONOMY_FILTER_CURRENT_BLOCK_TITLE);
784 $depth = _taxonomy_filter_validate_depth($url_tokens['depth']);
785 $tids = _taxonomy_filter_validate_tids($url_tokens['tids']);
786 $block_data = taxonomy_filter_block_current($tids, $depth);
787
788 $new = '';
789 $new .= '<div class="clear-block block block-taxonomy_filter" id="block-taxonomy_filter-2">';
790 $new .= '<div class="content">';
791 $new .= '<ul>';
792 $new .= theme('taxonomy_filter_block_current_content', $block_data['terms'], $block_data['info']);
793 $new .= '</ul>';
794 $new .= '</div>';
795 $new .= '</div>';
796 $variables['content'] = $new . $variables['content'];
797 }
798 }
799 }

  ViewVC Help
Powered by ViewVC 1.1.2