One Way to Use WordPress as a Shopping Cart
January 9, 2009Alrighty then! So I just finished up a site (subcontract, so unfortunately I can’t share it) where we started to code out the site in ZenCart, but ended up plopping it into WordPress. ZenCart seemed a little too powerful for the job, and the client was very familiar with WordPress. Plus they wanted a really specific design, and in the timeframe I was given, there was no way I could pull it off in ZenCart – but in WordPress I could.
So what I did was write some custom functions for the client to use. They typically use PayPal, but for this job, they decided maybe Mal’s was a better option – the main reason? Because when you set up products in PayPal, you have to create them one at a time within the PayPal interface, and then copy and paste the generated code where you need it.
Now, in all honesty, I don’t know if that’s necessarily true. I did do a site where a client wanted to use PayPal in the past – and she had three products. However, it was last year, so I don’t recall the exact method in getting them on her site. I vaguely recall it being like this, but I could have sworn most of the code was exactly the same for each product, and I just had to change the price and product name. But I could be wrong (if anyone knows if I’m right or wrong, please tell me…because if I’m right, then this tutorial WILL work for PayPal as well, with slight modifications).
So, with Mal’s, it doesn’t matter – basically you get a user ID, and that’s what gets things into *your* account. Then you slap some customizable code wherever you want, however often you want onto your site, and bam – your site is a shopping cart. It’s pretty nice, actually. Now, you must remember though – Mal’s allows unlimited items in your cart… but only if they are physical items. If they are downloadables, you are limited to 50 – then you have to upgrade your account. This is why it worked so well for my client – it was a site for a brick-and-mortar shop he runs – he just wanted to have online sales in addition to the regular ones.
All that information aside, here’s what I did. Somehow, I found this awesome tutorial from Function on how to add custom write panels to your admin area. This thing is so unbelievably great that it’s now a standard function I add to all the themes I create. In essence, it just makes using Custom Fields pretty much foolproof and more automated. It’s downright kick-ass. So you should probably read this article to get the basics down so you understand what’s going on there. For this tutorial, we’re heavily modifying these custom write panels – they’re just the beginning of what we need to do. I’m just going to assume (for the rest of this tutorial) that you “get it” and are ready to turn your WordPress site (or even just a category) into a shopping cart area.
So we’ll start with Mal’s. (If you don’t have an account, get one. It’s free. I have one (I got it for this client so I could familiarize myself with it) and it’s been about 3 months now, and I have yet to get a lick of spam from them. ) So log into your account, and the image you see here is what you’ll see when you log in. If you look, you’ll see in the top left-hand corner is your user ID – it’s also the username you log in with. And no, that’s not really my user ID – I made it up. But you get the point. You need to know that number for later purposes.
While we’re here, I’m going to show you some other stuff you might want to see, because they’ll help you understand what I’m doing. So go to “Support” (in the very top right) and the first link you see is “Creating Buy Now buttons”. if you click that, a submenu appears, which gives you all kinds of options for buttons and link code you can use so people will buy your stuff. (You might want to take a moment to look through these things so you can see where I’m coming from later – a lot of these variables are what I’ll be using for the custom fields we’re putting in, and it’s good to know what they are being used for.)
Now that we’ve looked at the variables I’ll be using (and what they are for) I’ll tell you this: I’m not going to share how to set up your Mal’s cart. That’s something else entirely. This is going to assume you have an account, you have everything in Mal’s set up how you want, you understand what all those button variables are, and you’re ready to add it to your WordPress site. So let’s get to it.
We’ll start with the seriously customized Custom Fields. Open up your functions.php file (wp-content/themes/YOUR THEME/functions.php – if you don’t have one, make one. No biggie.) and add in the following:
// begin array to create the new write areas
$new_meta_boxes =
array(
"image" => array(
"name" => "image",
"std" => "",
"title" => "Product Image",
"description" => "Enter full path to image here."
),
"price" => array(
"name" => "price",
"std" => "",
"title" => "Product Price",
"description" => "Only numbers and periods! DO NOT ENTER \"$\"!"
),
"size" => array(
"name" => "sizes",
"std" => "",
"title" => "Available Sizes",
"description" => "Enter comma-separated values. (ex: \"Small, Medium, Large\")"
),
"colors" => array(
"name" => "colors",
"std" => "",
"title" => "Available Colors",
"description" => "Enter comma-separated values. (ex: \"Red, White, Blue\")"
),
"catalog" => array(
"name" => "catalog",
"std" => "",
"title" => "Catalog Number",
"description" => "Enter catalog number here."
),
"cannotbuy" => array(
"name" => "cannotbuy",
"std" => "",
"title" => "Cannot Purchase Online",
"description" => "If this is an item that is not allowed to be sold online, type in \"yes\" or \"y\"."
),
"sale" => array(
"name" => "sale",
"std" => "",
"title" => "Sale Price",
"description" => "Enter in a dollar amount or percentage off - be sure to include the \"$\" or \"%\" symbols."
),
"quantity" => array(
"name" => "quantity",
"std" => "",
"title" => "Quantity in Stock",
"description" => "Enter in a value for how many items you have in stock."
)
);
// build HTML input fields from the arrays above
function new_meta_boxes() {
global $post, $new_meta_boxes;
foreach($new_meta_boxes as $meta_box) {
$meta_box_value = get_post_meta($post->ID, $meta_box['name'] . '_value', true);
if($meta_box_value == "")
$meta_box_value = $meta_box['std'];
echo '<input type="hidden" name="' . $meta_box['name'] . '_noncename" id="' . $meta_box['name'] .'_noncename" value="' . wp_create_nonce( plugin_basename(__FILE__) ) . '" />';
echo '<p style="font-size:1.1em; color:#999; margin-bottom:0; padding-bottom:0;">' . $meta_box['title'] . '</p>';
echo '<input type="text" name="' . $meta_box['name'] . '_value" value="' . $meta_box_value . '" /><br />';
echo '<p style="font-style:italic; color:#999; margin-top:0; padding-top:0;"><label for="' . $meta_box['name'] . '_value">' . $meta_box['description'] . '</label></p>';
}
}
// create the meta boxes
function create_meta_box() {
global $theme_name;
if ( function_exists('add_meta_box') ) {
add_meta_box( 'new-meta-boxes', 'Extra Post Information', 'new_meta_boxes', 'post', 'normal', 'high' );
}
}
// save the data entered
function save_postdata( $post_id ) {
global $post, $new_meta_boxes;
foreach($new_meta_boxes as $meta_box) {
// Verify
if ( !wp_verify_nonce( $_POST[$meta_box['name'] . '_noncename'], plugin_basename(__FILE__) )) {
return $post_id;
}
if ( 'page' == $_POST['post_type'] ) {
if ( !current_user_can( 'edit_page', $post_id ))
return $post_id;
} else {
if ( !current_user_can( 'edit_post', $post_id ))
return $post_id;
}
$data = $_POST[$meta_box['name'] . '_value'];
if(get_post_meta($post_id, $meta_box['name'] . '_value') == "")
add_post_meta($post_id, $meta_box['name'] . '_value', $data, true);
elseif($data != get_post_meta($post_id, $meta_box['name'] . '_value', true))
update_post_meta($post_id, $meta_box['name'] . '_value', $data);
elseif($data == "")
delete_post_meta($post_id, $meta_box['name'] . '_value', get_post_meta($post_id, $meta_box['name'] . '_value', true));
}
}
add_action('admin_menu', 'create_meta_box');
add_action('save_post', 'save_postdata');
Yeah, it’s a lot, I know. But those are the wonderful custom fields for your admin area (based – again – off Function’s tutorial, I’ve just modified everything for the purposes of what we’re doing… so it’s not as simple as his example!) So what I’ve done is added several fields – for the image, price, sizes, colors, etc. Once you’ve saved this, upload it to your theme folder and open up your WordPress back-end and go to “Write Post” – you’ll see all these lovely little custom fields beneath your “write” area – ready and waiting to be utilized.
Now, what are we going to DO with these fields? Right now, you can enter in whatever you want, and all it’ll do is save your crap to the database and take up space. Doesn’t do much, you know. So let’s put them to work.
What we need to do is query the database, and grab all that custom field information, and pull it all out as variables. Since we’re setting up variables, you’ll also need to grab the stuff you need to connect to your Mal’s account, like the URL Mal’s sends you in the welcome email (it usually looks like ww**.aitsafe.com/something/add.cfm”, where the ** are numbers that are attributed to your account, and the “something” is the rest of the url they give you.) You also need the “review” URL (which is the same as the first one, but ends in “review.cfm”) and your login/user/account name.
So next in your functions.php file, you need to add:
function product_display($type) {
global $post;
$malsURL = 'MALS URL HERE';
$malsviewURL = 'MALS REVIEW URL HERE';
$malsID = 'MALS ACCOUNT NAME HERE';
$returnURL = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
$title = get_the_title();
$catalog = get_post_meta($post->ID, 'catalog_value', true);
$image = get_post_meta($post->ID, 'image_value', true);
$price = get_post_meta($post->ID, 'price_value', true);
$sizes = get_post_meta($post->ID, 'sizes_value', true);
$colors = get_post_meta($post->ID, 'colors_value', true);
$inperson = get_post_meta($post->ID, 'cannotbuy_value', true);
$sale = get_post_meta($post->ID, 'sale_value', true);
$stock = get_post_meta($post->ID, 'quantity_value', true);
Now we have everything we need set up as a variable, ready to be used as we see fit. Our first issue to work around is this: What if something’s on sale? or has a coupon? So let’s put in a bit of code that does the math for us. This snippet will take the price we’ve entered in our custom fields, and IF we put in a discount (be it a percentage or a dollar discount) this little puppy will do the math and output the correct price.
// set values for price - if dollar amount off or percentage off for sale pricing
if($sale != '') {
if(stristr($sale,'%')) {
$percentage = str_replace('%','',$sale);
$percentprice = round($price - ($price * ($percentage/100)),2);
$saletag = $percentage . "% off!";
$sale = '<input type="hidden" name="price" value="' . $percentprice . '">';
} else if(stristr($sale,'$')) {
$dollaroff = str_replace('$','',$sale);
$dollarprice = round($price - $dollaroff,2);
$saletag = "$" . $dollaroff . " off!";
$sale = '<input type="hidden" name="price" value="' . $dollarprice . '">';
}
}
Next – what if we have stock levels? We have a field available to enter in the stock level of our item. For now, unfortunately (and this is the only caveat we have to this tutorial) you have to do the stock levels manually. I still haven’t quite figured out the callback method so this will be reduced automatically when someone makes a purchase. But I’m working on it! But the manual method works (and when I figure out the callback, it’ll just work better), and it’s doable for now. What this does is, if the stock is low, it’ll put up a warning to “grab them before they’re gone,” and if you’re out, then it’ll say “Out of Stock.”
// let's check the stock levels
if($stock != '') {
if($stock == '0') {
$stocklevel = 'We\'re sorry. We are currently Out of Stock on this product. If you\'d like to place a back-order, or for more information, please call us at xxx-xxx-xxxx.';
} else if($stock <= '5' && $stock > '0' ) {
$stocklevel = 'Only '. $stock . ' of these items are left in stock. Grab \'em before they\'re gone!';
}
}
Now, the biggie. What if you have 10 blue shirts, size XL in your store, but you’r completely out of small blue shirts? How would you differentiate? Well that’s where this bit comes in. What it’ll do is check to see if a color is out of stock – if it is, it won’t display the dropdown attribute option for that color. If a size is out of stock, it’ll do the same. And the super-awesome thing is it’ll also check for both. So if you’re out of small blue shirts (but you have small red shirts) it’ll still display the red ones.
// create option values if sizes and/or colors are set
if(($sizes != "") && ($colors == "")) {
$optionValues .= '<select name="product[]">' . "\n";
$getallsizes = explode(", ",$sizes);
$count = count($getallsizes);
for($i=0;$i<$count;$i++) {
$optionValues .= '<option value="' . $title . ' ' . $getallsizes[$i] . '">' . $title . ' ' . $getallsizes[$i] . '</option>' . "\n";
}
$optionValues .= '</select>' . "\n\n";
}
if(($colors != "") && ($sizes == "")) {
$optionValues .= '<select name="product1[]">' . "\n";
$getallcolors = explode(", ",$colors);
$count = count($getallcolors);
for($i=0;$i<$count;$i++) {
$optionValues .= '<option value="' . $title . ' ' . $getallcolors[$i] . '">' . $title . ' ' . $getallcolors[$i] . '</option>' . "\n";
}
$optionValues .= '</select>' . "\n\n";
}
if(($colors != "") && ($sizes != "")) {
$optionValues .= '<select name="product1[]">' . "\n";
$getallcolors = explode(", ",$colors);
$getallsizes = explode(", ",$sizes);
$countsizes = count($getallsizes);
$countcolors = count($getallcolors);
$total = ($countcolors*$countsizes);
if($countsizes>$countcolors) {
for($i=0;$i<$countcolors;$i++) {
foreach($getallsizes as $gs) {
$optionValues .= '<option value="' . $title . ' ' . $getallcolors[$i] . ' ' . $gs . '">' . $title . ' ' . $getallcolors[$i] . ' ' . $gs . '</option>' . "\n";
}
}
} else if($countsizes<$countcolors) {
for($i=0;$i<$countsizes;$i++) {
foreach($getallcolors as $gc) {
$optionValues .= '<option value="' . $title . ' ' . $gc . ' ' . $getallsizes[$i] . '">' . $title . ' ' . $gc . ' ' . $getallsizes[$i] . '</option>' . "\n";
}
}
}
$optionValues .= '</select>' . "\n\n";
}
Now, the final bit. When you’re doing a category listing, you don’t want the full descriptions and such to show up in the page. Usually, you just want maybe an image, a price and a name, and have it link to the actual full product description. So we’re going to make our function differentiate between the two so we can have the best of both worlds. This is the part where, on the category page, it’ll just show the title and image. On the actual post page, it’ll have everything – attributes, price, description, and the necessary buttons to purchase. The fill post version also takes all of this stuff we did above, and compiles it together to make the loveliness that is a Mal’s shopping cart.
if($type == 'full') { ?>
<small>Catalog ID: <?php echo $catalog; ?></small>
<h3>$<?php echo $price; ?></h3>
<?php if($sale != '') { ?>
<p class="alert"><?php echo $saletag; ?></p>
<?php }
if($stock != '') { ?>
<p class="alert stock"><?php echo $stocklevel; ?></p>
<?php } ?>
<?php if($inperson != "") { ?>
<p class="cantbuy">In-store purchase only. For questions call xxx-xxx-xxxx.</p>
<?php } ?>
<div class="image">
<img src="<?php echo $image; ?>" alt="" />
</div>
<?php the_content(); ?>
<hr class="clear" />
<div class="buttons">
<form id="buy_now" method="post" action="<?php echo $malsURL; ?>">
<input type="hidden" name="userid" value="<?php echo $malsID; ?>">
<input type="hidden" name="product" value="<?php echo $title; ?>">
<?php echo $optionValues; ?>
<input type="hidden" name="return" value="">
<?php if($sale != '') {
echo $sale;
} else { ?>
<input type="hidden" name="price" value="<?php echo $price; ?>">
<?php } ?>
<input type="image" class="button" src="<?php bloginfo('template_directory') ?>/images/buy-now<?php if($stock == '0' || $inperson != '') { echo '-disabled'; }?>.gif" value="BUY NOW!"<?php if($stock == '0' || $inperson != '') { echo ' disabled'; }?>>
</form>
<form id="view_cart" method="post" action="<?php echo $malsviewURL; ?>">
<input type="hidden" name="userid" value="">
<input type="hidden" name="return" value="">
<input type="image" class="button" src="/images/view-cart.gif" value="View Cart">
</form>
</div>
<?php } else if($type == 'summary') { ?>
<p><a href="<?php echo $image; ?>"><img src="<?php echo $image; ?>" class="thumbnail" title="Click to View Larger Image" alt="" /></a></p>
<p>$<?php echo $price; ?></p>
<?php }
}
Now, a couple of things to note:
- You can use ANY currency for this. You’ll notice that I made the “$” the standard, but all you have to do is replace it in a couple of spots with whatever country currency you want to use. Even the custom fields for the prices and discounts are numbers only – the actual currency type is standardized with the function. You just have to be sure that whatever you use for currency, you have set up your Mal’s cart to reflect that same currency.
- There is minimal styling in place in this code.I try to keep my code as style-free as possible, but in this case, you really need to automate it. Of course you can change the HTML as you please. Right now, it’s set up to use images for the submit buttons. Feel free to upload your own images to your themes images folder, or just swap that out to whatever.
- This could quite possibly work with PayPal (or other carts I’m not aware of). Like I said, I’m not quite sure if PayPal is like Mal’s, where almost all the code is exactly the same, save the name, price and whatnot. If it is, then you could easily convert this to PayPal – because all this is doing is basically entering dynamic values into a small piece of default code. You just need to know what that code is, and I’m sure you could swap this out for pretty much anything.
- I’ve set redirects in this too. One thing I hate is when I go to a shopping cart, add something to purchase, and then I want to see my cart status so I click on the button to view it. When I’m done, and I return to the site, it takes me to the home page of the site. I HATE THAT. I hate it almost as much as when you go to a site and a midi version of some song you want to forget is playing automatically at full volume with no way to turn it off. It hate it so much it’s actually a reason I abandon shopping carts. So I’ve put in a redirect – if you are an a product page and click the “view cart” button, this code will redirect you right back to the page you left from when you come back.
Now, we need to actually implement this. So you want to open up your category.php file (or if it’s a specific category, name it properly to reflect that you’re creating a template for your cart categories) and add in the necessary code to display your function output. Are you ready? Now, within the Loop, in the “entry” area…you want to put in the following:
<?php product_display(’summary’); ?>
BAM. That’s it.
Now, open up “single.php”, and within the Loop, where you want the content to show (normally, where the_content(); is) pop in:
<?php product_display(‘full’); ?>
Now, any time you want to add in a product to your cart, you just write a normal post. Use the write are to put in your description of the product (images are not necessary, unless you want additional ones). In the custom write fields, just put in the ones you want content for – price, discounts, any attributes. Make sure you’ve got it in the category you want, and publish. There you go – you’ve just added a product to your new WordPress/Mal’s shopping cart.
By the way – if you want it a little easier, here’s the full function file for your stealing pleasure. All I ask is that you leave the credits (that are in the code) in there. And if you’d like to post a link back to me, that’s cool too.










P.O. Box 46
Hi!
Your post is exactly what I’ve been looking for: a simple, yet powerfull way to display products on Wordpress. With this I can make use of my little experience styling Wordpress themes and make product catalogs for my clients!
My only problem is…
I’ve copied the whole “functions.php” file into a new, almost blank theme. I’ve then created a post using the beautiful Custom Fields.
But I can’t get the product content to display!
I’ve copy-pasted the in the single.php AND in the index.php files… but nothing shows up!
Is there something more to it?
Thanks!
No, there’s nothing more to it. What you see above should work. Did you copy the functions from the link at the bottom? Did you check your error logs to see if anything’s reported error-wise? I can’t really say what the problem is, since there’s not much to go on.
An alternative you might want to use is the plugin I’ve developed based on this tutorial. It’s still not finished, but I did do a beta release. Feel free to download it and give it a try.