[Okta Webinar] Learn how to a build a cloud-first strategyRegister Now

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 77
  • Last Modified:

Cart items not showing in header until page refreshed

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
Black Sulfur
Asked:
Black Sulfur
  • 8
  • 7
1 Solution
 
Ray PaseurCommented:
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
 
Black SulfurAuthor Commented:
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
 
Ray PaseurCommented:
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
Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

 
Black SulfurAuthor Commented:
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
 
Black SulfurAuthor Commented:
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
 
Ray PaseurCommented:
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
 
Ray PaseurCommented:
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
 
Black SulfurAuthor Commented:
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
 
Ray PaseurCommented:
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
 
Black SulfurAuthor Commented:
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
 
Ray PaseurCommented:
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
 
Black SulfurAuthor Commented:
Haha, you crack me up sometimes :)

What do you use or do you have your own custom designed cart system?
0
 
Ray PaseurCommented:
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
 
Black SulfurAuthor Commented:
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
 
Ray PaseurCommented:
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

Concerto Cloud for Software Providers & ISVs

Can Concerto Cloud Services help you focus on evolving your application offerings, while delivering the best cloud experience to your customers? From DevOps to revenue models and customer support, the answer is yes!

Learn how Concerto can help you.

  • 8
  • 7
Tackle projects and never again get stuck behind a technical roadblock.
Join Now