Solved

Cart items not showing in header until page refreshed

Posted on 2016-11-12
15
23 Views
Last Modified: 2016-11-13
When I click "add to cart", I redirect to the cart page and it will show a total of "1" for that item on the cart page. I also have a cart icon in the header which should show the same total. I am using the same session variable for both totals yet for some reason the total in the header only updates if I refresh the page. I find this strange since both are using exactly the same session variable. The header however is in header.php which is included in cart.php.

This is the code that adds products to the cart:

function add_to_cart($link) {
	
	if(isset($_GET['add'])) {
		
		$stmt = $link->prepare("SELECT `prod_qty` FROM `bb_products` WHERE `prod_id` = ?");
		$stmt->bind_param("i", $_GET['add']);
		$stmt->execute();
		$result = $stmt->get_result();
		$numRows = $result->num_rows;
		if($numRows > 0) {
			while($row = $result->fetch_assoc()) {
				
				if($row['prod_qty'] != $_SESSION['product_' . $_GET['add']]) {
					
					$_SESSION['product_' . $_GET['add']]+=1;
					header("location:cart.php");
					exit;
					
				} else {
					
					echo "Not enough stock on hand";
				}
			}
		}
		
		$stmt->close();
	}
}

Open in new window


The code in both the header and cart pages to display the qty is:

<?php echo isset($_SESSION['item_qty']) ? $_SESSION['item_qty'] : $_SESSION['item_qty'] = 0; ?>

Open in new window

0
Comment
Question by:Black Sulfur
  • 8
  • 7
15 Comments
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884602
Not sure we can tell from these code fragments, but here are a couple of ideas.  

The second fragment makes reference to $_SESSION['item_qty'] but this variable is not mentioned anywhere in the first fragment.

If you're testing this in a browser, make sure that the browser is not able to cache the HTTP requests.  You can find specific instructions by making a Google search for something like:
"turn off cache in (IE|Safari|Firefox|Chrome|Opera)"
0
 

Author Comment

by:Black Sulfur
ID: 41884612
Sorry, you are right.

On the cart page I have:

 <?php show_cart($link); ?>

Open in new window


This is the show cart function. The cart functionality code is taken from a tutorial I did. I don't know if this is the common way to do it but I thought it was a bit odd with the substr bit. But I can't actually judge because I am no expert. That is a sidebar issue I think. Unless it has a direct impact on why I am having the problem I posted about.

function show_cart($link) {
	
	$total = 0;
	$item_qty = 0;
	
	foreach($_SESSION as $name => $value) {
		
		if($value > 0) {
			
		if(substr($name, 0, 8) == "product_") {
								
			$length = strlen($name - 8);
			$id = substr($name, 8, $length);
			
	$stmt = $link->prepare("SELECT * FROM `bb_products` WHERE `prod_id` = ?");
	$stmt->bind_param("i", $id);
	$stmt->execute();
	$result = $stmt->get_result();
	$numRows = $result->num_rows;
	if($numRows > 0) {
		while($row = $result->fetch_assoc()) {
			$prod_id = $row['prod_id'];
			$prod_name = htmlentities($row['prod_name'], ENT_QUOTES, "UTF-8");
			$price = htmlentities($row['sale_price']);
			$subtotal = $value * $price;
			$item_qty += $value;
			$show_cart = <<<SHOWCART
			
			<tr>
                  <td class="image hidden-xs">
                      <img src="http://placehold.it/100x50" alt="product">
                  </td>
                  <td class="details">
                    <div class="clearfix">
                      <div class="pull-left">
                        <a href="#" class="title">
                          {$prod_name}
                        </a>

                      </div>
                      <div class="action pull-right">
                        <div class="clearfix">
                          <a href="cart.php?update={$prod_id}"><button class="btn-success btn-raised ripple-effect">
                            <i class="ti-plus">
                            </i>
							</button></a>
							<a href="cart.php?remove={$prod_id}"><button class="btn-warning btn-raised ripple-effect">
                            <i class="ti-minus">
                            </i>
                          </button></a>
                          <a href="cart.php?delete={$prod_id}"><button class="btn-danger btn-raised ripple-effect">
                            <i class="ti-trash">
                            </i>
                          </button></a>
                          
                        </div>
                      </div>
                    </div>
                  </td>
                  <td class="qty">
                    <input type="text" value="{$value}" name="">
                  </td>
                  <td class="unit-price hidden-xs">
                    <span class="currency">
                      R
                    </span>
                    {$price}
                  </td>
                  <td class="total-price">
                    <span class="currency">
                      R
                    </span>
                    {$subtotal}
                  </td>
                </tr>
SHOWCART;
echo $show_cart;

		
		}
		
$_SESSION['item_total'] = $total += $subtotal;
$_SESSION['item_qty'] = $item_qty;
		
	}
	
	$stmt->close();
			
			
			}		
		}
	}
}

Open in new window

0
 
LVL 108

Accepted Solution

by:
Ray Paseur earned 500 total points
ID: 41884628
Wow, I don't know what to say.  You probably want to go back to find that tutorial and kill it with fire.  It looks like something from the last millennium!

Here are some thoughts about the design...

If you put your shopping cart in the PHP session the cart will expire when the session expires.  That's terrible UI because it means that the client can never shop, leave, return, and find the previously selected contents of the shopping cart.  The cart should be a collection,such as an array of objects, kept in the database, and recovered into the session (or a similar dependency-injectable variable) at page-load time.  The database cart should be updated as the client makes changes.

There is a concept in software design that separates logic from presentation.  You can find information about it by searching for terms like Model-View-Controller or MVC Design.  Having a function that echos a lot of HTML is a violation of this design idea.  It means greater complexity and more difficult testing (in fact, automated testing is virtually impossible with a logic function that produces browser output).  A better design would prepare the data objects in the Model, and pass the prepared objects to the View, where the rendering would take place.

Here's an example of why we separate logic from presentation:
$price = htmlentities($row['sale_price']);
$subtotal = $value * $price;

Open in new window

The first instruction prepares a variable for browser output.  The second instruction uses the browser output (string) as a numeric value in a computation.  Even though PHP will let you use loose data typing like this, it leads us to sloppy thinking.  An arithmetic logic variable should remain numeric, a display variable should be string.

Sorry, I don't know of any good shopping cart examples, but I know there are a lot of open-source shopping carts.  Maybe look for one built in more recent times and follow its general design as you build your own.
0
 

Author Comment

by:Black Sulfur
ID: 41884630
Just a quick question about what you said regarding storing the cart. I did consider keeping the cart items in a database but what happens if the user never buys anything and doesn't come back to the site. How do those disregarded items get removed from the database at a later point or don't they? If they don't then won't your database just keep getting bigger with useless info i.e.: orders that were never placed. Some people might want that data for analytics but some won't?

I am disappointed that the code is outdated. I have looked at Magento and Prestashop but they seem really massive. I just want to do something small from scratch as it is much less intimidating and there isn't a mountain of code to try sift through.
0
 

Author Comment

by:Black Sulfur
ID: 41884631
The second instruction uses the browser output (string) as a numeric value in a computation.  Even though PHP will let you use loose data typing like this, it leads us to sloppy thinking.  An arithmetic logic variable should remain numeric, a display variable should be string.

What would be the correct way to do this then?

$price = htmlentities($row['sale_price']);
$subtotal = $value * $price;

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884639
your database just keep getting bigger with useless info i.e.: orders that were never placed
This is the opposite of "useless info" -- it's the only insight you can get into why you got an abandoned shopping cart.  Your marketing department will have all kinds of analytics and A:B tests for your cart design, trust me.  Even a tiny percentage increase in conversions from cart to purchase can mean big money.

Search for some shopping cart design ideas.  You might find something at SitePoint.  Most of their stuff is really good.
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884640
What would be the correct way to do this then?
Redesign the application to separate the logic (calculations) from presentation (HTML).  There isn't any answer in those two lines of code; it's a top-down redesign.  Right now, your application depends on the output of HTMLEntities() being a numeric string.  HTMLEntities() does not necessarily return a numeric string - it returns an entitized string for browser display.  The Model should do the calculations and prepare data objects for the View.  The View is where you might use htmlentities().
0
Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

 

Author Comment

by:Black Sulfur
ID: 41884641
Yep, totally agree that it won't be useless to companies like Amazon who have teams of people to slice and dice that kind of detail. But for me who might sell one or 2 items on my site, I really am not going to analyze that. But anyway, it would be something good for me to practice doing even if I didn't intend on using that info myself.

For the sake of my particular scenario though, are you saying you cannot see from the code why I would be having the problem I do in that on the cart page everything is displaying fine but the header cart total display only shows on page refresh?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884646
One last comment on this, then I gotta go.  You can "prune" the database.  To do this, you add a TIMESTAMP column to the table.  When you consider the database to have gotten too big, you can begin your deletions with a query that orders by the TIMESTAMP column ASC.

And sorry, I can't see the problem from the code examples.  It's a data-dependent problem, so I would look carefully at variable names and scopes.  Maybe sprinkle var-dump() into the script.  In the second script $item_qty appears to be used as though it is a subtotal, not a quantity, and I can't find anywhere that it gets displayed.  That's one of the big benefits of MVC logic - you can separate the responsibilities of computation from presentation.  Debugging becomes instantly easy!

Beware the loose-typing of string variables when they are used in arithmetic statements.
http://php.net/manual/en/language.types.type-juggling.php
0
 

Author Comment

by:Black Sulfur
ID: 41884651
Okay, thanks for the info, it's really helpful. If you get time to look at this I found another add to cart script. Not sure if approve of this one? Hopefully it's better than the last one.


// get the product id
$id = isset($_GET['add']) ? $_GET['add'] : "";
$quantity = isset($_GET['quantity']) ? $_GET['quantity'] : 1;
//$page = isset($_GET['page']) ? $_GET['page'] : 1;
 
// make quantity a minimum of 1
$quantity=$quantity<=0 ? 1 : $quantity;
 
// add new item on array
$cart_item=array(
    'quantity'=>$quantity
);
 
/*
 * check if the 'cart' session array was created
 * if it is NOT, create the 'cart' session array
 */
if(!isset($_SESSION['cart'])){
    $_SESSION['cart'] = array();
}
 
// check if the item is in the array, if it is, do not add
if(array_key_exists($id, $_SESSION['cart'])){
    // redirect to product list and tell the user it was added to cart
    header('Location: cart.php?action=exists&id=' . $id . '&page=' . $page);
}
 
// else, add the item to the array
else{
    $_SESSION['cart'][$id]=$cart_item;
 
    // redirect to product list and tell the user it was added to cart
    header('Location: cart.php?action=added&page=' . $page);
}

Open in new window

0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884759
There's not really much difference.  It still uses the PHP session to hold the cart.  And it looks like if I have a box of corn flakes in my cart, and I try to add another box of corn flakes, it won't work.  I say "looks like" because I can't really tell for sure, but it seems that way.  

Sitepoint forums seems to like Shopify.
https://www.sitepoint.com/community/t/shopping-cart/212670
https://www.shopify.com/

Some other open-source suggestions.
https://www.opencart.com/
https://www.x-cart.com/

Maybe also Zeus cart, Zen cart, Prestashop, OSCommerce?  Magento seems to bloated for a learning tool.
0
 

Author Comment

by:Black Sulfur
ID: 41884773
Haha, you crack me up sometimes :)

What do you use or do you have your own custom designed cart system?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884793
I use whatever my clients want me to use.  I don't sell anything online in my own site.  

Forgot to mention it, but PayPal has some well-thought-of shopping functionality, too.
https://developer.paypal.com/
0
 

Author Comment

by:Black Sulfur
ID: 41884817
Okay, last question. If your clients don't specify what you must use and they give you carte blanche, what would you choose to do i.e.: use a framework or do it by hand?
0
 
LVL 108

Expert Comment

by:Ray Paseur
ID: 41884834
Sorry, I can't answer this.  It's a bit like asking "What car is best?"  Any choice I might make would be built upon years of experience and experimentation with different build processes.  I'd probably choose a framework, but "probably" is about as close as I can get.  The car analogy omits many important things, such as "do you have a family" or "how far do you need to commute" -- in other words, there is not any one answer that responds well to the breadth of options.
0

Featured Post

Free Trending Threat Insights Every Day

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

Join & Write a Comment

Things That Drive Us Nuts Have you noticed the use of the reCaptcha feature at EE and other web sites?  It wants you to read and retype something that looks like this.Insanity!  It's not EE's fault - that's just the way reCaptcha works.  But it is …
This article discusses four methods for overlaying images in a container on a web page
Explain concepts important to validation of email addresses with regular expressions. Applies to most languages/tools that uses regular expressions. Consider email address RFCs: Look at HTML5 form input element (with type=email) regex pattern: T…
The viewer will learn how to create and use a small PHP class to apply a watermark to an image. This video shows the viewer the setup for the PHP watermark as well as important coding language. Continue to Part 2 to learn the core code used in creat…

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

19 Experts available now in Live!

Get 1:1 Help Now