/[drupal]/contributions/modules/ubercart/uc_catalog/uc_catalog.module
ViewVC logotype

Contents of /contributions/modules/ubercart/uc_catalog/uc_catalog.module

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


Revision 1.15 - (show annotations) (download) (as text)
Thu Jul 10 12:41:01 2008 UTC (16 months, 2 weeks ago) by islandusurper
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--2
Changes since 1.14: +728 -388 lines
File MIME type: text/x-php
Begin the Ubercart 6.x-2.x branch.
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * Übercart Catalog module.
7 *
8 * Provides classification and navigation product nodes using taxonomy. When
9 * installed, this module creates a vocabulary named "Product Catalog" and stores
10 * the vocabulary id for future use. The user is responsible for maintaining the
11 * terms in the taxonomy, though the Catalog will find products not listed in it.
12 *
13 * Coded by Lyle Mantooth
14 */
15
16 /**
17 * Data structure to mimic Drupal's menu system.
18 */
19 class uc_treeNode {
20 var $tid = 0;
21 var $name = 'Catalog';
22 var $children = array();
23 var $depth = -1;
24 var $sequence = 0;
25
26 function uc_treeNode($term = null) {
27 if ($term) {
28 $this->tid = $term->tid;
29 $this->name = $term->name;
30 $this->depth = $term->depth;
31 $this->sequence = $term->sequence;
32 }
33 }
34
35 /**
36 * Determines if new child is an immediate descendant or not.
37 *
38 * This function is completely dependent on the structure of the array returned
39 * by taxonomy_get_tree(). Each element in the array knows it's depth in the tree
40 * and the array is a preorder iteration of the logical tree structure. Therefore,
41 * if the parameter is more than one level deeper than $this, it should be passed
42 * to the last child of $this.
43 */
44 function add_child(&$child) {
45 if ($child->depth - $this->depth == 1) {
46 $this->children[] = $child;
47 }
48 else {
49 $last_child =&$this->children[count($this->children)-1];
50 $last_child->add_child($child);
51 }
52 }
53 }
54
55 /******************************************************************************
56 * Drupal Hooks *
57 ******************************************************************************/
58
59 /**
60 * Implementation of hook_menu().
61 */
62 function uc_catalog_menu() {
63 global $user;
64 $items = array();
65
66 $items['catalog'] = array(
67 'title' => variable_get('uc_catalog_name', t('Catalog')),
68 'page callback' => 'theme',
69 'page arguments' => array('uc_catalog_browse'),
70 'access arguments' => array('view catalog'),
71 'type' => MENU_SUGGESTED_ITEM,
72 );
73 $items['admin/store/settings/catalog'] = array(
74 'title' => 'Catalog settings',
75 'description' => 'Configure the catalog settings.',
76 'page callback' => 'uc_catalog_settings_overview',
77 'access arguments' => array('administer catalog'),
78 'type' => MENU_NORMAL_ITEM,
79 );
80 $items['admin/store/settings/catalog/overview'] = array(
81 'title' => 'Overview',
82 'access arguments' => array('administer catalog'),
83 'weight' => -10,
84 'type' => MENU_DEFAULT_LOCAL_TASK,
85 );
86 $items['admin/store/settings/catalog/edit'] = array(
87 'title' => 'Edit',
88 'page callback' => 'uc_catalog_admin_settings',
89 'access arguments' => array('administer catalog'),
90 'weight' => -5,
91 'type' => MENU_LOCAL_TASK,
92 );
93 $items['admin/store/settings/catalog/edit/catalog'] = array(
94 'title' => t('Catalog'),
95 'weight' => -10,
96 'access arguments' => array('administer catalog'),
97 'type' => MENU_DEFAULT_LOCAL_TASK,
98 );
99 $items['admin/store/settings/catalog/edit/grid'] = array(
100 'title' => 'Grid',
101 'page callback' => 'drupal_get_form',
102 'page arguments' => array('uc_catalog_grid_admin_form'),
103 'access arguments' => array('administer catalog'),
104 'weight' => -5,
105 'type' => MENU_LOCAL_TASK,
106 );
107 $items['admin/store/products/orphans'] = array(
108 'title' => 'Find orphaned products',
109 'description' => 'Find products that have not been categorized.',
110 'page callback' => 'uc_catalog_orphaned_products',
111 'access arguments' => array('administer catalog'),
112 'weight' => -4,
113 'type' => MENU_NORMAL_ITEM,
114 );
115
116 return $items;
117 }
118
119 /**
120 * Implementation of hook_perm().
121 */
122 function uc_catalog_perm() {
123 return array('view catalog', 'administer catalog');
124 }
125
126 /**
127 * Implementation of hook_enable().
128 *
129 * Add imagecache preset "uc_category".
130 */
131 function uc_catalog_enable() {
132 if (module_exists('imagecache')) {
133 $result = db_query("SELECT presetid FROM {imagecache_preset} WHERE presetname = 'uc_category'");
134 if (!db_fetch_object($result)) {
135 db_query("INSERT INTO {imagecache_preset} (presetname) VALUES ('category')");
136 $id = db_last_insert_id('imagecache_preset', 'presetid');
137 db_query("INSERT INTO {imagecache_action} (presetid, weight, data) VALUES (%d, 0, '%s')", $id, 'a:4:{s:8:"function";s:5:"scale";s:3:"fit";s:6:"inside";s:5:"width";s:2:"96";s:6:"height";s:2:"96";}');
138 cache_clear_all('imagecache:presets', 'cache');
139 }
140 }
141 }
142
143 function uc_catalog_theme() {
144 return array(
145 'uc_catalog_block_start' => array(),
146 'uc_catalog_block_end' => array(),
147 'uc_catalog_browse' => array(
148 'arguments' => array('tid' => 0),
149 ),
150 'uc_catalog_products' => array(
151 'arguments' => array('products' => NULL),
152 ),
153 'uc_catalog_product_grid' => array(
154 'arguments' => array('products' => NULL),
155 ),
156 'uc_catalog_item' => array(
157 'arguments' => array(
158 'here' => NULL,
159 'active_link' => NULL,
160 'lis' => NULL,
161 'expand' => NULL,
162 'inpath' => NULL,
163 'link' => NULL,
164 'count_children' => NULL,
165 ),
166 ),
167 );
168 }
169
170 /**
171 * Implementation of hook_nodeapi().
172 */
173 function uc_catalog_nodeapi(&$node, $op, $a3 = null, $a4 = null) {
174 static $parents = array();
175
176 if (in_array($node->type, module_invoke_all('product_types'))) {
177 switch ($op) {
178 case 'view':
179 if ($a4 == true && variable_get('uc_catalog_breadcrumb', true)) {
180 $crumbs = array();
181 if (variable_get('site_frontpage', 'node') != 'catalog') {
182 $crumbs[] = l(t('Home'), '');
183 }
184 $terms = taxonomy_node_get_terms_by_vocabulary($node, variable_get('uc_catalog_vid', 0));
185 if (count($terms)) {
186 $crumbs[] = l(variable_get('uc_catalog_name', t('Catalog')), variable_get('uc_catalog_url', 'catalog'));
187 $used_tids = array();
188 foreach ($terms as $term) {
189 if (!isset($parents[$term->tid])) {
190 $parents[$term->tid] = taxonomy_get_parents_all($term->tid);
191 }
192 //drupal_set_message('<pre>'. print_r($parents[$term->tid], true) .'</pre>');
193 foreach (array_reverse($parents[$term->tid]) as $parent) {
194 if (!in_array($parent->tid, $used_tids)) {
195 $crumbs[] = l($parent->name, uc_catalog_path($parent));
196 $used_tids[] = $parent->tid;
197 }
198 }
199 }
200 }
201 drupal_set_breadcrumb($crumbs);
202 }
203 break;
204 }
205 }
206 }
207
208 /**
209 * Implementation of hook_taxonomy().
210 */
211 function uc_catalog_taxonomy($op, $type, $object = null) {
212 switch ($type) {
213 case 'vocabulary':
214 if ($object['vid'] == variable_get('uc_catalog_vid', 0)) {
215 switch ($op) {
216 case 'delete':
217 variable_del('uc_catalog_vid');
218 variable_del('uc_catalog_name');
219 variable_del('uc_catalog_description');
220 break;
221 case 'update':
222 variable_set('uc_catalog_name', check_plain($object['name']));
223 variable_set('uc_catalog_description', filter_xss_admin($object['description']));
224 break;
225 }
226 }
227 break;
228 case 'term':
229 switch ($op) {
230 case 'insert':
231 if (module_exists('pathauto')) {
232 $category = (object) $object;
233 if ($category->name) {
234 $count = _uc_catalog_pathauto_alias($category, $op);
235 }
236 }
237 $field_name = 'image';
238 if ($file = file_save_upload($field_name)) {
239 $file->filepath = str_replace('\\', '/', $file->filepath);
240 $image_path = file_create_path();
241 $file = file_copy($file, $image_path .'/'. $file->filename);
242 if ($file) {
243 file_set_status($file, 1);
244 if (image_get_info($file->filepath)) {
245 db_query("INSERT INTO {uc_catalog_images} (fid, tid, filename, filepath, filemime, filesize) VALUES (%d, %d, '%s', '%s', '%s', %d)",
246 $file->fid, $object['tid'], $file->filename, $file->filepath, $file->filemime, $file->filesize
247 );
248 }
249 else {
250 form_set_error($field_name, t('Uploaded file is not a valid image'));
251 file_delete($file->filepath);
252 }
253 }
254 }
255 break;
256 case 'update':
257 if (module_exists('pathauto')) {
258 $category = (object) $object;
259 if ($category->name) {
260 $count = _uc_catalog_pathauto_alias($category, $op);
261 }
262 }
263 $field_name = 'image';
264 if ($object['remove']) {
265 db_query("DELETE FROM {uc_catalog_images} WHERE tid = %d", $object['tid']);
266 }
267 else if ($file = file_save_upload($field_name)) {
268 $file->filepath = str_replace('\\', '/', $file->filepath);
269 $file = file_copy($file, file_create_path() .'/'. $file->filename);
270 if ($file) {
271 file_set_status($file, 1);
272 if (image_get_info($file->filepath)) {
273 db_query("DELETE FROM {uc_catalog_images} WHERE tid = %d", $object['tid']);
274 db_query("INSERT INTO {uc_catalog_images} (fid, tid, filename, filepath, filemime, filesize) VALUES (%d, %d, '%s', '%s', '%s', %d)",
275 $file->fid, $object['tid'], $file->filename, $file->filepath, $file->filemime, $file->filesize
276 );
277 }
278 else {
279 form_set_error($field_name, t('Uploaded file is not a valid image'));
280 file_delete($file->filepath);
281 }
282 }
283 }
284 break;
285 case 'delete':
286 $category = (object) $object;
287 if ($file = db_fetch_object(db_query("SELECT fid, filepath FROM {uc_catalog_images} WHERE tid = %d", $category->tid))) {
288 file_delete($file->filepath);
289 db_query("DELETE FROM {uc_catalog_images} WHERE fid = %d", $file->fid);
290 }
291 path_set_alias(uc_catalog_path($category));
292 break;
293 }
294 break;
295 }
296 }
297
298 /**
299 * Add an image field to the catalog's taxonomy term form.
300 */
301 function uc_catalog_form_alter(&$form, &$form_state, $form_id) {
302 if ($form_id == 'taxonomy_form_term' && $form['vid']['#value'] == variable_get('uc_catalog_vid', 0)) {
303 $form['#attributes'] = array("enctype" => "multipart/form-data");
304
305 $form['name']['#weight'] = -1;
306 $form['image']['#weight'] = 0;
307 $form['image']['image'] = array('#type' => 'file',
308 '#title' => t('Image'),
309 '#weight' => 0,
310 );
311 $image = uc_catalog_image_load($form['tid']['#value']);
312 if ($image) {
313 if (module_exists('imagecache')) {
314 $image_display = theme('imagecache', 'uc_category', $image->filepath);
315 }
316 else {
317 $image_display = theme('image', $image->filename, t('Term image'));
318 $form['image']['image']['#description'] = t('The image will not be resized. Consider installing <a href="@url">Image cache</a>.', array('@url' => url('http://drupal.org/project/imagecache')));
319 }
320 $form['image']['remove'] = array('#type' => 'checkbox',
321 '#title' => t('Remove category image: !image', array('!image' => $image_display)),
322 '#weight' => 1,
323 );
324 }
325
326 $form['description']['#description'] = t('A description of the term. Displayed to customers at the top of catalog pages.');
327 }
328 }
329
330 /**
331 * Implementation of hook_link_alter().
332 *
333 * Rewrite taxonomy term links to point to the catalog.
334 */
335 function uc_catalog_link_alter(&$node, &$links) {
336 // Link back to the catalog and not the taxonomy term page
337 foreach ($links AS $module => $link) {
338 if (strstr($module, 'taxonomy_term')) {
339 $tid = explode('_', $module);
340 $tid = $tid[2];
341 $term = taxonomy_get_term($tid);
342 if ($term->vid == variable_get('uc_catalog_vid', 0)) {
343 $links[$module]['href'] = uc_catalog_path($term);
344 }
345 }
346 }
347 }
348
349 /**
350 * Displays a menu for navigating the "Product Catalog"
351 */
352 function uc_catalog_block($op = 'list', $delta = 0, $edit = array()) {
353 switch ($op) {
354 case 'list':
355 $blocks[0]['info'] = variable_get('uc_catalog_name', t('Catalog'));
356 return $blocks;
357
358 case 'view':
359 $block = array();
360 if (user_access('view catalog')) {
361 switch ($delta) {
362 case 0:
363 // Get the vocabulary tree information.
364 $vid = variable_get('uc_catalog_vid', 0);
365 $tree = taxonomy_get_tree($vid);
366 // Then convert it into an actual tree structure.
367 $seq = 0;
368 $menu_tree = new uc_treeNode();
369 $level = array();
370 $curr_depth = -1;
371 foreach ($tree as $knot) {
372 $seq++;
373 $knot->sequence = $seq;
374 $knothole = new uc_treeNode($knot);
375 // Begin at the root of the tree and find the proper place.
376 $menu_tree->add_child($knothole);
377 }
378 // Now, create a structured menu, separate from Drupal's menu.
379 $content .= theme("uc_catalog_block_start");
380 foreach ($menu_tree->children as $branch) {
381 list($inpath, $html) = _uc_catalog_navigation($branch);
382 $content .= $html;
383 }
384 $content .= theme("uc_catalog_block_end");
385 $subject = variable_get('uc_catalog_name', t('Catalog'));
386 if (variable_get('uc_catalog_block_title', true)) {
387 $subject = l($subject, 'catalog');
388 }
389 $block = array('subject' => $subject, 'content' => $content);
390 break;
391 }
392 }
393 return $block;
394 }
395 }
396
397 /**
398 * Theme the beginning of the catalog block.
399 *
400 * @ingroup themeable
401 * @see theme_uc_catalog_item
402 * @see theme_uc_catalog_block_end
403 */
404 function theme_uc_catalog_block_start() {
405 return '<ul class="menu">';
406 }
407
408 /**
409 * Theme the end of the catalog block.
410 *
411 * @ingroup themeable
412 * @see theme_uc_catalog_block_start
413 * @see theme_uc_catalog_item
414 */
415 function theme_uc_catalog_block_end() {
416 return '</ul>';
417 }
418
419 /******************************************************************************
420 * Module Hooks *
421 ******************************************************************************/
422
423 function uc_catalog_pathauto($op) {
424 switch ($op) {
425 case 'settings':
426 $settings = array();
427 $settings['module'] = 'uc_catalog';
428 $settings['token_type'] = 'taxonomy';
429 $settings['groupheader'] = t('Catalog path settings');
430 $settings['patterndescr'] = t('Pattern for catalog pages');
431 $settings['patterndefault'] = t('catalog/[catpath-raw]');
432 $patterns = token_get_list('taxonomy');
433 foreach ($patterns as $type => $pattern_set) {
434 if ($type != 'global') {
435 foreach ($pattern_set as $pattern => $description) {
436 $settings['placeholders']['['. $pattern .']'] = $description;
437 }
438 }
439 }
440 $settings['supportsfeeds'] = '0/feed';
441 $settings['bulkname'] = t('Bulk generate aliases for catalog pages that are not aliased');
442 $settings['bulkdescr'] = t('Generate aliases for all existing catalog pages which do not already have aliases. Note: Bulk Update may not complete on large or slow sites. See the README.txt for more information.');
443
444 return (object) $settings;
445 }
446 }
447
448 /**
449 * Generate aliases for all categories without aliases
450 *
451 */
452 function uc_catalog_pathauto_bulkupdate() {
453 $catalog_vid = variable_get('uc_catalog_vid', 0);
454 $query = "SELECT tid, vid, name, src, dst FROM {term_data} LEFT JOIN {url_alias} ON src LIKE CONCAT('catalog/', tid, '/%%') WHERE src IS NULL AND vid = %d";
455 $result = db_query_range($query, $catalog_vid, 0, variable_get('pathauto_max_bulk_update', 50));
456
457 $count = 0;
458 $placeholders = array();
459 while ($category = db_fetch_object($result)) {
460 $count = _uc_catalog_pathauto_alias($category, 'bulkupdate') + $count;
461 }
462
463 drupal_set_message(format_plural($count,
464 "Bulk generation of terms completed, @count alias generated.",
465 "Bulk generation of terms completed, @count aliases generated."));
466 }
467
468 /**
469 *
470 * Function to create aliases for taxonomy objects
471 *
472 * @param object $category a taxonomy object
473 *
474 */
475 function _uc_catalog_pathauto_alias($category, $op) {
476 _pathauto_include();
477 $count = 0;
478
479 $placeholders = pathauto_get_placeholders('taxonomy', $category);
480
481 $src = uc_catalog_path($category);
482 if ($alias = pathauto_create_alias('uc_catalog', $op, $placeholders, $src, $category->vid)) {
483 $count++;
484 }
485 return $count;
486 }
487
488 function uc_catalog_path_alias_types() {
489 return array('catalog/' => t('catalog pages'));
490 }
491
492 /******************************************************************************
493 * Übercart Hooks *
494 ******************************************************************************/
495
496 /**
497 * Implementation of Übercart's hook_store_status().
498 *
499 * Provide status information about the "Product Catalog" and products not listed in the catalog.
500 */
501 function uc_catalog_store_status() {
502 $statuses = array();
503 $cat_id = variable_get('uc_catalog_vid', 0);
504 $catalog = taxonomy_vocabulary_load($cat_id);
505 if ($catalog) {
506 $statuses[] = array('status' => 'ok', 'title' => t('Catalog vocabulary'),
507 'desc' => t('Vocabulary !name has been identified as the !uber catalog.', array('!name' => l($catalog->name, 'admin/content/taxonomy/'. $catalog->vid), '!uber' => '&Uuml;bercart'))
508 );
509
510 $excluded = 0;
511 $result = db_query("SELECT DISTINCT * FROM {node} AS n LEFT JOIN {term_node} AS tn ON n.nid = tn.nid LEFT JOIN {vocabulary_node_types} AS vnt ON n.type = vnt.type WHERE n.type <> 'image' AND tn.tid IS NULL AND vnt.vid = %d", $cat_id);
512 if (db_fetch_object($result)) {
513 $statuses[] = array('status' => 'warning', 'title' => t('Unlisted products'),
514 'desc' => format_plural($excluded, 'There is @count product not listed in the catalog.', 'There are @count products not listed in the catalog.')
515 . t(' Products are listed by assigning a category from the Product Catalog vocabulary to them. ')
516 . l(t('Find orphaned products here.'), 'admin/store/products/orphans'),
517 );
518 }
519 }
520 else {
521 $statuses[] = array('status' => 'error',
522 'title' => t('Catalog vocabulary'),
523 'desc' => t('No vocabulary has been recognized as the Ubercart catalog. Choose one on <a href="!admin_catalog">this page</a> or click <a href="!admin_vocab">here</a> to create one first.', array('!admin_catalog' => url('admin/store/catalog/setup'), '!admin_vocab' => url('admin/content/taxonomy'))),
524 );
525 }
526 return $statuses;
527 }
528
529 /**
530 * Implementation of Übercart's hook_product_class.
531 *
532 * Add and remove product node types to the catalog vocabulary as they are
533 * created and deleted.
534 */
535 function uc_catalog_product_class($type, $op) {
536 $vid = variable_get('uc_catalog_vid', 0);
537 switch ($op) {
538 case 'insert':
539 if ($vid) {
540 db_query("INSERT INTO {vocabulary_node_types} (vid, type) VALUES (%d, '%s')", $vid, $type);
541 }
542 break;
543 case 'delete':
544 if ($vid) {
545 db_query("DELETE FROM {vocabulary_node_types} WHERE vid = %d AND type = '%s'", $vid, $type);
546 }
547 break;
548 }
549 }
550
551 /******************************************************************************
552 * Menu Callbacks *
553 ******************************************************************************/
554
555 /**
556 * Display an overview of all catalog settings.
557 */
558 function uc_catalog_settings_overview() {
559 $sections = array();
560
561 $sections[] = array(
562 'edit' => 'admin/store/settings/catalog/edit',
563 'title' => t('Catalog settings'),
564 'items' => array(
565 t('The catalog vocabulary id is !vid.',
566 array('!vid' => variable_get('uc_catalog_vid', 0))),
567 t('The base URL pointing to the catalog is !url.',
568 array('!url' => 'catalog')),
569 variable_get('uc_catalog_breadcrumb', true) ?
570 t('The catalog breadcrumb will be shown.') :
571 t('The catalog breadcrumb will not be shown.'),
572 variable_get('uc_catalog_breadcrumb_nodecount', false) ?
573 t('The number of nodes in a category will be shown in the catalog breadcrumb.') :
574 t('The number of nodes in a category will not be shown in the catalog breadcrumb.'),
575 format_plural(variable_get('uc_catalog_category_columns', 3), 'Subcategories will be displayed in @count column.', 'Subcategories will be displayed in @count columns.'),
576 ),
577 );
578 $sections[] = array(
579 'edit' => 'admin/store/settings/catalog/edit/grid',
580 'title' => t('Products grid settings'),
581 'items' => array(
582 variable_get('uc_catalog_grid_display', false) ?
583 t('The catalog will be displayed on a grid.') :
584 t('The catalog will be displayed on a table list.'),
585 format_plural(variable_get('uc_catalog_grid_display_width', 3), 'The grid will be displayed in @count column.', 'The grid will be displayed in @count columns.'),
586 variable_get('uc_catalog_grid_display_title', true) ?
587 t('Every cell on the grid will display the Product Title.') :
588 t('Cells on the grid will not display Product Titles.'),
589 variable_get('uc_catalog_grid_display_model', true) ?
590 t('Every cell on the grid will display the Product SKU.') :
591 t('Cells on the grid will not display Product SKU.'),
592 variable_get('uc_catalog_grid_display_sell_price', true) ?
593 t('Every cell on the grid will display the Product Selling Price.') :
594 t('Cells on the grid will not display Product Selling Prices.'),
595 variable_get('uc_catalog_grid_display_add_to_cart', true) ?
596 t('Every cell on the grid will display the Add to Cart button.') :
597 t('Cells on the grid will not display Add to Cart buttons.'),
598 variable_get('uc_catalog_grid_display_attributes', true) ?
599 t('Every cell on the grid will display Product Attibutes.') :
600 t('Cells on the grid will not display Product Attibutes.'),
601 ),
602 );
603 $sections[] = array(
604 'edit' => 'admin/store/settings/catalog/edit/blocks',
605 'title' => t('Catalog block settings'),
606 'items' => array(
607 variable_get('uc_catalog_block_nodecount', true) ?
608 t('The number of nodes in a category will be shown in the catalog block.') :
609 t('The number of nodes in a category will not be shown in the catalog block.'),
610 variable_get('uc_catalog_show_subcategories', true) ?
611 t('Subcategories with no products to display will be shown on category pages.') :
612 t('Subcategories with no products to display will not be shown on category pages.'),
613 variable_get('uc_catalog_expand_categories', false) ?
614 t('Categories in the catalog block will always be expanded.') :
615 t('Categories in the catalog block will be expanded only when selected.'),
616 ),
617 );
618
619 $output = theme('uc_settings_overview', $sections);
620 return $output;
621 }
622
623 /**
624 * Determines if the "Product Catalog" vocabulary has been set up.
625 *
626 * @see uc_catalog_admin_form
627 */
628 function uc_catalog_admin_settings() {
629 $output = '';
630 $vid = variable_get('uc_catalog_vid', null);
631 if ($vid) {
632 $catalog = taxonomy_vocabulary_load($vid);
633 $output .= t('Vocabulary %name is set as the product catalog. ', array('%name' => $catalog->name));
634 //$output .= l(t('Build a term hierarchy for products there.'), 'admin/content/taxonomy/'. $vid .'/add/term');
635 //drupal_set_message($output);
636 $output .= l(t('View the catalog here.'), 'admin/content/taxonomy/'. $vid);
637 }
638
639 $output .= drupal_get_form('uc_catalog_admin_form');
640
641 return $output;
642 }
643
644 /**
645 * Determines if the "Product Catalog" vocabulary has been set up.
646 *
647 * @see uc_catalog_admin_form
648 */
649 function uc_catalog_grid_admin_settings() {
650 $output = '';
651
652 $output .= drupal_get_form('uc_catalog_grid_admin_form');
653
654 return $output;
655 }
656
657 /**
658 * Determines if the "Product Catalog" vocabulary has been set up.
659 *
660 * @see uc_catalog_admin_form
661 */
662 function uc_catalog_blocks_admin_settings() {
663 $output = '';
664
665 $output .= drupal_get_form('uc_catalog_blocks_admin_form');
666
667 return $output;
668 }
669
670 /**
671 * Load catalog information for display.
672 *
673 * Retrieve image, product, and subcategory information for the current term id.
674 *
675 * @param $tid
676 * Taxonomy term id.
677 * @return
678 * A catalog object containing all the information needed to display a catalog page.
679 */
680 function uc_catalog_get_page($tid) {
681 $catalog = new stdClass();
682 $vid = variable_get('uc_catalog_vid', 0);
683
684 if ($tid) {
685 $term = taxonomy_get_term($tid);
686 $name = $term->name;
687 $description = $term->description;
688 }
689 else {
690 $tid = 0;
691 $name = variable_get('uc_catalog_name', t('Catalog'));
692 $description = variable_get('uc_catalog_description', '');
693 }
694 $catalog->tid = $tid;
695 $catalog->vid = $vid;
696 $catalog->name = $name;
697 $catalog->description = $description;
698 $catalog->children = array();
699 if ($file = uc_catalog_image_load($catalog->tid)) {
700 if (module_exists('imagecache')) {
701 $file_path = file_create_url(file_directory_path() .'/imagecache/uc_category/'. $file->filepath);
702 }
703 else {
704 $file_path = $file->filepath;
705 }
706 $info = image_get_info($file_path);
707 $catalog->image = $info;
708 $catalog->image['filepath'] = $file->filepath;
709 }
710 $types = module_invoke_all('product_types');
711 $links = array();
712 $child_list = array();
713 $children = taxonomy_get_children($tid, $vid);
714 foreach ($children as $child) {
715 $n = 0;
716 foreach ($types as $type) {
717 $n += taxonomy_term_count_nodes($child->tid, $type);
718 }
719 $child->nodes = $n;
720 // Display child category's image.
721 if (module_exists('imagecache') && $file = uc_catalog_image_load($child->tid)) {
722 $imagecache_path = file_create_url(file_directory_path() .'/imagecache/uc_category/'. $file->filepath);
723 $info = image_get_info($imagecache_path);
724 $child->image = $info;
725 $child->image['filepath'] = $file->filepath;
726 }
727 // Display list of child category's children categories.
728 // If more than $max_gc_display, show "More..." link to child.
729 $grandchildren_list = taxonomy_get_children($child->tid, $vid);
730 $child->children = $grandchildren_list;
731 $catalog->children[] = $child;
732 }
733 //$node_resource = taxonomy_select_nodes(array($tid));
734 return $catalog;
735 }
736
737 /**
738 * Display a formatted catalog page.
739 *
740 * If the category has products in it, display them in a TAPIr table. Subcategories
741 * are linked along the top of the page. If it does not have products, display
742 * subcategories in a grid with their images and subcategories.
743 *
744 * @param $tid
745 * Catalog term id from URL.
746 * @return
747 * Formatted HTML of the catalog page.
748 */
749 function theme_uc_catalog_browse($tid = 0) {
750 drupal_add_css(drupal_get_path('module', 'uc_catalog') .'/uc_catalog.css');
751
752 $output = '';
753 $catalog = uc_catalog_get_page((int)$tid);
754 drupal_set_title(check_plain($catalog->name));
755 drupal_set_breadcrumb(uc_catalog_set_breadcrumb($catalog->tid));
756 $types = module_invoke_all('product_types');
757 $links = array();
758 $child_list = array();
759 foreach ($catalog->children as $child) {
760 if ($child->nodes) {
761 $links[] = array('title' => $child->name . (variable_get('uc_catalog_breadcrumb_nodecount', false) ? ' ('. $child->nodes .')' : ''), 'href' => uc_catalog_path($child),
762 'attributes' => array('rel' => 'tag'),
763 );
764 }
765 if ($child->image) {
766 $image = '<div>';
767 if (module_exists('imagecache')) {
768 $image .= l(theme('imagecache', 'uc_category', $child->image['filepath']), uc_catalog_path($child), array('html' => TRUE));
769 }
770 else {
771 $image .= l(theme('image', $child->image['filepath']), uc_catalog_path($child), array('html' => TRUE));
772 }
773 $image .= '</div>';
774 }
775 else {
776 $image = '<div></div>';
777 }
778 $grandchildren = array();
779 $j = 0;
780 $max_gc_display = 3;
781 foreach ($child->children as $i => $grandchild) {
782 if ($j > $max_gc_display) {
783 break;
784 }
785 $g_child_nodes = 0;
786 foreach ($types as $type) {
787 $g_child_nodes += taxonomy_term_count_nodes($grandchild->tid, $type);
788 }
789 if ($g_child_nodes) {
790 $grandchildren[$i] = l($grandchild->name, uc_catalog_path($grandchild), array('class' => 'subcategory'));
791 $j++;
792 }
793 }
794 //$grandchildren = array_slice($grandchildren, 0, intval(count($grandchildren) / 2) + 1, true);
795 if ($j > $max_gc_display) {
796 array_push($grandchildren, l(t('More...'), uc_catalog_path($child), array('class' => 'subcategory')));
797 }
798 if ($child->nodes) {
799 $cell_link = $image .'<strong>'. l($child->name, uc_catalog_path($child)) .'</strong>';
800 if (variable_get('uc_catalog_show_subcategories', true)) {
801 $cell_link .= "<br/><span>". implode(', ', $grandchildren) ."</span>\n";
802 }
803 $child_list[] = $cell_link;
804 }
805 }
806 if ($catalog->image) {
807 $output .= theme('imagecache', 'uc_thumbnail', $catalog->image['filepath'], $catalog->name, $catalog->name, array('class' => 'category'));
808 }
809 $header = array();
810 $tbl_columns = uc_product_table_header();
811 foreach ($tbl_columns as $column) {
812 $header[] = $column['cell'];
813 }
814 $order = substr(tablesort_sql($header), 10);
815 if (empty($_REQUEST['order'])) {
816 $order = 'p.ordering, n.title, n.nid';
817 }
818 $product_types = module_invoke_all('product_types');
819
820 $sql = "SELECT DISTINCT(n.nid), n.sticky, n.title, n.created, p.model, p.ordering
821 FROM {node} n
822 INNER JOIN {term_node} tn ON n.nid = tn.nid
823 INNER JOIN {uc_products} AS p ON n.vid = p.vid
824 WHERE tn.tid = %d AND n.status = 1
825 AND n.type IN (". db_placeholders($product_types, 'varchar') .")
826 ORDER BY ". $order;
827 $sql_count = '';
828 switch ($GLOBALS['db_type']) {
829 case 'mysql':
830 case 'mysqli':
831 $sql_count = "SELECT COUNT(DISTINCT(n.nid))
832 FROM {node} n
833 INNER JOIN {term_node} tn ON n.nid = tn.nid
834 INNER JOIN {uc_products} AS p ON n.nid = p.nid
835 WHERE tn.tid = %d
836 AND n.status = 1
837 AND n.type IN (". db_placeholders($product_types, 'varchar') .")";
838 break;
839 case 'pgsql':
840 $sql_count = "SELECT DISTINCT n.nid, COUNT(*)
841 FROM {node} n
842 INNER JOIN {term_node} tn ON n.nid = tn.nid
843 INNER JOIN {uc_products} AS p ON n.nid = p.nid
844 WHERE tn.tid = %d
845 AND n.status = 1
846 AND n.type IN (". db_placeholders($product_types) .")
847 GROUP BY n.nid";
848 break;
849 }
850
851 $sql = db_rewrite_sql($sql);
852 $sql_count = db_rewrite_sql($sql_count);
853 $sql_args = array($catalog->tid);
854 foreach ($product_types as $type) {
855 $sql_args[] = $type;
856 }
857 $catalog->products = array();
858 $result = pager_query($sql, variable_get('uc_product_nodes_per_page', 12), 0, $sql_count, $sql_args);
859 while ($node = db_fetch_object($result)) {
860 $catalog->products[] = $node->nid;
861 }
862 if (count($catalog->products)) {
863 if (count($links)) {
864 $output .= theme('links', $links, array('class' => 'links inline')) ."<br />\n";
865 }
866 $output .= $catalog->description;
867 $output .= theme('uc_catalog_products', $catalog->products);
868 $output .= theme('pager');
869 }
870 else {
871 // Display table of child categories similar to an osCommerce site's front page.
872 $columns = variable_get('uc_catalog_category_columns', 3);
873 $cat_rows = array();
874 $row = array();
875 $i = 1;
876 foreach ($child_list as $cell) {
877 $row[] = array('data' => $cell, 'class' => 'category');
878 if ($i % $columns == 0) {
879 $cat_rows[] = $row;
880 $row = array();
881 }
882 $i++;
883 }
884 if (count($row) > 0 && count($row) < $columns) {
885 if (count($cat_rows) >= 1) {
886 $row = array_merge($row, array_fill(count($row), $columns - count($row), array('data' => '&nbsp;', 'class' => 'category')));
887 }
888 $cat_rows[] = $row;
889 }
890 $output .= $catalog->description;
891 $output .= theme('table', array(), $cat_rows, array('class' => 'category'));
892 }
893
894 return $output;
895 }
896
897 /**
898 * Display a formatted list of products.
899 *
900 * @param $products
901 * An array of product nids.
902 * @return
903 * A TAPIr table.
904 * @ingroup themeable
905 */
906 function theme_uc_catalog_products($products) {
907 if (!$products) {
908 $output .= '<div class="no-products">'. t('No products are available in this category.') .'</div>';
909 return $output;
910 }
911 else {
912 if (variable_get('uc_catalog_grid_display', false)) {
913 return theme('uc_catalog_product_grid', $products);
914 }
915 else {
916 $table_args = array('nids' => $products);
917 return tapir_get_table('uc_product_table', $table_args);
918 }
919 }
920 }
921
922 function theme_uc_catalog_product_grid($products) {
923 $product_table = '<div class="category-grid-products"><table>';
924 $count = 0;
925 foreach ($products as $nid) {
926 $product = node_load($nid);
927
928 if ($count == 0) {
929 $product_table .= "<tr>";
930 }
931 else if ($count % variable_get('uc_catalog_grid_display_width', 3) == 0) {
932 $product_table .= "</tr><tr>";
933 }
934
935 $titlelink = l($product->title, "node/$nid", array('html' => TRUE));
936 if (module_exists('imagecache') && isset($product->field_image_cache) && file_exists($product->field_image_cache[0]['filepath'])) {
937 $imagelink = l(theme('imagecache', 'product_list', $product->field_image_cache[0]['filepath']), "node/$nid", array('html' => TRUE));
938 }
939 else {
940 $imagelink = '';
941 }
942
943 $product_table .= '<td>';
944 if (variable_get('uc_catalog_grid_display_title', TRUE)) {
945 $product_table .= '<span class="catalog_grid_title">'. $titlelink .'</span>';
946 }
947 if (variable_get('uc_catalog_grid_display_model', TRUE)) {
948 $product_table .= '<span class="catalog_grid_ref">'. $product->model .'</span>';
949 }
950 $product_table .= '<span class="catalog_grid_image">'. $imagelink .'</span>';
951 if (variable_get('uc_catalog_grid_display_sell_price', TRUE)) {
952 $product_table .= '<span class="catalog_grid_sell_price">'. uc_currency_format($product->sell_price) .'</span>';
953 }
954 if (variable_get('uc_catalog_grid_display_add_to_cart', TRUE)) {
955 if (variable_get('uc_catalog_grid_display_attributes', TRUE)) {
956 $product_table .= theme('uc_product_add_to_cart', $product);
957 }
958 else {
959 $product_table .= drupal_get_form('uc_catalog_buy_it_now_form_'. $product->nid, $product);
960 }
961 }
962 $product_table .= '</td>';
963
964 $count++;
965 }
966 $product_table .= "</tr></table></div>";
967 return $product_table;
968 }
969
970 /******************************************************************************
971 * Module Functions *
972 ******************************************************************************/
973
974 /**
975 * Catalog settings form.
976 *
977 * Configure the display of the catalog breadcrumb.
978 *
979 * @ingroup forms
980 */
981 function uc_catalog_admin_form() {
982 $form = array();
983
984 $vocabs = array();
985 $vocabularies = taxonomy_get_vocabularies();
986 foreach ($vocabularies as $vid => $vocabulary) {
987 $vocabs[$vid] = $vocabulary->name;
988 }
989
990 // JTR - catalog-top-level sub-textfield
991 $form['catalog-top-level'] = array('#type' => 'fieldset',
992 '#title' => t('Catalog top level'),
993 '#collapsible' => true,
994 '#collapsed' => false,
995 '#attributes' => array('class' => 'catalog-top-level'),
996 );
997 $form['catalog-top-level']['uc_catalog_vid'] = array('#type' => 'select',
998 '#title' => t('Catalog vocabulary'),
999 '#description' => t("The taxonomy vocabulary that will be considered the product catalog."),
1000 '#default_value' => variable_get('uc_catalog_vid', 0),
1001 '#options' => $vocabs,
1002 );
1003 $form['catalog-top-level']['uc_catalog_breadcrumb'] = array('#type' => 'checkbox',
1004 '#title' => t('Display the catalog breadcrumb'),
1005 '#default_value' => variable_get('uc_catalog_breadcrumb', true),
1006 );
1007 $form['catalog-top-level']['uc_catalog_breadcrumb_nodecount'] = array('#type' => 'checkbox',
1008 '#title' => t('Display node counts in the catalog breadcrumb'),
1009 '#default_value' => variable_get('uc_catalog_breadcrumb_nodecount', false),
1010 );
1011 $form['catalog-top-level']['uc_catalog_show_subcategories'] = array('#type' => 'checkbox',
1012 '#title' => t('Display subcategories in the catalog view'),
1013 '#default_value' => variable_get('uc_catalog_show_subcategories', true),
1014 );
1015 $form['catalog-top-level']['uc_catalog_category_columns'] = array('#type' => 'select',
1016 '#title' => t('Number of columns in the grid of categories'),
1017 '#default_value' => variable_get('uc_catalog_category_columns', 3),
1018 '#options' => drupal_map_assoc(uc_range(1, 5)),
1019 );
1020
1021 $form['block-display'] = array('#type' => 'fieldset',
1022 '#title' => t('Catalog block settings'),
1023 '#collapsible' => true,
1024 '#collapsed' => false,
1025 '#attributes' => array('class' => 'block-display'),
1026 );
1027 $form['block-display']['uc_catalog_block_title'] = array('#type' => 'checkbox',
1028 '#title' => t('Block title links to top level catalog page'),
1029 '#default_value' => variable_get('uc_catalog_block_title', true),
1030 '#description' => t("If selected, the block title is a link, otherwise plain text."),
1031 );
1032 $form['block-display']['uc_catalog_expand_categories'] = array('#type' => 'checkbox',
1033 '#title' => t('Always expand categories in the catalog block'),
1034 '#default_value' => variable_get('uc_catalog_expand_categories', false),
1035 );
1036 $form['block-display']['uc_catalog_block_nodecount'] = array('#type' => 'checkbox',
1037 '#title' => t('Display node counts in the catalog block'),
1038 '#default_value' => variable_get('uc_catalog_block_nodecount', true),
1039 );
1040
1041 $form['catalog-products-list'] = array('#type' => 'fieldset',
1042 '#title' => t('Catalog products list'),
1043 '#collapsible' => true,
1044 '#collapsed' => false,
1045 '#attributes' => array('class' => 'catalog-products-list'),
1046 );
1047 $form['catalog-products-list']['uc_product_nodes_per_page'] = array(
1048 '#type' => 'textfield',
1049 '#title' => t('Product nodes per page'),
1050 '#default_value' => variable_get('uc_product_nodes_per_page', 12),
1051 '#description' => t("Determines how many products will be listed on every catalog category. Notice that if you are using grid display it must be multiple of the grid width value, otherwise the last row will not match."),
1052 '#size' => 2,
1053 );
1054
1055 return system_settings_form($form);
1056 }
1057
1058 /**
1059 * Catalog settings form.
1060 *
1061 * Configure the display of the catalog breadcrumb.
1062 *
1063 * @ingroup forms
1064 */
1065 function uc_catalog_grid_admin_form() {
1066 $form = array();
1067
1068 // JTR - elements for products grid view administration
1069 $form['catalog-grid'] = array('#type' => 'fieldset',
1070 '#title' => t('Products grid display'),
1071 '#collapsible' => true,
1072 '#collapsed' => false,
1073 '#weight' => -3,
1074 '#attributes' => array('class' => 'catalog-grid'),
1075 );
1076 $form['catalog-grid']['uc_catalog_grid_display'] = array(
1077 '#type' => 'checkbox',
1078 '#title' => t('Display products in grid'),
1079 '#default_value' => variable_get('uc_catalog_grid_display', false),
1080 '#description' => t("Select it if you want the products to be displayed on a grid instead of a list table."),
1081 );
1082 $form['catalog-grid']['uc_catalog_grid_display_width'] = array(
1083 '#type' => 'textfield',
1084 '#title' => t('Width of grid'),
1085 '#default_value' => variable_get('uc_catalog_grid_display_width', 3),
1086 '#size' => 2,
1087 );
1088 $form['catalog-grid']['uc_catalog_grid_display_title'] = array(
1089 '#type' => 'checkbox',
1090 '#title' => t('Display product title'),
1091 '#default_value' => variable_get('uc_catalog_grid_display_title', true),
1092 );
1093 $form['catalog-grid']['uc_catalog_grid_display_model'] = array(
1094 '#type' => 'checkbox',
1095 '#title' => t('Display product model (SKU)'),
1096 '#default_value' => variable_get('uc_catalog_grid_display_model', true),
1097 );
1098 $form['catalog-grid']['uc_catalog_grid_display_sell_price'] = array(
1099 '#type' => 'checkbox',
1100 '#title' => t('Display product sell price'),
1101 '#default_value' => variable_get('uc_catalog_grid_display_sell_price', true),
1102 );
1103 $form['catalog-grid']['uc_catalog_grid_display_add_to_cart'] = array(
1104 '#type' => 'checkbox',
1105 '#title' => t('Display product add To cart'),
1106 '#default_value' => variable_get('uc_catalog_grid_display_add_to_cart', true),
1107 );