I am struggling with a weird situation here with arrays in PHP. I am trying to create a simple cart using a session variable.
Problem:
When the cart is empty, the program creates a new product with the itemid and qty variables when a product is added to cart (as required). It also does same when other new products are added.
It also is able to update the quantity of products if added again (as required).
But the problem here is it never finds the 1st product I add, so whenever I add that product again, it stacks the product every time and does not update the quantity of the product. Whereas for other products other than 1st, it acts as expected.
eg. when product A is added to empty cart, it adds itemid as A and qty = 1. When the product A is added again to an empty cart, it adds the itemid as A and qty=1 again (does not do qty=2). If I add B, C or others repeatedly it updates their qty as required
<?php
public function addinTable($id){
$this->loadModel('Carts');
/////////inserting into the cart table//////////7
$item = $this->Products->get($id);
$session = $this->request->session();
$allProducts = $session->read('Cart');
if(null!=$allProducts){
echo "<br>if(allProducts is NOT EMPTY)<br>";
if(array_search($id,array_column($allProducts, 'itemid'))){
//if the id is already in list
echo "<br><b>ITEM Is IN the list already</b>";
$key = array_search($id,array_column($allProducts, 'itemid'));
echo "<br> key is ", $key;
$newqty = debug($allProducts[$key]['qty']);
echo "<br> new qty +1 = ".$newqty+=1;
debug($allProducts[$key]['qty']++);
$session->write('Cart',$allProducts);
debug( $session->read('Cart'));
}
else{
echo"<br><b>The id is not found but cart is not empty</b>";
$allProducts[] = array('itemid'=>$id,
'qty' => 1
);
debug( $session->read('Cart'));
}
}
else{///////////if cart is empty at first
echo"<br><b>The cart is empty</b>";
$allProducts[] = array('itemid'=>$id,'qty' => 1);
debug($allProducts[0]);
debug($allProducts);
debug($allProducts[0]['itemid']);
// if(array_search($id,array_column($allProducts, 'itemid'))==true){echo "hello";}
$session->write('Cart',$allProducts);
debug($session->read('Cart'));
}
$session->write('Cart',$allProducts);//save the item
}
?>
array_search() returns the index, which is 0 for the first product. 0 evaluates to false.
You need a comparison against false here.
Change
if(array_search($id,array_column($allProducts, 'itemid'))) { //...
to
if(array_search($id,array_column($allProducts, 'itemid')) !== false) { //...
here's a fiddle that demonstrates this change: https://3v4l.org/m62Ya
Related
I am getting an empty array from the woocommerce_add_cart_item_data filter when a product is added to the shopping cart. Example added to functions.php of WordPress theme;
function TEST_post_filter($a,$b,$c) {
print_r($a); //THIS IS EMPTY ARRAY ie returns Array()
return $a;
}
add_filter('woocommerce_add_cart_item_data', 'Test_post_filter',10,3);
Any idea why this might be? I have found no reference to this issue anywhere. I have tried both basket behaviours ie Redirect to the basket page after successful addition and/ or Enable AJAX add to basket buttons on archives. I can't get my head around it. Plugins I have activated are WooCommerce, and WooCommerce Stripe Gateway.
UPDATE - Code which adds product options to product screen
function option_add_to_product() {
global $product;
//get pizza categories
$categories = get_terms( 'product_cat', array(
'hide_empty' => false,
));
$use_product = [];
for($i=0;$i<count($categories);$i++) {
if(strtolower($categories[$i]->slug) === 'bespoke_product')
array_push($use_product,$categories[$i]->term_id);
}
$include_product = false;
if(! count($use_product))
return false;
for($i=0;$i<count($use_product);$i++) {
$this_product_categories = $product->get_category_ids();
for($ii=0;$ii<count($this_product_categories);$ii++) {
if($this_product_categories[$ii] === $use_prouduct[$i]) {
$include_product = true;
break;
}
}
}
if(! $include_product)
return false;
//template to add product option
require plugin_dir_path(__FILE__) . 'templates/add_product_option.php';
}
You can see the html from add_product_option.php will be added to the product if the product has a a category with the slug "bespoke_product". Note, this method of getting a match for a product is temporary (just technical debt for now).
When the filter woocommerce_add_cart_item_data is called the data posted from the product form is available to the corresponding function. Unsanitised data might read as follows:
[extra_option_one] => 0
[extra_option_two] => 0
[extra_options_three] => 1
[extra_option_four] => 0
[order_note] =>
Each of those options will have a lookup table with a related price e.g. extra_options_three might be £1.50. This cost of this option and any others selected needs to up the price of the specific item being added to the cart. It should not be represented separately. The definition of the option added should go into the product field everywhere that purchased item is shown. I'm working through step by step, but it's not easy at the point I am at! I'm guessing the next is tha I'm going to be able to update the item in this order?
The woocommerce_add_cart_item_data hook is used to add custom data to the cart item on simple add to cart submission, like additional fields included in the <form> where "add to cart" button is located…
So if you are not submitting extra custom data from custom fields on add to cart event on (from single product pages), the first function argument is going to be an empty array…
See those related answer threads using this hook.
I know this is a dump/basic question but I'm stuck and could use some help being a newbie.
What I'm Trying to Achieve: I want to have a foreach loop to get all of the product names in my users cart.
Problem: The foreach loop stops after the second iteration (if there are three things in the cart and I dump, only 2 are shown(the first and second)).
I know what a foreach loop does. I think my problem lays in my variable names but I tried messin around with them to no avail.
if (is_null($cart) || $cart->getSubmitted(true)) {
$cart = new UserCart();
// since new cart no need to check for duplicate product quantity
// add product to cart
$this->addFlash('notice', 'Creating a new cart because one didnt exist for the user before.');
}
else {
$quantity = new Quantity();
//If the cart is set
$getProductsInCurrentUsersCart = $cart->getQuantities(); //All Products In Users Cart (ARRAY COLLECTION/PERSITENT COLLECTION)
foreach ($getProductsInCurrentUsersCart as $key => $value) {
dump($getProductsInCurrentUsersCart);
$getProductsInCurrentUsersCart = $value->getProduct()->getName(); //SHOULD BE ALL PRODUCTS IN CART
if ($getProductsInCurrentUsersCart === $quantity->setProduct($productBeingAddedToCart)->getProduct()->getName()) {
$this->addFlash('notice', 'Comparission was TRUE.');
$quantity->setQuantity($quantity->getQuantity() + 1);
}
else {
$quantity->setQuantity(1);
$quantity->setProduct($productBeingAddedToCart);
$this->addFlash('notice', 'Comparisson was FALSE.');
} //ENDS IF/ELSE
} //EXECUTING ONCE??????????
$cart->setTimestamp(new \DateTime()); // Set Time Product was Added
// $quantity->setQuantity(1); // Set Quantity Purchased
$cart->setSubmitted(false); // Set Submitted
$cart->setUser($this->getUser()); // Sets the User ONCE
$cart->addQuantity($quantity); // Add Quantity ONCE
$quantity->setUserCart($cart); // Create a UserCart ONCE
$em->persist($productBeingAddedToCart);
$em->persist($cart);
$em->persist($quantity);
$em->flush();
$this->addFlash('notice', 'The product: '.$productBeingAddedToCart->getName().' has been added to the cart!');
}
Any help is really appreciated!
$getProductsInCurrentUsersCart = $value->getProduct()->getName();
Here you are redefining the list variable inside the loop. Try with $getProductsInCurrentUsersCart2 and also change it below this line. See if that solves it or not. Then come up with a better name :)
My client and I are trying to achieve something that we are maybe not supposed to do. We have a demanding set of non-standard products that include different types of product conditions, e.g. grade B ware etc. In addition product data is coming in in form of feeds from several suppliers. In order not to clutter up the product listing we would like to convert existing, manually edited simple products into grouped ones (or whatever is appropriate) with associated new simple products programmatically on the fly and vice versa whenever necessary, i.e. when there are at least two different sub products.
So far we managed to do this somehow, a test scenario produces the seemingly right product structure – correctly associated products are displayed in the backend, the quantities have been correct before. The problem occurs with the frontend check on 'isSaleable()' for both the grouped product and the associated products, it returns 'false' no matter what we do. When we enforce the display of the qty input boxes and add-to-cart button they will (naturally?) just product the error message 'Please specify the quantity of product(s)'. We tried to set 'is_salable' by different means throughout the code. What else is missing? Any little hint, any advice here would be appreciated!
The code is quite lengthy already, and probably there's already some redundancy in there because of our attempts to somehow fix this. There's a main script that fetches a product collection and compares each entry with the existing supplier feeds. The essential part then is the function call to convert the product:
if (sizeof($newProducts[$productsSku]) > 1 && $_product->getTypeId() == 'simple') {
$newProductQtys = createGroupedProduct($_product, $newProducts[$productsSku]);
}
There are 2 functions for the actual conversion process, one which creates duplicates of the master products (type = simple) and sets their values accordingly:
function createDuplicate($product, $values) {
global $suppliers, $conditions_arr;
$sku = $product->getSku();
$newSku = $sku.'-v'.$suppliers[$values['feed']]['id'];
$qty = $values['qty'];
$feed = $values['feed'];
$cost = $values['cost'];
$item_condition = $values['item_condition'];
$box_condition = $values['box_condition'];
$notes = stripslashes($values['notes']);
$newProduct = $product->duplicate();
$newProduct->setTypeId('simple');
$newProduct->setStoreId(0);
$newProduct->setWebsiteIds(array(1));
$newProduct->setVisibility(2);
$newProduct->setSku($newSku);
$newProduct->setData('media_gallery', array());
$newProduct->setStatus(Mage_Catalog_Model_Product_Status::smileyfrustrated:TATUS_ENABLED);
$newProduct->setPrice((real)($cost + $cost*$suppliers[$feed]['price_increase']));
$newProduct->setTaxClassId(2);
$newProduct->getResource()->save($newProduct);
$productId = $newProduct->getId();
// Check if there is a stock item object
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);
$stockItemData = $stockItem->getData();
if (empty($stockItemData)) {
// Create the initial stock item object
$stockItem->setData('inventory_manage_stock_default', 1);
$stockItem->setData('manage_stock',1);
$stockItem->setData('is_in_stock', $qty ? 1 : 0);
$stockItem->setData('is_salable', 1);
$stockItem->setData('use_config_manage_stock', 1);
$stockItem->setData('stock_id',1);
$stockItem->setData('product_id',$productId);
$stockItem->setData('qty',$qty);
$stockItem->setTypeId( $newProduct->getTypeId() );
$stockItem->save();
// Init the object again after it has been saved so we get the full object
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($productId);
}
// Set the quantity
$stockItem->setData('qty',$qty);
$stockItem->setData('is_salable', 1);
$stockItem->save();
// $newProduct->assignProduct($newProduct, 1, 1);
$newProduct->setIsSalable(1);
$newProduct->setStatus(Mage_Catalog_Model_Product_Status::smileyfrustrated:TATUS_ENABLED);
$newProduct->save();
$event = Mage::getSingleton('index/indexer')->logEvent($newProduct,$newProduct->getResource()->getType(),Mage_Index_Model_Event::TYPE_SAVE,false);
Mage::getSingleton('index/indexer')->getProcessByCode('cataloginventory_stock')->setMode(Mage_Index_Model_Process::MODE_REAL_TIME)->processEvent($event);
return $productId;
}
and
function createGroupedProduct($product, $newProductsArr) {
global $suppliers;
$origProductId = $product->getId();
$sku = $product->getSku();
$newProductId = array();
$newProductQtys = array();
$qty = 0;
$price = 999999;
$product->setTypeId('grouped');
$product->save();
foreach($newProductsArr as $key => $values) {
$id = createDuplicate($product, $values);
$newProductId[] = $id;
$newProductQtys[$id] = $values['qty'];
// add up all stock quantities of all slave products for master
$qty += $values['qty'];
// determine lowest price among all slave products
$subItemPrice = (real)($values['cost'] + $values['cost']*$suppliers[$values['feed']]['price_increase']);
if ($subItemPrice < $price) $price = $subItemPrice;
}
if (sizeof($newProductId) > 1) {
$products_links = Mage::getModel('catalog/product_link_api');
foreach($newProductId as $key => $id) {
$products_links->assign('grouped', $origProductId, $id);
}
}
// set new values for grouped product according to slave products values
$product->setPrice($price);
$product->getResource()->save($product);
// Check if there is a stock item object
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($origProductId);
$stockItemData = $stockItem->getData();
if (empty($stockItemData)) {
// Create the initial stock item object
$stockItem->setData('manage_stock',1);
$stockItem->setData('is_in_stock', $qty ? 1 : 0);
$stockItem->setData('is_salable', 1);
$stockItem->setData('use_config_manage_stock', 1);
$stockItem->setData('stock_id',1);
$stockItem->setData('product_id',$origProductId);
$stockItem->setData('qty',$qty);
// $stockItem->setTypeId( $product->getTypeId() );
$stockItem->setTypeId('grouped');
$stockItem->save();
// Init the object again after it has been saved so we get the full object
$stockItem = Mage::getModel('cataloginventory/stock_item')->loadByProduct($origProductId);
}
// Set the quantity
$stockItem->setData('qty',$qty);
$stockItem->setData('is_in_stock', $qty ? 1 : 0);
$stockItem->setData('is_salable', 1);
$stockItem->save();
$product->setStatus(Mage_Catalog_Model_Product_Status::smileyfrustrated:TATUS_ENABLED);
$product->save();
$event = Mage::getSingleton('index/indexer')->logEvent($product,$product->getResource()->getType(),Mage_Index_Model_Event::TYPE_SAVE,false);
Mage::getSingleton('index/indexer')->getProcessByCode('cataloginventory_stock')->setMode(Mage_Index_Model_Process::MODE_REAL_TIME)->processEvent($event);
$cache = Mage::getSingleton('core/cache');
$cache->flush();
return $newProductQtys;
}
We tried using the store ID '1' as well and had some success with the shopping cart when the front end used the same kind of mass-product-add-to-cart form that we integrated into the product listing. But the associated products then showed no product name and no image, and not in the admin at all.
If more code from the main script is necessary I will happily provide this.
In Prestashop, I've created a custom form where I show a list with all products and the user can fill the corresponding quantities. By submitting the form, I clear the cart and fill it with the new values and finally redirect to the checkout page.
Everything's working fine, but only when the cart already exists. In a case of an empty cart (cart_id==null), I cannot add the products. I tried with several ways to create a $cart but I didn't manage to do so.
I don't get any exceptions, the code is executed without errors, it's just that at the end, in the checkout page, the cart remains empty; I repeat, only when the cart was already empty. In the case of a cart with products in it, then the process is just perfect!
I would appreciate some help on this.
Here is my small controller that gets the products and quantities from the form and adds them in the cart:
include('../../config/config.inc.php');
include('../../header.php');
// Filling the array of products
$products = array();
foreach ($_POST as $key => $value)
if (substr($key, 0, 9) === 'quantity_')
$products[substr($key, 9)] = $value;
// First of all, we remove all products
$prods = $cart->getProducts();
foreach ($prods as $prod)
$cart->deleteProduct($prod['id_product']);
// Adding the new products
foreach ($products as $product_id => $quantity)
if ($quantity > 0)
$cart->updateQty($quantity, $product_id);
// Redirecting to the checkout page.
header("Location: " . $_POST['redirect']);
exit();`
Thank you in advance!
I had the same problem with Prestashop not correctly creating a new cart upon calling the CartCore in many different ways - neither context or direct calls did work out.
Found this gem from someone else over here:
// get cart id if exists
if ($this->context->cookie->id_cart)
{
$cart = new Cart($this->context->cookie->id_cart);
}
// create new cart if needed
if (!isset($cart) OR !$cart->id)
{
$cart = new Cart();
$cart->id_customer = (int)($this->context->cookie->id_customer);
$cart->id_address_delivery = (int) (Address::getFirstCustomerAddressId($cart->id_customer));
$cart->id_address_invoice = $cart->id_address_delivery;
$cart->id_lang = (int)($this->context->cookie->id_lang);
$cart->id_currency = (int)($this->context->cookie->id_currency);
$cart->id_carrier = 1;
$cart->recyclable = 0;
$cart->gift = 0;
$cart->add();
$this->context->cookie->id_cart = (int)($cart->id);
$cart->update();
}
This is working for me now. As you see it goes a little more in depth than just asking the context to retrieve or create a new cart. hth.
You probably need to include this line when you are outside of a class
$context = Context::getContext();
And then add a cart variable that defines cart attributes ( in ur case assigns a id )
$cart = $context->cart; // gets the cart id or creates a new one
Should work fine now
BR's ( dont forget to accept the answer if it helps you :) )
As a complement to previous posts.
If you set that configuration : Configuration::updateValue('PS_CART_FOLLOWING', 1) (display the last cart of the customer instead of creating a new one each time).
You will always get the cart id $this->context->cart->id at NULL when trying to create a new cart at the customer's first log in (after creating a new account) using the following code:
if (is_null($this->context->cart)) {
$this->context->cart =
new Cart($this->context->cookie->id_cart);
}
I manage to solve the problem by adding some code to after the invalid cart creation.
/**
* Manage the possible errors when trying to create
* a new cart for a customer.
*
* The new cart is saved in the current context ($this->context->cart).
*/
private function createCart()
{
if (is_null($this->context->cart)) {
$this->context->cart =
new Cart($this->context->cookie->id_cart);
}
if (is_null($this->context->cart->id_lang)) {
$this->context->cart->id_lang = $this->context->cookie->id_lang;
}
if (is_null($this->context->cart->id_currency)) {
$this->context->cart->id_currency = $this->context->cookie->id_currency;
}
if (is_null($this->context->cart->id_customer)) {
$this->context->cart->id_customer = $this->context->cookie->id_customer;
}
if (is_null($this->context->cart->id_guest)) {
if (empty($this->context->cookie->id_guest)){
$this->context->cookie->__set(
'id_guest',
Guest::getFromCustomer($this->context->cookie->id_customer)
);
}
$this->context->cart->id_guest = $this->context->cookie->id_guest;
}
if (is_null($this->context->cart->id)) {
$this->context->cart->add();
$this->context->cookie->__set('id_cart', $this->context->cart->id);
}
}
After initializing the cart that way, I'm now able to add products to the cart with no problem.
Good success everyone
The shopping cart I am building only seems to update the quantity for the first element of the array. So for example the first item in my shopping cart would have a quantity of 1 and then when I added another quantity of 2 from the products page the total then changes to 3 which is what I want. If I however repeat these steps for another item it will add them into the array separately rather than grouping them together
if(isset($_GET['add'])){
foreach ($_SESSION['cart'] as $key => $item){
if ($item['id'] == $itemID) {
$newQuan = $item['quantity'] + $quantity;
unset($_SESSION['cart'][$key]);
$_SESSION['cart'][] = array("id" => $itemID,"quantity" => $newQuan);
header('Location:xxx');//stops user contsanlty adding on refresh
exit;
}
else{
$_SESSION['cart'][] = array("id" => $itemID,"quantity" => $quantity);
header('xxx');//stops user contsanlty adding on refresh
exit;
}
}
}
Can anyone help me out as to why the first element gets updated only ?
Your problem is the else-case in the foreach-loop. The very first item gets checked by the if and then - when the first item does not match - the else case activates and adds the new item.
else{
$_SESSION['cart'][] = array("id" => $itemID,"quantity" => $quantity);
header('xxx');//stops user contsanlty adding on refresh
exit;
}
What you would want to do, is to check the whole cart and then - if the article was not found - add it to the cart. For this I would suggest to use a variable for checking whether you found the entry inside the loop. For inspiration I inserted the code below. There are only minor changes needed: Add the found-variable and initialize it (to not found), set the variable to found in your if-case and check whether the variable is set after quitting the foreach-loop (which if it is not, you know for sure that you want to add the item to your cart).
$foundMyArticle = 0;
foreach ($_SESSION['cart'] as $key => $item){
if ($item['id'] == $itemID) {
$foundMyArticle = 1;
... THE OTHER CODE
} //end of the foreach
if($foundMyArticle == 0)
{ //COPY THE CODE FROM THE ELSE-CASE HERE }
I've not tested it, but this could be a little simpler:
if(isset($_GET['add']))
{
if(!isset($_SESSION['cart'])) $_SESSION['cart'] = array();
if(!isset($_SESSION['cart'][$itemID]))
{
$_SESSION['cart'][] = array('id' => $itemID, 'quantity' => $quantity);
}
else
{
$_SESSION['cart'][$itemID]['quantity'] += $quantity;
}
}
Firstly, the question and the code don't seem really clear enough, but i'll try my best to give suggestions i think might help (I'll make some assumptions).
Where are these variables coming from?
$itemID, $quantity
Going on the assumption that they're coming in the $_GET, I'd say it would be better to save your cart information like so:
$itemCartIndex = strval($itemID);
//convert the integer item id to a string value -- or leave as string if already a string
$currentQuantity = (isset($_SESSION["cart"][$itemCartIndex]))? intval($_SESSION["cart"][$itemCartIndex]["quantity"]):0;
//set it by default if the index does not exist in the cart already
$currentQuantity += $quantity;
//update the quantity for this particular item
$_SESSION["cart"][$itemCartIndex] = array("quantity"=>$currentQuantity,...,"price"=>12.56);
//set up the index for this item -- this makes it easy to remove an item from the cart
//as easy as unset($_SESSION["cart"][$itemCartIndex]
With that done, displaying/presenting the cart back to the owner is trivial.
Good luck