Magento Configurable Product : Replace Options by Radio button

I am working to replace the options of configurable products by radio buttons.

There are interesting custom modules like:

But It is not really what I want.

My expected behavior is the following : the second attribute values group are updated when the user click on the first attribute ie When the end user click on a format, I load (via Ajax) the available dimension and the corresponding price.. Like the OSP module, I want to use the simple product price.

app/design/frontend/default/<…>/template/catalog/product/view/type/options/configurable.phtml:

<script type="text/javascript">
//<![CDATA[
  var doAjaxCall=function(Forms) {
                var reloadurl = '/configurable/ajax/update';
                new Ajax.Request(reloadurl, {
                        method: 'post',
                        parameters: Forms,
                        onComplete: function(transport) {
				//console.log("response=" + transport.responseText);
				//$('ajaxdiv').update(transport.responseText);
				jQuery("#ajaxdiv").html(transport.responseText);
			}
		});
	};
  // Update Price
  var updatePrice=function(prix) {
                var priceFormat = <?php echo $this->helper('tax')->getPriceFormat(); ?>;
                var newPrice=formatCurrency(prix, priceFormat);
                jQuery('span .price:lt(2)').each(function() {
			// console.log( jQuery(this).html() );
                        jQuery(this).html(newPrice);
		});
        };
//]]>
</script>
<?php 
$session = Mage::getSingleton('checkout/session');
$product=$this->getProduct();
$quote=$session->getQuote();
$selected=array();
if($quote->hasItems())
{
	foreach ($quote->getAllItems() as $item) 
	{
		if($item->getHasChildren()) {
		    foreach($item->getChildren() as $child) {
			array_push($selected,$product->getIdBySku($child->getSku()));
		    }
		} else {
		    array_push($selected,$product->getIdBySku($item->getSku()));
		}
	}	
}
echo ($this->getHtml($selected)); 
?>

I generate the HTML of the <input> tags into my Block Module.

An extract of my Block/Configurable.html module:

# more Configurable/Catalog/Block/Product/View/Type/Configurable.php 
<?php

class MyStockPhoto_Configurable_Catalog_Block_Product_View_Type_Configurable extends Mage_Catalog_Block_Product_View_Type_Configurable
{

	// Debug
	private function mydebug(&$var)
	{
		ob_start();
		var_dump($var);
		$result=ob_get_clean();
		return $result;
	}


	/**
	 * Validating of super product option value
	 *
	 * @param array $attributeId
	 * @param array $value
	 * @param array $options
	 * @return boolean
	 */
	protected function _validateAttributeValue($attributeId, &$value, &$options)
	{
		if(isset($options[$attributeId][$value['value_index']])) {
			return true;
		}

		return false;
	}

	/**
	 * Validation of super product option
	 *
	 * @param array $info
	 * @return boolean
	 */
	protected function _validateAttributeInfo(&$info)
	{
		if(count($info['options']) > 0) {
			return true;
		}
		return false;
	}

	/**
	 * Calculation real price
	 *
	 * @param float $price
	 * @param bool $isPercent
	 * @return mixed
	 */
	protected function _preparePrice($price, $isPercent = false)
	{
		if ($isPercent && !empty($price)) {
			$price = $this->getProduct()->getFinalPrice() * $price / 100;
		}

		return $this->_registerJsPrice($this->_convertPrice($price, true));
	}

	/**
	 * Calculation price before special price
	 *
	 * @param float $price
	 * @param bool $isPercent
	 * @return mixed
	 */
	protected function _prepareOldPrice($price, $isPercent = false)
	{
		if ($isPercent && !empty($price)) {
			$price = $this->getProduct()->getPrice() * $price / 100;
		}

		return $this->_registerJsPrice($this->_convertPrice($price, true));
	}

	/**
	 * Replace ',' on '.' for js
	 *
	 * @param float $price
	 * @return string
	 */
	protected function _registerJsPrice($price)
	{
		return str_replace(',', '.', $price);
	}

	/**
	 * Convert price from default currency to current currency
	 *
	 * @param float $price
	 * @param boolean $round
	 * @return float
	 */
	protected function _convertPrice($price, $round = false)
	{
		if (empty($price)) {
			return 0;
		}

		$price = $this->getCurrentStore()->convertPrice($price);
		if ($round) {
			$price = $this->getCurrentStore()->roundPrice($price);
		}

		return $price;
	}

	protected function find_price($myoptions,$sattr1,$sval1,$sattr2,$sval2)
	{
		//Mage::log("search A:$sattr1 V:$sval1 A:$sattr2 V:$sval2");
		foreach($myoptions as $id => $attributes)
		{
			if(isset($attributes[$sattr1][$sval1]) && isset($attributes[$sattr2][$sval2]))
				return $attributes[$sattr1][$sval1];
		}
	}

	// selected = Product ID Array of selected product
	public function getHtml($selected=null)
	{
		$_product= $this->getProduct();
		$baseCurrencyCode = Mage::app()->getStore()->getBaseCurrencyCode();
		$currentCurrencyCode = Mage::app()->getStore()->getCurrentCurrencyCode();
		$configs = $this->getRegularConfigNew();
		// Update Session
		$session = Mage::getSingleton('core/session');
		// Write configs into session for controllers use
		$session->setData('configs', $configs);
		$selected_uniq=array_unique($selected,SORT_NUMERIC);
		$selected_attr=array();
		foreach($selected_uniq as $id)
		{
			$product=Mage::getModel('catalog/product');
			$product->load($id);
			if($product->getId())
			{
				foreach($this->getAllowAttributes() as $attribute)
				{
					$productAttribute   = $attribute->getProductAttribute();
					$productAttributeId = $productAttribute->getId();
					$attributeValue     = $product->getData($productAttribute->getAttributeCode());
					$productAttribute   = $attribute->getProductAttribute();
					$productAttributeId = $productAttribute->getId();
					$attributeValue     = $product->getData($productAttribute->getAttributeCode());
					$selected_attr[$productAttributeId]= $attributeValue;
				}		
			}
		}
		$html="";
		if($_product->isSaleable() && count($this->getAllowAttributes()))
		{
			$prev_key="";
			$prev_value="";
			$j=0;
			$price=0;
			$url="/configurable/ajax/update";
			$html .= "<dl>";
			foreach ($configs['attributes'] as $key => $_attribute)
			{
				$i=0;
				if($j>0) $html .= '<div id="ajaxdiv">';
				$html .= '<dt><label class="required"><em>*</em>&nbsp;' . $_attribute['label'] . '</label></dt>';
				$html .= '<div class="input-box">';
				foreach($_attribute['options'] as $value)
				{
					$maxattr=count($_attribute['options']);
					$html .= '<dd';
					if($i == ($maxattr-1)) $html .= ' class="last"';
					$html .= '>';
					$html .= '<label class="label-radio-configurable" id="attribute'. $key . '" price="' . (string)((float)$value['price'] + (float) Mage::helpe
r('directory')->currencyConvert($_product->getPrice(), $baseCurrencyCode, $currentCurrencyCode)) . '">';
					$html .= '<input type="radio" name="super_attribute[' . $key . ']" id="attribute' . $key . '" class="validate-custom-configurable" value="' 
. $value['id'] . '"';
					if(isset($selected_attr[$key]) && $value['id'] == $selected_attr[$key]) 
					{
						$html .= ' checked';
						if($j==0) { $prev_key=$key;$prev_value=$value['id'];}
					}
					if($j>0) $price=$this->find_price($configs['options_price'],$prev_key,$prev_value,$key,$value['id']);
					if($j>0 && $price != 0) $html .= ' onclick="updatePrice(\'' . sprintf("%.2f",$price) .'\');" price="' . sprintf("%.2f",$price) . ' ' . $curr
entCurrencyCode .'"';
					if($j==0) $html .= ' onclick="doAjaxCall(Form.serialize(this.form));"';
                                        // Default Selection if not selected
                                        //if(($maxattr==1 && $i == 0)||(!isset($selected_attr[$key]) && $i==0 && $j==0)) $html .= ' checked ';
					$html .= '/>';
					$html .= ' ' . $value['label'];
					if($j>0 && $price != 0) $html .= ' (' . sprintf("%.2f", $price) . ' ' . $currentCurrencyCode . ')';
					$html .= '</label>';
					$html .= '</dd>';
					$i++;
				}
				if($j>0) $html .= '</div>';
				$html .= '</div>';
				$j++;
			}
			$html .= '</dl>';
		}
		return $html;
	}

	public function getJsonConfigNew()
	{
	$attributes = array();
	$options    = array();
	$options_price = array();
	$store      = $this->getCurrentStore();
	$taxHelper  = Mage::helper('tax');
	$currentProduct = $this->getProduct();

	$preconfiguredFlag = $currentProduct->hasPreconfiguredValues();
	if ($preconfiguredFlag) {
		$preconfiguredValues = $currentProduct->getPreconfiguredValues();
		$defaultValues       = array();
	}

	foreach ($this->getAllowProducts() as $product) {
		$productId  = $product->getId();
		foreach ($this->getAllowAttributes() as $attribute) {
			$productAttribute   = $attribute->getProductAttribute();
			$productAttributeId = $productAttribute->getId();
			$attributeValue     = $product->getData($productAttribute->getAttributeCode());
			if (!isset($options[$productAttributeId])) {
				$options[$productAttributeId] = array();
			}

			if (!isset($options[$productAttributeId][$attributeValue])) {
				$options[$productAttributeId][$attributeValue] = array();
			}
			$options[$productAttributeId][$attributeValue][] = $productId;

			if (!isset($options_price[$productAttributeId])) {
				$options_price[$productAttributeId] = array();
			}

			if (!isset($options_price[$productAttributeId][$attributeValue])) {
				$options_price[$productAttributeId][$attributeValue] = array();
			}
			$options_price[$productAttributeId][$attributeValue] = $product->getFinalPrice();
		}
	}

	$this->_resPrices = array(
			$this->_preparePrice($currentProduct->getFinalPrice())
			);

	foreach ($this->getAllowAttributes() as $attribute) {
		$productAttribute = $attribute->getProductAttribute();
		$attributeId = $productAttribute->getId();
		$info = array(
				'id'        => $productAttribute->getId(),
				'code'      => $productAttribute->getAttributeCode(),
				'label'     => $attribute->getLabel(),
				'options'   => array()
			     );

		$optionPrices = array();
		$prices = $attribute->getPrices();
		if (is_array($prices)) {
			foreach ($prices as $value) {
				if(!$this->_validateAttributeValue($attributeId, $value, $options)) {
					continue;
				}
				$currentProduct->setConfigurablePrice(
						$this->_preparePrice($value['pricing_value'], $value['is_percent'])
						);
				$currentProduct->setParentId(true);
				Mage::dispatchEvent(
						'catalog_product_type_configurable_price',
						array('product' => $currentProduct)
						);
				$configurablePrice = $currentProduct->getConfigurablePrice();

				if (isset($options[$attributeId][$value['value_index']])) {
					$productsIndex = $options[$attributeId][$value['value_index']];
				} else {
					$productsIndex = array();
				}

				$info['options'][] = array(
						'id'    => $value['value_index'],
						'label' => $value['label'],
						'price' => $this->_preparePrice($value['pricing_value'], $value['is_percent']),
						'products'   => isset($options[$attributeId][$value['value_index']]) ? $options[$attributeId][$value['value_index']] : array(),
						);
				$optionPrices[] = $configurablePrice;
			}
		}
		/**
		 * Prepare formated values for options choose
		 */
		foreach ($optionPrices as $optionPrice) {
			foreach ($optionPrices as $additional) {
				$this->_preparePrice(abs($additional-$optionPrice));
			}
		}
		if($this->_validateAttributeInfo($info)) {
			$attributes[$attributeId] = $info;
		}
		// Add attribute default value (if set)
		if ($preconfiguredFlag) {
			$configValue = $preconfiguredValues->getData('super_attribute/' . $attributeId);
			if ($configValue) {
				$defaultValues[$attributeId] = $configValue;
			}
		}
	}

	$taxCalculation = Mage::getSingleton('tax/calculation');
	if (!$taxCalculation->getCustomer() && Mage::registry('current_customer')) {
		$taxCalculation->setCustomer(Mage::registry('current_customer'));
	}

	$_request = $taxCalculation->getRateRequest(false, false, false);
	$_request->setProductClassId($currentProduct->getTaxClassId());
	$defaultTax = $taxCalculation->getRate($_request);

	$_request = $taxCalculation->getRateRequest();
	$_request->setProductClassId($currentProduct->getTaxClassId());
	$currentTax = $taxCalculation->getRate($_request);

	$taxConfig = array(
			'includeTax'        => $taxHelper->priceIncludesTax(),
			'showIncludeTax'    => $taxHelper->displayPriceIncludingTax(),
			'showBothPrices'    => $taxHelper->displayBothPrices(),
			'defaultTax'        => $defaultTax,
			'currentTax'        => $currentTax,
			'inclTaxTitle'      => Mage::helper('catalog')->__('Incl. Tax')
			);

	$config = array(
			'attributes'        => $attributes,
			'template'          => str_replace('%s', '#{price}', $store->getCurrentCurrency()->getOutputFormat()),
			'basePrice'         => $this->_registerJsPrice($this->_convertPrice($currentProduct->getFinalPrice())),
			'oldPrice'          => $this->_registerJsPrice($this->_convertPrice($currentProduct->getPrice())),
			'productId'         => $currentProduct->getId(),
			'chooseText'        => Mage::helper('catalog')->__('Choose an Option...'),
			'taxConfig'         => $taxConfig,
			'options_price'	    => $options_price
		       );

	if ($preconfiguredFlag && !empty($defaultValues)) {
		$config['defaultValues'] = $defaultValues;
	}

	//Mage::log("config=" . $this->mydebug($config));
	return Mage::helper('core')->jsonEncode($config);
	}

	public function getRegularConfigNew()
	{
		$attributes = array();
		$options    = array();
		$options_price = array();
		$store      = $this->getCurrentStore();
		$taxHelper  = Mage::helper('tax');
		$currentProduct = $this->getProduct();

		$preconfiguredFlag = $currentProduct->hasPreconfiguredValues();
		if ($preconfiguredFlag) {
			$preconfiguredValues = $currentProduct->getPreconfiguredValues();
			$defaultValues       = array();
		}

		foreach ($this->getAllowProducts() as $product) {
			$productId  = $product->getId();
			foreach ($this->getAllowAttributes() as $attribute) {
				$productAttribute   = $attribute->getProductAttribute();
				$productAttributeId = $productAttribute->getId();
				$attributeValue     = $product->getData($productAttribute->getAttributeCode());
				if (!isset($options[$productAttributeId])) {
					$options[$productAttributeId] = array();
				}

				if (!isset($options[$productAttributeId][$attributeValue])) {
					$options[$productAttributeId][$attributeValue] = array();
				}
				$options[$productAttributeId][$attributeValue][] = $productId;

				if (!isset($options_price[$productId])) {
					$options_price[$productId] = array();
				}
				if (!isset($options_price[$productId][$productAttributeId])) {
					$options_price[$productId][$productAttributeId] = array();
				}

				if (!isset($options_price[$productId][$productAttributeId][$attributeValue])) {
					$options_price[$productId][$productAttributeId][$attributeValue] = array();
				}
				$options_price[$productId][$productAttributeId][$attributeValue] = $product->getFinalPrice();
			}
		}

		$this->_resPrices = array(
				$this->_preparePrice($currentProduct->getFinalPrice())
				);

		foreach ($this->getAllowAttributes() as $attribute) {
			$productAttribute = $attribute->getProductAttribute();
			$attributeId = $productAttribute->getId();
			$info = array(
					'id'        => $productAttribute->getId(),
					'code'      => $productAttribute->getAttributeCode(),
					'label'     => $attribute->getLabel(),
					'options'   => array()
				     );

			$optionPrices = array();
			$prices = $attribute->getPrices();
			if (is_array($prices)) {
				foreach ($prices as $value) {
					if(!$this->_validateAttributeValue($attributeId, $value, $options)) {
						continue;
					}
					$currentProduct->setConfigurablePrice(
							$this->_preparePrice($value['pricing_value'], $value['is_percent'])
							);
					$currentProduct->setParentId(true);
					Mage::dispatchEvent(
							'catalog_product_type_configurable_price',
							array('product' => $currentProduct)
							);
					$configurablePrice = $currentProduct->getConfigurablePrice();

					if (isset($options[$attributeId][$value['value_index']])) {
						$productsIndex = $options[$attributeId][$value['value_index']];
					} else {
						$productsIndex = array();
					}

					$info['options'][] = array(
							'id'    => $value['value_index'],
							'label' => $value['label'],
							'price' => $this->_preparePrice($value['pricing_value'], $value['is_percent']),
							'products'   => isset($options[$attributeId][$value['value_index']]) ? $options[$attributeId][$value['value_index']] : array
(),
							);
					$optionPrices[] = $configurablePrice;
				}
			}
			/**
			 * Prepare formated values for options choose
			 */
			foreach ($optionPrices as $optionPrice) {
				foreach ($optionPrices as $additional) {
					$this->_preparePrice(abs($additional-$optionPrice));
				}
			}
			if($this->_validateAttributeInfo($info)) {
				$attributes[$attributeId] = $info;
			}
			// Add attribute default value (if set)
			if ($preconfiguredFlag) {
				$configValue = $preconfiguredValues->getData('super_attribute/' . $attributeId);
				if ($configValue) {
					$defaultValues[$attributeId] = $configValue;
				}
			}
		}

		$taxCalculation = Mage::getSingleton('tax/calculation');
		if (!$taxCalculation->getCustomer() && Mage::registry('current_customer')) {
			$taxCalculation->setCustomer(Mage::registry('current_customer'));
		}

		$_request = $taxCalculation->getRateRequest(false, false, false);
		$_request->setProductClassId($currentProduct->getTaxClassId());
		$defaultTax = $taxCalculation->getRate($_request);

		$_request = $taxCalculation->getRateRequest();
		$_request->setProductClassId($currentProduct->getTaxClassId());
		$currentTax = $taxCalculation->getRate($_request);

		$taxConfig = array(
				'includeTax'        => $taxHelper->priceIncludesTax(),
				'showIncludeTax'    => $taxHelper->displayPriceIncludingTax(),
				'showBothPrices'    => $taxHelper->displayBothPrices(),
				'defaultTax'        => $defaultTax,
				'currentTax'        => $currentTax,
				'inclTaxTitle'      => Mage::helper('catalog')->__('Incl. Tax')
				);

		$config = array(
				'attributes'        => $attributes,
				'template'          => str_replace('%s', '#{price}', $store->getCurrentCurrency()->getOutputFormat()),
				'basePrice'         => $this->_registerJsPrice($this->_convertPrice($currentProduct->getFinalPrice())),
				'oldPrice'          => $this->_registerJsPrice($this->_convertPrice($currentProduct->getPrice())),
				'productId'         => $currentProduct->getId(),
				'chooseText'        => Mage::helper('catalog')->__('Choose an Option...'),
				'taxConfig'         => $taxConfig,
				'options_price'	    => $options_price
			       );

		if ($preconfiguredFlag && !empty($defaultValues)) {
			$config['defaultValues'] = $defaultValues;
		}

		//:$config = array_merge($config, $this->_getAdditionalConfig());
		//Mage::log("config=" . $this->mydebug($config));
		return $config;
	}
}

Note: I have modified the getRegularConfig Megento’s method to add the price of the simple products (‘options_price’ attribute here).

And I have created my Ajax controllers to update the second block of attribute values when we click on the first attribute.

Below the code of the controllers :

# more  Configurable/controllers/AjaxController.php 
<?php
require_once 'Mage/Catalog/controllers/ProductController.php';
class MyStockPhoto_Configurable_AjaxController extends Mage_Catalog_ProductController
{
	// Debug
	private function mydebug(&$var)
	{
		ob_start();
		var_dump($var);
		$result=ob_get_clean();
		return $result;
	}

	/**
	 * Product view action
	 */
	public function viewAction()
	{
		// Get initial data from request
		$categoryId = (int) $this->getRequest()->getParam('category', false);
		$productId  = (int) $this->getRequest()->getParam('id');
		$specifyOptions = $this->getRequest()->getParam('options');

		// Prepare helper and params
		$viewHelper = Mage::helper('catalog/product_view');

		$params = new Varien_Object();
		$params->setCategoryId($categoryId);
		$params->setSpecifyOptions($specifyOptions);

		// Render page
		try {
			$viewHelper->prepareAndRender($productId, $this, $params);
		} catch (Exception $e) {
			if ($e->getCode() == $viewHelper->ERR_NO_PRODUCT_LOADED) {
				if (isset($_GET['store'])  && !$this->getResponse()->isRedirect()) {
					$this->_redirect('');
				} elseif (!$this->getResponse()->isRedirect()) {
					$this->_forward('noRoute');
				}
			} else {
				Mage::logException($e);
				$this->_forward('noRoute');
			}
		}
	}
	
        protected function find_price($myoptions,$sattr1,$sval1,$sattr2,$sval2)
        {
                //Mage::log("search A:$sattr1 V:$sval1 A:$sattr2 V:$sval2");
                foreach($myoptions as $id => $attributes)
                {
                        if(isset($attributes[$sattr1][$sval1]) && isset($attributes[$sattr2][$sval2]))
                                return $attributes[$sattr1][$sval1];
                }
        }

	public function updateAction()
	{
		$productId=$this->getRequest()->getParam('product');
		//Mage::log("ID=$productId");
		$super_attribute=$this->getRequest()->getParam('super_attribute');
		$params=$this->getRequest()->getParams();
		if(!isset($params)) $params=Mage::app()->getRequest()->getParams();
		
		foreach($super_attribute as $skey => $svalue) break;
		Mage::log("KEY=$skey VALUE=$svalue");
		// Mage::log("Params=".$this->mydebug($params));
		// Get Session
                $session = Mage::getSingleton('core/session');
		$configs=($session->getData('configs'));
		//Mage::log("configs=".$this->mydebug($configs));
                $baseCurrencyCode = "€";
                $currentCurrencyCode = $baseCurrencyCode;
		if(true)
		{
			$html="";
                        $price=0;
			$j=0;
			foreach ($configs['attributes'] as $key => $_attribute)
			{
				$i=0;
				if($j > 0)
				{
					$html .= '<dt><label class="required"><em>*</em>&nbsp;' . $_attribute['label'] . '</label></dt>';
					$html .= '<div class="input-box">';
					foreach($_attribute['options'] as $value)
					{
						$html .= '<dd';
						if($i == (count($_attribute['options'])-1)) $html .= ' class="last"';
						$html .= '>';
						$price=$this->find_price($configs['options_price'],$skey,$svalue,$key,$value['id']);
						$html .= '<label class="label-radio-configurable" id="attribute'. $key . '" price="' . (string)$price . + ' €' . '">';
						$html .= '<input type="radio" name="super_attribute[' . $key . ']" id="attribute' . $key . '" class="validate-custom-configurable" v
alue="' . $value['id'] . '" onclick="updatePrice(\'' . sprintf("%.2f",$price) . '\');"';
						$html .= ' price="' . sprintf("%.2f",$price) . ' ' . $currentCurrencyCode .'"';
						$html .= '/>';
						$html .= ' ' . $value['label'];
						$html .= ' (<strong style="color: #FF0000;">' . sprintf("%.2f", $price) . ' ' . $currentCurrencyCode . '</strong>)';
						$html .= '</label>';
						$html .= '</dd>';
						$i++;
					}
					$html .= '</div>';
				}
				$j++;
			}
		}
		echo $html;
	}
}
?>

Update : The new template of my configurable products is now online and It is working as expected : You can see the result on my store : www.mystockphoto.fr.

My article helps you ! Don’t hesitate to donate ! 

[pfund-progress-bar campaign_id= »940″]

My Module API to create Configurable Product is available here !

Voila,

Nicolas Portais
Author Photographer
http://www.mystockphoto.fr/

Ce contenu a été publié dans Non classé, avec comme mot(s)-clé(s) , , . Vous pouvez le mettre en favoris avec ce permalien.

2 Responses to Magento Configurable Product : Replace Options by Radio button

  1. dushyantjoshia dit :

    Nice Article. But could you please post the entire code. The code is not working here

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha (solve the arithmetic equation) * Time limit is exhausted. Please reload CAPTCHA.