Grabbing cart data when not in the cart

vossavantvossavant Member
in Help edited June 2010
Hi FoxyFellas,

I've got a rather complex setup where I have to run some math on the cart contents and output total savings, etc., plus I'd like to have thumbnails in the cart.

Please feel free to tell me if this is dumb, but I'm thinking of building my own cart using an ExpressionEngine teomplate. This would allow me to parse the EE template tags and do the things I need to do. Can I grab the cart contents with JSON on this EE page, or...is that just the worst idea you've seen in a long time?

(Brett: Hey Luke, get a load of this guy -- we built him a cart platform and he's trying to build his own cart...within our cart...lol)
Comments
  • lukeluke FoxyCart Team
    Heya vossavant. No, not crazy at all! Actually, some of the coolest integrations we've seen have involved custom shopping cart systems using the FoxyCart JSON. Check this one out as an example: http://www.modernash.com/products/cart
    You can drop in an ikea url like this one: http://www.ikea.com/us/en/catalog/products/90133982 and it will do some cool stuff in the background for you.

    Check these links for more info:
    http://wiki.foxycart.com/docs/json
    http://wiki.foxycart.com/docs/json/tutorial
    http://wiki.foxycart.com/docs/jsonp
  • Sweet, thanks!

    The docs say the JSON object is loaded whenever foxycart_includes.js is called...which is on all of my pages. In order to access this object, do I need to explicitly call it, like this...
    $(document).ready(function() {
    	$.getJSON('http://mysite.foxycart.com/cart?output=json&cart=view&callback=?' + fc_AddSession(), function(data){
    		// do something with `data`
    		alert('total price: $' + data.total_price);
    	});
    });
    

    ...and then use the jQuery html() function to dynamically write the cart contents to my EE template...or is there a better way?
  • lukeluke FoxyCart Team
    No, you shouldn't have to. Define a function called fc_BuildFoxyCart() and put all of your stuff in there. By the time that method is called, fc_json should be defined. The tutorial I linked to above should have more information.

    We had a store that was doing things incorrectly calling the json cart 6 times with every page load! When they got blown up on gizmodo, tauw, cnet, etc... no one was happy because we were getting hammered. So yeah, please limit the calls to the json cart to only what you absolutely need.
  • vossavantvossavant Member
    edited June 2010
    Thanks for the response Luke. Turns out I don't think I'll need to use the FC function to build the cart.

    My approach is to use ExpressionEngine's (EE's) tags to build the cart instead. This is the only way I can have all the flexibility I need. Process would be like this:

    1. Store the EE product IDs as a custom option
    2. Grab the EE product IDs from the JSON object and parse with PHP
    3. Embed the EE product IDs in the EE tags (so we can pull the correct products)

    I have to use PHP because I can parse PHP before the EE tags.

    In an effort to spare you guys some time on this next question, I did a bunch of homework trying to find an answer, but had no luck. I'm trying to read the FoxyCart JSON object into a PHP file so I can parse it. I know the object is sitting there; I'm just not sure how to grab it.

    I tried this:
    $json_stuff = json_decode(file_get_contents("https://example.foxycart.com/cart?output=json";));
    echo $json_stuff->total_weight;
    

    But that outputs a 0, even though I verified there is a total weight by visiting that URL.

    Doing the following:
    $json_url = file_get_contents("https://example.foxycart.com/cart?output=json";);
    echo $json_url;
    

    Outputs:
    { "products":[ ], "product_count": 0, "total_price": 0, "total_weight": 0, "session_id": "7luumgcnjkef4e8dbfuf7", "custom_fields":{ }, "messages":{ "errors":[], "warnings":[], "info":[] } }
    

    So it looks like only session_id is populated. Maybe file_get_contents isn't the way to go...?

    I'm sorry to pester you guys with this; I know it's more of a PHP question. I ask here because you know the FC JSON object better than anyone, and I want to make sure I'm calling it only when I need to (see previous post by Luke).
  • brettbrett FoxyCart Team
    Huh. I was going to recommend using CURL not file_get_contents, since that often won't work on remote files, but you're getting something. The issue looks to be the session. When you're requesting the &output=json you also need to include the &fcsid=FOO or FC will have no way of knowing what cart you're actually requesting. Make sense?
  • vossavantvossavant Member
    edited June 2010
    Hey Brett,

    Thanks - what you're saying kinda makes sense. What I don't understand is that the session ID is the only thing that actually shows up when I use file_get_contents to load the JSON. If the JSON is already present on the page I'm using (the page that has the PHP snippet in it that loads the JSON) and it has the session ID, why would I need to pass the session ID to the JSON to load it? Can't I just...reach out and grab what's already there?

    I guess the more important determination is getting the FCSID and appending it to that URL. I read the docs on JSONP and it says something about adding the session ID using fc_AddSession(). Is that what you're talking about?

    I'll try working that function into my PHP snippet later on tonight, so if I get to that before I hear back I'll report my findings. Thanks again for your help.
  • vossavantvossavant Member
    edited June 2010
    Hey guys,

    Please disregard my previous message. I followed the tutorial here and got a custom cart working at my own URL (http://www.example.com/cart). Adding products via JSON works like a charm and everything loads great there. There are just two catches:

    1. When clicking "add to cart" the form action has to point to http://example.foxycart.com/cart or else no product is added. Maybe this is the correct behavior. Only problem is...
    2. When I cache my custom cart template URL (http://www.example.com/cart) it does not work when I load http://example.foxycart.com/cart. When I say "does not work" I mean it does not appear to load the JSON object. The cart skeleton is there, but no products appear.

    I know this is pretty vague, so I can whisper actual URLs if helpful. Any help the community can provide would be greatly appreciated.

    If I get this working I'd like to write a blog post on building a custom cart and incorporating with ExpressionEngine (partially for my own future reference :))
  • vossavantvossavant Member
    edited June 2010
    Update - please continue to disregard my previous messages :)

    The cart wasn't generating at http://example.foxycart.com/cart because jQuery wasn't being called properly. I've got the cart showing up now and working at http://example.foxycart.com, but now the remove links don't work. I've tried recreating the functionality of the default FoxyCart cart; e.g., by making sure the remove links all look like this:
    <a href="#" onclick="fc_RemoveItem(X); return false;" title="Remove this item">Remove</a>
    

    Where X is the item's # in the cart.

    I've then made sure that the quantity input field is generated. The input value is set to 0 as fc_RemoveItem() says:
    function fc_RemoveItem(item_count) {
    			jQuery("#quantity"+item_count).val(0);  // this happens, but...
    			fc_UpdateCart();
    		}
    

    But then the page reloads and the removed item is still in the cart, with the quantity value set as before.
  • lukeluke FoxyCart Team
    Hey vossavant. Brett may understand what's going on here, but I'm a bit lost. What do you want us to ignore and what should we focus on as far as your questions go? As far as I understood, the original issue was just that your curl url needs to have the correct session id appended to it so you know which cart to pull, right? If that's still the issue, that needs to be solved first.

    As a side note, we generally won't be around on Sundays USA time so we're not disregarding you on purpose. :)
  • Hey Luke,

    Thanks for getting back. I know that you guys aren't responsive on the weekend, so no problem. You need some time to yourselves :)

    You can ignore everything but my most previous message -- I ended up posting and then subsequently solving my own problems.

    I managed to get my own custom cart working by following the cart tutorial on this wiki page. The only issue I'm currently having with my custom cart is that the "Remove" functionality does not work. You can see my custom cart here; visit the store here if you need to add some products. I feel better about this cart because I don't need to use PHP or cURL to get to it; simply accessing it via fc_json.[x] works great.

    Interestingly, I couldn't get fc_BuildFoxyCart() to fire, so I didn't use it.
  • lukeluke FoxyCart Team
    Hey vossavant. I'm not able to add any products because they don't have prices. As for the "remove" functionality, it's really just a cart update with a quantity set to 0 for the product you want to remove. The fc_BuildFoxyCart() should fire off as long as you've defined a function with that same name and you have the foxycart_includes setup correct (which it appears to be)... we'll have to look into that.
  • Hey sorry about the lack of prices Luke...we're still adding those. Here are a couple of products that do have prices, if you're interested in giving them a whirl:
      [li]
    Bath tub #1[/li]
    [li]Bath tub #2[/li]


    I made sure to define fc_BuildFoxyCart after including foxycart_includes.js; placed an alert function in there, but that never fires.
  • lukeluke FoxyCart Team
    Oh, I see the problem. You're not using the default foxybox but you've built out the cart as a completely separate page. The fc_BuildFoxyCart method would fire off on your site after the thickbox cart is closed. That's all wired up in the foxycart includes file which isn't included on the cart template hosted on our site. If you're already on that page, you can just do a jQuery onload and access the json object right there. If you're already on the cart page and you want to modify things in the cart, that will be a little tricky because you'll probably have to reload the cart page entirely. Not too sure because you're doing some custom stuff there.
  • Thanks Luke. I see now where it says the build cart function fires after closing the FoxyBox. So the question becomes: how do I drop a product from the JSON object by clicking "Remove" on my custom cart? It looks like this is normally done by setting the Qty to 0. I thought I could copy the default cart functionality:

    1. Using jQuery, build a qty input field that has the same name and ID as the ones in your default cart, like:

    <input type="text" class="fc_cart_item_quantity" id="quantity1" name="quantity1" value="1">

    2. Build the "Remove" links like:

    <a href="#" onclick="fc_RemoveItem(1); return false;" title="Remove this item">Remove</a>

    The "Remove" click does set qty to 0, but that might not mean anything since my input fields may not actually be talking to the FoxyCart scripts -- if that makes sense.

    I realize I'm out in Custom Land and that I signed myself up for this, so if you don't know where to point me I totally understand. That being said -- any thoughts on how to get my remove links talking with your scripts and the JSON object is appreciated. I'll keep working on it.

    As an aside, this cart is by far the most customized FoxyCart implementation I've done, and I continue to be very impressed and amazed at just how flexible and powerful your product is. Thanks again for making FoxyCart a developer's dream!
  • lukeluke FoxyCart Team
    Thanks vossavant. We may use that quote. :)

    Setting the quantity is just the first part, then you'll need to actually submit the cart with an update action. Your best bet may be to take a look at the default FoxyCart implementation and use FireBug's net tab to look at what data is being sent back and forth. The links I put in the first reply should have some examples of how to do this via the JSONP too. Hope that helps point you in the right direction.
  • brettbrett FoxyCart Team
    Hi @vossavant.
    Just wanted to chime in and say "wow". I loaded up your cart and was thoroughly confused for a moment, because the cart was most definitely at *.foxycart.com, but it wasn't the standard cart. I don't believe anybody's ever taken that approach.

    Please vote for this though:
    http://requests.foxycart.com/forums/4162-general-requests/suggestions/121058-template-language-editable-cart-checkout-templat?ref=title

    Your customized cart is probably a PRIME example of how awesome a full template language would be. (It's one of my pet requests, fwiw, hence the excitement.) Great work so far.
  • Thanks for the kind words Brett! With hindsight I can tell you that it's not too difficult to do just about anything with FoxyCart, JSON, and jQuery. I added my 3 votes to your templating idea. Sounds great.
  • Hey Luke,

    I found the info on removing items from the cart here. The docs say to "send" something like:
    &cart=update&1:quantity=0&1:id=<product id from json>&2:quantity=0&2:id=<product id from json>
    

    If I type in a URL like...

    http://example.foxycart.com/cart.php?&cart=update&1:quantity=0&1:id=<product id from json>&2:quantity=0&2:id=<product id from json>

    ...the product is removed fine. My questions are...do I need to point my form action to a URL like that? Wouldn't that require me writing a function separate from fc_RemoveItem, since that function doesn't work for me? Where is that URL being generated on the default cart? I don't see any submit buttons or hidden fields or form actions pointing to anything like that. I ask because I need to recreate that string in my custom cart for the remove button to work. The thing is, I'm already taking advantage of some of your functions (fc_RemoveItem, fc_PreventCheckout) and don't want to rewrite them if I don't have to.

    I hope my question(s) makes sense.
  • lukeluke FoxyCart Team
    I'm still a little confused on the whole custom cart thing... is there a reason you can't just use the default cart as your cart template and then have everything work as expected? To make things work you'll probably just have to copy everything the default cart does anyway which involves having the form action set to your store url's cart along with all the necessary hidden form fields built into the standard cart. With all of those in place and everything named exactly as our cart is setup, the fc_RemoveItem and similar functions should work as expected but at that point, since you're replicating the entire cart anyway, why not just use the standard cart?
  • Hey Luke,

    I thought about using the default cart at the beginning, but if you take a look at what I've got (attachment) you'll see a few extra columns and rows that aren't in the default cart. Rather than manipulate everything to death with jQuery and CSS, I figured I'd build from scratch.

    I suppose I could use some jQuery functions (like insertAfter and insertBefore) to get my stuff where I want it, but I think it's easier if I figure out a way to get the remove functionality working. I won't bug you guys on this anymore; thanks for all of your help on this. I'm totally down for Brett's idea of a templating language!

    mylegwork-cart.png
  • fc_adamfc_adam FoxyCart Team
    edited June 2010
    Something like this should work for you. Let's say your remove link had a class of 'fc_cart_remove_link'. Set it to a href of the following:
    https://FOXYDOMAIN.foxycart.com/cart?&cart=update&1:quantity=0&1:id=PRODUCTID
    
    $("a.fc_cart_remove_link").click(function(){
        $.getJSON($(this).attr('href') + '&output=json&callback=?' + fc_AddSession(), function(data){    
          // You'd need to remove the relevant row from the table here
    fc_json = data; // Replaces the json so everything else can use it
    fc_UpdateCart("FOXYDOMAIN"); }); // Updates the cart
        });
        return false;
      });
    
  • brettbrett FoxyCart Team
    Thanks @fc_adam for chiming in. I haven't tested, but it looks solid.

    @vossavant, I'm kind of with Luke in the sense that I probably would have gone with hacking the existing cart to death rather than rebuilding it, but fwiw I do definitely see why you took the approach you did, and realistically it's probably a better option (and basically is a case study for how awesome a template language would be). Just want to make it clear we're not passing judgement or anything.
  • vossavantvossavant Member
    edited June 2010
    Thanks fc_adam. Your approach works great even without the jQuery, but only for the first product in the list. Adding the jQuery has no effect; the 1st product is still the only one that gets removed on click. For the other products, I just get a page refresh.

    Edit: Just noticed that fc_addSession is not defined. Not sure why that is...

    I suspect that if I knew what to put where you say "you'd need to remove the relevant row from the table here" then it would work. Would you mind clarifying that piece? I'm almost there, and really appreciate the help you all have lent so far.


    @brett,

    lol

    I understand what you're saying. Reinventing the wheel isn't something I like to do; however, everything outside of the "remove" functionality was pretty easy to get going. A templating language would be more than welcome, but what you're able to do without it is pretty amazing.
  • brettbrett FoxyCart Team
    I think what Adam means by "you'd need to remove the relevant row from the table here" is to remove the <tr> element from the DOM. Right? I think that makes sense.

    The fc_AddSession() is available via the foxycart_includes.js, which isn't loaded on the cart (AND SHOULDN'T BE! it'll actually break things). So replace that with...
    $.getJSON($(this).attr('href') + '&output=json&fcsid='+fc_json.session_id+'&callback=?', function(data){
    
    I think that'd do what you needed for that section.

    As to not removing more than one product, I'm not sure about that, but hopefully the two notes above help resolve that issue.
  • Hey Brett,

    Thanks for your response. I was about to write you another note on how I couldn't get this to work, but I figured it out. Maybe you can understand why this works:

    Say I'm trying to remove the 4th item in my cart; I'd pass this:
    https://secure.example.com/cart?cart=update&4:quantity=0&4:id=1414141
    

    That wasn't doing anything, so I eventually discovered that having the same item # for every item in the cart works. Thus, no matter which item I want to remove, I pass in #1 for the item:
    https://secure.example.com/cart?cart=update&1:quantity=0&1:id=1414141
    https://secure.example.com/cart?cart=update&1:quantity=0&1:id=9359983
    https://secure.example.com/cart?cart=update&1:quantity=0&1:id=4589026
    

    I hope that makes sense.

    I don't need to use the click() function at all. I can verify that the JSON object is empty and the appropriate items are removed after each click. Do you see anything funny with how this works?
  • brettbrett FoxyCart Team
    Yeah, I see the confusion there. I think it's twofold:
    1) It used to be based on the numbers like that, but that was awkward so we made it based on IDs.
    2) The 1: isn't actually necessary. I've updated the docs, but the 1: and 2: and etc are used if you're modifying multiple quantities at once. If you don't start at 1: though you'll run into problems.

    So you're code is fine. You could remove the 1: prefixes if you wanted. That's why it works :)
Sign In or Register to comment.