Web Page Templates Icons, Clipart, Logos


Hot Topics

Post Archive


Aug 04, 2009 01:15 AM EDT

X-Cart modification: adding a 2nd image upload field

X-Cart is an e-commerce package that is written in PHP with the use of Smarty tags for its template system. For about $200, it includes a lot of functionality out of the box, and you can buy prebuilt skins for another $60 or so. For those interested in SEO, there is a module called CDSEO that you can purchase by a third party that’ll change the URLs from including GET request variables to a folder style SEO friendly format for another $150 or so. After the add ons, you can have a cart up and running for about $400.

The smarty system leaves a lot to be desired, so beware that it’s going to take longer than you’d normally think if you want to skin the site yourself, especially the first time you work with X-cart. One of the biggest challenges is knowing which template to modify. X-cart helps with this by providing a “webmaster mode”, which changes the status bar to reflect the folder and template structure of a particular section of the page. It’s quite handy because many of the template files are in strange places, and there are a ton of different template files.

X-Cart also loads pages slower than you would expect from a PHP site, which might be because of Smarty templates, but I’m not certain of that.

Note: this article is referring to version 4.0. 4.1 is out now, but I’ve heard that the newer versions are somewhat unstable until they’ve been out there for a while. 4.1 hasn’t been around long enough for me to use in a production environment yet. These instructions will
likely help with 4.1 as well. Of course, you’ll need to modify them to fit the newer codebase.

One issue I’ve come across is the need to put a small thumbnail image for each product listed on the shopping cart checkout pages. Below is how I modified the code to allow a 2nd picture to be uploaded in X-Cart’s admin area. I use one upload for a 250 pixel wide picture on the product detail page, and a 70 pixel wide image on the cart checkout page.

This article is assuming that you know PHP pretty well and can either grasp the Smarty concepts easily or have a familiarity with them. If you need further explanation about Smarty, please comment and I’ll write more about that in another post.


Modifying X-cart to allow 2 picture upload fields

First, back up your x-cart files and database in case something goes wrong.

Then, modify the following files:

In include/product_modify.php:

Add this code directly below the ‘if’ block with the comment “Check if image selected is not expired”:
If that comment can’t be found, look for the same block of code except that it’s looking for an imtype of “T” instead of “S”.
The two “if” blocks could probably be combined into 1, if you’d like. Please note that as is, you can only upload one image at a time.
If you want to be able to upload both at once, you’ll need to modify the code beyond the example to handle that.

//Cart Image
if ($file_upload_data["imtype"] == "S") {

if ($file_upload_data["counter"] == 1) {

$smarty->assign("file_upload_data", $file_upload_data);
else {
if ($file_upload_data["source"] == "L")

Also in include/product_modify.php, change the # Prepare for thumbnail updating (around line 278) to this:

# Prepare for thumbnail updating
$image_posted = func_check_image_posted($file_upload_data, "T");
$cartimage_posted = func_check_image_posted($file_upload_data, "S");

$store_in = ($config["Images"]["thumbnails_location"] == "FS"?"FS":"DB");
$cartstore_in = ($config["Images"]["cartimages_location"] == "FS"?"FS":"DB");

And add this code block directly after the $image_posted “if” block:

if ($cartimage_posted) {

$cartimage_data = func_get_image_content($file_upload_data, $productid);
$row_exists = func_query_first("select * from $sql_tbl[thumbnails] where productid = '$productid'");
if ($row_exists['productid'] == "") {
db_query("INSERT INTO $sql_tbl[thumbnails] (productid, ".($cartstore_in == "FS"?"cartimage_path":"cartimage").", cartimage_type) VALUES ('$productid', '$cartimage_data[image]', '$cartimage_data[image_type]')");
} else {
db_query("UPDATE $sql_tbl[thumbnails] SET ".($cartstore_in == "FS"?"cartimage_path":"cartimage")." = '$cartimage_data[image]', cartimage_type = '$cartimage_data[image_type]' WHERE productid = '$productid'");

On skin1/main/product_details.tpl, add this text below the normal thumbnail table row:

<!-- Cart Image -->
{if $productids ne ''}<TD width="15" class="TableSubHead"> </TD>{/if}
<TD colspan="2">{include file="main/subheader.tpl" title="Small Cart Image"}</TD>

{if $productids ne ''}<TD width="15" class="TableSubHead"><INPUT type="checkbox" value="Y" name="fields[thumbnail]"></TD>{/if}
<TD class="ProductDetails" valign="top"><FONT class="FormButton">Small Image</FONT><BR>(recommended size 50x50 or smaller)</TD>
<TD class="ProductDetails">
{include file="product_cartthumbnail.tpl" productid=$product.productid product=$product.product}
<TABLE border="0" cellpadding="0" cellspacing="0" width="100%">
<INPUT type="button" value="{$lng.lbl_change_image}" onclick='javascript: if (confirm("{$lng.txt_change_image_text|strip_tags}")){ldelim}popup_image_selection("S", "{$product.productid}", "{$query_string}");{rdelim}'>
<INPUT type="button" value="{$lng.lbl_delete_image}" onclick='javascript: if (confirm("{$lng.txt_change_image_text|strip_tags}")){ldelim}self.location="product_modify.php?mode=delete_thumbnail&productid={$product.productid}"{rdelim}'>
{if $file_upload_data.file_path}
<!-- End Cart Image -->

In include/image_selection.php, add this case in the $imtype switch:

case "S":
$config_data["location"] = $config["Images"]["cartimages_location"];
$config_data["path"] = $config["Images"]["cartimages_path"];
$config_data["path_only"] = $config["Images"]["cartimages_path_only"];

Save image.php as cartimage.php, then change the code portion to the following (leave the x-cart license comment stuff alone):
Also note that I’ve included <?php even though it shows up above the comments. Of course, you only need this in one spot.

require "./top.inc.php";
require "./config.php";

if (empty($productid)) $productid = "";

$image_out = ""; $image_type = ""; $image_path = "";

if (!empty($tmp)) {


if (!empty($file_upload_data["file_path"]) && $file_upload_data["id"]==$productid && $file_upload_data["imtype"]=="S") {
$image_out = func_file_get($file_upload_data["file_path"], true);


if (empty($image_out)) {

$result = db_query("SELECT cartimage as image, cartimage_path as image_path, cartimage_type as image_type FROM $sql_tbl[thumbnails] WHERE productid='$productid' AND variantid = '$variantid'");
$result = db_query("SELECT cartimage as image, cartimage_path as image_path, cartimage_type as image_type FROM $sql_tbl[thumbnails] WHERE productid='$productid' AND variantid = ''");

if (db_num_rows($result)) {
list($image, $image_path, $image_type) = db_fetch_row($result);

if ($image == "") {
header("Content-type: image/gif");
func_readfile($default_image, true);
} else {
header("Content-type: image/gif");
func_readfile($default_image, true);
//echo "Image: " . $image_type;


if ($config["Images"]["thumbnails_location"] == "DB") {
if (!empty($image))
$image_out = $image;
$no_image_db = true;

if ($config["Images"]["thumbnails_location"] == "FS" || !empty($no_image_db)) {
if (!empty($image_path)) {
header("Content-type: $image_type");
func_readfile($image_path, true);


if (!empty($image_out)) {
header("Content-type: $image_type");
echo $image_out;
} else {
header("Content-type: image/gif");
func_readfile($default_image, true);

Create a new file called skin1/product_cartthumbnail.tpl, and put this code in it:

{* $Id: product_cartthumbnail.tpl,v 1.14 2007/09/14 09:53:29 max Exp $ *}
{if $config.Appearance.show_thumbnails eq "Y"}
<IMG id="{$id}" src="{if $tmbn_url}{$tmbn_url}{else}{if $full_url}{$http_location}{else}{$xcart_web_dir}{/if}/cartimage.php?productid={$productid}{if $file_upload_data.file_path}&tmp=y{/if}{/if}" alt="{$product|escape}" border="0">

In include/func.php, in the func_get_image_content function, add this to the $file_upload_data[”imtype”] switch:

case "S":
$config_data["location"] = $config["Images"]["cartimages_location"];

In the database:

Modify xcart_thumbnails (assuming you used the prefix “xcart” when installing it, otherwise modify the table with the appropriate prefix)
to include the following fields:

cartimage mediumblob allow nulls
cartimage_path varchar(255) allow nulls
cartimage_type varchar(64) allow nulls

In xcart_config, add the following rows (modify the table name if you used a different prefix other than xcart):

INSERT INTO xcart_config (name, comment, value, category, orderby, type, defvalue)
values ('cartimages_location', 'location of small cart images', 'DB', 'Images', '130', 'text', 'DB')

INSERT INTO xcart_config (name, comment, value, category, orderby, type, defvalue)
values ('cartimages_path', 'FS junk - not needed', '', 'Images', '140', 'text', '')

INSERT INTO xcart_config (name, comment, value, category, orderby, type, defvalue)
values ('cartimages_path_only', 'FS junk - not needed', 'N', 'Images', '150', 'checkbox', 'N')

After that, test it and see if everything works. If not, you’ll need to troubleshoot the code to see where you missed something.

Good Luck,

Darren xcart | php | cdseo
Aug 04, 2009 01:06 AM EDT

X-Cart Image Upload error

In x-cart, we couldn’t upload an image because the form gave us an error. After a lot of troubleshooting, here’s what we found to make the upload script work:

We made sure these folders and their subfolders had ‘write’ (777) permissions set:
1. /templates_c
2. /files
3. /log

Also, we made sure the directory set in the PHP configuration option ‘upload_tmp_dir’ (in the php.ini file) had the permissions set to 777.

Pretty easy fix. Where we got tripped up was the fact that the log folder had to have write permissions. Why that is related to the image files, I’ll never know!

Darren xcart
Aug 04, 2009 12:30 AM EDT

X-cart 4.1 multiple monthly payments module

This is more of a set of modifications rather than an actual module, but the end result is the same.

First thing you’ll need to do is backup your existing site and database. I’d recommend using a test install of Xcart so that nothing in production gets messed up. With that in mind, the first step is to alter the pricing table by using the following alter table command. If you have a different version of MySQL, you might need to tweak this a bit.

ADD COLUMN `paymentprice` DECIMAL(12,2) NOT NULL DEFAULT 0 AFTER `numpymnts`,
ADD COLUMN `sourceproductcode` VARCHAR(255) DEFAULT 0 AFTER `paymentprice`,
ADD COLUMN `price_override` SMALLINT(5) UNSIGNED NOT NULL DEFAULT 0 AFTER `mastervariant`,
ADD INDEX `numpymnts`(`numpymnts`),
ADD INDEX `paymentprice`(`paymentprice`),
ADD INDEX `sortby`(`sortby`),
ADD INDEX `sourceproductcode`(`sourceproductcode`),
ADD INDEX `mastervariant`(`mastervariant`),
ADD INDEX `price_override`(`price_override`)

The new columns are as follows:
numpyments = number of payments
paymentprice = price the export expects to see (might be one payment or the total)
sourceproductcode = product code (sku) that export expects to see
sortby = the order in which the variants show up on the admin page
mastervariant = overrides the ’starting at’ price
price_override = use this table for the price instead of the orders table for reporting

Next, you’ll need to modify some of the admin template files, such as:

Modify Files:
/skin1/modules/Product_Options/product_variants.tpl - add fields to the variants html table - don’t add the price_override column.

/modules/Product_Options/func.php - edit func_get_product_variants and add in the columns that were added to the product_variants.tpl file

When you submit the variants, the form goes to:

mode = product_variants_modify
productid = [variable]
submode = “data”
geid = “”

Once sumbitted, the code is run in this ELSEIF block in modules/Product_Options/product_variants.php:
} elseif ($mode == ‘product_variants_modify’ && $vs && $submode != ‘prices’) {

In here, you need to edit the $query_price_data array to include the additional fields; for example:

## BB Edit - added additional fields
$query_price_data = array(
"price" => $v['price'],
"variantid" => $k,
"productid" => $productid,
"quantity" => 1,
"membershipid" => 0,
"numpymnts" => $v['numpymnts'],
"paymentprice" => $v['paymentprice'],
"sortby" => $v['sortby'],
"sourceproductcode" => $v['sourceproductcode'],
"mastervariant" => $v['mastervariant']

Next, you need to edit the modify options page, otherwise, if you change options, it’ll remove your new field data.

When submitting this form, it passes these variables to product_modify.php:

classid= your classid
productid = your productid

If you change add[is_modifier] (price modifier = ‘y’, else it’s blank), it rebuilds the variants by calling func_rebuild_variants in modules/Product_Options/func.php

//Rebuild variants: . . . . product_modify.php?productid=18&section=options&classid=71

In func_rebuild_variants, change the $_product[’prices’] $data variable to:

$data = array(
"productid" => $productid,
"quantity" => $p['quantity'],
"membershipid" => $p['membershipid'],
"variantid" => $variantid,
"price" => $p['price'],
"numpymnts" => $p['numpymnts'],
"paymentprice" => $p['paymentprice'],
"sortby" => $p['sortby'],
"sourceproductcode" => $p['sourceproductcode'],
"mastervariant" => $p['mastervariant']

This will keep your data from being lost in the new columns. And that’s it, as far as back end functionality for the multi pay option. Depending on how your templates are set up, you’ll probably want to use the new columns to force the “mastervariant” column to show up in the “starting at” price. Do this by ordering that query by mastervariant in descending order. The rest of the columns really come in handy when you need to see the full price such as in reports, modifying omniture code, and to produce export files where the fulfillment company wants to see the full amount instead of the per payment price.

Darren xcart | data backup | database | mysql | ecommerce
Aug 04, 2009 12:12 AM EDT

Xcart 4.1 and CDSEO module creates bugs in the Review module

Xcart is a fairly popular e-commerce shopping cart program, and one of the add-on modules that you can buy from a third party company is called CDSEO. This rewrites all of the links to be SEF using a folder-style syntax instead of the regular ?variable=value syntax.

However, it causes some problems with X-Cart. One such problem is the Review Product form on the product detail page (product.php).

To fix this bug, you need to add hidden fields to the form instead of having them inside the form’s “action”.

In other words, change:

<form method=”post” action=”/product.php?mode=review&productid={$product.productid}” id=”reviewform”>


<form method=”post” action=”/product.php?productid={$product.productid}” id=”reviewform” method=”post”>
<input type=”hidden” name=”productid” value=’{$product.productid}’ />
<input type=”hidden” name=”mode” value=”review” />

Next, you’ll need to edit vote.php at the document root of your Xcart install and add a slash at the beginning of the link.

So change:




This is because the CDSEO module creates a pseudo-directory and thus your browser thinks that it’s in that folder and tries to redirect you to the wrong path.

Darren xcart | bugs
Displaying all 4 posts

Online Information for Geeks





Resource Links