Zen Cart API
Zen Cart API is the application programming interface for Zen Cart.
initSystem
The term initSystem, apart from being a tag used to group certain PHP files together in the new documentation, embraces all files that are automatically included / initialized before any command scripts can be run.
Zen Cart® v1.x uses a (non Object Oriented) page controller pattern to decide the scripts to run, based on HTTP_GET parameters.
The most important of these is the 'main_page' HTTP_GET parameter.
Depending on that parameter, a command script is then run.
Each commmand script resides in a directory in / includes / modules / pages
.
For example if main_page = login the command script would be taken from the / includes / modules / pages / login /
directory.
However the first thing every command script always does is require () the /includes/application_top.php file. This is the heart of the initSystem.
It is application_top.php
that is responsible for initialising basic subsystems (database abstraction / sessions / languages etc.) and loading global configuration data.
In the past this was done using a hard-coded script. From v1.3.0 on, however, Zen Cart® now uses a control array to decide which functions / classes / data files are to be included and initialised.
This allows contribution authors and third party developers to gain access to and extend the initSystem without compromising upgradeability.
In the following sections we will work through exactly how the Zen Cart® engine uses application_top.php to initialise core systems.
application_top.php - A little bit of history In terms of its osCommerce roots, application_top.php was the file included on every page / script needed to invoke and handle basic core sub-systems. Any function / class that was needed globally by any page needed to be initialised here.
From a customisation perspective this was a bad thing. If third party code (contributions) needed to access a new global function / class then application_top.php would need to be 'hacked'. This would obviously cause problems on upgrades, when application_top.php would be overwritten, and any customisations would be lost.
Zen Cart® attempted to mitigate this by providing certain override directories where extra data / functions files could be placed that would be automatically included when application_top.php was run.
The problem with this system is that it only provides for a very few places within the running order of application_top.php where new code can be introduced. It also did not provide at all for the addition of new classes. What was required was an application_top.php that allowed for the placing of any new function / class / script that was completely under the developer's control. Futhermore, some method of loading and invoking classes was also required.
Since v1.3, Zen Cart® achieves this by abstracting the code run by application_top.php into a control array. This array stores details of functions / classes / init scripts that need to be run, and the order in which they are run in a special PHP array. Given this it is now possible for third party developers to 'hook' into application_top.php and be confident that any future code upgrades will not normally overwrite their own code.
application_top.php - Breakpoints In Zen Cart® there is now almost no procedural code in application_top.php. The small amount that is there will be discussed later. The bulk of procedural code in application_top.php is now given over to handling breakpoints. Breakpoints can simply be described as points of importance. We currently have approximately 20 breakpoints in application_top.php. At each breakpoint something important happens - we may load a function or class, initialise a class, load a script fragment, and so on. The important point is to recognise that at each breakpoint, third party code can, by adding to the control array, also load functions, load classes, initialise classes, run a class method or load (require) a script fragment.
The Control Array Control arrays are automatically loaded from the directory / includes / auto_loaders. Every * .php file within that directory is expected to have a certain structure. In v1.3 we use a file called config.core.php as the main file for governing application_top.php. Third party developers can add their own control array files. The structure of each file should look like this:
$ autoLoadConfig [0] = array ();
The value after $ autoLoadConfig (in this case [0]) represents the order in which the actions happen (eg the Breakpoint), such that $ autoLoadConfig [0] will occur before $ autoLoadConfig [1]. Note also that any two entries where the breakpoint is the same will occur in the order they appear within the file. The actual contents of the array () part depends upon what effect is needed. Let's consider a number of different scenarios.
First I just want to require a file to be loaded. For this, the control array entry would be:
$ autoLoadConfig [0] [] = array ('autoType' => 'require', 'loadFile' => DIR_WS_INCLUDES. 'somefile.php');
The autotype parameter tells us that we just want to require a file
The loadFile parameter tells us which file we want to load.
Loading function files can also obviously be done using the above.
Similarly if we want to 'include' a file:
$ autoLoadConfig [0] [] = array ('autoType' => 'include', 'loadFile' => DIR_WS_INCLUDES. 'somefile.php');
We then have a special type of 'require'. The initSystem introduces a special class of .php files called init_ scripts. These are stored in the includes / init_includes directory. Each of these contains a small amount of procedural code that can be run as part of the initSystem process. The reason for separating them out into a special directory is to allow for those init_scripts to be overridden, more of which will be discussed later. For now, to load an init_script we use the following control array structure.
$ autoLoadConfig [] = array (array ('autoType' => 'init_script', 'loadFile' => 'init_database.php'));
Where the auto_loader system comes into its own is in the handling of class files. With a class file we want to load the class file definition, then instantiate the class, and finally possibly run a class method (all running thus within the scope of application_top.php)
In terms of the control array we have the following entries to help us.
$ autoLoadConfig [0] [] = array ('autoType' => 'class', 'loadFile' => 'shopping_cart.php'); $ autoLoadConfig [30] [] = array ('autoType' => 'classInstantiate', 'className' => 'cache', 'objectName' => 'zc_cache'); $ autoLoadConfig [80] [] = array ('autoType' => 'classInstantiate', 'className' => 'shoppingCart', 'objectName' => 'cart', 'checkInstantiated' => true, 'classSession' => true); $ autoLoadConfig [120] [] = array ('autoType' => 'objectMethod', 'objectName' => 'navigation', 'methodName' => 'add_current_page');
Taking these options one by one
Where autotype => 'class' all we are really doing here is 'including' the 'loadFile'. However, in this case we draw the file from the includes / classes (DIR_WS_CLASS) directory.
Where autotype => 'classInstantiate' executes code of the form objectName = new className ();
An example based on the code above is
$ zc_cache = new cache ();
One corollary to this is that we may need to instantiate a class that is bound to a session, like the shopping_cart class. In this case as from the example above we get
$ _SESSION ['Cart'] = new shoppingCart ();
and in fact we take that one step further, Normally we only want to instantiate a session object if it is not already a session object. In this case we take advantage of the 'checkInstantiated' property, which would generate code:
if (! $ _ SESSION ['cart']) { $ _SESSION ['Cart'] = new shoppingCart (); }
The final example, where autotype-'objectMethod 'shows how to run a class method within application_top.php. At the time of writing there is no provision for passing method parameters, so the code generated would be (based on the example above):
$ navigation-> add_current_page ();
Notes on admin autoloaders The goal of v1.3.x is to eventually remove and refactor all functions into classes. Further, these classes will be common between admin and catalog code.
However this presents a problem with the autoloading of class files. Currently the autoloader code, will default to loading a class from the catalog includes / classes directory rather than admin / includes / classes.
To provide for that interim period where we still need to to load admin class files from admin / includes / classes, we provide an extra option to the 'autotype' => class option.
consider this
$ autoLoadConfig [0] [] = array ('autoType' => 'class', 'loadFile' => 'class.base.php');
if this is used in an admin autoloader it will load the class from the catalog classes directory. For the base class this is fine as the code can be shared between catalog and admin. However, at the moment the split_page_results_class is different between admin and catalog. So in order to load an admin-specific class we use:
$ autoLoadConfig [0] [] = array ('autoType' => 'class', 'loadFile' => 'split_page_results.php', 'classPath' => DIR_WS_CLASSES);
Overriding / Extending the system autoloader There are two ways of overriding / extending the inbuilt auto_loader and thus affecting what happens during the loading of application_top.php. The usual method would be to simply add a new file to the / includes / auto_loader / directory. The file you add here should have start with config and have a .php extension (ie: config.your_app_name.php), and should contain one or more control array definitions. This is the recommended method to use for adding code to be executed within application_top.php, and allows contribution authors to customise the code here in a way that will be generally unaffected by system upgrades.
Additionally, within the / includes / auto_loader / directory is another directory called overrides. This can be used to override any autoloader file in the / includes / auto_loader / directory. For example, the main autoloader file used in Zen Cart® is config.core.php. If a file called config.core.php is placed in the overrides directory, this will be used instead of the original.
init_scripts and application_top.php Introduction The initSystem allows you to automate the including / requiring of files and to automate the loading / instantiating of classes. However we still also need to be able to run some procedural code. We also want to allow 3rd parties to override that procedural code. init_scripts allow us to do this.
init_scripts There are currently 18 init_scripts in the base 1.3.0 release. These init_scripts are in the includes / init_includes directory. init_add_crumbs.php (Responsible for initialising the Breadcrumb) init_cart_handler.php (Responsible for handling Cart actions) init_category_path.php (Reponsible for initialising Category Paths) init_currencies.php (Responsible for initialising the Currencies Sub-System) init_customer_auth.php (Responsible for checking customer status, either thru Down for Maintenance or the Approval level) init_database.php (Responsible for initialising the DB layer) init_db_config_read.php (Responsible for reading configuration data from database) init_file_db_names.php (Responsible for loading File and Database tablename Defines) init_general_funcs.php (Resposible for loading general functions from the includes / functions directory as well as the extra_functions folder) init_gzip.php (Responsible for loading Gzip output-buffering functions) init_header.php (Responsible for running page-header procedures) init_languages.php (Responsible for loading multiple-language support sub-system) init_sanitize.php (Responsible for loading input-sanitising code) init_sefu.php (Responsible for loading code to provide search-engine-friendly URLs) init_sessions.php (Responsible for loading Session code) init_special_funcs.php (Responsible for loading specialized but necessary functions) init_templates.php (Responsible for initialising the template System and activating template-specific language-content defines) init_tlds.php (Responsible for setting Top Level Domain Variables)
Overriding init_scripts It is very simple to override a core init script. The directory includes / init_incudes contains a directory called overrides. If I wanted to override the incudes / init_includes / init_sessions.php script then I would simply create a file called init_sessions.php in the includes / init_includes / overrides directory.
Procedural code in application_top.php Despite the use of the autoloader system, there is still a little procedural code left in application_top.php; although most of this procedural code is given over to processing autoloaders themselves.
Below is the code from the catalog includes / application_top.php. Note: I have removed all documentation tags for clarity
define ('DEBUG_AUTOLOAD', false); define ('IS_ADMIN_FLAG', false); define ('PAGE_PARSE_START_TIME', microtime ()); ini_set ("arg_separator.output", "&"); if (file_exists ('includes / local / configure.php')) { include ('includes / local / configure.php'); } if (defined ('STRICT_ERROR_REPORTING') && STRICT_ERROR_REPORTING == true) { error_reporting (E_ALL); } Else { error_reporting (E_ALL & ~ E_NOTICE); } if (file_exists ('includes / configure.php')) { include ('includes / configure.php'); } Else { header ('location: zc_install / index.php'); } if (! is_dir (DIR_FS_CATALOG. '/ includes / classes')) header ('location: zc_install / index.php'); if ($ za_dir =dir (DIR_WS_INCLUDES. 'extra_configures')) { while ($ zv_file = $ za_dir-> read ()) { if (preg_match ('/ \. php $ /', $ zv_file)> 0) { include (DIR_WS_INCLUDES. 'extra_configures /'. $ zv_file); } } } $ loader_file = 'config.core.php'; $ base_dir = DIR_WS_INCLUDES. 'auto_loaders /'; if (file_exists (DIR_WS_INCLUDES. 'auto_loaders / overrides /'. $ loader_file)) { $ base_dir = DIR_WS_INCLUDES. 'auto_loaders / overrides /'; } include ($ base_dir. $ loader_file); if ($ loader_dir = dir (DIR_WS_INCLUDES. 'auto_loaders')) { while ($ loader_file = $ loader_dir-> read ()) { if ((preg_match ('/ ^ config \ ./', $ loader_file)> 0) && (preg_match ('/ \. php $ /', $ loader_file)> 0)) { if ($ loader_file! = 'config.core.php') { $ base_dir = DIR_WS_INCLUDES. 'auto_loaders /'; if (file_exists (DIR_WS_INCLUDES. 'auto_loaders / overrides /'. $ loader_file)) { $ base_dir = DIR_WS_INCLUDES. 'auto_loaders / overrides /'; } include ($ base_dir. $ loader_file); } } } } if (((! file_exists ('includes / configure.php') &&! file_exists ('includes / local / configure.php'))) || (DB_TYPE ==) || (! file_exists ('includes / classes / db / '.DB_TYPE.' /query_factory.php '))) { header ('location: zc_install / index.php'); exit; } require ('includes / autoload_func.php'); require (DIR_WS_INCLUDES. 'counter.php'); $ customers_ip_address = $ _SERVER ['REMOTE_ADDR']; if (! isset ($ _ SESSION ['customers_ip_address'])) { $ _SESSION ['Customers_ip_address'] = $ customers_ip_address; }
Observer Class
Introduction One of the many goals of the Zen Cart® project has always been to make it easier for third party developers to add functionality to the core code in an easy and unobtrusive manner. To do this we have in the past relied on the override and auto inclusion systems. However these still do not give developers an easy method of hooking into many areas of core code, without 'hacking' core files themselves.
The observer / notifier system was introduced to give developers unprecedented access to core code, without the need to touch any core files at all. Although ostensibly written for an object-oriented code base, we will see later how it can be used with general procedural code as well.
Extending All Classes In order to implement the observer / notifier system, some structural changes have been made to Zen Cart®. Firstly two new classes have been introduced: the base class (class.base.php) and the notifier class (class.notifier.php).
The base class contains the code that is used to implement the observer / notifier system. However to make it effective all other Zen Cart® classes now have to be declared as children of the base class. You will see this if you look at the source of any of the Zen Cart® classes.
class currencies extends base {
The notifier class will be discussed later, when we look at extending the observer / notifier system (ONS) into procedural code.
Notifiers: Big Brother is watching So, what is all the fuss about?
The point of the ONS is that developers can write code that wait for certain events to happen, and then when they do, have their own code executed.
So, how are events defined, where are they triggered?
Events are triggered by code added to the core for v1.3 (with more to be added over time). In any class that wants to notify of an event happening we have added:
$ this-> notify ('EVENT_NAME');
An example would probably help here:
In the shopping cart class after an item has been added to the cart this event is triggered:
$ this-> notify ('NOTIFIER_CART_ADD_CART_END');
There are many other events that have notifiers in Zen Cart® v1.3 and newer; a list for see here.
All of this notifying is all well and good, but how does this help developers?
Observe and Prosper To take advantage of notifiers, developers need to write some code to watch for them. Observers need to be written as a class. There's even a nice directory, includes / classes / observers, where developers can put these classes.
Lets take an example. Using the notifier mentioned above (NOTIFIER_CART_ADD_CART_END), how would I write a class that watched for that event?
<? php class myObserver extends base { function myObserver () { $ this-> attach ($ this, array ('NOTIFIER_CART_ADD_CART_END')); } ... }
As you can see we have defined a new class called myObserver and in the constructor function for that class (function myObserver) have attached this myObserver class to the event NOTIFIER_CART_ADD_CART_END.
"Fine," I hear you saying, "but how do I actually do anything useful?"
Ok, good question. Whenever an event occurs, the base class looks to see if any other observer class is watching that event. If it is, the base class executes a method in that observer class. Remember the $ this-> notify ('EVENT_NAME') from above? Well, when that event occurs, the base class calls the update method of all observers. Lets see some more code:
class myObserver extends base { function myObserver () { $ this-> attach ($ this, array ('NOTIFIER_CART_ADD_CART_END')); } function update (& $ callingClass, $ notifier, $ paramsArray) { ... Do some stuff } }
Now, whenever the NOTIFIER_CART_ADD_CART_END occurs, our myObserver :: update method will be executed. Note that attach () may be called as a method of whatever class you want to listen to ($ _SESSION ['cart'], in this case) or by the internal class variable $ this. Both are available since each are part of the class base, where the attach method resides.
Some notes about the parameters ... the attach method has two parameters: & $ observer - Reference to the observer class, used to generated a unique ID for the new listener $ eventIDArray - An array of notifiers that this observer is listening for
The update method is passed three parameters. These are:
& $ callingClass - This is a reference to the class in which the event occurred, allowing you access to that class's variables $ notifier - The name of the notifier that triggered the update (It is quite possible to observe more than one notifier) $ paramsArray - Not Used Yet (for future)
NB! The observer / notifier system is written for an OOP-based application, as the observer expects to attach to a class that has notifiers within its methods. However a lot of the code within Zen Cart® is still procedural in nature and not contained within a class.
To work around this, we added the 'stub' notifier class. So if you want to create an observer for a notifier that lies within procedural code (like in page headers) you should add the notifier into your myObserver class like this:
class myObserver extends base { function myObserver () { global $ zco_notifier; $ zco_notifier-> attach ($ this, array ('NOTIFY_HEADER_END_CHECKOUT_CONFIRMATION')); }
Including observers into your code Please note that the includes / classes / observers directory is not an autoload directory, so you will need to arrange for application_top.php to autoload your observer class as was described above (add a new config.xxxxx.php file in the auto_loaders folder, etc). Let's assume you are using the freeProduct class (see the example below), and you have saved this in includes / classes / observers / class.freeProduct.php.
You now need to arrange for this class to be loaded and instantiated. To do this you need to use the application_top.php autoload system.
In includes / auto_loaders create a file called config.freeProduct.php containing
<? php
$ autoLoadConfig [10] [] = array ('autoType' => 'class', 'loadFile' => 'observers / class.freeProduct.php'); $ autoLoadConfig [90] [] = array ('autoType' => 'classInstantiate', 'className' => 'freeProduct', 'objectName' => 'freeProduct');
?> Note: 10 has been chosen to cause the observer class to be loaded before the session is started. Note: 90 has been chosen as the offset since the observer needs to attach to the $ SESSION ['cart'] class (see the freeProduct example below), which is instantiated at offset 80.
To tie this all together, let's look at a real world example. A Real World Example One of the most-often requested features is the ability for the store to automatically add a free gift to the Shopping Cart if the customer spends more than a certain amount.
The code has to be intelligent: it has to not only add the free gift when the shopper spends over a certain amount, but also remove the gift if the user changes the contents of the shopping cart, such that the total falls below the threshold.
Traditionally, although the code for this is not particularly difficult, it would have meant 'hacking' the core shoppingCart class in a number of places. With the ONS, this can be achieved with one very small custom class and absolutely no hacking whatsoever.
Here's the code.
<? php / ** * Observer class used to add a free product to the cart if the user spends more than $ x * * / class freeProduct extends base { / ** * The threshold amount the customer needs to spend. * * Note this is defined in the shops base currency, and so works with multi currency shops * *var Decimal * / var $ freeAmount = 50; / ** * The id of the free product. * * Note. This must be a true free product. eg price = 0 Also make sure that if you do not want the customer * To be charged shipping on this, that you have it set correctly. * *var Integer * / var $ freeProductID = 57; / ** * Constructor method * * Attaches our class to the $ _SESSION ['cart'] class and watches for 2 notifier events. * / function freeProduct () { $ _SESSION ['Cart'] -> attach ($ this, array ('NOTIFIER_CART_ADD_CART_END', 'NOTIFIER_CART_REMOVE_END')); } / ** * Update Method * * Called by observed class when any of our notifiable events occur * *param Object $ class *param String $ eventID * / function update (& $ class, $ eventID, $ paramsArray = array ()) { if ($ eventID == 'NOTIFIER_CART_REMOVE_END' && (isset ($ _ SESSION ['freeProductInCart']) && $ _SESSION ['freeProductInCart'] == TRUE)) { if (! $ _ SESSION ['cart'] -> in_cart ($ this-> freeProductID)) { $ _SESSION ['UserRemovedFreeProduct'] = TRUE; } } if (! isset ($ _ SESSION ['userRemovedFreeProduct']) || $ _SESSION ['userRemovedFreeProduct']! = TRUE) { if ($ _SESSION ['cart'] -> show_total ()> = $ this-> freeAmount &&! $ _ SESSION ['cart'] -> in_cart ($ this-> freeProductID)) { $ _SESSION ['Cart'] -> add_cart ($ this-> freeProductID); $ _SESSION ['FreeProductInCart'] = TRUE; } } if ($ _SESSION ['cart'] -> show_total () <$ this-> freeAmount && $ _SESSION ['cart'] -> in_cart ($ this-> freeProductID)) { $ _SESSION ['Cart'] -> remove ($ this-> freeProductID); } if ($ _SESSION ['cart'] -> in_cart ($ this-> freeProductID)) { $ _SESSION ['Cart'] -> contents [$ this-> freeProductID] ['qty'] = 1; } } } ?>
A couple notes:
First, I have set the options for the system in the class itself. This is obviously a bad idea, and it would be much better to have an admin module to set these options.
Second, notice that we are actually watching for two events in the one class.
$ _SESSION ['Cart'] -> attach ($ this, array ('NOTIFIER_CART_ADD_CART_END', 'NOTIFIER_CART_REMOVE_END'));
so we are watching for the NOTIFIER_CART_ADD_CART_END and NOTIFIER_CART_REMOVE_END of the shopping_cart class.
The update class is extremely simple but in its simplicity manages to do all the work we require of it. It first tests to see if the total in the cart is over the threshold and, if it has not already, adds the free product to the cart.
It then tests to see if the cart total has dropped below the threshold and, if the free product is in the cart, removes it.
Now that was cool, how about something a little more difficult.
Another Real World Example Again we return to the Shopping Cart and promotions. Another oft-requested feature is the BOGOF promotion, or Buy One Get One Free. This is a little more difficult to achieve than our previous example, as there is some manipulation needed of the cart totals. However as you will see it is still pretty much a breeze.
<? php / ** * Observer class used apply a Buy One Get One Free (bogof) algorithm to the cart * * / class myBogof extends base { / ** * An array of ids of products that can be BOGOF. * *var Array * / var $ bogofsArray = array (10,4); // Under Siege2-Dark Territory & The replacement Killers / ** * Integer number of bogofs allowed per product * * For example if I add 4 items of product 10, that would suggest that I pay for 2 and get the other 2 free. * However you may want to restrict the customer to only getting 1 free regardless of the actual quantity * *var Integer * / var $ bogofsAllowed = 1; / ** * Constructor method * * Watches for one notifier event, triggered from the shopping cart class. * / function myBogof () { $ this-> attach ($ this, array ('NOTIFIER_CART_SHOW_TOTAL_END')); } / ** * Update Method * * Called by observed class when any of our notifiable events occur * * This is a bit of a hack, but it works. * First we loop through each product in the bogof Array and see if that product is in the cart. * Then we calculate the number of free items. As it is buy one get one free, the number of free items * Is equal to the total quantity of an item / 2. * Then we have to hack a bit (would be nice if there was a single cart method to return a product's in-cart price) * We loop thru the cart until we find the bogof item, get its final price, calculate the saving * And adjust the cart total accordingly. * *param Object $ class *param String $ eventID * / function update (& $ class, $ eventID) { $ cost_saving = 0; $ products = $ _SESSION ['cart'] -> get_products (); foreach ($ this-> bogofsArray as $ bogofItem) { if ($ _SESSION ['cart'] -> in_cart ($ bogofItem)) { if (isset ($ _ SESSION ['cart'] -> contents [$ bogofItem] ['qty']) && $ _SESSION ['cart'] -> contents [$ bogofItem] ['qty']> 1) { $ numBogofs = floor ($ _ SESSION ['cart'] -> contents [$ bogofItem] ['qty'] / 2); if ($ numBogofs> $ this-> bogofsAllowed) $ numBogofs = $ this-> bogofsAllowed; if ($ numBogofs> 0) { for ($ i = 0, $ n = sizeof ($ products); $ i <$ n; $ i ++) { if ($ products [$ i] ['id'] == $ bogofItem) { $ final_price = $ products [$ i] ['final_price']; break; } } $ cost_saving. = $ final_price * $ numBogofs; } } } } $ _SESSION ['Cart'] -> total - = $ cost_saving; } } ?>
NB: There are still some weaknesses here ...
First although the adjust total is correctly shown on the shopping cart page and sidebox, the line total is not adjusted.
Secondly this will probably produce a confusing output at checkout.
Third: Have not tested for tax compliance yet (TODO) Notifiers currently set in Zen Cart Notifier points for Zen Cart 1.3.7
Shopping Cart class NOTIFIER_CART_INSTANTIATE_START NOTIFIER_CART_INSTANTIATE_END NOTIFIER_CART_RESTORE_CONTENTS_START NOTIFIER_CART_RESTORE_CONTENTS_END NOTIFIER_CART_RESET_START NOTIFIER_CART_RESET_END NOTIFIER_CART_ADD_CART_START NOTIFIER_CART_ADD_CART_END NOTIFIER_CART_UPDATE_QUANTITY_START NOTIFIER_CART_UPDATE_QUANTITY_END NOTIFIER_CART_CLEANUP_START NOTIFIER_CART_CLEANUP_END NOTIFIER_CART_COUNT_CONTENTS_START NOTIFIER_CART_COUNT_CONTENTS_END NOTIFIER_CART_GET_QUANTITY_START NOTIFIER_CART_GET_QUANTITY_END_QTY NOTIFIER_CART_GET_QUANTITY_END_FALSE NOTIFIER_CART_IN_CART_START NOTIFIER_CART_IN_CART_END_TRUE NOTIFIER_CART_IN_CART_END_FALSE NOTIFIER_CART_REMOVE_START NOTIFIER_CART_REMOVE_END NOTIFIER_CART_REMOVE_ALL_START NOTIFIER_CART_REMOVE_ALL_END NOTIFIER_CART_GET_PRODUCTS_START NOTIFIER_CART_GET_PRODUCTS_END NOTIFIER_CART_SHOW_TOTAL_START NOTIFIER_CART_SHOW_TOTAL_END NOTIFY_CART_USER_ACTION NOTIFY_HEADER_START_SHOPPING_CART NOTIFY_HEADER_END_SHOPPING_CART
Order Class: NOTIFY_ORDER_PROCESSING_STOCK_DECREMENT_BEGIN NOTIFY_ORDER_PROCESSING_STOCK_DECREMENT_END NOTIFY_ORDER_PROCESSING_CREDIT_ACCOUNT_UPDATE_BEGIN NOTIFY_ORDER_PROCESSING_ATTRIBUTES_BEGIN NOTIFY_ORDER_PROCESSING_ONE_TIME_CHARGES_BEGIN
Email: NOTIFY_EMAIL_AFTER_EMAIL_FORMAT_DETERMINED NOTIFY_EMAIL_BEFORE_PROCESS_ATTACHMENTS NOTIFY_EMAIL_AFTER_PROCESS_ATTACHMENTS NOTIFY_EMAIL_AFTER_SEND (individual email) NOTIFY_EMAIL_AFTER_SEND_ALL_SPECIFIED_ADDRESSES (full batch)
Modules: NOTIFY_MODULE_START_META_TAGS NOTIFY_MODULE_END_META_TAGS NOTIFY_MODULE_START_CREATE_ACCOUNT NOTIFY_FAILURE_DURING_CREATE_ACCOUNT NOTIFY_LOGIN_SUCCESS_VIA_CREATE_ACCOUNT NOTIFY_MODULE_END_CREATE_ACCOUNT
Checkout: NOTIFY_CHECKOUT_PROCESS_BEGIN NOTIFY_CHECKOUT_PROCESS_BEFORE_ORDER_TOTALS_PRE_CONFIRMATION_CHECK NOTIFY_CHECKOUT_PROCESS_BEFORE_ORDER_TOTALS_PROCESS NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_TOTALS_PROCESS NOTIFY_CHECKOUT_PROCESS_AFTER_PAYMENT_MODULES_BEFOREPROCESS NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_CREATE NOTIFY_CHECKOUT_PROCESS_AFTER_PAYMENT_MODULES_AFTER_ORDER_CREATE NOTIFY_CHECKOUT_PROCESS_AFTER_ORDER_CREATE_ADD_PRODUCTS NOTIFY_CHECKOUT_PROCESS_AFTER_SEND_ORDER_EMAIL NOTIFY_CHECKOUT_PROCESS_HANDLE_AFFILIATES NOTIFY_HEADER_START_CHECKOUT_CONFIRMATION NOTIFY_HEADER_END_CHECKOUT_CONFIRMATION NOTIFY_HEADER_START_CHECKOUT_PAYMENT NOTIFY_HEADER_END_CHECKOUT_PAYMENT NOTIFY_HEADER_START_CHECKOUT_PAYMENT_ADDRESS NOTIFY_HEADER_END_CHECKOUT_PAYMENT_ADDRESS NOTIFY_HEADER_START_CHECKOUT_PROCESS NOTIFY_HEADER_END_CHECKOUT_PROCESS NOTIFY_HEADER_START_CHECKOUT_SHIPPING NOTIFY_HEADER_END_CHECKOUT_SHIPPING NOTIFY_HEADER_START_CHECKOUT_SHIPPING_ADDRESS NOTIFY_HEADER_END_CHECKOUT_SHIPPING_ADDRESS NOTIFY_HEADER_START_CHECKOUT_SUCCESS NOTIFY_HEADER_END_CHECKOUT_SUCCESS NOTIFY_MODULE_START_CHECKOUT_NEW_ADDRESS NOTIFY_MODULE_END_CHECKOUT_NEW_ADDRESS
Individual Pages (Header scripts): NOTIFY_HEADER_START_ACCOUNT NOTIFY_HEADER_END_ACCOUNT NOTIFY_HEADER_START_ACCOUNT_EDIT NOTIFY_HEADER_ACCOUNT_EDIT_UPDATES_COMPLETE NOTIFY_HEADER_END_ACCOUNT_EDIT NOTIFY_HEADER_START_ACCOUNT_HISTORY NOTIFY_HEADER_END_ACCOUNT_HISTORY NOTIFY_HEADER_START_ACCOUNT_HISTORY_INFO NOTIFY_HEADER_END_ACCOUNT_HISTORY_INFO NOTIFY_HEADER_START_ACCOUNT_NOTIFICATION NOTIFY_HEADER_END_ACCOUNT_NOTIFICATION NOTIFY_HEADER_START_ACCOUNT_PASSWORD NOTIFY_HEADER_END_ACCOUNT_PASSWORD NOTIFY_HEADER_START_ADDRESS_BOOK NOTIFY_HEADER_END_ADDRESS_BOOK NOTIFY_HEADER_START_ADDRESS_BOOK_PROCESS NOTIFY_HEADER_ADDRESS_BOOK_DELETION_DONE NOTIFY_HEADER_ADDRESS_BOOK_ENTRY_UPDATE_DONE NOTIFY_HEADER_ADDRESS_BOOK_ADD_ENTRY_DONE NOTIFY_HEADER_END_ADDRESS_BOOK_PROCESS NOTIFY_HEADER_START_CREATE_ACCOUNT NOTIFY_FAILURE_DURING_CREATE_ACCOUNT NOTIFY_LOGIN_SUCCESS_VIA_CREATE_ACCOUNT NOTIFY_HEADER_END_CREATE_ACCOUNT NOTIFY_HEADER_START_CREATE_ACCOUNT_SUCCESS NOTIFY_HEADER_END_CREATE_ACCOUNT_SUCCESS NOTIFY_MAIN_TEMPLATE_VARS_START_DOCUMENT_GENERAL_INFO NOTIFY_MAIN_TEMPLATE_VARS_PRODUCT_TYPE_VARS_DOCUMENT_GENERAL_INFO NOTIFY_MAIN_TEMPLATE_VARS_EXTRA_DOCUMENT_GENERAL_INFO NOTIFY_MAIN_TEMPLATE_VARS_END_DOCUMENT_GENERAL_INFO NOTIFY_PRODUCT_TYPE_VARS_START_DOCUMENT_GENERAL_INFO NOTIFY_PRODUCT_TYPE_VARS_END_DOCUMENT_GENERAL_INFO NOTIFY_MAIN_TEMPLATE_VARS_START_DOCUMENT_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_PRODUCT_TYPE_VARS_DOCUMENT_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_EXTRA_DOCUMENT_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_END_DOCUMENT_PRODUCT_INFO NOTIFY_PRODUCT_TYPE_VARS_START_DOCUMENT_PRODUCT_INFO NOTIFY_PRODUCT_TYPE_VARS_END_DOCUMENT_PRODUCT_INFO NOTIFY_HEADER_START_DOWNLOAD NOTIFY_DOWNLOAD_VIA_SYMLINK___BEGINS NOTIFY_DOWNLOAD_WITHOUT_REDIRECT___COMPLETED NOTIFY_DOWNLOAD_WITHOUT_REDIRECT_VIA_CHUNKS___COMPLETED NOTIFY_HEADER_END_DOWNLOAD NOTIFY_HEADER_START_GV_FAQ NOTIFY_HEADER_END_GV_FAQ NOTIFY_HEADER_START_GV_SEND NOTIFY_HEADER_END_GV_SEND NOTIFY_HEADER_START_INDEX NOTIFY_HEADER_END_INDEX NOTIFY_HEADER_START_INDEX_MAIN_TEMPLATE_VARS NOTIFY_HEADER_INDEX_MAIN_TEMPLATE_VARS_RELEASE_PRODUCT_TYPE_VARS NOTIFY_HEADER_END_INDEX_MAIN_TEMPLATE_VARS NOTIFY_HEADER_START_LOGIN NOTIFY_LOGIN_SUCCESS NOTIFY_LOGIN_FAILURE NOTIFY_HEADER_END_LOGIN NOTIFY_HEADER_START_LOGOFF NOTIFY_HEADER_END_LOGOFF NOTIFY_HEADER_START_EZPAGE NOTIFY_HEADER_END_EZPAGE NOTIFY_HEADER_START_PAGE_NOT_FOUND NOTIFY_HEADER_END_PAGE_NOT_FOUND NOTIFY_HEADER_START_PASSWORD_FORGOTTEN NOTIFY_HEADER_END_PASSWORD_FORGOTTEN NOTIFY_MAIN_TEMPLATE_VARS_START_PRODUCT_FREE_SHIPPING_INFO NOTIFY_MAIN_TEMPLATE_VARS_PRODUCT_TYPE_VARS_PRODUCT_FREE_SHIPPING_INFO NOTIFY_MAIN_TEMPLATE_VARS_EXTRA_PRODUCT_FREE_SHIPPING_INFO NOTIFY_MAIN_TEMPLATE_VARS_END_PRODUCT_FREE_SHIPPING_INFO NOTIFY_PRODUCT_TYPE_VARS_START_PRODUCT_FREE_SHIPPING_INFO NOTIFY_PRODUCT_TYPE_VARS_END_PRODUCT_FREE_SHIPPING_INFO NOTIFY_HEADER_START_PRODUCT_INFO NOTIFY_HEADER_END_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_START_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_PRODUCT_TYPE_VARS_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_EXTRA_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_END_PRODUCT_INFO NOTIFY_PRODUCT_TYPE_VARS_START_PRODUCT_INFO NOTIFY_PRODUCT_TYPE_VARS_END_PRODUCT_INFO NOTIFY_MAIN_TEMPLATE_VARS_START_PRODUCT_MUSIC_INFO NOTIFY_MAIN_TEMPLATE_VARS_PRODUCT_TYPE_VARS_PRODUCT_MUSIC_INFO NOTIFY_MAIN_TEMPLATE_VARS_EXTRA_PRODUCT_MUSIC_INFO NOTIFY_MAIN_TEMPLATE_VARS_END_PRODUCT_MUSIC_INFO NOTIFY_PRODUCT_TYPE_VARS_START_PRODUCT_MUSIC_INFO NOTIFY_PRODUCT_TYPE_VARS_END_PRODUCT_MUSIC_INFO NOTIFY_HEADER_START_SITE_MAP NOTIFY_HEADER_END_SITE_MAP NOTIFY_HEADER_START_UNSUBSCRIBE NOTIFY_HEADER_END_UNSUBSCRIBE
PayPal ™: NOTIFY_PAYMENT_PAYPAL_RETURN_TO_STORE NOTIFY_PAYMENT_PAYPAL_CANCELLED_DURING_CHECKOUT NOTIFY_PAYMENT_PAYPAL_INSTALLED NOTIFY_PAYMENT_PAYPAL_UNINSTALLED
Sideboxes: NOTIFY_SIDEBOX_START_EZPAGES_SIDEBOX NOTIFY_SIDEBOX_END_EZPAGES_SIDEBOX NOTIFY_HEADER_START_EZPAGES_HEADER NOTIFY_HEADER_END_EZPAGES_HEADER NOTIFY_FOOTER_START_EZPAGES_FOOTER NOTIFY_FOOTER_END_EZPAGES_FOOTER
Search: NOTIFY_HEADER_START_ADVANCED_SEARCH_RESULTS NOTIFY_SEARCH_COLUMNLIST_STRING NOTIFY_SEARCH_SELECT_STRING NOTIFY_SEARCH_FROM_STRING NOTIFY_SEARCH_WHERE_STRING NOTIFY_SEARCH_ORDERBY_STRING NOTIFY_HEADER_END_ADVANCED_SEARCH_RESULTS
EZ-Pages: NOTIFY_START_EZPAGES_FOOTERBAR NOTIFY_END_EZPAGES_FOOTERBAR NOTIFY_START_EZPAGES_HEADERBAR NOTIFY_END_EZPAGES_HEADERBAR