Archive for the ‘Ecommerce’ category

How to fix the flaw in the WP Ecommerce table rate shipping module

January 25th, 2012

Catchy title eh! It’s difficult to name such a post but I have just diagnosed a client’s site and realised that there was a bit of an error in the WPEC (WPSC) table rate shipping module.

Reading the code it looks like the table rate module is designed to be used exclusively or in conjunction with a secondary service. The flaw I have found is that table rate is coded to always return a price regardless of whether you want one or not.

Basically my client wanted to use the weight shipping module for all postage except if the cart amount was more than £200 in which case free postage would be offered. Simple right?.. just add a layer (row) into the table rate settings with a minimum price of 200 and a value of 0. This would mean that weight based is used until the table rate conditional kicks in at £200 and offers cheaper postage (free in fact).

No.. sadly not correct :(

Table rate is written so that is always returns a price regardless of whether you want it to or not. Basically if you have a single row (layer) in the settings for the module it will show it. The system works well at the top end where price is greater than or equal to but there must always be a base price in the module (value of 0.00 or 0.01 if it doesn’t save) to catch those which fail the PHP logic. Note the following function to get a quote (taken directly from tablerate.php):

    function getQuote() {

        global $wpdb, $wpsc_cart;
        if (isset($_SESSION['nzshpcrt_cart'])) {
            $shopping_cart = $_SESSION['nzshpcrt_cart'];
        }
        if (is_object($wpsc_cart)) {
            $price = $wpsc_cart->calculate_subtotal(true);
        }

        $layers = get_option('table_rate_layers');

        if ($layers != '') {

            // At some point we should probably remove this as the sorting should be
            // done when we save the data to the database. But need to leave it here
            // for people who have non-sorted settings in their database
            krsort($layers);

            foreach ($layers as $key => $shipping) {

                if ($price >= (float)$key) {

                    if (stristr($shipping, '%')) {

                        // Shipping should be a % of the cart total
                        $shipping = str_replace('%', '', $shipping);
                        $shipping_amount = $price * ( $shipping / 100 );

                    } else {

                        // Shipping is an absolute value
                        $shipping_amount = $shipping;

                    }

                    return array("Table Rate"=>$shipping_amount);

                }

            }

            $shipping = array_shift($layers);

            if (stristr($shipping, '%')) {
                $shipping = str_replace('%', '', $shipping);
                $shipping_amount = $price * ( $shipping / 100 );
            } else {
                $shipping_amount = $shipping;
            }

            return array("Table Rate"=>$shipping_amount);

        }
    }

If you read through the code it basically loops through all of the layers to find the conditional price point that matches and returns the price. The oddity is the next set of code which, I suppose, is a fall back. Sadly the fall back is entirely unnecessary and causes this issue. The code starts from the following onwards:

$shipping = array_shift($layers);

In fact the simplest way to ‘fix’ the function is to put a return  statement just before that line:

return false;
$shipping = array_shift($layers);

Once that is in place you are free to use the module properly once again. I might write this as a separate shipping module for people to download as changing the name of each layer would be a nice idea as well as setting a maximum price point for each layer.

WP Ecommerce template redirect

August 18th, 2011

Today I spent a good two to three hours making zero progress on a site which I was upgrading. I am making changes to the design but sadly didn’t get that far as first I decided to update WordPress and the plugins. The upgrade to WP 3.2.1 went well as did every other plugin except WP Ecommerce. I know this plugin to be a troublemaker but sadly as it’s the only half decent cart WordPress has to offer (and it’s pretty dire really).

The issue I was facing is that we have a custom page template for the shop to include a different sidebar and some other small changes. Upon upgrading the page template decided to revert to the theme’s page.php file instead of the template-shop.php we were using previously. Lots of head scratching and shouting followed and a couple of reverts from backups but eventually I got it down to a single function in the theme.functions.php file in the wpsc-includes directory. There are a couple of fixes you could use although the most straightforward is a hack to one of their core files… Sadly for me I don’t like doing that as the next time you upgrade you get to do it all over again. Luckily they had the foresight to add an action call at the top of the function so I wrote the following.

The Code

add_action('wpsc_swap_the_template', 'include_shop');

function include_shop() {
    global $wp_query,$wpsc_query;

    $products_page_id = wpec_get_the_post_id_by_shortcode('[productspage]');
    $term = get_query_var( 'wpsc_product_category' );
    $tax_term = get_query_var ('product_tag' );
    $obj = $wp_query->get_queried_object();
    $id = isset( $obj->ID ) ? $obj->ID : null;

    if( get_query_var( 'post_type' ) == 'wpsc-product' || $term || $tax_term || ( $id == $products_page_id )){

	$shop_template = trailingslashit(TEMPLATEPATH) . 'template-shop.php';
	require_once($shop_template);
	die;
    }
}

How to integrate it

To get this to work you just need to add it to your theme functions.php file and change where I have “template-shop.php” to be the name of your own template. This may well not even be an issue unless upgrading from an old version of WPSC but this fix worked for me.

As an aside I note the following comment left by one of the developers

// have to pass 'page' as the template type. This is lame, btw, and needs a rewrite in 4.0

Note: this was an issue when migrating from WP Ecommerce versions 3.7.7 to 3.8.6