Show Shipping Method elsewhere on invoice.php

In the standard osCommerce invoice page, the shipping method and cost is shown in the order_totals, as below;

You can see that this order used “Flat Rate (Best Way)”…

On the official osCommerce forum, Tony asked;

I wish to add the shipping/postal method selected during checkout as part of the delivery label. Does anybody know the code to do this?

I am using integrated label paper (the paper with a sticker attached which I peel off with the delivery address) and have got everything else I want to display on the label (OID, Shipping Address, Return Address).

My answer was;

Stored in order_totals table of database, so easiest way would be to create a function that gets the value of text based on order_id and ot_shipping. Sounds complicated but should be straightforward once you dig in.

The asked found a solution, but it’s a horrible way;

[php]for ($i = 0, $n = sizeof($order->totals); $i < $n; $i++) { if ($order->totals[$i][‘code’] == ‘ot_shipping’) {
$myshipping = $order->totals[$i][‘title’];
echo $myshipping;[/php]

Which is iterating through all the order_totals in order to match “ot_shipping” and then display it. OK, so, it works fine and is not causing much overhead. But so ugly!

Here’s a piece of code I just cooked up which gets the shipping method;

Step 1. Add this to /admin/includes/functions/general.php

[php]function clubosc_get_shipping_method($oID) {
$shipping_query = tep_db_query(“select title from ” . TABLE_ORDERS_TOTAL . ” where class=’ot_shipping’ AND orders_id = ‘” . (int)$oID . “‘”);
$shipping_value = tep_db_fetch_array($shipping_query);
return substr($shipping_value[‘title’], 0, -1);

Step 2. Add this whereever you want in admin/invoice.php


For this blog post, let’s add it near the “Payment Method” line of text, so do this:


info[‘payment_method’]; ?>


Step 3. Add this to admin/includes/languages/english/invoice.php

[php]define(‘ENTRY_SHIPPING_METHOD’, ‘Shipping Method:’);[/php]

Save all files and upload. This are of your invoice should now look like this:

Easy as 123. Or is it?

Deconstructing the code

[php]function clubosc_get_shipping_method($oID)[/php]
Simply a name, and a variable to pass through.

[php] $shipping_query = tep_db_query(“select title from ” . TABLE_ORDERS_TOTAL . ” where class=’ot_shipping’ AND orders_id = ‘” . (int)$oID . “‘”);
$shipping_value = tep_db_fetch_array($shipping_query); [/php]

Grabbing the correct data from the database. In this case scanning the orders_total table for the text column that has column values of the “order_id” and where the class text is “ot_shipping”.

[php] return substr($shipping_value[‘title’], 0, -1);[/php]

Showing the data on the page, without the ending “:” – this is necessary as the actual textual methos of shipping is “Flat Rate (Best Way):” – obviously we don’t want to show the end colon!

Yes, it is as easy as 123!

Automatic Coupon Code for Existing Buyers (via admin/invoice.php)

Chris writes;

Love the GV DC contribution. Except that my boss wants a 15% coupon that will expire in 30 days attached to each invoice that goes out of here. Any ideas/help on adding:
Random code generator for the codes.
Adding a date field to the coupon.
Checking the date before the coupon is processed.
Automatically generating the code upon Invoice printing

This is quite a departure from how the Coupon System works, but is doable. Here’s how;

Step 1: Upgrade to Version 5 of the Coupon System.

Doing this means that these items are taken care of;

Adding a date field to the coupon.
Checking the date before the coupon is processed.

Step 2: Add Coupon Creation code to admin/invoice.php

This file needs to create a randomly named coupon, good for the next 30 days (from date of purchase). A little lateral thinking enabled me to make an “insert into” line that;

1. Creates a coupon using a random name (invoice_id-5_random_characters), eg; 10-rteop
This meant utilising the tep_create_random_value function, easy enough.
2. Makes the coupon a “single use” coupon good for 1 order only.
This is a standard setting in Version 5 of coupons
3. Makes the expiry date 30 days from the date of purchase.
Expiry dates are standard in V5 – I had to use the mysql interval to add 30 days onto it, fairly straightforward.
4. Make the Coupon 15%
Percentage Coupons are standard in all versions of the Coupon Mod

Step 3: Attach the Coupon Code to the Order / Invoice

The previous step (#2) was fairly straightforwad, but I then had to somehow attach the Coupon Code to the order. The easiest way to do this was simnply to add a new column to the DB order table to hold the Random Coupon Code. I just made a has_voucher varchar 32 to hold the details. Then I enclosed the code in the previous step inside a tep_not_null(has_voucher) to determine whether a coupon should be made or not.

Step 4: Add the Coupon Details to the Invoice

Easy. A simple echo with the relevant details, looks like this;

This means that the Invoice they receive in the post (or by email) from you, has the Coupon Code on it, and that Coupon Code is ready for use straightaway.

And here is the Coupon ready to be used;

All of the above works, both in theory and in practice. However, the code base is ugly! For production release it needs refining and that takes money and time.


A great way to get repeat business is to offer existing buyers a discount on their next order. By setting a 30 day expire on the coupon it entices buyers to buy as quicly as possible. Each and every time they order, their Invoice will create a new coupon code for them to use next time.

How Much To Spend For Free Shipping

On the osCommerce Forum, Jim asks;

I notice that oscommerce has the default ability to have all orders over a certain amount to qualify for free shipping. Is there a contribution that would add text to the effect of

“You are only [X amount of money] away from qualifying for free shipping.”

With the amount of money being based on the cart contents of the time. It would be a nice device to have to push up the average order amount, anyone know of such a contribution?

There probably is a contribution, but by the time you’ve found it, and checked to make sure the code is OK, it’s quicker to simply come up with some code that does the same thing.

Step 1. make the language definitions

Open up includes/languages/english.php and add the following lines of code directly before the end ?> in the file

[php]define(‘SHIPPING_CHARGE’, ‘Only another %s until you qualify for free shipping.’);
define(‘SHIPPING_FREE’, ‘You qualified for FREE shipping!’);[/php]

These lines have to be in the english.php as one or the other of these will show in ALL osCommerce pages in your store. Did you notice the %s rather than the actual price? We’re going to do something special with that, read on 🙂

Step 2: Amend the Shopping Cart infoBox

In this file we are going to paste code which shows one or other of the language definitions based upon the value of the cart contents!

So, open up /includes/boxes/shopping_cart.php and paste the following code directly before this line of code <!– shopping_cart_eof //–>


show_total() < MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER) ? sprintf(SHIPPING_CHARGE, tep_output_string_protected($currencies->format(MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER – $cart->show_total()))) : SHIPPING_FREE; ?>


Save both files and upload. Voila. Easy as 123.

Deconstructing the PHP

1. We know that the value of the cart contents is assigned to $cart->show_total()
2. We know that the value of the free shipping in the order_total module is assigned to MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER

So this piece of code: $cart->show_total() < MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER compares the two. Depending upon which is true (which is greater than the other), this piece of code: sprintf(SHIPPING_CHARGE, tep_output_string_protected($currencies->format(MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER – $cart->show_total()))) : SHIPPING_FREE; shows either the SHIPPING_CHARGE language, or the SHIPPING_FREE language.

How about that %s ?

Well, that is used by the sprintf() function to format data that is passed to it. You can see that part of our code looks like this: sprintf(SHIPPING_CHARGE, tep_output_string_protected($currencies->format(MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER – $cart->show_total()))) – the 2nd part of this code is the value %s (in other words the total of the free shipping amount LESS the cart total). Make sense?

Images, images, images

When the value of the cart is LESS than the Free Ship Amount;

And when the value of the cart is equal to or greater than the Free Ship Amount;

Easy as 123!

FAQ: Free Shipping in osCommerce

Another question that I see asked time after time is;

How do set up osCommerce so that any order over £50 has free shipping?

The easiest way is to go into your admin area > modules > order_total

Now click on the shipping module, and press [edit]. This brings up a screen like this:

The bit that we are particularly interested in is this:

Simply insert a number in that box! If you want free shipping over £50, insert 50. Free shipping over £75, insert 75. And so on. Once done, press [update].

Note that this order_total module setting OVER-RIDES any charge that is applied via a shipping module.

Isn’t that easy?

Show Stock Availability in osCommerce Product Info

Dana asks;

Im trying to show the amount of items that I have available on each product page please help

This is an often asked question and is really simple to do. Open up product_info.php and add this code somewhere:


This is a standard php function and will output (in numbers) the amount of product you have in stock. Couldn’t be easier really.

How to make this more friendly

How about having a series of messages showing availability rather than just numbers…one way to do this would be to make our own function which uses the existing tep_get_products_stock function and adds in a few pieces of php of our own…

Step 1 – the new function

So, open up /includes/functions/html_output.php and add this code:

[php]function clubosc_products_stock($pID) {
switch(tep_get_products_stock($pID)) {
case 10:
case 9:
case 8:
case 7:
case 6:
case 5:
case 4:
case 3:
case 3:
case 1:
return $in_stock;

What we have done here is create a NEW function called clubosc_products_stock – you could name this absolutely anything to suit your needs. This new function uses the existing function I already spoke of above, to get the number of products in stock. It then compares that number against a “case” and shows the relevant message! Easy as 123. No?

Basically the “case” is saying IF the number in stock EQUALS me, then show a message. In the example above, if the number in stock is 1, then the message TEXT_ULTRA_LIMITED_AVAILABILITY will show. If the number in stock is 2000, then TEXT_UNLIMITED_AVAILABILITY will show as the message.

Got it now?

Step 2 – language

Next up is to add those messages, so open up /includes/languages/{ your language }/product_info.php and add:

[php]define(‘TEXT_LIMITED_AVAILABILITY’, ‘We have a few in stock…’);
define(‘TEXT_VERY_LIMITED_AVAILABILITY’, ‘We have very few in stock…’);
define(‘TEXT_ULTRA_LIMITED_AVAILABILITY’, ‘Only 1 left, buy it now!’);
define(‘TEXT_UNLIMITED_AVAILABILITY’, ‘We have loads in stock…’);[/php]

Obviously repeat in each language that your shop uses.

Step 3 – add the function to the product page

Open up product_info.php and add this code somewhere:


Save it all, reload your page, and see what shows. Easy as 123.

Change the SWITCH

So, let’s say you want to add a new message inside the switch, with a new message for stock between 15 and 11 items available. Easy, just add a new BLOCK of code inside the switch, like this:

[php]case 15:
case 14:
case 13:
case 12:
case 11:

And remember to also add the new language piece!

Show Images instead of Text

Easy enough, just create the images you need for each BLOCK of availability and set the image (instead oft ext) as the $in_stock – like this:

[php]$in_stock = tep_image(DIR_WS_IMAGES . ‘loads.gif’);[/php]

Have fun!

Split an image into the breadcrumb

“M” asks;

Is it possible to replace “Top” with an image, and not effect the rest of the breadcrumbs; I mean not cause the colored background increase in height. Rephrasing…is it possible to overlay and image, that would replace “Top” on the breadcrumb line so that I could surround the image in a matching square or circle background that would seemlesly merge with the background stripe of the breadcrumb background color.

and supplies an image;

This is fairly easy – in short you have to split the “i” image up into three parts;

1. the middle piece which is the same HEIGHT as the breadcrumb bar.
2. the top piece
3. the bottom piece

Then use CSS to place each piece appropriately in your design.

1. middle piece goes in the breadcrumb, then indent the text of the breadcrumb
2. top piece goes at the BOTTOM LEFT of the td ABOVE the breadcrumb
3. bottom piece goes at the TOP LEFT of the td BELOW the breadcrumb

Read more about CSS at




More Help

I show how to do something very similar in both of my “designing oscommerce” and “oscommerce sts” ebooks. In the designing one I show how to split up an image and use css to place it in a couple of areas, and in the sts book I show how to move the breadcrumb along to suit a design. More info on these eBooks by going to – and if you buy one, you get the other FREE.

Product Weight By Attribute

Theresa asks;

We have products on os commerce that are sold in two different weights. As the product attribute only has a field for one weight, how can we add the variation in weights so that shipping costs are calculated properly?

Assuming you are using the product attributes to differentiate between your product sizes/dimensions, there is a contribution that adds weight to attributes. This makes it very simple to do something like:

Product A (1kg)
– small (no extra weight)
– large (extra weight of 0.5kg [or whatever])


The extra weight is then parsed as normal via the shipping modules and the correct fee should be charged…

That should just about do it, shouldn’t it?

Shipping Modules are fun to code

Here is a question from a client;

Im setting a a new oscommerce website and cant seem to get the shipping working. I would need to have about 5 zones. Each zone would contain different countries. For each zone there is a basic rate per pound. eg $35 . Each additional pound cost $5 etc per zone. That cost differs per zone. Also i would need packaging cost.

I’ve not seen anything quite like this available as a contribution – so instead of spending hours looking for it, I decided it would be more cost effective to code this up from scratch. It was actually fairly straightforward. Here’s the interesting info;

In the Admin section, I simply made an input form for the module. For each Zone that is set up, the client can insert 3 different prices. In the image below, I have set up 2 zones…

As you can see, each Zone has 3 inputs: “1st”, “rest” and “handling”. “1st” takes care of the first unit of weight, and “rest” takes care of any subsequent units. Handling is obvious! In Zone 1 (in the image) I set up 3 countries: AG,BB,DM. So the costings inserted in the three price fields will be used for those 3 countries. In Zone 2, similarly, 3 countries US,CA,FR with different prices for “1st” etc.

You will also notice above these Zones, an area entitled “Cost for all other Zones” – this is a fail-safe method of making sure that each country gets a quotation for postage. A country that is not in any existing zone will default to this.

In the actual codebase for the module, the relevant piece of code that works out the actual price is as follows:

[php]$shipping_cost = $shipping;
if ($shipping_weight > 1) $shipping_cost += ($shippingtoo * ($shipping_weight – 1));
$shipping_cost += $handling;[/php]

Which basically says;

[php]$shipping_cost = $shipping;[/php]

This is for items of a total of 1 unit of weight or less

[php]if ($shipping_weight > 1) $shipping_cost += ($shippingtoo * ($shipping_weight – 1));[/php]

Here we are saying IF the total weight is GREATER than 1, then $shipping_cost should be INCREASED by the “rest” ($shippingtoo) amount multipled by the $shipping_weight -1. Remember that we have to do -1 as the first unit has already been worked out!

[php]$shipping_cost += $handling;[/php]

Easy and straightforward, add the handling fee on top!

Code hints

You might notice me using something weird in these calculations, the += sign. What this does is simply add something onto an existing total. It’s a shorthand way of saying;

[php]$shipping_cost = $shipping_cost + $handling;[/php]

It’s a bit less work to just say

[php]$shipping_cost += $handling;[/php]

So, there you have it. I thought it might be interesting for you to see a bit about how I code things up – I try to make things as simple as possible.

Why not just use “Zone Rates” module?

If you have a bit of knowledge about osCommerce, you are probably thinking “he could have just used Zones Rate”. Well, that’s true, but there are good reasons why you should not…

1. Using Zones Rate you would have to set up EVERY country into a Zone to get a shipping quote. In mine you do not need to do this. Each country NOT in a Zone will default to “all other zones”.

2. Zones Rate cannot handle an open-ended system of weight, as the database field is simply too small – so if the customer ordered 400 units, with each unit costing say $5, my version can work this out very easily. Using the standard Zones Module would be IMPOSSIBLE (under normal use).

Stop People Checking Out? Huh?

Interesting question posed at the osCommerce forum;

All my products are 5lbs each. Is there a way to set a minimum order of 10lbs. This would mean they have to purchase a minimum of two items (2 of the same product or 2 different products).

Is there a way in the USPS shipping module or any other file to set a minimum order of 10lbs or 2 products?

Easiest way is to do it on the 2 product minimum purchase, as I have already covered this in a previous post. cart->count_contents() is the code to use in this case…

So here is my answer to the question…

Add this in checkout_shipping.php, underneath require(‘includes/application_top.php’);

[php]if ($cart->count_contents() < 2 ) tep_redirect(tep_href_link(FILENAME_SHOPPING_CART, 'error_message=' . urlencode(ERROR_NOT_ENOUGH_IN_CART)));[/php] How simple was that? The line of code basically says:

IF the number of products in the cart at checkout time is LESS THAN 2, then REDIRECT the user back to the Shopping Cart and DISPLAY an error message to tell him/her so.

Obviously you also need to make the define in the language file (includes/languages{your language}/shopping_cart.php):

[php]define(‘ERROR_NOT_ENOUGH_IN_CART’, ‘You have not purchased enough stuff. Buy more you fool.’);[/php]

Nice, quick and easy solution – always best to keep things as simple as possible in case you ever want to change it in the future.

Coupons v1 to v5 – worth it? Points, Rewards?

Jason asks;

I use Discount Coupon v1.2 on my site and it works and works well – looking at your site its hard to see whats available in version 2.3.4 and now 5 which isn’t in version 1 to see if its actually worth upgrading. Do you have a list of whats new in the later versions?

The main changes are as follows;

Admin changes:
+ ability to see when each coupon was last used
+ ability to view all orders that used each coupon
+ ability to set a “use once, one time” coupon (instead of per customer)
+ ability to set a minimum spend before a coupon can be applied

Shop changes:
+ moved coupon input box to shopping cart (away from checkout process)
+ ability to remove a coupon after it has been applied
+ now works with Tax calcaulations

Coming Soon:
– ability to set an expiry date per coupon

Also, age old question I know but any update on the GV side of the contribution?

As yet, no-one has offered to sponsor development, hence it’s (very) low down on the to-do list, as it’s something that I personally do not need.

Final point then – does this work with Point and Rewards Module – I only ask the instructions for it specifically mention things which need done if using CCGV and, while I obviously know your contrib Is NOT CCGV, it does similar things so was curious to know if this was tested or if you knew of any incompatibilities?

Should work OK with all contributions, IF those contributions are decently coded. I don’t know of any incompatilities with that particular contribution. My coupon system is coded far more cleanly than CCGV so I think that there should be no problem. An idea would be for someone 😉 to install a new osc, then Points and Rewards, then v1.2 of coupons and see if it all plays together nicely.