Template override for characteristics

  • Posts: 57
  • Thank you received: 2
12 years 7 months ago #46495

Hi All,

I'm trying to produce a characteristic over-ride to stop out of stock items showing in the drop down. However, I am currently hitting a brick wall.

For the characteristics:

You need to create the file templates/YOUR_TEMPLATE/html/hikashop_characteristics.php.

- DONE

We invite you to look at the file administrator/components/com_hikashop/type/characteristic.php for the default code of the function you will define in it.
In that file, you will be able to define the function:
hikashop_characteristics_html(&$element,&$params)

- DONE

Question, if the file templates/YOUR_TEMPLATE/html/hikashop_characteristics.php is loaded into the class (require_once ($chromePath); ) then why are the parameters $element and $params passed as references. Surely the require_once loads the file and it becomes a part of the class and so has direct access to the class variables.

if (file_exists($chromePath)){
require_once ($chromePath);
if(function_exists('hikashop_characteristics_html')){
$html = hikashop_characteristics_html($element,$params,$this);
}

function hikashop_characteristics_html(&$element,&$params)


Note: hikashop_characteristics_html is called passing three variables, but only two are listed in the parameter list of the function.

=> The $element variable will contain the whole product information from which you can extract the characteristics information and the params variable can help you get some parameters from the HikaShop configuration. You need to return the HTML of the characteristics selection at the end of your function.


To get a base to start from I have copied the code from characteristic.php (line 89 onwards) including the 'display' function. To prevent a name clash between this 'display' and the original one in the characteristic.php, I've renamed the function and only call in the new file to 'display_characteristics'.

The theory is that the over-ride now consists of the very same code/functionality to create the characteristics as would occur if the over-ride didn't exist. The problem is that the display breaks.

If I clear $html ( $html=''; ) just before the return, I still get the broken output, so it looks as though there is an issue before that point and the return is somehow happening before hitting the intended exit point but I can't for the life of me, see the cause.

What am I missing? Has anyone got an example of a working over-ride that they are willing to share for customisation?

Regards,
Martyn.

Broken display




Expected display



<?php
function hikashop_characteristics_html(&$element,&$params)
{
	switch($params->get('characteristic_display'))
	{
		case 'table':
			if(count($this->characteristics)==2)
			{
				$html = '';
				$firstCharacteristic = reset($this->characteristics);
				$secondCharacteristic = end($this->characteristics);
				$html.= '<table class="hikashop_product_characteristic_chooser"><tr><td></td>';
				if(empty($secondCharacteristic->values)){
				}else{
					foreach($secondCharacteristic->values as $value){
						$html.='<td>'.$value->characteristic_value.'</td>';
					}
				}
				$html.='</tr>';
				$this->options=' onclick="return hikashopUpdateVariantData(this.value);"';
				$size=0;
				if(!empty($firstCharacteristic->values)){
					foreach($firstCharacteristic->values as $value){
						$html.='<tr><td style="text-align:right">'.$value->characteristic_value.'</td>';
						if(strlen($value->characteristic_value)>$size)$size=strlen($value->characteristic_value);
						if(!empty($secondCharacteristic->values)){
							foreach($secondCharacteristic->values as $value2){
								$class = '';
								$classspan = '';
								foreach($element->variants as $k => $variant){
									$char1 = false;
									$char2 = false;
									foreach($variant->characteristics as $variantCharacteristic){
										if($variantCharacteristic->characteristic_id==$value->characteristic_id){
											$char1 = true;
										}elseif($variantCharacteristic->characteristic_id==$value2->characteristic_id){
											$char2 = true;
										}
										if($char1&&$char2){
											if(!$variant->product_published || $variant->product_quantity==0){
												$class = ' hikashop_product_variant_out_of_stock';
												$classspan=' hikashop_product_variant_out_of_stock_span';
											}
											break 2;
										}
									}
								}
								$name = '_'.$value->characteristic_id.'_'.$value2->characteristic_id;
								$radio="\n\t<span class=\"hikashop_product_characteristic_span".$classspan."\"><input type=\"radio\" class=\"hikashop_product_characteristic".$class."\" name=\"hikashop_product_characteristic\" id=\"hikashop_product_characteristic".$name."\" value=\"".$name."\" ".$this->options;
								if($this->characteristics[$value->characteristic_parent_id]->default->characteristic_id==$value->characteristic_id && !empty($this->characteristics[$value2->characteristic_parent_id]->default->characteristic_id) && $this->characteristics[$value2->characteristic_parent_id]->default->characteristic_id==$value2->characteristic_id){
									$radio.=' checked';
								}
								$radio.=" /></span>";
								$html.='<td>'.$radio.'</td>';
							}
						}
						$html.='</tr>';
					}
				}
				$html.='</table>';
				if($params->get('characteristic_display_text')){
					$space = '';
					for($i=0;$i<=$size;$i++){
						$space.='&nbsp;&nbsp;';
					}
					$html='<table class="hikashop_product_characteristic_chooser"><tr><td></td/><td>'.$space.$secondCharacteristic->characteristic_value.'</td></tr><tr><td>'.$firstCharacteristic->characteristic_value.'</td><td>'.$html.'</td></table>';
				}
			        break;
			}
		default:
		case 'radio':
		case 'dropdown':
			$main_html = '<table class="hikashop_product_characteristics_table">';
			foreach($this->characteristics as $characteristic){
				$main_html.='<tr>';
				$values = array();
				if(!empty($characteristic->values)){
					foreach($characteristic->values as $k => $value){
						$values[$k]=$value->characteristic_value;
					}
				}
				$html=$this->display($characteristic->characteristic_id,@$characteristic->default->characteristic_id,$values,$params->get('characteristic_display'));
				if($params->get('characteristic_display_text')){
					$html=$characteristic->characteristic_value.'</td><td>'.$html;
				}
				$main_html.='<td>'.$html.'</td></tr>';
			}
			$main_html.='</table>';
			$html = $main_html;
			break;
	}
	$html.='
	<noscript>
		<input type="submit" class="button" name="characteristic" value="'.JText::_('REFRESH_INFORMATION').'"/>
	</noscript>';
	return $html;
}

function display_characteristics($map,$value,$values,$characteristic_display='dropdown')
{
	if(empty($values) || !is_array($values)){
		return JText::_('NO_VALUES_FOUND');
	}
	if(is_array($this->characteristics)){
		$characteristic_id = $map;
		$map = 'hikashop_product_characteristic['.$characteristic_id.']';
		$id = 'hikashop_product_characteristic_'.$characteristic_id;
	}else{
		$id = $map;
	}
	$this->values = array();
	foreach($values as $key => $val){
		if(strlen($val)!=0 && empty($val)){
			$val = $val.'&nbsp;';
		}
		$this->values[] = JHTML::_('select.option', $key,$val);
	}
	if($characteristic_display!='radio'){
		$characteristic_display='generic';
	}
	$html = JHTML::_('select.'.$characteristic_display.'list',   $this->values, $map, 'class="inputbox" size="1"'.$this->options, 'value', 'text', (int)$value,$id );
	return $html;
}
?>

Attachments:
Last edit: 12 years 7 months ago by expertbeginner. Reason: Damn auto generated smilies

Please Log in or Create an account to join the conversation.

  • Posts: 57
  • Thank you received: 2
12 years 7 months ago #46508

Hi,

Right, copied the whole installation to a test server and turned on PHP Error Reporting and found the culprit:

Fatal error: Using $this when not in object context in /Library/WebServer/Documents/peaklander/templates/peaklander/html/hikashop_characteristics.php on line 79

Line 79: foreach($this->characteristics as $characteristic){

Now to find a solution.

Cheers,
Martyn.

Please Log in or Create an account to join the conversation.

  • Posts: 82868
  • Thank you received: 13377
  • MODERATOR
12 years 7 months ago #46537

I've updated the documentation. You should add the $obj variable in your code and replace $this by $obj as explained now in the developer documentation.

Please Log in or Create an account to join the conversation.

  • Posts: 57
  • Thank you received: 2
12 years 7 months ago #46602

Hi Nicholas,

Thanks for the update. I've made the changes and can confirm that the reference to '$obj->characterisitics' works.

I found, however, that whatever changes I made to the override, the expected results were not being displayed.

To try and narrow the cause down I changed the over-ride code to:

<?php
function hikashop_characteristics_html(&$element,&$params,&$obj)
{
	switch($params->get('characteristic_display'))
	{
		case 'table':
			$html='';
		break;

		default:
		case 'radio':
		case 'dropdown':
			$html = '<table class="hikashop_product_characteristics_table">'.
			'<tr><td>Empty Table Data</td></tr>'.
			'</table>';
		break;
		return $html;
	}
}
?>

Expecting to see 'Empty Table Data' in the place of the drop-down. This wasn't the case the fully populated drop down is displayed.
Going back to the 'characteristics.php' file I made the following modification to check the '$html' variable on return and set it if it is found to be empty:
function displayFE(&$element,$params){
		if(empty($element->main->characteristics)) return '';
		$this->characteristics=&$element->main->characteristics;
		$this->load($params->get('characteristic_display'));
		$app =& JFactory::getApplication();
		$chromePath = JPATH_THEMES.DS.$app->getTemplate().DS.'html'.DS.'hikashop_characteristics.php';
		if (file_exists($chromePath)){
			require_once ($chromePath);
			if(function_exists('hikashop_characteristics_html')){
				$html = hikashop_characteristics_html($element,$params,$this);
				if(empty($html)){
					$html="<tr><td>Empty string returned</td></tr>";
				}
			}
		}

The result:



I know for a fact that the over-ride is being called; if I remove the ';' from the end of the '</table>'; line, I get the error 'Parse error: parse error in /Library/WebServer/Documents/peaklander/templates/peaklander/html/hikashop_characteristics.php on line 16' - which is the break; that follows it.

From this it is apparent that the $html being passed back, on arrival in characteristic.php, is empty and characteristic.php creates the drop-down accordingly. Any ideas as to why $html is empty?

Regards,
Martyn.

Attachments:
Last edit: 12 years 7 months ago by expertbeginner. Reason: [color] not acted upon in [code] section

Please Log in or Create an account to join the conversation.

  • Posts: 57
  • Thank you received: 2
12 years 7 months ago #46609

Hi,

I've spotted it.

Moved the 'return $html;' to outside of the 'switch($params->get('characteristic_display')){'

Sometimes you get too close to see what's really there.

Cheers,
Martyn.

Please Log in or Create an account to join the conversation.

  • Posts: 57
  • Thank you received: 2
12 years 7 months ago #46822

Hi,

Right, I have written the over-ride to populate the drop-down only with items that have stock, i.e. none-zero, but it's not quite there yet.

I have a product that has 15 variants, 2 of those items have a positive stock level, the remainder are set at zero. The default (selected) item for the drop-down is one that has no stock. In my code I check to see if the default item has stock. If it hasn't then I set the default (selected) item to be the first item that has stock:

if(!$default_item_has_stock){
				$obj->characteristics[$first_characteristic_parent_id]->default->variant_characteristic_id = $first_variant_characteristic_id;
				$obj->characteristics[$first_characteristic_parent_id]->default->variant_product_id = $first_variant_product_id;
				$obj->characteristics[$first_characteristic_parent_id]->default->ordering = $first_ordering;
				$obj->characteristics[$first_characteristic_parent_id]->default->characteristic_id = $first_characteristic_id;
				$obj->characteristics[$first_characteristic_parent_id]->default->characteristic_parent_id = $first_characteristic_parent_id;
				$obj->characteristics[$first_characteristic_parent_id]->default->characteristic_value = $first_characteristic_value;
				$obj->characteristics[$first_characteristic_parent_id]->default->characteristic_alias = $first_characteristic_alias;
				$default_characteristic_id = $first_variant_characteristic_id;
			}

I have used a print_r in the 'characterisitics.php' code that calls the override and can confirm that the default section is as set with the above code.

On choosing the product on the front end, the first item is listed in the drop-down, but it shows as having no stock - which is not the case.
Choose the second item on the list and it shows the stock level. Now choosing the first item on the list shows that it has stock. See the graphic.



If I go the the back end and set the default item for this product to either of the items that are in stock, it works as expected.

It seems logical that the display of the 'No stock' / 'Add to cart' would be derived from the $element->main->characteristics array. Is this the case? Or is there some other area in the array that the changes need to be made? I've looked through the array but can't see any other places where a change could/should be made.

The only other resolution I can think of at the moment is to update the database with the new default item. I don't want to do that if it can be helped. I'd much prefer a cleaner, more elegant solution. Neither am I convinced that this would solve the issue.

Any help/guidance would be appreciated.

Regards,
Martyn.

Attachments:
Last edit: 12 years 7 months ago by expertbeginner. Reason: removed 'all but' from 'all but 2 of those items'

Please Log in or Create an account to join the conversation.

  • Posts: 82868
  • Thank you received: 13377
  • MODERATOR
12 years 7 months ago #46918

The default data displayed on the product page is calculated before the characteristic dropdowns are displayed.
The simplest will be for you to add some javascript to update the data displayed with the value selected in the dropdown after the page has loaded with some code like that:
$js = "do_nothing( function() {
var dropdown = document.getElementById('hikashop_product_characteristic_".$characteristic_id."');
hikashopUpdateVariant(dropdown);
});";
$doc =& JFactory::getDocument();
$doc->addScriptDeclaration("\n<!--\n".$js."\n//-->\n");

Please Log in or Create an account to join the conversation.

  • Posts: 57
  • Thank you received: 2
12 years 7 months ago #47009

Hi Nicolas,

Thanks for the javascript.

After trying it out and a bit of trial-and-error in discovering that the '$characterisitic_id' is the parent id ($obj->characteristics->variant_characteristic_id;), I can confirm that it is working as intended.

Many thanks,
Martyn

Please Log in or Create an account to join the conversation.

  • Posts: 2
  • Thank you received: 0
11 years 6 months ago #105178

Hello.

Is this code universal for all hikashop sites? Or it will works only for this site?
If it is universal can you please post step by step it, so many users can do it by themselves.

Many thanks!

Please Log in or Create an account to join the conversation.

  • Posts: 82868
  • Thank you received: 13377
  • MODERATOR
11 years 6 months ago #105219

Hi,

Simple: turn off the option "show out of stock products" in the configuration and you won't see the out of stock variants anymore.
That option has been added to HikaShop a few months after this thread.

Please Log in or Create an account to join the conversation.

  • Posts: 2
  • Thank you received: 0
11 years 6 months ago #105237

Thank you for the answer! And good job!

The topic is about override characteristics, so it is applicable the visualization for the characteristics?
I mean if the product has 5 colors instead of drop-down (or radio buttons) menu to be shown icons with the colors, or icons of the pictures added to the characteristics.

For example see this product page or this !

Many thanks! You really doing a great job here!

Last edit: 11 years 6 months ago by valioba.

Please Log in or Create an account to join the conversation.

  • Posts: 26158
  • Thank you received: 4028
  • MODERATOR
11 years 6 months ago #105259

Hi,

In the latest version of HikaShop (2.1.3) we include a new way to display the characteristics (in a table).
With overrides, it is possible to do such visualization for your product pages but it requires some development skills.
You can use the new characteristics view as a base to have the list of all characteristics and, instead of displaying it as a table, list it with the images (or keep the table and add the image).

Regards,


Jerome - Obsidev.com
HikaMarket & HikaSerial developer / HikaShop core dev team.

Also helping the HikaShop support team when having some time or couldn't sleep.
By the way, do not send me private message, use the "contact us" form instead.

Please Log in or Create an account to join the conversation.

  • Posts: 13201
  • Thank you received: 2322
11 years 6 months ago #105260

Hi,

This is not possible by default, you will have to create your own type of display for that.
In the type (administrator/components/com_hikashop/types/characteristic.php) you can create your own display, and depending on the value of the variants, display and image or icon.

It require custom code and php knowledges.

Please Log in or Create an account to join the conversation.

  • Posts: 10
  • Thank you received: 0
10 years 3 days ago #181001

Hello,

I did figure out how to use the characterisitics. But they show as radio buttons , is it possible to change them to a drop-down list. Also how can I add images to the list?

I attached a pic of the radio buttons list.

Attachments:

Please Log in or Create an account to join the conversation.

  • Posts: 82868
  • Thank you received: 13377
  • MODERATOR
10 years 2 days ago #181022

Hi,

If you want images, I would recommend to follow this tutorial:
www.hikashop.com/support/support/documen...isplay-by-color.html

If you want instead to have a dropdown, you can change the "characteristic display method" option of the configuration to "dropdown". However, it's not possible to have images inside dropdowns in proper HTML, so you can't have both.

Please Log in or Create an account to join the conversation.

Time to create page: 0.104 seconds
Powered by Kunena Forum