1. Introduction
A much requested feature in Zen Cart™ was the ability to have unique information layouts for different types of products.
For example a Music Video needs to have different information stored and displayed, compared to say a Garden Bench.
Previously there has been no easy way for a Zen Cart™ Store user to do this without ripping apart the core code. The Product Type system was designed to help alleviate that problem.
Throughout this mini-tutorial we will use the Music Product type that comes as standard with V1.2 as an example. It is not in anyway meant to be an exhaustive treatise on implementing your own product type, as this will always depend on exactly what you are trying to implement.
However it should provide enough of an overview to get you started. More information is available in the support forum.
2. Database Schema
The Product Types System uses a number of required, and some non-required tables within the Zen Cart™ database. The required database tables are:
PRODUCT_TYPES
PRODUCT_TYPE_LAYOUT
GET_TERMS_TO_FILTER
PRODUCT_TYPES
The _PRODUCT_TYPES database is used to track base information relating to the product types currently installed. It consists of 8 fields.
type_id
type_name
type_handler
type_master_type
allow_add_to_cart
default_image
date_added
last_modified
type_id is an auto_incrementing field and is used to cross reference the type with other Database Tables used by the Product Type System.
type_name is user defined, but you should try and stick with the naming conventions that the core team have decided on. For example in Zen Cart™ 1.2 we have Products - General for the standard product, and Product - Music for a product type designed for Music CD's. Then we have Document - General for a basic layout for an information only Document, and Document-Product for a Document that can be sold. These names are used in the drop down that appears in the admin product creation pages.
type_handler again is user defined and is used to build the URL to the code that actually does the work for the product type. It is best to define this similarly to the type_name. For example if the type_name is Product-Music, the type_handler would be product_music. For compatibility across operating systems you should always stick to lower case for the type_handler. More explanation will be given later as to how the type_handler is used to access the unique code for a given product type.
type_master_type is used to link product types together. This is mainly used if you want to build separate sideboxes to display a category tree of just certain product types. For example the Document types are linked so that we can provide a sidebox that can be used just to navigate categories containing Document Types.
allow_add_to_cart. Provision is made with this field to create product_types that are for information purpose only, and because of that you do not want to allow the shopper to add them to the cart. The basic Document type is a good example of this.
default_image is reserved for future usage.
date_added/last_modified are for internal code use only.
PRODUCT_TYPE_LAYOUT
It has always been possible in Zen Cart™, using the admin interface, to decide which elements of a product's information are displayed. Originally this information was saved in the CONFIGURATION table. However as different product types will have differing types of information, we now use a separate table for product types.
The layout of this table is similar to an entry in the configuration table. The fields are
configuration_id
configuration_title
configuration_key
configuration_value
configuration_description
product_type_id
sort_order
last_modified
date_added
use_function
set_function
an example here is an entry for the music product type.
INSERT INTO product_type_layout (configuration_title, configuration_key, configuration_value, configuration_description, product_type_id, sort_order, set_function, date_added) VALUES ('Show Record Company', 'SHOW_PRODUCT_MUSIC_INFO_RECORD_COMPANY', '1', 'Display Record Company on Product Info 0= off 1= on', '2', '4', 'zen_cfg_select_drop_down(array(array(\'id\'=>\'1\', \'text\'=>\'True\'), array(\'id\'=>\'0\', \'text\'=>\'False\')), ', now());
This lets the store admin decide whether the Record Company linked to the music product is shown on the product info page. Of course you would need to code the music product info page to use this value e.g.
if (SHOW_PRODUCT_MUSIC_INFO_RECORD_COMPANY == '1') {
?>
<tr>
<td class="main" align="center" colspan="2">
<?php echo sprintf(TEXT_RECORD_COMPANY_URL, zen_href_link(FILENAME_REDIRECT, 'action=url&goto=' .
urlencode($products_record_company_url), 'NONSSL', true, false)); ?>
</td>
</tr>
<?php
} // SHOW_PRODUCT_MUSIC_INFO_URL
This is just one example, and you should look at the product info code (and associated entries in the PRODUCT_TYPE_LAYOUT table for more examples.
GET_TERMS_TO_FILTER
This table is not strictly part of the core Product Types System, but is used to handle new filter sideboxes.
Filter sideboxes are used to filter product lists based on some variables.
The main example of this is the manufacturers sidebox. This allows you to filter a product lists based on the manufacturer of the product.
e.g. show all products whose manufacturer is Microsoft.
The music product type adds two filter sideboxes, Record Company and Music Genre.
There is only one field in this table:
get_term_name - this is the name of the $_GET variable that is returned by the filter sidebox. The relevance of this will be discussed in more depth when we look at catalog side code for the Product Type System.
3. Admin Code
In previous versions all code for handling adding categories/products was contained within the admin/categories.php file. To accommodate the Product Types System, this file needed to be split up.
admin/categories.php now deals only with displaying and managing the category tree. It also contains the button for adding a new product. On requesting a new product, categories.php will call the file [product handler].php. The [product handler] is the name stored in the product_types database table. e.g product_music.php is the admin handler for the Music Type product.
This handler file is basically a skeleton and in general you can just directly copy the product.php handler to be your handler file. Note you will also have to create a corresponding language file.
The product handler page then includes a number of needed files.
The two most important are:
admin/includes/modules/[handler_name]/collect_info.php
admin/includes/modules/[handler_name]/preview_info.php
again [handler name] is the type_handler entry in the product_types table.
These two files are responsible for actually creating a new entry in the product table and as such will need the most customizing if your product type contains new fields/options for your product type.
collect_info.php contains the code that is used to collect the product details e.g.
product name
product description
product price
etc.
preview_info.php is used to preview the created product prior to adding it to the database permanently.
Within the admin/includes/modules directories there are an number of other files you can override. By this I mean by adding a file of the same name to your admin/includes/modules/[handler name]/ directory, it will be used in preference.
Those files are:
update_product.php
This code is used to update the various tables to actually add the product to the database. You only need to override this file if your product type requires extra fields to be added to the database.
e.g the Music Type stores Genre Type, and record company in a separate table called product_music_extra, it therefore needs to add code to update.php to make sure information from collect_info.php is added to this table.
copy_to_confirm.php
This code is used when you ask to copy a product to a new product. If your product type uses extra tables to store information then you need to add code here to ensure that information is copied to the new product
e.g. the Music Type adds code here to make sure data in products_music_extra table is copied to the new product.
delete_product_confirm.php
This code is used when you delete a product. You may want to remove information stored in other tables associated with your product type here.
move_product_confirm.php
This code is used when moving a product between categories, in general there should be no reason to override this file as moves are done using the product_id. However someone somewhere may have use for it.
4. Catalog Code
The changes needed to support a product type in the catalog code are less onerous than in the admin area.
Essentially you only need to provide a handler page to show the product_info. To create a new product info page you must first create a new directory /includes/modules/pages/[handler name]_info
Initially you should copy all of the files contained within the includes/modules/pages/product_info/ directory into your includes/modules/pages/[handler name]_info/ directory.
Usually the only file you will need to edit within this directory is main_template_vars.php. And, technically, you shouldn't even need to edit that file at all. Instead, simply create your own script in the/includes/templates/YOUR_TEMPLATE/[handler name]_info/extra_main_template_vars folder. This file will be loaded by the basic main_template_vars.php file (you still have to copy it from the product_info folder so it can process the basics) and prepare the needed contents for your template (assuming you code the logic for this in that file).
e.g. The Music Type adds code here to load information regarding Music genre, Record Company etc. from the product_music_extra table.
You then need to create a template for the product info page for your Product Type. The template should be placed in includes/templates/template_default/templates or alternatively in includes/templates/[your template]/templates if you want to keep it separate from core code.
The template file should be called:
tpl_[handler name]_info_display.php, again [handler name] being the same as the entry in the type_handler field of the product_types table.
You will of course have to adjust the template to include any extra information associated with your Product type.
One important point: Within the template generally a number of constants are used to decide if a certain element is displayed. For example in the standard product info page, SHOW_PRODUCT_INFO_QUANTITY if set to 1 will display the quantity in stock. These constants are loaded from the database/product_type_layout table.
It is good practice to create separate constants for each product type within this table. For example, the Music type uses SHOW_PRODUCT_MUSIC_INFO_QUANTITY instead of SHOW_PRODUCT_INFO_QUANTITY. This allows admin to set the layouts of different product types separately from each other.
5. Filter Side boxes
One important addition to the Product Types System in the catalog are sideboxes which can filter a product listing. You may already be familiar with this when using the Manufacturers sidebox. This allows you to restrict a product listing to a specific manufacturer.
The Music type adds two additional filter sideboxes. These are Music Genre and Record Company. If you look at the code say for the Music genre sidebox in includes/modules/sideboxes/music_genre.php you can see that the ID for the music genre selected will be passed in the url as a $_GET variable called music_genre_name. In order for this to be processed correctly we need an automatic way of registering these filter terms. As mentioned earlier in the section on databases you can do this by adding the name of the filter variable to the get_terms_to_filter database table.
6. Written Product Type Contributions
As an example of how to create a product type you might want to look at the Book product type created by Justin K (jazzyjus). This includes an excellent readme file, and nicely commented code.