Tableless catalog

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

I'm wondering how many people would like to see a tableless catalog. I started by using a teaser view for product listings, instead of the standard table view, and I just finished working getting the categories and subcategories displaying without tables.

I've looked through a few of the live sites, and I've noticed some people doing the same. My code isn't quite module worthy yet, but if there is an interest in moving towards a tableless design, I would be willing to polish my code up and make a patch.

Posts: 3959
Joined: 08/07/2007
AdministratorHead Code Monkey - I eat bugs.

Mike, just wanted to say that I really like what you're doing with your catalog there. Smiling

I was also surprised/happy to see your Holiday LED site featured at the top of Robert Douglass's website. I guess you did some training w/ him through Lullabot? It's definitely paying off. Cool

Posts: 41
Joined: 09/07/2007

Mike,

My site will use a tableless catalog. I'm just getting started on the categories and subcategories pages. I would be very interested in seeing what custom code you have created for these views.

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

Here is my current code. There are a few items I still need to work on.
1. Sorting products by the list order
2. Add a pager feature
3. Testing with other catalog structures besides mine. I currently have a Main Category(LEDs for the pro), Sub category(C6 Lights), and a product list page.

There are probably some other things that you will notice. I would like to break this into smaller theme sections, to make it easier to override a small section.

<?php
function holiday4_uc_catalog_browse($tid = 0){
 
drupal_add_css(drupal_get_path('module', 'uc_catalog') .'/uc_catalog.css');
 
//clear $output
 
$output = '';
  if (
$catalog->image){
   
$output .= theme('imagecache', 'thumbnail', $catalog->image['filepath'], $catalog->name, $catalog->name, array('class' => 'category'));
  }
 
//load the catalog
 
$catalog = uc_catalog_get_page($tid);
  if(
$catalog->name == 'Catalog') {
   
drupal_set_title('The LED Christmas Light Experts');
  }
  else {
   
drupal_set_title($catalog->name);
   
$output .= '<h1 class="uc_catalog_category_title">'.$catalog->name.'</h1>';
  }

 
$output .= $catalog->description;
 
$output .= '<div class="uc_catalog_clear_both"></div>';

 
drupal_set_breadcrumb(uc_catalog_set_breadcrumb($catalog->tid));

 
$types = array_keys(uc_product_node_info());
 
$links = array();
 
$child_list = array();

 
//Categories with subcategories(needs more logic)
 
$cat_val = 0;
  foreach(
$catalog->children as $category) {
    if(
$category->nodes >=1) {
      if(
$category->children != NULL) {
       
$output .= '<div class="uc_catalog_category '.(($cat_val % 2) ? 'uc_catalog_category_even' : 'uc_catalog_category_odd').'">'."\n";
       
$output .= '  <h2 class="uc_catalog_heading">'."\n";
       
$output .= '    '.l($category->name, taxonomy_term_path($category))."\n";
       
$output .= '  </h2>'."\n";
       
$output .= '  '.l( theme('imagecache', 'main_category', $category->image['filepath'], $category->name, $category->name, array('class' => 'uc_catalog_category_img')), taxonomy_term_path($category) , array(), NULL, NULL, FALSE, TRUE);
       
$output .= '  <div class="uc_catalog_main_catagory_description">'.$category->short_description.'</div>'."\n";

       
$sub_val = 0;
        foreach(
$category->children as $subcategory) {
         
$subcategory->image = db_fetch_array(db_query('SELECT f.filepath FROM term_node t INNER JOIN files f ON t.nid = f.nid WHERE f.filename NOT LIKE "" AND t.tid = %d LIMIT 1', $subcategory->tid));
          if(
$subcategory->image) {
            if(
$sub_val >=3) { break;}
           
$output .= '<div class="uc_catalog_subcategory '.(($sub_val % 2) ? 'uc_catalog_even' : 'uc_catalog_odd').'">'."\n";
           
$output .= '    '.l(theme('imagecache', 'thumbnail', $subcategory->image['filepath'], $subcategory->name, $subcategory->name, array('class' => 'uc_subcategory_img')), taxonomy_term_path($subcategory) , array(), NULL, NULL, FALSE, TRUE) ;
           
$output .= '  <div class="uc_catalog_subheading">'."\n";
           
$output .= '    '.l($subcategory->name, taxonomy_term_path($subcategory))."\n";
           
$output .= '  </div>'."\n";
           
$output .= '</div>'."\n";
           
$sub_val++;
          }
        }
       
$output .= '</div>'."\n";
       
$cat_val++;
      }
      else {
       
$output .= '<div class="'.(($cat_val % 2) ? 'uc_catalog_subcategory_even' : 'uc_catalog_subcategory_odd').'">'."\n";
       
$output .= '  <div class="uc_catalog_subcategory_link">'."\n";
       
$output .= '    '.l($category->name, taxonomy_term_path($category))."\n";
       
$output .= '  </div>'."\n";
       
$output .= '  '.l(theme('imagecache', 'sub_category', $category->image['filepath'], $category->name, $category->name, array('class' => 'uc_catalog_subcategory_img')), taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE)."\n";
       
$output .= '  <div class="uc_catalog_subcategory_description">'."\n";
       
$output .= '    '.$category->short_description."\n";
       
$output .= '  </div>'."\n";
       
$output .= '  <div class="uc_catalog_teaser_more">'.l('more', taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE).'</div>'."\n";
       
$output .= '</div>'."\n";
       
$cat_val++;
      }
    }
  }

 
$product_query = taxonomy_select_nodes(array($catalog->tid));
 
$val = 0;
 
$product_types = array_keys(uc_product_node_info());
  while(
$products = db_fetch_object($product_query)) {

    if(
$product = node_load($products->nid)) {
     
$stripe = ($val % 2) ? 'uc_catalog_even' : 'uc_catalog_odd';
     
$output .= '<div class="uc_category_product '.$stripe.'">'.node_view($product, TRUE).'</div>'."\n";
     
$val++;
    }
  }
  return
$output;
}
?>

Let me know what you think. I'd love to improve upon this.

Posts: 1920
Joined: 08/07/2007
AdministratoreLiTe!

Might want to display the catalog image after you've loaded it. Otherwise, it doesn't exist yet.

And this is a very picky detail, but your $stripe class is backwards. $val % 2 = 1 when $val is odd.

Other than that, it looks like everything should work.

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

Thanks for the tips.

Posts: 41
Joined: 09/07/2007

Mike,

Thanks so much for this. It's really helping me understand the uc_catalog_browse function better. I might actually be able to use it now instead of views. I asked you about this before, did you find out what your work around for getting the Term ID out of your catalog URLs was?

I'll post my uc_catalog_browse function when I finish it in the next few days.

Posts: 41
Joined: 09/07/2007

Where do your set the $category->short_description at? I only have $category->description in my /admin/content/taxonomy/edit/term/ term settings.

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

That was a custom field I've added with hook_form_alter.

<?php
function hook_alter($form_id, &$form){
  if (
$form_id == 'taxonomy_form_term' && $form['vid']['#value'] == variable_get('uc_catalog_vid', 0)
||
$form_id == 'taxonomy_form_vocabulary' && $form['vid']['#value'] == variable_get('uc_catalog_vid',
0 )){
     
$form['image']['remove'] = array('#type' => 'checkbox',
       
'#title' => t('Remove category image: !image', array('!image' => $image_display)),
       
'#weigt' => 1,
      );
    }
  }
}
?>

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

As far as the URL's go, For the time being I've manually created URL aliases. I don't have too many categories right now, so it's not too bad, but I would like to do a ubercart/pathauto module at some point.

Posts: 41
Joined: 09/07/2007

Sorry for so many questions, but where do I place the hook_alter() function and does it need to be called somewhere? Also, it looks like this hook_alter is for the category image and not added a "short_description" field to the form.

Posts: 41
Joined: 09/07/2007

I finished my theme_uc_catalog_browse function. I found a module, Taxonomy Enhancer http://drupal.org/project/taxonomy_enhancer, that I am using instead of doing the hook_form_alter. It allows me to add a "Basic Description" field to my category terms. I'm just doing a database query to get the new field, but it works for what I need. I added some logic to determine how many blocks to fit into a row and also a little to determine if I want to print the category description above or below the category blocks. I don't have a live site up yet, you can see what it looks like here, http://www.xikar.com/redesign/Final_Site/Cigar_cutter_family_page.pdf and here, http://www.xikar.com/redesign/Final_Site/Xi1_model_page.pdf.

<?php
function xikar_uc_catalog_browse($tid = 0){
 
drupal_add_css(drupal_get_path('module', 'uc_catalog') .'/uc_catalog.css');
 
//clear $output
 
$output = '';
  if (
$catalog->image){
   
$output .= theme('imagecache', 'thumbnail', $catalog->image['filepath'], $catalog->name, $catalog->name, array('class' => 'category'));
  }
 
//load the catalog
 
$catalog = uc_catalog_get_page($tid);
  if(
$catalog->name == 'Catalog') {
   
drupal_set_title('The LED Christmas Light Experts');
  }
  else {
   
drupal_set_title($catalog->name);
  }

 
drupal_set_breadcrumb(uc_catalog_set_breadcrumb($catalog->tid));

 
$types = array_keys(uc_product_node_info());
 
$links = array();
 
$child_list = array();

 
//Categories with subcategories
 
$new_row = 0;
 
$count_row = 0;
 
$bottom_description = 0;
 
$top_description = 1;
  foreach(
$catalog->children as $category) {
    if(
$category->nodes >=1) {
      if(
$category->children != NULL) { // product category catalog pages
         
if($top_description == 1){
           
$output .= '<div id="products_description">' . $catalog->description . '</div>'; // category description text at top of page
       
}
        if(
$new_row == 1){
           
//do nothing
       
}else{ // open row div
           
$output .= '<div class="uc_catalog_subcategory_row">';
        }
       
$output .= '<div id="uc_catalog_subcategory_container">';
       
$output .= '<div class="uc_catalog_subcategory_link">'; // category image
       
$output .= l(theme('imagecache', 'product_list', $category->image['filepath'], $category->name, $category->name, array('class' => 'uc_catalog_subcategory_img')), taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE) . '<br />' . '</div>';
       
$output .= '<div class="uc_catalog_subcategory_text">'; // category text and links
       
$output .= l($category->name, taxonomy_term_path($category)) . '<br />';
       
$output .= '<ul>';
       
$sub_val = 0;
        foreach(
$category->children as $subcategory) {
            if(
$sub_val >=6) { break;} // only show this many subcategories
           
$output .= '<li>' . l($subcategory->name, taxonomy_term_path($subcategory))."</li>\n";
           
$sub_val++;
        }
       
$output .= '</ul>';
       
$output .='<div class="uc_catalog_subcategory_see_more">' . l("See All $category->name", taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE) . '</div></div>';
       
$output .= '<div class="clear"></div>';
       
$output .= '</div>';
        if(
$new_row == 1){ // after second block is printed, close the row div
             
$output .= '</div><br /><div class="clear"></div>';
            
$new_row = 0;
           
$count_row = 0;
        }else{
           
$new_row++;
           
$count_row = 1;
        }
       
$top_description = 0;
      }
     
// **************************
     
else { // product family catalog pages
       
if($new_row == 1){
           
//do nothing
       
}else{ // open row div
           
$output .= '<div class="uc_catalog_subcategory_row">';
        }
       
$output .= '<div id="uc_catalog_subcategory_container">';
       
$output .= '<div class="uc_catalog_subcategory_link">'; // category image
       
$output .= l(theme('imagecache', 'product_list', $category->image['filepath'], $category->name, $category->name, array('class' => 'uc_catalog_subcategory_img')), taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE) . '<br />' . '</div>';
       
$output .= '<div class="uc_catalog_subcategory_text">'; // category text and links
       
$output .= l($category->name, taxonomy_term_path($category)) . '<br />' . db_result(db_query('SELECT value FROM taxonomy_enhancer_data WHERE tid = %d', $category->tid)) . '<div class="uc_catalog_subcategory_see_more">' . l('See All Models', taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE) . '</div></div>';
       
$output .= '<div class="clear"></div>';
       
$output .= '</div>';
        if(
$new_row == 1){ // after second block is printed, close the row div
             
$output .= '</div><br /><div class="clear"></div>';
            
$new_row = 0;
           
$count_row = 0;
        }else{
           
$new_row++;
           
$count_row = 1;
        }
       
$bottom_description = 1;
      }
    }
  }
  if (
$count_row == 1){ // if there is only 1 block in the row, close the row div
     
$output .= '</div><br /><div class="clear"></div>';
  }
 
$product_query = taxonomy_select_nodes(array($catalog->tid));
 
$val = 0;
 
$product_types = array_keys(uc_product_node_info());
  while(
$products = db_fetch_object($product_query)) {
    if(
$product = node_load($products->nid)) {
     
$output .= node_view($product, TRUE)."\n";
     
$bottom_description = 1;
    }
  }
 
// if statement to print description at bottom
 
if($bottom_description == 1){
 
$output .= '<div id="products_description">' . $catalog->description . '</div>'; // category description text at bottom of page
 
}
 
$output .= $result;
  return
$output;
}
?>

Here's most of the CSS for this code:

/* Product Family Catalog Page Styles */
.uc_catalog_subcategory_row{
margin:1em 0 1em 0;
}
#uc_catalog_subcategory_container{
border:#fafafa solid 1px;
margin-right:1em;
width:16em;
float:left;
}
#uc_catalog_subcategory_container:hover{
border:#00539b solid 1px;
}
.uc_catalog_subcategory_link img{
width:100%; /* Allows image to scale with font size */
}
.uc_catalog_subcategory_link{
width:4.7em; /* Allows image to scale with font size */
float:left;
}
.uc_catalog_subcategory_text{
float:right;
padding-left:.5em;
width:10.25em;
height:7.8em;
}
.uc_catalog_subcategory_text ul{
margin:.5em 0 0 .25em;
font-size:.75em;
}
.uc_catalog_subcategory_text li{
margin:.25em 0 .25em 1em;
list-style-type:disc;
list-style-image: url('images/blue_bullet.gif');
}
.uc_catalog_subcategory_see_more{
text-align:right;
}
#products_description{
clear:both;
}
#products_description p{
margin:1em 0 0 0;
}
.clear{
clear:both;
}

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

Can't wait to see it live.

You might want to change this

  //load the catalog
  $catalog = uc_catalog_get_page($tid);
  if($catalog->name == 'Catalog') {
    drupal_set_title('The LED Christmas Light Experts');   <------------
  }
  else {
    drupal_set_title($catalog->name);
  }

Posts: 41
Joined: 09/07/2007

Oops, I really never paid any attention to that part because my Catalog is called Products, so it didn't matter. I just removed the whole if statement.

Thanks again for your help on this Mike!

Posts: 13
Joined: 03/14/2008

This really helps!

For those like me who were wondering what to do with this. This code goes to your template.php

Rename:

function xikar_uc_catalog_browse($tid = 0){

to:
function mythemename_uc_catalog_browse($tid = 0){

To not get an error, if you dont use taxonomy_enhancer module, comment these lines

$output .= '<div id="uc_catalog_subcategory_container">';
$output .= '<div class="uc_catalog_subcategory_link">'; // category image
$output .= l(theme('imagecache', 'product_list', $category->image['filepath'], $category->name, $category->name, array('class' => 'uc_catalog_subcategory_img')), taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE) . '<br />' . '</div>';
$output .= '<div class="uc_catalog_subcategory_text">'; // category text and links
$output .= l($category->name, taxonomy_term_path($category)) . '<br />' . db_result(db_query('SELECT value FROM taxonomy_enhancer_data WHERE tid = %d', $category->tid)) . '<div class="uc_catalog_subcategory_see_more">' . l('See All Models', taxonomy_term_path($category), array(), NULL, NULL, FALSE, TRUE) . '</div></div>';
$output .= '<div class="clear"></div>';
$output .= '</div>';

Posts: 13
Joined: 03/14/2008

Mike mentioned two features to do:
1. Sorting products by the list order
2. Add a pager feature

Could someone help with it? I dont think I can, unfortunately. Especially pager is important. This function seems to ignore the Product nodes per page setting in /admin/store/settings/catalog/edit

Thanks a lot!

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

The sorting is very easy. The pager shouldn't be too difficult. Are you using the code posted above?

Posts: 13
Joined: 03/14/2008

Yes, just with few modifications mentioned above (commenting the Taxonomy Enhancer stuff). I would very much appreciate any help with paging, I have no clue how/where to do this.

Sorting would be very nice too. But paging is a crucial function.

Thanks Mike.

Posts: 83
Joined: 08/07/2007
Bug FinderGetting busy with the Ubercode.

do you have a url where I can see the current site?

Posts: 13
Joined: 03/14/2008

In PM

Posts: 13
Joined: 03/14/2008

I've been trying to display products in catalog different way than Grid or table. I managed to override uc_catalog_products in template.php function like this.

<?php
function zen_uc_catalog_products($products) {
  if (!
$products) {
   
$output .= '<div class="no-products">'. t('No products are available in this category.') .'</div>';
    return
$output;
  }
  else {
    if (
variable_get('uc_catalog_grid_display', false)) {
      return
theme('uc_catalog_product_grid', $products);
    }
    else {
         
//$table_args = array('nids' => $products, 'attributes' => array('class' => 'category-products'));
          //return tapir_get_table('uc_product_table', $table_args);
         
         
foreach($products as $product) {
             
$node = node_load($product);
             
$output .= node_view($node, TRUE)."\n";             
          } 

          return
$output;     
    }
  }
}
?>

Rename zen_uc_catalog_products to yourthemename_uc_catalog_products. It replaces the table view with teasers, which can be modified by contemplates. This way I am able to display all CCK fields the way I want.

Hope it helps.