Zencart + Ajax made easy (part 2)
This is the second part of the series “Zencart + Ajax made easy”, you can read the previous part here
In this second part we will continue to focus on the server-side code, we start by addressing how we should handle Zencart’s default redirection method, and then we will see how we can process only blocks of code we want to return while skipping the rest.
Redirect me not
If you call Zencart’s default pages “ajax-ically”, the first problem you will run into would be zen_redirect. Take a look at the file includes/modules/pages/contact_us/header_php.php for example, around line 65 you will find this:
Lets see what this zen_redirect() function does:
* Redirect to another page or site
* @param string The url to redirect to
*/
function zen_redirect($url) {
global $request_type;
// Are we loading an SSL page?
if ( (ENABLE_SSL == true) && ($request_type == 'SSL') ) {
// yes, but a NONSSL url was supplied
if (substr($url, 0, strlen(HTTP_SERVER . DIR_WS_CATALOG)) == HTTP_SERVER . DIR_WS_CATALOG) {
// So, change it to SSL, based on site's configuration for SSL
$url = HTTPS_SERVER . DIR_WS_HTTPS_CATALOG . substr($url, strlen(HTTP_SERVER . DIR_WS_CATALOG));
}
}
// clean up URL before executing it
while (strstr($url, '&&')) $url = str_replace('&&', '&', $url);
// header locates should not have the & in the address it breaks things
while (strstr($url, '&')) $url = str_replace('&', '&', $url);
header('Location: ' . $url);
zen_exit();
}
Obviously, if we leave it that way, then when this page is called “ajax-ically”, the redirection will not have the expected affect, so we need to:
- Redirect normally if the page is not called via Ajax method
- Otherwise, we tell the client-side “listener” that a redirection is to be executed.
So I had to replace the above zen_redirect call by”
Our redirect() method will check if the page is being called “ajax-ically” or not and perform appropriate action based on that.
if($this->status){
Json::setJsonAndExit(array('status' => 'redirect', 'url' => $url,'redirect_type' => $redirect_type, 'content' => '', 'id' => $id));
}
else
zen_redirect($url);
}
You will notice 2 additional params: $redirect_type and $id there, we will re-visit this later to see why we need them.
Return me not
One of the reasons why we use Ajax is that we don’t want to reload everything. For example, when I submit the contact us form, I only expect to see the center column being updated with success/error message. The header, footer, sideboxes should stay the same.
So how do we do that? I decided that we may break the content into multiple blocks, each block may also contain multiple sub-blocks.
My index.php, for example, now looks like this:
$language_page_directory = DIR_WS_LANGUAGES . $_SESSION['language'] . '/';
$directory_array = $template->get_template_part($code_page_directory, '/^header_php/');
foreach ($directory_array as $value) {
require($code_page_directory . '/' . $value);
}
if($Ajax->startBlock('head')){
require($template->get_template_dir('html_header.php',DIR_WS_TEMPLATE, $current_page_base,'common'). '/html_header.php');
$Ajax->endBlock();
}
require($template->get_template_dir('main_template_vars.php',DIR_WS_TEMPLATE, $current_page_base,'common'). '/main_template_vars.php');
$directory_array = $template->get_template_part(DIR_WS_MODULES . 'pages/' . $current_page_base, '/^on_load_/', '.js');
foreach ($directory_array as $value) {
$onload_file = DIR_WS_MODULES . 'pages/' . $current_page_base . '/' . $value;
$read_contents='';
$lines = @file($onload_file);
foreach($lines as $line) {
$read_contents .= $line;
}
$za_onload_array[] = $read_contents;
}
$directory_array=array();
$tpl_dir=$template->get_template_dir('.js', DIR_WS_TEMPLATE, 'jscript/on_load', 'jscript/on_load_');
$directory_array = $template->get_template_part($tpl_dir ,'/^on_load_/', '.js');
foreach ($directory_array as $value) {
$onload_file = $tpl_dir . '/' . $value;
$read_contents='';
$lines = @file($onload_file);
foreach($lines as $line) {
$read_contents .= $line;
}
$za_onload_array[] = $read_contents;
}
// set $zc_first_field for backwards compatibility with previous version usage of this var
if (isset($zc_first_field) && $zc_first_field !='') $za_onload_array[] = $zc_first_field;
$zv_onload = "";
if (isset($za_onload_array) && count($za_onload_array)>0) $zv_onload=implode(';',$za_onload_array);
//ensure we have just one ';' between each, and at the end
$zv_onload = str_replace(';;',';',$zv_onload.';');
// ensure that a blank list is truly blank and thus ignored.
if (trim($zv_onload) == ';') $zv_onload='';
if($Ajax->startBlock('body')){
require($template->get_template_dir('tpl_main_page.php',DIR_WS_TEMPLATE, $current_page_base,'common'). '/tpl_main_page.php');
$Ajax->endBlock();
}
?>
end();?>
Please note that I skipped out several parts in the file and just post the important parts. Why did I have to put this in the index.php? It may not be the best place, but it is the easiest place that I can do the least edits and still able to “catch” the big 3 blocks (“head”, “body”, “foot”).
Zen 1.4 which is due soon seems to change the structure of index.php, and we will see if we can somehow put these “calls” somewhere better.
Similarly, in your common/tpl_main_page.php you can break the content into “rightColumn”, “leftColumn”, “centerColumn”, … And if you want you can also break those sub-blocks into even smaller blocks. Now that you have broken them into blocks, you have to tell $Ajax the structure of your blocks:
If your structure is consistent throughout the site (at least for the main blocks), the “call” can be placed somewhere that will always be loaded, includes/init_includes is a good place for that.
And now to specify the blocks you want to return:
Since you may want to return different blocks depending on the page, you may want to place this in the header_php.php file which is called at the beginning of each page. For our contact_us page, that file is located in includes/modules/pages/contact_us/
And that’s it part 2, let me know if you have any question.
Related posts:
- Zencart + Ajax made easy (part 3) As an update to the long delayed series Zencart Ajax...
- Zencart + Ajax made easy (part 1) In the first part, I will address several server-side isses...
- Zencart Ajax Checkout In our continuous effort to help shop owners convert more...



How would this work with zen cart admin? e.g. if you wanted to speed up zen cart’s admin from continuously refreshing the page in things like using catgories or the layout controller by using ajax? is that possible?? could you just put your code in the index.php on the admin side??
It can certainly work with the admin side, however you have to remember that Zen’s backend does not have every page loaded through the index.php file just like the frontend.
We will probably have to insert the code into application_top and application_bottom in this case. Right now I’m waiting for Zen 2.0 to see if there is any change on the backend’s file structure.
Yes, admin is definitely tough. I’m trying to use your tutorial to work out how to do a simple admin page with ajax – creating a layout controller that doesn’t refresh every time you look at something as an example. Put your ajax class into admin/includes/classes/ajax.php and then $Ajax->start(); and Ajax->end() into application_top and application_bottom in admin. But get php fatal errors and can’t even log into admin when that happens.
Will you be doing an ajax admin tutorial as part of this series?
Also, is there a forum section for using ajax with zen cart? This blog seems to be the only place it is being tackled as a subject.
Really appreciate the help you are putting into helping and educate the rest of us.
Hi Bob,
This tutorial still has several parts to come, at least 2. After that I will tackle the admin part. I have been pretty busy playing with the Ajax Check Out for ZenCart as well.
With Jquery included by default in Zen 2.0, you can be sure that more and more Ajax contributions for ZenCart will be made by everyone.
In the continuous effort to help our clients convert from leads to sale, we have been developing an Ajax checkout module for Zencart that makes the checkout process more “seamless”, we will soon introduce the demo of this module to you within a few days. You can subscribe to our newsletter on our homepage to get the notified as soon as it comes out.
is the tutorial code available as yet?