HTML in osCommerce Product Descriptions

Rob asks;

If you don’t mind me asking, what are the current limitations with HTML in the product descriptions? The reason I ask is that I currently utilize HTML tables within the product descriptions to provide a matrix of dimensions for variations of a common product (length, width, unit weight, etc). Is this detrimental without a special contribution? Thanks.

There are not any limitations, other than the fact that in a new install of osC there is no editor present to allow someone who knows no HTML to insert into the product descriptions. In other words, that person has to learn HTML or use a wysiwyg editor, then copy/paste the HTML appropriately.

There is no detrimental effect to what you are doing. But wouldn’t it be easier to be able to do it all from the product adding screen? There are contributions for this…

Use as little code as possible when writing PHP

I’ve commented on this many times in the past across a number of forums and blogs. If you use as little PHP as possible to get something done, it is usually far easier to keep track of, both for yourself and for future readers of your code. Here’s a typical example, taken from the osCommerce forum;

Does anyone know how to show credit card numbers seperated by dashes like on admin/orders.php thanks in advance for the help

What this guy wants is a credit card number to be written like this: 4111-1111-1111-1111 instead of 4111111111111111 – quite why he wants it is beside the point as he should not be storing the info anyway in my opinion, but anyway, that doesn’t really matter as the point of this article is not about the legalities of storing CC numbers, but more about writing code nicely…

No-one replied to his thread, so he came up with a workable solution himself;

[php]$cc_p1=substr($order->info[‘cc_number’],0,4);
$cc_p2=substr($order->info[‘cc_number’],4,4);
$cc_p3=substr($order->info[‘cc_number’],8,4);
$cc_p4=substr($order->info[‘cc_number’],12,4);
echo $cc_p1 . ‘-‘ . $cc_p2 . ‘-‘ . $cc_p3 . ‘-‘ . $cc_p4;[/php]

Here he is splitting the $order->info[‘cc_number’] into 4’s and adding a – between each. Easy enough. But look at the ugly code!

My solution is like this:

[php]echo rtrim(chunk_split($order->info[‘cc_number’], 4 , “-“), “-“);[/php]

Here I am using chunk_split to split the $order->info[‘cc_number’] into 4’s and adding a – at the same time after (not between) each block of 4. The only problem is that this will add a – onto the end of the number – to combat this I am using rtrim to take off the end – : so I go from this 411111111111111 to this: 4111-1111-1111-1111- to this: 4111-1111-1111-1111

Easy as 123? Well maybe not if you are not that skilled in PHP 😉

Of course, I am not saying that my way is the right way – there are probably many ways in which the same effect can be achieved. What you have to agree with is that my line of code is much sexier than the first block of code posted and much easier to read!

Have fun with PHP and osCommerce! You can click the links in the PHP snippets above to learn more about rtrim, chunk_split etc

Show quantity in cart on each product_info.php page

On the official osCommerce forum, Will asks;

Does anyone know how I could had on the product page (product_info.php), near the buy it now button, a line of text saying: You have XXXX units of this item currently in your cart.

I didn’t really read the question so gave the advice to use the in_cart class for this. Wrong!

Will then went away and came up with some code to do this, which is like this:

[php]$superid = $product_info[‘products_id’];
$products = $cart->get_products();
for ($i=0, $n=sizeof($products); $i<$n; $i++) { if ($products[$i]['id'] == $superid) { $qtyencart = $products[$i]['quantity']; echo"Vous avez $qtyencart unité de cet item dans votre panier actuellement.”;
break;
}
}[/php]

Workable, but ugly and complicated. Here’s my take on getting the same thing, coded to osCommerce conventions;

[php]echo $cart->get_quantity($product_info[‘products_id’]);[/php]

will bring you the number of products in the cart on the product info page. Use this with sprintf to show the text;

includes/languages/english/product_info.php
[php]define(‘TEXT_THE_QUANTITY’, ‘You have %s units of this item currently in your cart.’);[/php]

includes/languages/french/product_info.php
[php]define(‘TEXT_THE_QUANTITY’, ‘Vous avez %s unité de cet item dans votre panier actuellement.’);[/php]

in product_info.php
[php]echo sprintf(TEXT_THE_QUANTITY, $cart->get_quantity($product_info[‘products_id’]));[/php]

Pretty easy!

call api in checkout process of oscommerce

Schilt asks;

Dear Sir, how do I go about to solved below problems ?…thank you in advance

Fatal error: Call to a member function call_api() on a non-object in /home/ /public_html/shop/checkout_process.php on line 127

call_api() is a function that tells your checkout_process to do something. call_api() is not a standard part of the checkout_process.php file, so it must be something that you (or someone else) has added (eg a contribution).

I had a quick look and see that “buy safe” uses a call_api() function so this would be your first clue as to what you ahve done and how to fix it.

So how should you fix it?

Try to remember the changes you made to add this call_api() in, and reverse the changes – in other words: uninstall!

Display Price in two different sizes?

At the official osCommerce forum, Matt asked;

How can I get the prices to display with two different sized fonts ie $129.95

You can plainly see that he is trying to show the cents in a different way than the dollars. This is very easy to accomplish;

Open up /includes/classes/currencies.php

Find:
[php]if ($calculate_currency_value == true) {
$rate = (tep_not_null($currency_value)) ? $currency_value : $this->currencies[$currency_type][‘value’];
$format_string = $this->currencies[$currency_type][‘symbol_left’] . number_format(tep_round($number * $rate, $this->currencies[$currency_type][‘decimal_places’]), $this->currencies[$currency_type][‘decimal_places’], $this->currencies[$currency_type][‘decimal_point’], $this->currencies[$currency_type][‘thousands_point’]) . $this->currencies[$currency_type][‘symbol_right’];
} else {
$format_string = $this->currencies[$currency_type][‘symbol_left’] . number_format(tep_round($number, $this->currencies[$currency_type][‘decimal_places’]), $this->currencies[$currency_type][‘decimal_places’], $this->currencies[$currency_type][‘decimal_point’], $this->currencies[$currency_type][‘thousands_point’]) . $this->currencies[$currency_type][‘symbol_right’];
}[/php]

Change to:
[php]if ($calculate_currency_value == true) {
$rate = (tep_not_null($currency_value)) ? $currency_value : $this->currencies[$currency_type][‘value’];
$format_string = $this->currencies[$currency_type][‘symbol_left’] . number_format(tep_round($number * $rate, $this->currencies[$currency_type][‘decimal_places’]), $this->currencies[$currency_type][‘decimal_places’], $this->currencies[$currency_type][‘decimal_point’], $this->currencies[$currency_type][‘thousands_point’]) . $this->currencies[$currency_type][‘symbol_right’];
$format_string = explode($this->currencies[$currency_type][‘decimal_point’], $format_string);
$format_string = $format_string[0] . $this->currencies[$currency_type][‘decimal_point’] . ‘‘ . $format_string[1] . ‘‘;
} else {
$format_string = $this->currencies[$currency_type][‘symbol_left’] . number_format(tep_round($number, $this->currencies[$currency_type][‘decimal_places’]), $this->currencies[$currency_type][‘decimal_places’], $this->currencies[$currency_type][‘decimal_point’], $this->currencies[$currency_type][‘thousands_point’]) . $this->currencies[$currency_type][‘symbol_right’];
$format_string = explode($this->currencies[$currency_type][‘decimal_point’], $format_string);
$format_string = $format_string[0] . $this->currencies[$currency_type][‘decimal_point’] . ‘‘ . $format_string[1] . ‘‘;
}[/php]

You can style the “sup” appropriately using css, this would be done in the stylesheet.css file.

Easy as 123.

Should I use the BTS for osCommerce

Stephen asks;

I have a css (almost tableless) design that I would like to use. I am planning to BTS to convert it for osC. Good idea?

I think I can safely say that I am still the only person who has made the same design in BTS (Basic Template System), STS (Simple Template System) and standard osCommerce. I did this to test which was better in terms of use and also forward use by the client…

BTS came second, with STS a poor third. However, since then STS has been re-written and has good support available in the osCommerce forum. BTS has almost zero support.

So, if you are fairly good with osCommerce, I’d say don’t use BTS or STS. Just recode the parts of osCommerce (v2.x series) that need to be recoded…

OR…

Use the new v3 version of osCommerce which has it’s own template system built in – it’s still in developmental stages, but each new user helps development to continue at a good pace.

Good luck!

Minimum weight to Checkout

In the official osCommerce Forum, Paul asks;

… I need to prevent any customer that has not got a minimum total weight in their cart from proceeding through the checkout; does anyone have any ideas on how this might be achieved most efficiently? I don’t want to be hand-held through making a contribution to do this, I am quite capable of writing the code myself … I realise that I could do this with a shipping module, in fact I have already written three custom shipping modules specifically for this site into which I could insert the checks on the total cart weight, but I am thinking there may be a more efficient way to implement the functionality we require, without having to resort to checking the cart weight from within 3 separate shipping modules.

This is fairly straightforward and my answer was this (as he did not want the code delivered to him on a plate);

checkout_shipping.php … look for $total_weight and “if” it to a tep_redirect

Paul replied;

Thanks for the reply; think I will hack it then … I was hoping I might stumble across a more elegant and reusable solution, but your suggestion will provide the required functionality with minimal changes.

So, more elegant and re-usable…this will make a good blog post for others to read, so let’s do it!

Step 1: Add the admin configuration

Best place for this is in admin > shipping/packaging

Running this piece of SQL code (in PHPMyAdmin) will add another entry in here:

[php]INSERT INTO configuration (configuration_title, configuration_key, configuration_value, configuration_description, configuration_group_id, sort_order, date_added)
VALUES (‘Enter the Minimum Weight you will ship’, ‘SHIPPING_MIN_WEIGHT’, ‘0’, ‘The minimum weight that you will ship. 0 = unlimited.’, ‘7’, ‘6’, now());[/php]

So that it now looks like this:

Step 2: Configure the minimum weight

Click on the “Enter the minimum weight you will ship” and press the [edit] button. You should see something like this;

As you can see, you should leave this at zero if you wish to allow ANY weight to checkout. If you wish to allow weight above 10 (units of weight), then insert the number 10 here and press [update]. Easy.

Step 3: Add the “check weight” code

Open up checkout_shipping.php and find these lines of code:

[php]$total_weight = $cart->show_weight();
$total_count = $cart->count_contents();[/php]

Right underneath, add this line of code:

[php]if ((SHIPPING_MIN_WEIGHT > 0) && ($total_weight < SHIPPING_MIN_WEIGHT)) tep_redirect(tep_href_link(FILENAME_SHOPPING_CART, 'error_message=' . urlencode(sprintf(ERROR_UNDERWEIGHT_SHIPPING, SHIPPING_MIN_WEIGHT, SHIPPING_MIN_WEIGHT-$total_weight)), 'NONSSL'));[/php] Save the file and upload it. I'll dissect that line of code later on in this blogpost. Step 4: Add the Error Message to the language file

Open up /includes/languages/english.php and add the following line of code:

[php]define(‘ERROR_UNDERWEIGHT_SHIPPING’, ‘The minimum shipping weight is %s kgs. You need to add another %s kgs to be able to checkout.’);[/php]

In this line of code I have assumed that your “unit of weight” that you use in your shop is Kilograms, hence the use of kgs. If you use ounces, change kgs to ounces, if you use grams, change it to grams. Easy enough? Save the file and upload it. Notice the %s used here? I’ll explain that later on.

That is all the changes that is needed.

And the result?

Assuming that your Minimum Shipping Weight is set above zero, then if the total weight of the cart contents is below this setting, an error message will be displayed, somewhat like this:

And if the Minimum Shipping weight is set to zero OR if the Minimum Shipping Weight has been exceeded, then checkout will simply progress as normal.

Wasn’t that easy? And so much quicker than;

a. asking if a contribution exists and waiting hours/days for a reply
b. installing the contribution if it does exist
c. bug testing and fixing the contribution if it’s broken

And, even better, you now know a bit about how osCommerce code works!

Dissecting the Code

[php]if ((SHIPPING_MIN_WEIGHT > 0) && ($total_weight < SHIPPING_MIN_WEIGHT))[/php] If the Minimum Shipping Weight is greater than Zero AND the total weight of the cart contents is less than the Minimum Shipping Weight, then; [php]tep_redirect(tep_href_link(FILENAME_SHOPPING_CART, 'error_message=' . urlencode(sprintf(ERROR_UNDERWEIGHT_SHIPPING, SHIPPING_MIN_WEIGHT, SHIPPING_MIN_WEIGHT-$total_weight)), 'NONSSL'));[/php] Redirect the buyer back to the shopping cart page, and show an error message asking him/her to buy more stuff! This particular piece of code is interesting; [php]sprintf(ERROR_UNDERWEIGHT_SHIPPING, SHIPPING_MIN_WEIGHT, SHIPPING_MIN_WEIGHT-$total_weight)[/php] sprintf allows us to pass parameters to the language definition. If you remember the language definition contianed a couple of %s "commands"...these %s are what is passed through, so in this case, I am saying: Use the ERROR_UNDERWEIGHT_SHIPPING language definition, but pass to it; 1. the SHIPPING_MIN_WEIGHT setting (which is the admin setting above zero) 2. the SHIPPING_MIN_WEIGHT less the total weight of the cart. This allows us to show the buyer, how much more weight he needs to have in his cart to be able to checkout. Easy as 123?

Free Shipping Unless Weight is greater than 1kg

John asks;

I’ve hunted high and low and can’t find a solution to this problem. I want to provide free shipping for orders over £20 … but needs to apply a charge if the total weight exceeds 1kg. Is there a way to do this – or a contribution that can be used to do this.

The simplest way to do this is to enable the shipping order_total module to over-ride all of your shipping modules if the amount of the order is greater than £20. This is easy, follow this previous blog post of mine.

However, you also need to disable this if the weight of the order exceeds 1kg. Easy!

Open up checkout_shipping.php and add this code:

[php]if ($total_weight > 1) $free_shipping = false;[/php]

Right underneath this existing code:

[php]$free_shipping = false;
if ( ($pass == true) && ($order->info[‘total’] >= MODULE_ORDER_TOTAL_SHIPPING_FREE_SHIPPING_OVER) ) {
$free_shipping = true;

include(DIR_WS_LANGUAGES . $language . ‘/modules/order_total/ot_shipping.php’);
}
} else {
$free_shipping = false;
}[/php]

That is it!

Deconstructing the new code

[php]if ($total_weight > 1)[/php]

$total_weight is a variable that is set to the weight of the cart contents. This is set up at line 61 of the standard checkout_shipping.php file;

[php]$total_weight = $cart->show_weight();[/php]

We are simply asking if $total_weight is greater than 1. 1 in this case being 1kg. If this is true, then:

[php]$free_shipping = false;[/php]

Completely obvious – set the $free_shipping to false! This is then used later on in the same file to determine whether or not the order_total module should over-ride your installed shipping modules (or not).

Easy as 123. If you can avoid using a contribution to do something, it is always preferable to do so. After all, the addition of this one line of code;

[php]if ($total_weight > 1) $free_shipping = false;[/php]

is surely simpler than finding and installing a contribution, and is surely simpler than amending all your installed shipping modules.

Find the value of your stock

Some people (myself included) use osCommerce as a stock-keeping program as well as a e-commerce sales program. There are drawbacks to doing it this way (eg, lack of “nice” reports, accountancy etc), but it’s certainly do-able.

A question in the official osCommerce forum went like this;

I need a simple bean counting script that will give me a total cash value of all in stock inventory…I have over 6000 items in stock – so I would rather not do it by hand…

Now, me not being a great whiz at Maths, guessed that the user needed to know the product_quantity multiplied by the product_price (per product of course). This is rather easy and goes like this;

[php]SELECT sum(`products_quantity` * `products_price`)
FROM `products`[/php]

This give the total value of all the product quantities you have in store, as shown;

Then I decided that this would be more useful to only show products that have a quantity greater than zero. After all, depending upon how you have your store set up it’s possible you have negative value quantities (over-sold products) – this would obviously skew the results terribly.

So, the new code looks like this:

[php]SELECT `products_id`, sum(`products_quantity` * `products_price`) AS total
FROM `products`
WHERE `products_quantity` > 0
GROUP BY `products_id`[/php]

Now the output looks like this;


(Note that I cut the graphics off, but it shows the value of each product individually)

From the two pieces of code above, I am sure that you can make different code to suit your needs. MySQL can be complicated to understand, but if you hunt Google there are loads of tutorials showing all sorts of cool code. To actually use the code, use PHPMyAdmin (comes standard almost all hosts), click the SQL tab and paste the code into the “Run SQL Query” input box, then press “GO”…

Easy as 123? Maybe not. But fairly easy, for sure.

Making a Test Mirror Site for osCommerce

Barbara asks;

I was asked to transfer the oscommerce site I’ve been working on to a different server and to create a “test mirror site”, where we could change pages, change PRODUCTS and get ready for a new season, so that they could test it and see the new version of the site live and when the right day came we could just switch the mirror for the live site. Any idea how this could be done? Or how easily? Do I need to set up different versions of the site in different databases? Can I just have a copy and have different products on each one?

OK – fairly easy. You need to be aware that osCommerce might work well on one server and totally fail on another – all depends upon the server software…that said;

Option 1. Buy a (temporary) domain name and new hosting

Would be the best way to test changes on a new server. Once the changes are complete, simply “park” the real domain on top of the temporary domain and update the two configure.php files from the temprary to the new domains. Downside = cost of domain name. You’d need to buy hosting on the new server anyway so that is not an issue.

Option 2. Run your new site in a folder/directory on your existing webpace

Not really a great option as it would be so easy to mix up the two sites.

Option 3. Run your new site offline on your computer

This is the option that EVERY person who runs osCommerce should be doing anyway – it’s super simple to set up. Basically, you create a mirror of your existing site to run offline. A good thing in case anything happens to your live site. At the same time you can also create your new site offline and save it onto a USB flash card for example to show your client…

A picture is worth 1000 words…basically you are running two stores (or three, or four, etc) – 1 is live on your webhosting, the other(s) are all on your home computer. You can find this package at oscbooks.com – I am running this exact same setup and at present I have 49 seperate osCommerce shops running on my computer, along with 49 MySQL databases. All working well…

Obviously, when the site is completed, you then upload to your new website hosting on your new server. Easy as 123.