Add custom JavaScript actions to wp-e-commerce cart updates

I just stared in horror wonder at the wp-e-commerce script that handles cart updates. Wow. Just… wow. Forget any thought of nicely hooking into that to add some extra client-side actions, it’s a mess and looks like it will probably get worse before it gets better. But fortunately, there is another way.

Update: for WP e-Commerce 3.8.11 and later, there is a new procedure

By staring instead at the function wpsc_add_to_cart() in the ajax.functions.php file, I can see that it generates some script and sends that to the browser to be executed. Apparently, nobody has heard of JSON or JSONP, or triggering custom jQuery events, or… but I digress. At the bottom of that function, after it spits out its script for replacing the cart with a complete new copy, there’s a hook!

do_action( 'wpsc_alternate_cart_html', $cart_messages );

What this means is that any additional script you want to run can be dropped into this hook, letting you tell the browser to, say, update a mini-cart in the page header like so:

EDIT: initially the code below had the function declared as public, because I copied it here from a class; public is now removed, so if you tried this code and got an error, please try again!

/**
* action hook for wp-e-commerce to provide our own AJAX cart updates
*/
function theme_cart_update() {
    $cart_count = wpsc_cart_item_count();
    $total = wpsc_cart_total_widget();
    echo <<<HTML
jQuery("#theme-checkout-count").html("$cart_count");
jQuery("#theme-checkout-total").html("$total");

HTML;
}

add_action('wpsc_alternate_cart_html', 'theme_cart_update');

I actually didn’t go for this in the end because I decided to just toss the standard cart widget in favour of a simpler one, thus reducing the size of the AJAX response considerably. But for the next website that needs both a cart widget and a count/total in the page header, job is already done.

Facebooktwittergoogle_plusredditlinkedinmailFacebooktwittergoogle_plusredditlinkedinmail
  • Chad Schneider

    Thanks for your code. The official Shopping Cart Widget that I can add to the footer does appear to update immediately. However, my theme (Storefront Echo) simply adds the wpsc_cart_total() to an item in the menu. What do I do to make the menu item update upon Add To Cart just as the widget is?

    Thanks,
    Chad

    • G’day Chad, have a chat to Storefront Themes about that. Matt has been working on this and might have a fix for you already. Let me know how you go.

  • IvanoC

    Hi Ross. In wpsc-products_page.php, I have been trying to add a ‘go to basket’ link to be dynamically displayed only when the add to basket has been pressed and the basket has more than one item. It only displays when the page is refreshed and I think your code would make it work properly.
    I am placing this close to the ‘add to cart’ input submit.
    I have copied my code to this link:
    http://pastebin.com/eV22Jzam
    Can you please let me know how to add the jquery function. Many thanks again.

    • G’day Ivano, try this one: http://pastebin.com/wua97sBX

      Basically, your code only spits out the link when the cart count is > 0. This new one spits out the link, but hides it (display:none) if the cart count is 0. When the Add to Cart button is clicked, the AJAX response will add the code to reveal the link.

  • IvanoC

    Brilliant Ross! It only seem to work on the first product on the list, and adds the ‘checkout’ link to the first product of the list even when other products further down the list are added to the basket. Is there any way of making the code part of the products loop (cannot think of another way of explaining this, sorry!).
    I have pasted the full code to this link including your snippet.
    http://pastebin.com/LscjA8r2
    Thanks again.

    • Ah, you have the link next to every product! I didn’t realise that. If you want the link to show up on all products (I’d recommend it) then change id="some-handle" to class="some-handle" and change the jQuery to jQuery('span.some-handle').fadeIn();

      Of course, you should also change some-handle to something meaningful!

  • IvanoC

    Thank you very very much Ross, if you were not the other side of the world I’d buy you a bier!
    I had to simply change your code to span class=”some-handle” style=”display:none;” to make it work correctly.

    • G’day Ivano, no worries! I’ll hoist one over this way anyway :)

  • IvanoC

    Oops.. meant a beer of course..!

  • RoyceC

    Im trying to accomplish “what I think” is what your solution is. I want to add a header toolbar with basic information such as: 2 Items in Cart | View Cart | Check Out. My intention is that i want these three links on the top of each page regardless if they leave the page with he products. Is your solution above accomplishing this?

    • G’day RoyceC, “what I think” you want is to call wpsc_cart_item_count() from your header, to show the number of items in your cart. What I’m describing above is a way to update that count whenever someone clicks on an Add to Cart button, which uses AJAX to update the cart without leaving the page.

      You actually have two choices here (at least!): use the method above, to add an extra call to the script returned to the browser after Add to Cart; or strip down the wpsc-cart_widget.php template so that it’s just the basic information you want in the header. Both work fine (but the latter means you can’t add a detailed cart widget to a sidebar).

  • peter modest

    hello, i just updated to wp e ecommerce 3.8.8.1, and this has stopped working! so frustrating. i can’t seem to get any custom functionality out of the ajax.functions.php file! anyone else experiencing this?

    • peter modest

      nevermind! the issue was that my ftp client did not properly refresh the data when i manually refreshed. closing and opening the client fixed the issue.

      • Glad to hear it’s working again :)

  • Marco

    Hi,

    many thanks for sharing that with us!
    I have a request: at the moment i have a page with an iframe; within the iframe i visualize the products. Whenever i add one of them to the cart, i would like to reload the cart widget in the header of the parent page.
    Then, onclick of the button within the iframe, i call a function within the parent page (i tested with javascript and alert function and it worked), but i am not able to reload the cart widget.
    I tried many solution but nothing, could you tell me how to reload the widget cart in the header? is your code working for my issue?
    Many thanks and have a nice life,
    Marco

    • G’day Marco, you want to be able to trigger a function in the parent page that will reload the cart. Of course, you don’t want to trigger a loop!

      Take a look at this gist and see if it works for you. At least, it should get you closer!

      cheers,
      Ross

      • Marco

        Hi Ross,

        the javascript you suggested worked immediatly!
        You Rules!

        Many thanks for your kindness,
        Marco

        • Marco

          Hi Ross,

          i am getting really frustrated! Can you tell me step by step how to reload the cart widget in the header of the parent page. at the moment i have a button like below:

          <button id='product__submit_button’ onclick=”window.parent.updateCartHeader();” class=”reverse wpsc_buy_button”>

          that is teh button to add a product within the page loaded into teh iframe. As you can see, it calls a function in the parent page. The function is the one you sent me:

          function myReloadCart() {
          form_values = “ajax=true&my_plugin_no_force_load=1”
          jQuery.post( ‘index.php?wpsc_ajax_action=get_cart’, form_values, function(returned_data) {
          eval(returned_data);
          });
          }

          But this solution works really fuzzy…sometime yes, someother no, or sometime with a delay of 5 10 seconds.
          Could you please help, i am lost .
          Thanks

          Marco

          • G’day Marco, are you getting any errors? e.g. running Chrome with Developer Tools open and the console showing, or Firefox with Firebug console showing, are there any errors displayed?

  • I battled for ages to figure out how to refresh a ‘mini cart’ without reloading the Page. Thanks, the above worked great and saved me a bundle of time.

    • No worries, glad it helped. wp-e-commerce doesn’t always make it easy, but there’s usually a way, if only you can find it :)

  • Pingback: WP e-Commerce Header Shopping Cart | WordPress Specialist()

  • Rajeev

    Hi i am using the
    to automatically update the cart count, when some one click on the add to cart button, but it cannot automatically update the count.
    Any help and thanks in advance.

  • Rajeev

    Hi i am using the echo wpsc_cart_item_count()
    to automatically update the cart count, when some one click on the add to cart button, but it cannot automatically update the count.
    Any help and thanks in advance.

    • G’day Rajeev, did you try the snippet above? If so, have you checked for Javascript errors? If you can post a link, I can try to diagnose it for you.

      cheers, Ross

      • Rajeev

        yes i have try
        you can check out from this link
        http://joesdiscountfurniture.com/products-page/

        many thanks for your reply
        waiting for your reply.

        • G’day Rajeev, I just clicked your Add To Cart button and the AJAX request doesn’t have any additional code (i.e. it has the standard wp-e-commerce cart widget contents, and the slideup() call, but nothing about updating your mini-cart). Where did you put the code snippet, and can you paste exactly the snippet you’re using somewhere like pastebin?

          • Rajeev

            Sorry me bit confused, regarding which code your have to talk

            thanks

        • Rajeev, where did you copy the code in the article to, i.e. the function theme_cart_update() from the code snippet above? Did you copy it to your functions.php file in your theme, or a plugin, or…???

          • Rajeev

            yes i have paste the
            function theme_cart_update() {
            $cart_count = wpsc_cart_item_count();
            if ($cart_count > 0)
            echo “jQuery(‘#some-handle’).fadeIn();n”;
            }
            add_action(‘wpsc_alternate_cart_html’, ‘theme_cart_update’);

            in function.php and

            <span id="some-handle" style=" 0) echo ‘display:block;’; ?>”>
            <a target="_parent" href="” title=”” class=”gocheckout_dyn”>

            this in header.php

            thanks

  • Rajeev

    0) echo ‘display:block;’; ?>”>
    <a target="_parent" href="” title=” _e(‘Checkout’, ‘wpsc’); ” class=”gocheckout_dyn”> _e(‘Checkout →’, ‘wpsc’);

    • G’day Rajeev, you’ve mixed up someone else’s code with what you want to do. Change your jQuery line to this:

      echo "jQuery('#some-handle').html("$cart_count");n";

      I recommend you change “some-handle” to something meaningful too, like I said to IvanoC :)

      • Rajeev

        thanks,
        its working but when i am change or refresh the page then it also become changed to 0.

        thanks

        • That means your code in your header.php isn’t calling wpsc_cart_item_count() to get the cart count. Fix that, and you’ll be off and running.

          • Rajeev

            thanks alot its working
            your are awesome…

  • Hi Ross, and thanks for your snippet! However i seem to have some troubles… It displays the jquery part of the code as text… And if i delete that part, the loading after clicking add to cart continues, like, forever… Would you have a solution?

    • G’day François, make sure that the line HTML; is hard up against the margin in your code; don’t indent it. If that’s not your problem, please do a pastebin of your code and link it here, and give me a link to your problem page.

      cheers,
      Ross

      • Hey Ross, Thanks for your help. However, i couldn’t find a solution… Here is the pastebin: http://pastebin.com/HwN1eMCJ and here is the test website i’m trying to implement it in: http://www.purplecap.fr/lustre/
        Can you help, please?

        • G’day François, it looks like you’ve got the jQuery code in the header.php.

          I suggest you take a look at Gary Eckstein’s post, because he runs through the whole process from all angles and it might help explain better than my post does.

          cheers,
          Ross

  • Thanks ;)
    This might help me a lot!
    I’ll keep you posted!

  • Hi – An even simpler way of doing this is as follows:

    1. Add an element to hold your total:

    This will display the number of items on a page-to-page basis. Then, in ajax-functions.php, find line 135:

    echo “jQuery(‘.cart_message’).delay(3000).slideUp(500);”;

    …and add another line just below it as follows:

    echo “jQuery(‘#incart’).html(“.wpsc_cart_item_count().”);”;

    A tiny bit hacktastic, but appears to work very neatly!

    • edit – that wiped my code, sorry. The first line should have been:

    • doesn't work either!

      echo(wpsc_cart_item_count());

    • G’day Kit, you could indeed to that… and then keep replacing that code every time you / your client updates the plugin and wipes out your code. IOW, you could do that if you want to set yourself up for problems and extra work :)

      A general rule about hacking code that will be replaced by an update is: don’t.

      WordPress and most useful plugins provide action and filter hooks that allow you to make customisations that will last through updates. Even when plugins don’t provide useful hooks themselves, you can often hack them into compliance through WordPress filters hooks. Learn to use them, and your clients will never need to send you an URGENT ASAP HELP email when they update their plugins and find out from their customers that their website has lost some vital functionality.

      cheers,
      Ross

  • Rajeev

    Hi I have a question that how i will add the products category as a menu item, just like the simple cate gory i have added from the WordPress backend as a menu.
    I am using the WP-ecommerce plugin.

    Thanks

  • Rajeev

    Hi,
    I am using the wp e-commerce plugin in one of my site.
    Now i want to show all the custom products fields on a single page{template} with there name and link. Is it possible? If yes, then how, i am really need the help.

    Thanks in advance.

    • G’day Rajeev,

      There’s a support forum for that: http://getshopped.org/forums/

      cheers,
      Ross

      • Rajeev

        Hi,
        Thanks for your reply. I have solved the problem with mysql database query.
        I have get the meta value according to meta key from wp_postmeta table.

        Thanks
        Rajeev

  • Jordan

    After sitting for about 2 hours staring at this and looking at the *cough* *cough* “documentation” *cough* over at getshopped, your solution has been a ray of light in what was otherwise, quite a crappy day :-)

    Thank you so much!

    • If nothing else, wp-e-commerce gives you plenty of staring exercise :)

      cheers,
      Ross

  • brian

    I am trying to solve this and not able to get it to work. I placed wpsc_cart_item_count() in my header.php file and it is displaying the proper product count after a refresh. I am having an issue getting your solution to update it using the ajax call.

    Where should the code be placed that is listed above in your solution?

    • G’day Brian,

      I suggest you add it to the functions.php file in your theme. If your theme is an off-the-shelf theme, the I suggest you create a child theme from it and place this code in its functions.php file.

      cheers,
      Ross

  • brian

    First off, thank you SSOOO much for helping with your script. Im sure it will come back to you in Karma.

    Now to your suggestion, I did try adding that code to my functions.php file in my custom built theme. I keep getting the following error on my servers error_log

    [Sun Sep 30 10:00:32 2012] [warn] [client 108.16.87.167] mod_fcgid: stderr: PHP Fatal error: Cannot redeclare theme_cart_update() (previously declared in /var/www/vhosts/curotec.com/subdomains/curotec.net/pjbs/wp-content/themes/PJs/functions.php:571) in /var/www/vhosts/curotec.com/subdomains/curotec.net/pjbs/wp-content/plugins/wp-e-commerce/wpsc-includes/ajax.functions.php on line 141, referer: http://pjbs.curotec.net/products/beef-steak/pjs-all-natural-beef-steak-slices/

    Any ideas?

    • G’day Brian,

      It sounds like you copied the code into the ajax.functions.php file in wp-e-commerce plugin. Don’t do that! :)

      You generally shouldn’t ever edit the files in plugins, because your edits will be replaced when you update the plugin. Besides which, that was the wrong place for this snippet. Just have it in your theme’s functions.php and nowhere else.

      cheers,
      Ross

  • brian

    Ross,

    I placed your code in the above article in the functions.php file located at => stylesheet_directory();

    I understand the concept of hooking into plugins so they don’t get overwritten. I bet you get that question a ton though. :)

    I did notice this though, I got a fresh ajax.functions.php file because I was making some mods to it for testing and I must have forgotten to take some code out.

    It seems to work now for the mini-cart, but only after you add an item to your cart once then refresh, then it works.

    Heres the URL for it: goo.gl/p0BLz

    Can you tell me what you see on your end? I don’t think its caching because I tried it on a bunch of different computers and did clear cached files.

    At least I’m making progress now though :D
    Thanks again for helping!

    • G’day Brian,

      Your script is correct, but the minicart doesn’t have the spans until something has been added to the cart, so the script can’t update anything. To see what I mean, add one item to the cart, reload the page, then add another. The second one updates the minicart.

      Somewhere on your site, you are replacing the contents of the minicart with the “no items” message, and wiping out your count and total spans. Fix that (or change your script to replace the minicart contents completely) and you’re set.

      cheers,
      Ross

  • brian

    Brilliant!!! Thank you Ross!!!!

    You have been a huge help!

  • brian

    Its working now perfectly!!!!

    goo.gl/CzUhr

    Thanks again Ross!!!!

    • No worries, glad you got it working.

      cheers,
      Ross

  • Tom

    This is so awesome, but I’ve been trying so hard to make my basket image change when you add something in the cart. The only problem I can’t seem to understand is when you refresh the page, how do you check the count and keep my basket image reflecting that it’s been filled.

    Thanks so much for the help.

    • G’day Tom, you need to have your template code check the cart count in PHP. My post only tells you about the JavaScript bit, but you can get the full picture from Gary Eckstein’s on the subject.

      cheers,
      Ross

  • Hi Ross,

    Thank you for this blog, very usefull. I used your method and had it perfectly working until I updated my WP e-Commerce today.. Would you mind taking a look?

    My code exacly as is: http://pastebin.com/dTabqgPN

    Observed behaviour:
    shoppingcart empty: 0 items | € 0,00
    Added 1 item costing 0,05: 1 items | € 10,05
    Added another item costing 0,06: 1 items | € 30,06
    Added another item costing 0,07: 1 items | € 30,07
    Refresh page: 3 items | € 10,18
    Add another item and the number of items resets back to 1.
    The 10,00 comes from shipping costs, which wasn’t counted in before. it seems to be added every time an item is added, and the item price itselve is not added but replaced.

    I’m not a programmer and I’m not sure where to look to go and solve this. Do you have any clue?
    If you want me to set you up with an account so you can view the shop, just let me know.

    • Update: Changed wpsc_cart_total_widget(); to wpsc_cart_total_widget(false,true,true); which gets rid of the shipping costs in the totals.

      Now it’s clear to me the shopping cart shows only the values for the last added item and not for the total until I do a refresh
      So first item added: 1 item | 0,05
      Second item added: 1 item | 0,06
      Third item added: 1 item | 0,07
      Refresh: 3 items | 0,18
      Forth item added: 1 item | 0,08

      Is this the ajax not updating things correctly or are the wpsc functions screwed up?

      • Are you getting any errors in your browser’s JavaScript console? Can you use Chrome’s developer tools or Firefox’s Firebug plugin to watch the AJAX packets and see what’s coming back from the server?

        cheers,
        Ross

        • I use Chrome and with the developer tools jacascript console I only get “FB.getLoginStatus() called before calling FB.init().”

          But when I remove all Facebook stuff, the bug is still there and the Facebook stuff was there before I updated.

          I’m not sure if this is what you are looking for, but I found these response headers in my developers tools network console: http://pastebin.com/fQGxbc4S

          If this is not what you are looking for, can you specify how I can get the proper info?

          • G’day Anna,

            It sounds like GetShopped have deliberately broken the old behaviour of their AJAX updates, so some new code will be required. This is why I never update plugins like WP e-Commerce on a live site before testing the update in a development environment — too often they break existing websites.

            I’ll need to face up to this sometime soon because I’ve built a few sites that use this behaviour, and they’ll need to be updated to the latest WP e-Commerce version at some point. When I get a chance, I’ll write a new post that supersedes this one, but I imagine it won’t be for a couple of weeks yet.

            cheers,
            Ross

          • Hi Ross,
            Thanks for your reply. I’m in the development stage at the moment, so it’s not a live environment, but nonetheless very frustrating. I’ll try to solve it, and if I can’t, I’ll downgrade the plugin.

            If I find a solution I’ll let you know! Thanks again for your help.

  • Daniel

    DO you have a time frame on when this will be updated?