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

Contents of /contributions/modules/nodeorder/nodeorder.module

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


Revision 1.11 - (show annotations) (download) (as text)
Sun Apr 26 12:47:36 2009 UTC (7 months ago) by pvanderspek
Branch: MAIN
Changes since 1.10: +125 -45 lines
File MIME type: text/x-php
merged changed from 6.x-1.x branch

#242077 by pvanderspek: make order nodes tab at admin/content/taxonomy/% optional
#259267 by pvanderspek: cache the results of nodeorder_can_be_ordered and nodeorder_orderable_tids
#259267 by pvanderspek: cache the results of nodeorder_can_be_ordered and nodeorder_orderable_tids and nodeorder_term_can_be_ordered
#107860 by marcp, pvanderspek: nodeorder should not show move up / down link when it does not apply
1 <?php
2 // $Id: nodeorder.module,v 1.9.2.36 2009/04/26 12:32:53 pvanderspek Exp $
3 // vim: syntax=php
4
5 /**
6 * @file
7 * Nodeorder module.
8 */
9
10 /**
11 * Implementation of hook_perm().
12 */
13 function nodeorder_perm() {
14 return array(
15 'order nodes within categories'
16 );
17 }
18
19 /**
20 * Implementation of hook_theme()
21 */
22 function nodeorder_theme() {
23 return array(
24 'nodeorder_admin_display_form' => array(
25 'template' => 'nodeorder-admin-display-form',
26 'arguments' => array('form' => NULL),
27 'file' => 'nodeorder.admin.inc',
28 ),
29 );
30 }
31
32 /**
33 * Implementation of hook_form_alter().
34 */
35 function nodeorder_form_alter(&$form, $form_state, $form_id) {
36 if ($form_id == 'taxonomy_form_vocabulary') {
37 $is_orderable = $form['module']['#value'] == 'nodeorder';
38
39 $form['settings']['orderable'] = array(
40 '#type' => 'checkbox',
41 '#title' => t('Orderable'),
42 '#description' => t('If enabled, nodes may be ordered within this vocabulary.'),
43 '#weight' => 0.0075, // Try to have this show up after the 'Required' checkbox
44 '#default_value' => $is_orderable
45 );
46
47 // Add a submit handler for saving the orderable settings
48 $form['#submit'][] = 'nodeorder_taxonomy_form_vocabulary_submit';
49
50 /*
51 * Why not implement hook_taxonomy?
52 * hook_taxonomy sometimes gets called after editing terms;
53 * in that case the orderable-value will not be available and thus the
54 * orderable-setting on the vocabulary will always be disabled
55 */
56 }
57 }
58
59 function nodeorder_taxonomy_form_vocabulary_submit($form, &$form_state) {
60 $vid = $form_state['values']['vid'];
61
62 if ($form_state['values']['orderable']) {
63 if ($form_state['values']['module'] != 'nodeorder') {
64 // Switching from non-orderable to orderable...
65 cache_clear_all('nodeorder:', 'cache', TRUE);
66
67 // Set weight_in_tid to nid for all rows in term_node where
68 // the tid is in this vocabulary...
69 $tree = taxonomy_get_tree($vid);
70
71 $tids = array();
72
73 foreach ($tree as $term) {
74 $tids[] = $term->tid;
75 }
76
77 if (count($tids) > 0) {
78 $order = 'n.sticky DESC, tn0.weight_in_tid';
79 $sql_max = "SELECT MAX(weight_in_tid) FROM {term_node} WHERE tid = %d";
80 $sql_update = "UPDATE {term_node} SET weight_in_tid = %d WHERE tid = %d AND nid = %d";
81
82 foreach ($tids as $i => $tid) {
83 //select *current* nodes for the current term
84 $result = nodeorder_select_nodes(array($tid), 'and', 0, FALSE, $order, 0);
85
86 while ($node = db_fetch_object($result)) {
87 db_lock_table('term_node');
88 $max = db_result(db_query($sql_max, $tid));
89 db_query($sql_update, $max + 1, $tid, $node->nid);
90 db_unlock_tables();
91 }
92 }
93 }
94
95 db_query("UPDATE {vocabulary} SET module = '%s' WHERE vid = %d", 'nodeorder', $vid);
96
97 drupal_set_message(t('You may now order nodes within this vocabulary.'));
98 }
99 }
100 else {
101 if ($form_state['values']['module'] == 'nodeorder') {
102 // Switching from orderable to non-orderable...
103 cache_clear_all('nodeorder:', 'cache', TRUE);
104
105 db_query("UPDATE {vocabulary} SET module = '%s' WHERE vid = %d", 'taxonomy', $vid);
106
107 // Set weight_in_tid to 0 for all rows in term_node where
108 // the tid is in this vocabulary...
109 $tree = taxonomy_get_tree($vid);
110
111 $tids = array();
112
113 foreach ($tree as $term) {
114 $tids[] = $term->tid;
115 }
116
117 if (count($tids) > 0) {
118 db_query("UPDATE {term_node} SET weight_in_tid = 0 WHERE tid IN (". implode(',', $tids) .")");
119 }
120
121 drupal_set_message(t('You may no longer order nodes within this vocabulary.'));
122 }
123 }
124 }
125
126 /**
127 * Implementation of hook_link().
128 */
129 function nodeorder_link($type, $node = 0, $main = 0) {
130 $links = array();
131
132 if (user_access('order nodes within categories') && variable_get('nodeorder_show_links_on_node', 1) > 0) {
133 // If this node belongs to any vocabularies that are orderable,
134 // stick a couple links on per term to allow the user to move
135 // the node up or down within the term...
136 if ($type == 'node') {
137 if (array_key_exists('taxonomy', $node)) {
138 $vocabularies = taxonomy_get_vocabularies();
139
140 if (variable_get('nodeorder_show_links_on_node', 1) == 2
141 && ((arg(0) == 'taxonomy' || arg(0) == 'nodeorder') && arg(1) == 'term')) {
142 $term = taxonomy_get_term(arg(2));
143 nodeorder_add_link($links, $vocabularies, $node, $term);
144 }
145 else if (variable_get('nodeorder_show_links_on_node', 1) == 1) {
146 foreach ($node->taxonomy as $term) {
147 nodeorder_add_link($links, $vocabularies, $node, $term);
148 }
149 }
150 }
151 }
152 }
153
154 return $links;
155 }
156
157 function nodeorder_add_link(&$links, $vocabularies, $node, $term) {
158 $vocabulary = $vocabularies[$term->vid];
159
160 if ($vocabulary->module == 'nodeorder') {
161 $weights = nodeorder_get_weight($term->tid, 0);
162 $weight = db_result(db_query("SELECT weight_in_tid FROM {term_node} WHERE nid = %d AND tid = %d", $node->nid, $term->tid));
163
164 if ($weight > $weights["min"]) {
165 $links['nodeorder_move_up_'. $term->tid] = array(
166 'href' => "nodeorder/moveup/". $node->nid ."/". $term->tid,
167 'title' => t("move up in ". $term->name),
168 'query' => drupal_get_destination(),
169 'attributes' => array('title' => t("Move this ". $node->type ." up in its category.")),
170 );
171 }
172
173 if ($weight < $weights["max"]) {
174 $links['nodeorder_move_down_'. $term->tid] = array(
175 'href' => "nodeorder/movedown/". $node->nid ."/". $term->tid,
176 'title' => t("move down in ". $term->name),
177 'query' => drupal_get_destination(),
178 'attributes' => array('title' => t("Move this ". $node->type ." down in its category.")),
179 );
180 }
181 }
182 }
183
184 function nodeorder_get_weight($tid, $reset) {
185 static $min_weights = array();
186 static $max_weights = array();
187
188 if ($reset) {
189 unset($min_weights[$tid]);
190 unset($max_weights[$tid]);
191 }
192
193 if (!$min_weights[$tid] || !$max_weights[$tid]) {
194 $result = db_query("SELECT tid, max(weight_in_tid) as max_weight, min(weight_in_tid) as min_weight FROM {term_node} WHERE tid = %d GROUP BY tid", $tid);
195
196 while ($row = db_fetch_object($result)) {
197 $min_weights[$row->tid] = $row->min_weight;
198 $max_weights[$row->tid] = $row->max_weight;
199 }
200 }
201
202 $weights["min"] = $min_weights[$tid];
203 $weights["max"] = $max_weights[$tid];
204 return $weights;
205 }
206
207 /**
208 * Implementation of hook_term_path() from Taxonomy.
209 */
210 function nodeorder_term_path($term) {
211 if (variable_get('nodeorder_replace_taxonomy_link', 1)
212 || arg(0) == 'nodeorder') { //if nodeorder is being used to display term pages
213 return 'nodeorder/term/'. $term->tid;
214 }
215 else {
216 return FALSE; //create regular taxonomy-links on taxonomy page
217 }
218 }
219
220 /**
221 * Implementation of hook_menu().
222 */
223 function nodeorder_menu() {
224 $items = array();
225
226 $items['admin/settings/nodeorder'] = array(
227 'title' => t('Nodeorder'),
228 'description' => t('Allows the ordering of nodes within taxonomy terms.'),
229 'page callback' => 'drupal_get_form',
230 'page arguments' => array('nodeorder_admin'),
231 'access arguments' => array('access administration pages'),
232 'type' => MENU_NORMAL_ITEM);
233
234 $items['nodeorder/term/%'] = array(
235 'title' => t('Nodeorder term'),
236 'page callback' => 'nodeorder_term_page', // I want to call taxonomy_term_page but can't change the sort order...
237 'page arguments' => array(2),
238 'access arguments' => array('access content'),
239 'type' => MENU_CALLBACK);
240
241 $items['nodeorder/order/%'] = array(
242 'title' => t('Order nodes'),
243 'page callback' => 'nodeorder_admin_display',
244 'page arguments' => array(2),
245 'access arguments' => array('order nodes within categories'),
246 'file' => 'nodeorder.admin.inc',
247 'type' => MENU_CALLBACK);
248
249 $items['taxonomy/term/%/view'] = array(
250 'title' => t('View'),
251 'page callback' => 'taxonomy_term_page',
252 'page arguments' => array(2),
253 'access arguments' => array('access content'),
254 'weight' => -10,
255 'type' => MENU_DEFAULT_LOCAL_TASK);
256 $items['taxonomy/term/%/order'] = array(
257 'title' => t('Order nodes'),
258 'page callback' => 'nodeorder_admin_display',
259 'page arguments' => array(2),
260 'access callback' => 'nodeorder_order_access',
261 'access arguments' => array(2),
262 'file' => 'nodeorder.admin.inc',
263 'weight' => 1,
264 'type' => MENU_LOCAL_TASK);
265
266 $items['nodeorder/term/%/view'] = array(
267 'title' => t('View'),
268 'page callback' => 'nodeorder_term_page',
269 'page arguments' => array(2),
270 'access arguments' => array('access content'),
271 'weight' => -10,
272 'type' => MENU_DEFAULT_LOCAL_TASK);
273 $items['nodeorder/term/%/order'] = array(
274 'title' => t('Order nodes'),
275 'page callback' => 'nodeorder_admin_display',
276 'page arguments' => array(2),
277 'access callback' => 'nodeorder_order_access',
278 'access arguments' => array(2),
279 'file' => 'nodeorder.admin.inc',
280 'weight' => 1,
281 'type' => MENU_LOCAL_TASK);
282
283 $items['nodeorder/moveup/%/%'] = array(
284 'title' => t('Move Up'),
285 'page callback' => 'nodeorder_move_in_category',
286 'page arguments' => array(1, 2, 3),
287 'access arguments' => array('order nodes within categories'),
288 'type' => MENU_CALLBACK);
289 $items['nodeorder/movedown/%/%'] = array(
290 'title' => t('Move Down'),
291 'page callback' => 'nodeorder_move_in_category',
292 'page arguments' => array(1, 2, 3),
293 'access arguments' => array('order nodes within categories'),
294 'type' => MENU_CALLBACK);
295
296 $items['admin/content/taxonomy/%/order'] = array(
297 'title' => t('Order nodes'),
298 'page callback' => 'nodeorder_overview_terms',
299 'page arguments' => array(3),
300 'access callback' => 'nodeorder_taxonomy_order_access',
301 'access arguments' => array(3),
302 'weight' => 5,
303 'type' => MENU_LOCAL_TASK);
304
305 return $items;
306 }
307
308 /**
309 * Custom access function which determines whether or not the user is allowed to reorder nodes and if the link should be shown at all
310 */
311 function nodeorder_order_access($tid) {
312 return user_access('order nodes within categories') && variable_get('nodeorder_link_to_ordering_page', 1) && nodeorder_term_can_be_ordered($tid);
313 }
314
315 /**
316 * Custom access function which determines whether or not the user is allowed to reorder nodes and if the vocabulary is orderable
317 */
318 function nodeorder_taxonomy_order_access($vid) {
319 return user_access('order nodes within categories') && variable_get('nodeorder_link_to_ordering_page_taxonomy_admin', 1) && nodeorder_vocabulary_can_be_ordered($vid);
320 }
321
322 /**
323 * Menu callback; displays all nodes associated with a term.
324 */
325 function nodeorder_term_page($str_tids = '', $depth = 0, $op = 'page') {
326 $terms = taxonomy_terms_parse_string($str_tids);
327 if ($terms['operator'] != 'and' && $terms['operator'] != 'or') {
328 drupal_not_found();
329 }
330
331 if ($terms['tids']) {
332 $result = db_query(db_rewrite_sql('SELECT t.tid, t.name FROM {term_data} t WHERE t.tid IN ('. db_placeholders($terms['tids']) .')', 't', 'tid'), $terms['tids']);
333 $tids = array(); // we rebuild the $tids-array so it only contains terms the user has access to.
334 $names = array();
335 while ($term = db_fetch_object($result)) {
336 $tids[] = $term->tid;
337 $names[] = $term->name;
338 }
339
340 if ($names) {
341 drupal_set_title($title = check_plain(implode(', ', $names)));
342
343 // Set the order that gets passed in to taxonomy_select_nodes.
344 // This probably breaks down when there's a query that spans
345 // multiple terms...
346 //
347 // First sort by sticky, then by weight_in_tid...
348 if ($terms['operator'] == 'or') {
349 $order = 'n.sticky DESC, tn.weight_in_tid';
350 }
351 else {
352 $order = 'n.sticky DESC, tn0.weight_in_tid';
353 }
354
355 switch ($op) {
356 case 'page':
357 // Build breadcrumb based on first hierarchy of first term:
358 $current->tid = $tids[0];
359 $breadcrumb = array();
360 while ($parents = taxonomy_get_parents($current->tid)) {
361 $current = array_shift($parents);
362 $breadcrumb[] = l($current->name, 'nodeorder/term/'. $current->tid);
363 }
364 $breadcrumb[] = l(t('Home'), NULL);
365 $breadcrumb = array_reverse($breadcrumb);
366 drupal_set_breadcrumb($breadcrumb);
367
368 module_load_include('inc', 'taxonomy', 'taxonomy.pages'); //.inc files are not loaded automatically
369 $output = theme('taxonomy_term_page', $tids, nodeorder_select_nodes($tids, $terms['operator'], $depth, TRUE, $order));
370
371 drupal_add_feed(url('taxonomy/term/'. $str_tids .'/'. $depth .'/feed'), 'RSS - '. $title);
372 return $output;
373
374 case 'feed':
375 $channel['link'] = url('nodeorder/term/'. $str_tids .'/'. $depth, array('absolute' => TRUE));
376 $channel['title'] = variable_get('site_name', 'Drupal') .' - '. $title;
377 // Only display the description if we have a single term, to avoid clutter and confusion.
378 if (count($tids) == 1) {
379 $term = taxonomy_get_term($tids[0]);
380 // HTML will be removed from feed description, so no need to filter here.
381 $channel['description'] = $term->description;
382 }
383
384 $result = taxonomy_select_nodes($tids, $terms['operator'], $depth, FALSE, $order);
385 $items = array();
386 while ($row = db_fetch_object($result)) {
387 $items[] = $row->nid;
388 }
389
390 node_feed($items, $channel);
391 break;
392 default:
393 drupal_not_found();
394 }
395 }
396 else {
397 drupal_not_found();
398 }
399 }
400 }
401
402 /**
403 * NOTE: This is nearly a direct copy of taxonomy_select_nodes() -- see
404 * http://drupal.org/node/25801 if you find this sort of copy and
405 * paste upsetting...
406 *
407 * Finds all nodes that match selected taxonomy conditions.
408 *
409 * @param $tids
410 * An array of term IDs to match.
411 * @param $operator
412 * How to interpret multiple IDs in the array. Can be "or" or "and".
413 * @param $depth
414 * How many levels deep to traverse the taxonomy tree. Can be a nonnegative
415 * integer or "all".
416 * @param $pager
417 * Whether the nodes are to be used with a pager (the case on most Drupal
418 * pages) or not (in an XML feed, for example).
419 * @param $order
420 * The order clause for the query that retrieve the nodes.
421 * @param $count
422 * If $pager is TRUE, the number of nodes per page, or -1 to use the
423 * backward-compatible 'default_nodes_main' variable setting. If $pager
424 * is FALSE, the total number of nodes to select; or -1 to use the
425 * backward-compatible 'feed_default_items' variable setting; or 0 to
426 * select all nodes.
427 * @return
428 * A resource identifier pointing to the query results.
429 */
430 function nodeorder_select_nodes($tids = array(), $operator = 'or', $depth = 0, $pager = TRUE, $order = 'n.sticky DESC, n.created DESC', $count = -1) {
431 if (count($tids) > 0) {
432 // For each term ID, generate an array of descendant term IDs to the right depth.
433 $descendant_tids = array();
434 if ($depth === 'all') {
435 $depth = NULL;
436 }
437 foreach ($tids as $index => $tid) {
438 $term = taxonomy_get_term($tid);
439 $tree = taxonomy_get_tree($term->vid, $tid, -1, $depth);
440 $descendant_tids[] = array_merge(array($tid), array_map('_taxonomy_get_tid_from_term', $tree));
441 }
442
443 if ($operator == 'or') {
444 $args = call_user_func_array('array_merge', $descendant_tids);
445 $placeholders = db_placeholders($args, 'int');
446 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1 ORDER BY '. $order;
447 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid IN ('. $placeholders .') AND n.status = 1';
448 }
449 else {
450 $joins = '';
451 $wheres = '';
452 $args = array();
453 foreach ($descendant_tids as $index => $tids) {
454 $joins .= ' INNER JOIN {term_node} tn'. $index .' ON n.vid = tn'. $index .'.vid';
455 $wheres .= ' AND tn'. $index .'.tid IN ('. db_placeholders($tids, 'int') .')';
456 $args = array_merge($args, $tids);
457 }
458 $sql = 'SELECT DISTINCT(n.nid), n.sticky, n.title, n.created FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres .' ORDER BY '. $order;
459 $sql_count = 'SELECT COUNT(DISTINCT(n.nid)) FROM {node} n '. $joins .' WHERE n.status = 1 '. $wheres;
460 }
461
462 $sql = db_rewrite_sql($sql);
463 $sql_count = db_rewrite_sql($sql_count);
464
465 if ($pager) {
466 if ($count == -1) {
467 $count = variable_get('default_nodes_main', 10);
468 }
469 $result = pager_query($sql, $count, 0, $sql_count, $args);
470 }
471 else {
472 if ($count == -1) {
473 $count = variable_get('feed_default_items', 10);
474 }
475
476 if ($count == 0) {
477 $result = db_query($sql, $args);
478 }
479 else {
480 $result = db_query_range($sql, $args, 0, $count);
481 }
482 }
483 }
484
485 return $result;
486 }
487
488 /**
489 * Move a node up or down in its category...
490 */
491 function nodeorder_move_in_category($direction, $nid, $tid) {
492 // Note that it would be nice to wrap this in a transaction...
493
494 $up = ($direction == 'moveup');
495 $node = node_load($nid);
496 $destination = isset($_REQUEST['destination'])? $_REQUEST['destination']: $_GET['q'];
497
498 // Get the current weight for the node
499 $weight = db_result(db_query("SELECT weight_in_tid FROM {term_node} WHERE nid = %d AND tid = %d", $node->nid, $tid));
500
501 if ($up) {
502 $weights = nodeorder_get_weight($tid, 0);
503 if ($weight == $weights["min"]) {
504 drupal_set_message(t('%title cannot be moved up as it already is at the top.', array('%title' => $node->title)), 'error');
505 drupal_goto($destination);
506 return;
507 }
508
509 $sql = 'SELECT DISTINCT(n.nid), n.vid, tn.weight_in_tid FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid = %d AND n.status = 1 AND tn.weight_in_tid <= %d ORDER BY tn.weight_in_tid DESC';
510 $direction = 'up';
511 }
512 else {
513 $weights = nodeorder_get_weight($tid, 0);
514 if ($weight == $weights["max"]) {
515 drupal_set_message(t('%title cannot be moved down as it already is at the bottom.', array('%title' => $node->title)), 'error');
516 drupal_goto($destination);
517 return;
518 }
519
520 $sql = 'SELECT DISTINCT(n.nid), n.vid, tn.weight_in_tid FROM {node} n INNER JOIN {term_node} tn ON n.vid = tn.vid WHERE tn.tid = %d AND n.status = 1 AND tn.weight_in_tid >= %d ORDER BY tn.weight_in_tid';
521 $direction = 'down';
522 }
523
524 $result = db_query_range($sql, $tid, $weight, 0, 2);
525
526 $node1 = db_fetch_object($result);
527 $node2 = db_fetch_object($result);
528
529 // Now we just need to swap the weights of the two nodes...
530 if (!$node1 || !$node2) {
531 drupal_set_message('There was a problem moving the node within its category.');
532 drupal_access_denied();
533 return;
534 }
535
536 $sql = "UPDATE {term_node} SET weight_in_tid = %d WHERE nid = %d AND tid = %d";
537
538 db_query($sql, $node1->weight_in_tid, $node2->nid, $tid);
539 db_query($sql, $node2->weight_in_tid, $node1->nid, $tid);
540
541 $term = taxonomy_get_term($tid);
542 drupal_set_message(t("<em>%title</em> was moved $direction in %category...", array('%title' => $node->title, '%category' => $term->name)));
543
544 // Now send user to the page they were on before...
545 drupal_goto($_GET['destination']);
546 }
547
548 /**
549 * Returns TRUE if the node has terms in any orderable vocabulary...
550 */
551 function nodeorder_can_be_ordered($node) {
552 $cid = 'nodeorder:can_be_ordered:'. $node->type;
553
554 if (($cache = cache_get($cid)) && !empty($cache->data)) {
555 return $cache->data;
556 } else {
557 $sql = "SELECT v.vid AS vid FROM {vocabulary_node_types} vnt JOIN {vocabulary} v ON vnt.vid = v.vid WHERE vnt.type = '%s' AND v.module = 'nodeorder'";
558 $result = db_query($sql, $node->type);
559
560 $can_be_ordered = FALSE;
561 if (db_fetch_object($result)) {
562 $can_be_ordered = TRUE;
563 }
564
565 //permanently cache the value for easy reuse
566 cache_set($cid, $can_be_ordered, 'cache');
567
568 return $can_be_ordered;
569 }
570 }
571
572 /**
573 * Returns an array of the node's tids that are in orderable vocabularies...
574 */
575 function nodeorder_orderable_tids($node) {
576 $tids = array();
577 $orderable_tids = array();
578 $cid = 'nodeorder:orderable_tids:'. $node->type;
579
580 if (($cache = cache_get($cid)) && !empty($cache->data)) {
581 $orderable_tids = $cache->data;
582 } else {
583 $sql = "SELECT v.vid AS vid FROM {vocabulary_node_types} vnt JOIN {vocabulary} v ON vnt.vid = v.vid WHERE vnt.type = '%s' AND v.module = 'nodeorder'";
584 $result = db_query($sql, $node->type);
585
586 while ($row = db_fetch_object($result)) {
587 $tree = taxonomy_get_tree($row->vid);
588 foreach ($tree as $term) {
589 $orderable_tids[] = $term->tid;
590 }
591 }
592
593 //permanently cache the value for easy reuse
594 cache_set($cid, $orderable_tids, 'cache');
595 }
596
597 // Now select only those tids which are actually assigned to this term
598 foreach ($node->taxonomy as $key => $value) {
599 $list_of_tids = nodeorder_get_tids($key, $value);
600
601 $tids = array_merge($tids, array_intersect($list_of_tids, $orderable_tids));
602 }
603
604 return $tids;
605 }
606
607 function nodeorder_get_tids($key, $value) {
608 $tids = array();
609
610 if (isset($value)) {
611 if ($key === "tags") {
612 foreach ($value as $vid => $names) {
613 $tids = array_merge($tids, nodeorder_get_tids($vid, $names));
614 }
615 }
616 else if (is_numeric($value)) {
617 $tids[] = $value;
618 }
619 else if (is_array($value)) {
620 foreach ($value as $tid) {
621 $tids[] = $tid;
622 }
623 }
624 else if (is_string($value)) {
625 $values = drupal_explode_tags($value);
626 $get_tid_sql = "SELECT tid FROM {term_data} WHERE name = '%s' AND vid = %d";
627 foreach ($values as $term_name) {
628 $tids[] = db_result(db_query($get_tid_sql, $term_name, $key));
629 }
630 }
631 }
632
633 return $tids;
634 }
635
636 /**
637 * Returns TRUE if the vocabulary is orderable...
638 */
639 function nodeorder_vocabulary_can_be_ordered($vid) {
640 $sql = "SELECT * FROM {vocabulary} WHERE module = 'nodeorder' AND vid = %d";
641 $result = db_query($sql, $vid);
642
643 if (db_fetch_object($result)) {
644 return TRUE;
645 }
646
647 return FALSE;
648 }
649
650 /**
651 * Returns TRUE if the term is in an orderable vocabulary...
652 */
653 function nodeorder_term_can_be_ordered($tid) {
654 $cid = 'nodeorder:term_can_be_ordered:'. $tid;
655
656 if (($cache = cache_get($cid)) && !empty($cache->data)) {
657 return $cache->data;
658 } else {
659 $sql = "SELECT vid FROM {term_data} WHERE tid = %d";
660 $vid = db_result(db_query($sql, $tid));
661
662 $sql = "SELECT * FROM {vocabulary} WHERE module = 'nodeorder' AND vid = %d";
663 $result = db_query($sql, $vid);
664
665 $term_can_be_ordered = FALSE;
666 if (db_fetch_object($result)) {
667 $term_can_be_ordered = TRUE;
668 }
669
670 //permanently cache the value for easy reuse
671 cache_set($cid, $term_can_be_ordered, 'cache');
672
673 return $term_can_be_ordered;
674 }
675 }
676
677 /**
678 * Implementation of hook_nodeapi().
679 */
680 function nodeorder_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
681 switch ($op) {
682 case 'presave':
683 if (nodeorder_can_be_ordered($node)) {
684 if (!isset($node->nodeorder)) {
685 $node->nodeorder = array();
686
687 // When a node gets loaded, store an element called 'nodeorder' that contains
688 // an associative array of tid to weight_in_tid...
689 $result = db_query('SELECT tid, weight_in_tid FROM {term_node} WHERE nid = %d', $node->nid);
690 while ($term_node = db_fetch_object($result)) {
691 $node->nodeorder[$term_node->tid] = $term_node->weight_in_tid;
692 }
693 }
694 }
695 break;
696 case 'delete':
697 // make sure the weight cache is invalidated
698 if (nodeorder_can_be_ordered($node)) {
699 $tids = nodeorder_orderable_tids($node);
700
701 if (count($tids) > 0) {
702 foreach ($tids as $i => $tid) {
703 nodeorder_get_weight($tid, 1); // reinitialize the cache
704 }
705 }
706 }
707 break;
708 case 'insert':
709 // Set the initial weight_in_tid to max+1... This makes sure that the weight
710 // will be unique for each nid/tid combination
711 //
712 // NOTE - fall through to 'update' since we do mostly the same thing there.
713 case 'update':
714 // Set the weight_in_tid -- taxonomy probably stomped it because
715 // we added the weight_in_tid column to term_node, and taxonomy
716 // just wants to delete and re-insert rows when things change...
717
718 // Note that we only want to set the weight_in_tid for tids that
719 // are in orderable vocabularies...
720 if (nodeorder_can_be_ordered($node)) {
721 $tids = nodeorder_orderable_tids($node);
722
723 if (count($tids) > 0) {
724 $sql = "UPDATE {term_node} SET weight_in_tid = %d WHERE tid = %d AND nid = %d";
725
726 foreach ($tids as $i => $tid) {
727 db_lock_table('term_node');
728 $weights = nodeorder_get_weight($tid, 0); // get the cached weights
729 db_query($sql, $weights["max"] + 1, $tid, $node->nid);
730 nodeorder_get_weight($tid, 1); // reinitialize the cache
731 db_unlock_tables();
732 }
733 }
734
735 // New nodes won't have any saved weight_in_tid values so this array will be empty...
736 if ($node->nodeorder) {
737 // Restore any saved weight_in_tid values...
738 $sql = "UPDATE {term_node} SET weight_in_tid = %d WHERE nid = %d AND tid = %d";
739 foreach ($node->nodeorder as $tid => $weight_in_tid) {
740 // weight_in_tid cannot be 0
741 if ($weight_in_tid != 0) {
742 db_query($sql, $weight_in_tid, $node->nid, $tid);
743 }
744 }
745 }
746 }
747 break;
748 }
749 }
750
751 /**
752 * Form for Admin Settings
753 */
754 function nodeorder_admin() {
755 $form['nodeorder_show_links'] = array(
756 '#type' => 'fieldset',
757 '#title' => t('Display ordering links'),
758 '#description' => t('Choose whether to show ordering links. Links can be shown for all categories associated to a node or for the currently active category. It is also possible to not show the ordering links at all.'),
759 );
760 $form['nodeorder_show_links']['nodeorder_show_links_on_node'] = array(
761 '#type' => 'radios',
762 '#title' => t('Choose how to display ordering links'),
763 '#default_value' => variable_get('nodeorder_show_links_on_node', 1),
764 '#description' => 'When displaying links based on the context, they will only be shown on taxonomy and nodeorder pages.',
765 '#options' => array(t('Don\'t display ordering links'), t('Display ordering links for all categories'), t('Display ordering links based on the active category')),
766 );
767
768 $form['nodeorder_link_to_ordering_page'] = array(
769 '#type' => 'checkbox',
770 '#title' => t('Display link to the ordering page'),
771 '#description' => t('If enabled, a tab will appear on all <em>nodeorder/term/%</em> and <em>taxonomy/term/%</em> pages that quickly allows administrators to get to the node ordering administration page for the term.'),
772 '#default_value' => variable_get('nodeorder_link_to_ordering_page', 1)
773 );
774
775 $form['nodeorder_link_to_ordering_page_taxonomy_admin'] = array(
776 '#type' => 'checkbox',
777 '#title' => t('Display link to the ordering page on taxonomy administration page'),
778 '#description' => t('If enabled, a tab will appear on <em>admin/content/taxonomy/%</em> pages that quickly allows administrators to get to the node ordering administration page for the term.'),
779 '#default_value' => variable_get('nodeorder_link_to_ordering_page_taxonomy_admin', 1)
780 );
781
782 $form['nodeorder_replace_taxonomy_link'] = array(
783 '#type' => 'checkbox',
784 '#title' => t('Replace the link to <em>taxonomy/term/%</em> by <em>nodeorder/term/%</em>'),
785 '#description' => t('If enabled, links to regular <em>taxonomy/term/%</em> pages will always be replaced by links to their <em>nodeorder/term/%</em> counterpart. Otherwise, this will only happen on the <em>nodeorder/term/%</em> pages.'),
786 '#default_value' => variable_get('nodeorder_replace_taxonomy_link', 1)
787 );
788
789
790 return system_settings_form($form);
791 }
792
793 /**
794 * Display a tree of all the terms in a vocabulary, with options to
795 * order nodes within each one.
796 *
797 * This code was cut and pasted from taxonomy_overview_terms. If
798 * If we were able to add another operation onto each term on the
799 * admin/content/taxonomy/VID page then we wouldn't even need this duplicate
800 * function.
801 *
802 * TODO - put in a patch for a taxonomy hook that lets us add
803 * admin operation links per term... maybe it would call
804 * module_invoke_all('taxonomy', 'list', 'term', $term) and
805 * array_merge the results with each $row[]...
806 */
807
808 function nodeorder_overview_terms($vid) {
809 if (!nodeorder_vocabulary_can_be_ordered($vid)) {
810 return t('This vocabulary is not orderable. If you would like it to be orderable, check the Orderable box ') .
811 l(t('here'), 'admin/content/taxonomy/edit/vocabulary'. $vid) .'.';
812 }
813
814 $header = array(t('Name'), t('Operations'));
815 $vocabularies = taxonomy_get_vocabularies();
816 $vocabulary = $vocabularies[$vid];
817 if (!$vocabulary) {
818 return drupal_not_found();
819 }
820
821 drupal_set_title(t('Terms in %vocabulary', array('%vocabulary' => $vocabulary->name)));
822 $start_from = $_GET['page'] ? $_GET['page'] : 0;
823 $total_entries = 0; // total count for pager
824 $page_increment = 25; // number of tids per page
825 $displayed_count = 0; // number of tids shown
826
827 $tree = taxonomy_get_tree($vocabulary->vid);
828 foreach ($tree as $term) {
829 $total_entries++; // we're counting all-totals, not displayed
830 if (($start_from && ($start_from * $page_increment) >= $total_entries) || ($displayed_count == $page_increment)) {
831 continue;
832 }
833 $rows[] = array((isset($term->depth) && $term->depth > 0 ? theme('indentation', $term->depth) : '') . l($term->name, "nodeorder/term/$term->tid"), l(t('order nodes'), "nodeorder/term/$term->tid/order"));
834 $displayed_count++; // we're counting tids displayed
835 }
836
837 if (!$rows) {
838 $rows[] = array(array('data' => t('No terms available.'), 'colspan' => '2'));
839 }
840
841 $GLOBALS['pager_page_array'][] = $start_from; // FIXME
842 $GLOBALS['pager_total'][] = intval($total_entries / $page_increment) + 1; // FIXME
843
844 if ($total_entries >= $page_increment) {
845 $rows[] = array(array('data' => theme('pager', NULL, $page_increment), 'colspan' => '2'));
846 }
847
848 return theme('table', $header, $rows, array('id' => 'taxonomy'));
849 }
850
851 /**
852 * Implementation of hook_views_data_alter().
853 */
854 function nodeorder_views_data_alter(&$data) {
855 // taxonomy weight
856 $data['term_node']['weight_in_tid'] = array(
857 'title' => t('Weight in tid'),
858 'help' => t('The term weight in tid field'),
859 'field' => array(
860 'handler' => 'views_handler_field',
861 'click sortable' => TRUE,
862 ),
863 'sort' => array(
864 'handler' => 'views_handler_sort',
865 ),
866 );
867 }
868
869 /**
870 * Implementation of hook_help().
871 */
872 function nodeorder_help($path, $arg) {
873 switch ($path) {
874 case 'nodeorder/term/%/order':
875 case 'nodeorder/order/%':
876 $term = taxonomy_get_term($arg[2]);
877 $output = '<p>'. t('This page provides a drag-and-drop interface for ordering nodes. To change the order of a node, grab a drag-and-drop handle under the <em>Node title</em> column and drag the node to a new location in the list. (Grab a handle by clicking and holding the mouse while hovering over a handle icon.) Remember that your changes will not be saved until you click the <em>Save order</em> button at the bottom of the page.') .'</p>';
878
879 return $output;
880 case 'admin/content/taxonomy/%/order':
881 $vocabulary = taxonomy_vocabulary_load($arg[3]);
882 $output = '<p>'. t('%capital_name is an orderable vocabulary. You may order the nodes associated with a term within this vocabulary by clicking the <em>order nodes</em> link next to the term.', array('%capital_name' => drupal_ucfirst($vocabulary->name)));
883
884 return $output;
885 }
886 }

  ViewVC Help
Powered by ViewVC 1.1.2