Author Topic: Parent Product Attributes and Child Products Hack v1.1  (Read 9523 times)

gtibbetts

  • Beginner
  • *
  • Posts: 26
Parent Product Attributes and Child Products Hack v1.1
« on: October 26, 2010, 11:44:34 am »
I have been developing a print site with Joomla 1.5 and Virtue Mart 1.1.5. When you display child products in a drop down box, each attribute is displayed with the child product.  I needed to find distinct values for each attribute and display a select box for each attribute.  So, I wrote a Hack. As the user selects options from each drop down I use javascript and php to get the product id and the price. I have a few lines of code to write and the hack will be done.

Lets say you create a parent product, then create several attributes for that product.  This hack searches product id's based on the selection of an unlimited number of attribute values.

Once I am done with the hack I will post it here.  For now I haven't hacked the VM admin, but plan to soon.

gtibbetts

  • Beginner
  • *
  • Posts: 26
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #1 on: October 31, 2010, 02:40:17 am »
I completed the first step of this hack.  The idea behind this hack is instead of displaying each child product in one list box with their attributes and price; we display a select box for each attribute name filled with that attributes values.  As the user selects attributes the next select box appears.  When the last attribute is selected the price is displayed. This can handle an unlimited number of attributes.

Currently I am using this hack in combination with the Converted Custom Attribute Hack found here http://forum.virtuemart.net/index.php?topic=39666.0 on Joomla 1.5 and Virtue Mart 1.1.5.  There is a possibility on VM 1.1.5 and Joomla 1.5 you may have to use some functions from VM 1.1.5 when using the Custom attribute hack.  The file is named ps_product_attribute.php.

When installing the Parent Product Attributes and Child Products Hack v1.1 download /administrator/components/com_virtuemart/classes/ps_product_attribute.php.  Comment out function list_attribute_drop( $product_id, $cls_suffix ). Copy and paste the new list_attribute_drop function and the clean function below.  In the near future I plan to add a check box or radio button in the admin to add this functionality to virtue mart.  I am currently using this Hack without AJAX.

Here are the two functions.

Code: [Select]
/* Hacked Child products to Display each attribute of the
* main product in a select box. The function gets all distinct
* attribute values. Based the selected Index of the select boxes,
* queries the database, and then displays a price and creates a hidden field
* for the product id.
*
* October 10th, 2010
* Hacked by Greg S. Tibbetts MBA, MPM greg@aagthosting.com
*/

/**
* Lists all child/sister products of the given product
*
* @param int $product_id
* @return string HTML code with Items, attributes & price
*/
function list_attribute_drop( $product_id, $cls_suffix ) {
     global $VM_LANG, $CURRENCY_DISPLAY, $mm_action_url, $sess ;
     require_once (CLASSPATH . 'ps_product.php') ;
     $ps_product = new ps_product( ) ;
     $Itemid = $sess->getShopItemid() ;
     $category_id = vmGet( $_REQUEST, 'category_id', "" ) ;
     $db = new ps_DB( ) ;
     $db_item = new ps_DB( ) ; 
     $additionalOption = $VM_LANG->_( 'PHPSHOP_PLEASE_SEL_ITEM' );
     $defaultValue = 0;
     $count = 0;
     $value = '';
     $selected = '';
     $variable = '';
     $var = '';
     error_reporting(0);
     $tpl = new $GLOBALS['VM_THEMECLASS']( ) ;
     $tpl->set( "cls_suffix", $cls_suffix ) ;
     $tpl->set( "product_id", $product_id ) ;
     // Set Advanced Attributes
     $tpl->set( "advanced_attribute", $this->list_advanced_attribute( $product_id, $db->f( "product_id" ) ) ) ;
     $tpl->set( "custom_attribute", $this->list_custom_attribute( $product_id, $db->f( "product_id" ) ) ) ;

     // Get list of the Product attributes for the drop down menus. One attribute per drop down.
     $q = "SELECT distinct a.attribute_name
          FROM jos_vm_product p, jos_vm_product_attribute_sku a
          WHERE a.product_id='" . $product_id . "' AND p.product_parent_id = a.product_id
          AND p.product_publish = 'Y' ORDER BY a.attribute_list ASC";

     $db->query($q);

     if( $db->num_rows() > 0 ){
          $flypage = $ps_product->get_flypage( $product_id ) ;
          $html = "<input type=\"hidden\" name=\"product_id\" value=\"$product_id\">\n" ;

          $rows = $db->num_rows();
          while($db->next_record()) {
               $count++;
               $attribute_name = $db->f( "attribute_name" );

               // get attribute values and product id's if $count = 1  
       if (($count == 1) || (isset($_GET[$att_name])) && $_GET[$att_name] != $additionalOption){
                    $html .= "<label for='" . $db->f( "attribute_name" ) . "_field'>" . $db->f( "attribute_name" ) . "</label>:\n" ;
                    // get distinct attribute values for an attribute name
                    $q = "SELECT DISTINCT a.attribute_value
 FROM #__{vm}_product p, #__{vm}_product_attribute a
          WHERE p.product_parent_id='" . $product_id . "' AND a.product_id = p.product_id
  AND a.attribute_name = '" . $db->f( "attribute_name" ) . "' AND p.product_publish='Y' order by a.attribute_id, a.attribute_value ASC";

$db_sku = new ps_DB( ) ;      
$db_sku->setQuery( $q ) ;
$db_sku->query();

if ($db_sku->num_rows() > 0){
     $resultBuffer = array();
     $c = 0;
     while($db_sku->next_record()){
          $resultBuffer[$c++] = str_replace("&","/",$db_sku->f( "attribute_value" ));
     }
     $r = false;
                     if (is_array($resultBuffer)){
                          foreach($resultBuffer as $n=>$v){
                               if (is_array( $resultBuffer[$n] )){
                                    $r = isNumArray( $resultBuffer[$n] );
                                    if ($r==false)
         break;
                               }
       else
                                    if (!is_numeric($v)){
                                         $r=false;
                                         break;
                                    }
    else
                                         $r=true;
                          }
                          if ($r = true){
       if ($resultBuffer[$c] < $resultBuffer[0]){
            $i = 0;
    foreach (asort($resultBuffer, SORT_NUMERIC) as $value)
                                        $resultBuffer[$i++] = $value;
}
  }
                    }
}
if (isset($_GET[$attribute_name])){
             $aname = str_replace("/","&",trim($this->clean($_GET[$attribute_name], 64)));
     $rows = $db->num_rows();
     $c = 0;

                     // query db for product id's
    $q = "SELECT DISTINCT a.product_id
          FROM jos_vm_product p, jos_vm_product_attribute a
                           WHERE p.product_parent_id='".$product_id."' AND a.product_id = p.product_id
   AND a.attribute_value LIKE '".$aname."' AND p.product_publish='Y'";

    $db_item->setQuery($q);
    $db_item->query();
 
     // create multidimensional array of
     // product id's for each attribute value selected
    if ($db_item->num_rows() > 0){
         $i = 0;
        while($db_item->next_record()){
              $idarray[$count-1][$i++] = $db_item->f( "product_id" );
      $idarray[$count-1][$i-1];
}
}
}
if (($count == $rows) && isset($_GET[$attribute_name])){
// Get a list of product id's for the last attribute select box
// Get attribute values for the last select box
     $id = array();
     for($checked_item = 0; $checked_item < count($idarray[0]); $checked_item++){
                  $occurrence = 1;
                  for($compared_array = 1; $compared_array < count($idarray); $compared_array++){          
                       for($compared_item = 0; $compared_item < count($idarray[$compared_array]); $compared_item++){
                            if($idarray[0][$checked_item] == $idarray[$compared_array][$compared_item]){
                                 $occurrence++;
if($occurrence == count($idarray)){
                                     $id[] = $idarray[0][$checked_item];
                                 }
                            }
                       }
                  }
             }
}
        if ($count == 1)
     $url = 'http://imagews.com/index.php?option=com_virtuemart&page=shop.product_details&flypage=' . $flypage . '&product_id=' . $product_id;
if (isset($_GET[$att_name])){
     $variable = "&" . $att_name . "=" . $_GET[$att_name];
     $url .= $variable;
}
$att_name = $db->f( "attribute_name" );        

        // Create the select box
$attributes = "&" . $attribute_name . "='+document.addtocart." . $attribute_name . ".options[document.addtocart." . $attribute_name . ".selectedIndex].value";
$html .= '<select id="' . $attribute_name . '" name="' . $attribute_name . '" onchange="window.location.href=\'' . $url . $attributes . '">';

// Is there an additional option?
        if (isset($additionalOption)){
            // Yes, but is it the default option?
            if ($defaultValue == $additionalOption)
                // Show the additional option as selected
                $html .= "<option value='" . $additionalOption . "' selected>" . $additionalOption . "</option>\n";
            else
                 // Just show the additional option
                 $html .= "<option value='" . $additionalOption . "'>" . $additionalOption . "</option>\n";
       }
       // check for a selected attribute name
       if (isset($_GET[$attribute_name])){
    $defaultValue = $_GET[$attribute_name];
            foreach ($resultBuffer as $result)
                   if ($result == $defaultValue)
                         $html .= "<option value='" . $result . "' selected>" . $result . "</option>";
                   else
                         $html .= "<option value='" . $result . "'>" . $result . "</option>";
        }  // end if attribute name
        else {
           // No defaultValue
           foreach ($resultBuffer as $result)
                 $html .= "<option value='" . $result . "'>" . $result . "</option>\n";
        }
        $html .= "</select><br>\n";
 
// Get and display price and hidden field for child product id
if (isset($id)){
     if (!empty($id[0])){
$html .= '<input type="hidden" name="prod_id[]" value="'.$id[0].'" />\n';
if( $_SESSION['auth']['show_prices'] && _SHOW_PRICES ) {
     $price = $ps_product->get_adjusted_attribute_price( $id[0] ) ;
     $price["product_price"] = $GLOBALS['CURRENCY']->convert( $price["product_price"], $price["product_currency"] ) ;
     if( $_SESSION["auth"]["show_price_including_tax"] == 1 ) {
          $tax_rate = 1 + $ps_product->get_product_taxrate( $pid ) ;
                          $price['product_price'] *= $tax_rate ;
     }
     $html .= '<p>Price: <strong>' . $CURRENCY_DISPLAY->getFullValue( $price["product_price"] ) . '</strong></p>';
}
}
else   
             $html .= '<p>There are no products with that attribute combination. Please modify your selection.</p>';
      }    
     }  
    } // end loop
   } // end if num rows
   else {
        $html = "<input type=\"hidden\" name=\"product_id\" value=\"$product_id\" />\n" ;
$html .= "<input type=\"hidden\" name=\"prod_id[]\" value=\"$product_id\" />\n" ;
   }
   $tpl->set( "drop_down", $html ) ;  
   $html = $tpl->fetch( 'product_details/includes/addtocart_drop.tpl.php' ) ;
   return array( $html , "drop" ) ;      
}

// clean $_GET variables and database values
// Hacked by Greg S. Tibbetts MBA, MPM greg@aagthosting.com
function clean($input, $maxlength){
     $input = substr($input, 0, $maxlength);
     $input = EscapeShellCmd($input);
     return ($input);
}

gtibbetts

  • Beginner
  • *
  • Posts: 26
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #2 on: November 03, 2010, 07:38:35 am »
This is Greg again.  As for now I have no knows bugs in this hack.  I already debugged it.  There is one known error.  When I coded it it worked, but it threw an invalid error when calling the sort() function in a foreach loop.

Here is the code.  

Code: [Select]
foreach (asort($resultBuffer, SORT_NUMERIC) as $value)
     $resultBuffer[$i++] = $value;

I also added the error_reporting(0) function so the error does not display on the page.

Things that I would like to hack further are as follows.

1) A check box or radio button in the admin to give the option to display child products with this function instead of the current list_attribute_drop function.

If anyone has any questions about this hack or would like help implementing the hack please contact me.

Email: greg@aagthosting.com
Greg S. Tibbetts MBA, MPM

gtibbetts

  • Beginner
  • *
  • Posts: 26
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #3 on: December 21, 2010, 02:28:57 am »
When posting to this thread please post all inquiries in this forum.  You can send me an email, but lets put his stuff in the forum for future users.

bruce2000

  • Beginner
  • *
  • Posts: 1
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #4 on: February 17, 2011, 15:21:27 pm »
 :)
The child items drop down list works!vm 1.1.7 j1.5.22
But there is a little thing, a extra "\n" come up,when it end up the attributes before the price field.
please look at the screen capture. We try to remove one of \n in your code, no luck.
Can you give a hint

RaiWbl

  • Beginner
  • *
  • Posts: 2
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #5 on: March 09, 2011, 14:28:25 pm »
That's what I was looking for. Nice

but i have some problems with the hack. After installing he shows me only one dropdown menu with the 1. attribute. But attribute 2 and 3 are not on the product detail page.

I using joomla 1.5.22 and virtuemart 1.1.7

everestrus

  • Beginner
  • *
  • Posts: 1
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #6 on: June 21, 2011, 17:06:56 pm »
I am using Joomla 1.5.22 and virtuemart 1.1.8
and made the changes in ps_product_attribute.php and it's seems to be working but it always showing me "There are no products with that attribute combination. Please modify your selection"
What I am doing wrong?
Thanks


palomino5

  • Beginner
  • *
  • Posts: 2
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #7 on: January 12, 2012, 16:36:54 pm »
Hi!
I'm trying to use your code of "Parent Product Attributes and Child Products Hack v1.1".

I've found a bug. If you are using products with multiple attributes it's working very well, but if there are some products with only one attribute this new code doesn't work well (it appears "There are no products with that attribute combination").

Have you seen it before?
Did you solve it?

Thank you very much.

Best regards.

gtibbetts

  • Beginner
  • *
  • Posts: 26
Re: Parent Product Attributes and Child Products Hack v1.1
« Reply #8 on: January 13, 2012, 20:59:45 pm »
When the hack says there are no products with that attribute selection it means that particular selection had no products that met all your criteria.  Maybe in the near future we can modify the code to deal with this.  When I wrote the hack I thought of a way to do this,but it was not necessary for the scope of what I was doing.