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.
/* 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);
}