Building a products attributes override

This week, I was working on a clients site that presented a problem with the pull-down menu of the product page. The old version of the template had the attributes image show in the pulldown menu with the image showing as you hover over the colors. The default configuration of Zen Cart shows all of the attributes below the attribute text.


But what we want looks like this:

Another incredibly important element to this project is that we want to make sure that as we move forward with upgrades to Zen Cart, that this change in behavior is persistent. If we were to go change the core functionality of Zen Cart, then an upgrade would trash this change and we’d have to go track it down. We are therefore only going to change files in our template. And we’re going to build an override into Zen Cart so that this sticks.

The first thing we want to do is customize the template to not display the image below the selection list. We desired functionality is to have it be a ‘tooltip’ type display during the rollover.


Inside your template, which is located in:
In the responsive_classic template, around line 50 you will the below image and take note that it has already been commented out.


This takes us to this.


I know what you’re thinking. Big whoop. You removed an image. Right. I know. Let’s move on to where things get more exciting.

The first part of the magic comes from telling Zen Cart to include a file when the engine starts up. This comes from a pretty simple file that is located in /includes/auto_loaders


We create a new file in this folder. You can name it anything you want, but I chose to use the same naming convention that is already in there. This name accurately describes what we’re trying to do: which is to change the html output of a pulldown menu.


The contents of this files includes two operations. First is tells Zen Cart to include a file and it gives it the path. The second is that it instantiates a new object for us to call later.

$autoLoadConfig[999][] = array('autoType'=>'class',
$autoLoadConfig[999][] = array('autoType'=>'classInstantiate',
// eof

Since the default functionality of the html pulldown doesn’t operate the way that we want, let’s quickly talk about how we’re going to override the default functionality of Zen Cart. It is very cool that the Zen Cart developers added the observer methods into the mix. They even explicitly wrote a comment that offers the ability to totally override the output. And when that is done, the default function bails out and returns the results. Notice the $GLOBALS[‘zco_notifier’]->notify(NOTIFY_ZEN_DRAW_PULL_DOWN_MENU_OVERRIDE’, etc etc etc). When the html_draw_pulldown function is called, if there is a method attached to the notifier, it detours off.


Let us create a new file located in: includes/classes/observers/class.html_output_draw_pulldown.php

Here is the top of the new file we’ve created. We extend the base class of Zen Cart. Then we have the __construct method. Take a look at line 11. The attach method has a parameter of NOTIFY_ZEN_DRAW_PULL_DOWN_MENU_OVERRIDE in it. This is how Zen Cart gets things bolted on to it.


class html_output_draw_pulldown extends base {

function __construct() {
global $zco_notifier;
$zco_notifier->attach($this, array('NOTIFY_ZEN_DRAW_PULL_DOWN_MENU_OVERRIDE'));


Take a look at line 14 with the function update. The 2nd argument is $eventID. This corresponds to the “if” statement on line 16. This starts us down the decision tree path to update the function. However, we don’t want to indiscriminately update every drawdown menu where ever it may get used. We want to target it to this page and type. Take a quick detour up one line to line 16 that has $body_id. This is a Zen Cart variable that has which page we are on. It removes misc punctuation, etc and formats it in a way that we can easily trap it. In this case ‘productinfo’.

To recap where we are so far. We have told Zen Cart to include a file, and instantiate a class called html_output_draw_pulldown. This class is attached to the notifier object to get called at the appropriate time by the $eventID variable.

Way back at the top of this article, there is a screenshot of the original function for the html pulldown. It has lists all of the parameters that would have been called for the standard function to be used. These parameters all get stuffed into the $paramsArray variable to be picked up by the update method in our new class. We have the form element name, the values, the default value, extra parameters and if the field is a required field. All of this gets passed over to our new code.

One other if statement that seemed to be appropriate to include is on line 20. This is where your field name may be different. On my clients site, it is

<select name="id[2]" id="attrib-2">

and on the demo data for Zen Cart it is

<select name="id[3]" id="attrib-3">

I know, pretty insignificant difference. But important for our “if” statement. And I guess this is all going to be a bit anticlimactic because, this just creates a string that builds up our html output to be returned. This is where you can customize the output to be whatever you want.

Now that we’ve gotten here with modifying the function, we run into another challenge. The default version of attributes.php doesn’t send over the image the way we need it. We will modify the attributes.php stock version for our own purposes here as well. The steps taken to accomplish this is to locate:

make a folder includes/modules/YOURTEMPLATE. copy includes/modules/attributes.php -> includes/modules/YOURTEMPLATE/


Open up the new version of attributes, and somewhere around line 115, we’re going to tweak the output just a bit.attributes_after

 $products_options_array[] = array('id' => $products_options->fields['products_options_values_id'],
'text' => $products_options->fields['products_options_values_name'],
'data-image' => 'images/' . $products_options->fields['attributes_image']

We’ve added the attributes_image to the bottom of the array. When we reload the Zen Cart site, our html output has the information in it now.


Toss in the css and javascript files. Then when the page loads, you get something that should look like this:


Download project files here