Add option value to product, then to cart with Magento - php

I searched around for a while and only came up wit solutions that added whole new option sets to products in a Magento store.
What I'm trying to accomplish is a way to add a Simple Product to the cart. This Simple Product has some predifined custom options (free text fields) that has to be filled by a php function.
So, how can I do this? Let's say I have a product with the ID "111" and a one custom option.
$qty = '1';
$product = Mage::getModel('catalog/product')->load("111");
// set option value in product model?
$cart = Mage::helper('checkout/cart')->getCart();
$cart->addProduct($product, $qty);
// set option value while passing product to car?
$cart->save();
Thanks in advance for any hinds.
BTW: setting option values via QueryString is relativly easy as seen here.

You don't set the custom option on the product model, you pass it in through the second argument to $cart->addProduct($product, $params).
The set up we have for a project, that requires an external app to add to the Magento cart, is to use a $params array of the following format:
$params = array(
'product' => 1, // This would be $product->getId()
'qty' => 1,
'options' => array(
34 => "value",
35 => "other value",
53 => "some other value"
)
);
The $params['options'] contains the custom option information. The keys are the custom option ids, you can see them if you inspect the custom options section of the product screen with Firebug, or similar.
The $params['product'] may be redundant, I wrote this script a while ago for a much earlier version of Magento.
Also, I'm fairly sure that the standard add to cart events will fire when you add this way, so you'll need to set them off yourself. There may be side effects.

In Magento 1.7 you have to wrap the params array in a Varien Object.
$params = array(
'product' => $_fancypack->getId(),
'qty' => 1,
'options' => array(
$this->_getOptionId($_fancypack,'Product SKU') => $product->getId() .'/'. $product->getSku()
)
);
$request = new Varien_Object();
$request->setData($params);
$quote->addProduct($_fancypack, $request);

You should write the input parameter for addproduct as the following format, it is tested by myself:
$params = array(
'product' => 1, // This would be $product->getId()
'qty' => 1,
'super_attribute' => array(
34 => "value",
35 => "other value",
53 => "some other value"
)
);

The problem with the current answer is that magento will not add a second line item if the SKU is the same but the options are distinct from the first. If you want a 3" apple and a 4" apple you would like to have separate line items. Or at least I do.
A HTTP call to the following URL
/store/checkout/cart/add?product=23&qty=1&options[41]=4
followed by
/store/checkout/cart/add?product=23&qty=1&options[41]=3
will add two line items.
But still this is just half of the battle, what do these option codes stand for?? Well the following PHP code will tell you. And since we are using an HTTP call the code will return javascript ready JSON.
<?php
include_once '../app/Mage.php';
Mage::app();
echo getProductOptionsIds($_GET['eventcode']);
function getProductOptionsIds($sku)
{
$ProductID = Mage::getModel('catalog/product')->getIdBySku($sku);
$Product = Mage::getModel('catalog/product')->load($ProductID);
$config = array();
$config['ProductID'] = $ProductID;
foreach ($Product->getOptions() as $option) {
// #var $option Mage_Catalog_Model_Product_Option
if ($option->getGroupByType() == Mage_Catalog_Model_Product_Option::OPTION_GROUP_SELECT) {
$_tmpValues = array();
foreach ($option->getValues() as $value) {
// #var $value Mage_Catalog_Model_Product_Option_Value
$_tmpValues[$value->getTitle()] = $value->getId();
}
$config[$option->getTitle().'list'] = $option->getId();
$optionValue = $_tmpValues;
} else {
$optionValue = $option->getId();
}
$config[$option->getTitle()] = $optionValue;
}
return json_encode($config);
}
?>

Related

Update basket custom attribute on basket/cart page WooCommerce Product Add-ons

I have been trying to make it so that I can update a custom field(per product) I have added on the basket/cart page using WooCommerce Product Add-ons.
I did get a method working as a test, but it is really a good solution, and most of it is a test/bad code. It also only works the second time for some reason - as if the cache is breaking it!
It will be changed via a textarea, but I have set a value for now to see if I can get it to work.
So, to clarify, on submit first time, nothing happens, secound time it updates the product, however it now doesn't update the attribute, it updates quantity etc(when I add a value in the code) but not the attribute.
I have set it to delete the product afterwards but it looses the attribute when I delete it so I have left the duplication in there for now until I fix the double update required for it to update the page!
Is there anything anyone can see that will point me in the direction of a quicker fix? Greatly apprecaite any help!!!
As you can see from the commenting out I have been trying a few ways, but keep failing!!
<?php
if ( ! empty( $_POST['update_cart'] ) ) {
$cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : '';
if ( sizeof( $woocommerce->cart->get_cart() ) > 0 ) {
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
if ( isset( $cart_totals[ $cart_item_key ]['addons'] ) ) {
WC()->cart->remove_cart_item($cart_item_key);
#print_r($woocommerce->cart->cart_contents[ $cart_item_key ]['addons']);
#$cart_item['addons'] = array('name' => 'Add your message', 'value' => 'testing the message box', 'price' => 0, 'field_name' => $cart_item['product_id'].'-add-your-message-1', 'field_type' => 'custom_textarea', 'price_type' => 'quantity_based' );
$data = array('name' => 'Add your message', 'value' => 'testing the message box', 'price' => 0, 'field_name' => $cart_item['product_id'].'-add-your-message-1', 'field_type' => 'custom_textarea', 'price_type' => 'quantity_based' );
#WC()->cart->add_to_cart($cart_item['product_id'], $cart_item['quantity'], $cart_item['variation_id'], $cart_item['addons']);
WC()->cart->add_to_cart($cart_item['product_id'], $cart_item['quantity'], $cart_item['variation_id'], $cart_item['addons']);
#$woocommerce->cart->cart_contents[$cart_item_key]['addons'][0]['value'] = 'test';
$woocommerce->cart->cart_contents[$cart_item]['addons'] = $data;
}
}
}
}
EDIT:
The below is updating the message box per item, which is great and exactly what was needed, just trying to get the session to accept the update. The cart is a multipage cart as that is what was requested, so when you go to the next page/checkout page you can see it has reverted back to the original message and you can see it in the cart session. Also, if you just refresh the page it reverts back(after you have already updated the page).
I have tried to edit via WC()->session->set but I think I am setting the wrong bit! I get some of the session set, but it doesn't set the correct entry!
add_action('woocommerce_update_cart_action_cart_updated', function ($cartUpdated) {
// loop through cart items, passing the $item array by reference, so it can be updated
foreach (WC()->cart->cart_contents as $key => &$item) {
// set the values of the addons array as required
$test = $_POST['cart'][$key]['addons'];
$item['addons'][0]['value'] = $test;
print_r(WC()->session->get( 'cart'));
}
});
EDIT - WORKING CODE:
Thank you to #benJ for the solution, very helpful! The session needed to be set, but not the way I thought I had to do it!
// hook on woocommerce_update_cart_action_cart_updated
add_action('woocommerce_update_cart_action_cart_updated', function ($cartUpdated) {
// loop through cart items, passing the $item array by reference, so it can be updated
foreach (WC()->cart->cart_contents as $key => &$item) {
// set the values of the addons array as required
$addon = $_POST['cart'][$key]['addons'];
$item['addons'][0]['value'] = $addon;
// set the session
WC()->cart->set_session();
}
});
Cheers
Iskander
If I understand your question correctly, you want to update an addon field on every product when you update the cart.
This can be achieved by adding a hook on woocommerce_update_cart_action_cart_updated and editing the cart items as required.
// hook on woocommerce_update_cart_action_cart_updated
add_action('woocommerce_update_cart_action_cart_updated', function ($cartUpdated) {
// loop through cart items, passing the $item array by reference, so it can be updated
foreach (WC()->cart->cart_contents as $key => &$item) {
// set the values of the addons array as required
$item['addons'][0]['value'] = 'your message here';
}
});
If you're only looking to do this for individual products, you can check their other values as you iterate over them.

WooCommerce remove_cart_item not removing items when logged in

Playing around with WooCommerce, trying to call remove item in a custom api implementation.
I can successfully get a list of cart items and add items to the cart in similar fashion. Yet, despite the code being nearly identical on every guide I can find, I cannot get the cart item to be removed.
I get the cart items something like this:
$ret = array();
global $woocommerce;
$items = $woocommerce->cart->get_cart();
foreach($items as $item => $values) {
$product = $values['data'];
$p = array(
'cart_item_key' => $item,
'id' => $product->get_id(),
'name' => $product->get_name(),
'slug' => $product->get_slug(),
'price' => $product->get_price(),
'description' => $product->get_description(),
'short_description' => $product->get_short_description(),
'permalink' => get_permalink( $product->get_id() ),
'quantity' => $values['quantity']
);
$ret[] = $p;
}
return $ret;
Gives me a nice clean array back I can see in the response.
I then take the cart_item_key and pass it back in to another method like so:
$payload = $request->get_params();
$ret = array();
global $woocommerce;
if ($payload['cart_item_key']){
$cartItemKey = WC()->cart->find_product_in_cart( $payload['cart_item_key'] );
$woocommerce->cart->remove_cart_item( $cartItemKey );
unset( $woocommerce->cart->cart_contents[$cartItemKey] );
}
return $ret;
I can see that $payload['cart_item_key'] is indeed the string value I expect to see that passed into the call. I can also see that $cartItemKey is the identical string value, so I'm 99.8% certain that I have the right value to pass in.
The remove_cart_item and unset methods are two different implementations I've seen and neither seems to have an effect. I've also tried using WC() in place of the global $woocommerce to zero success. Whether I query the cart items again here and return them, or just refresh the page, all items are still in the cart.
There is zero server caching I'm aware of - everything I know about I have specifically turned off for this sandbox.
Update
This does appear to work as expected in a fresh session. For some reason, when I'm logged in as the admin for the site, I am unable to clear out my cart, and no errors are being logged for anything like this on the server.

Magento php add to cart with Custom price

I have the following issue:
I make calculations via jQuery in the frontend and want to add a product to the cart with the price calculated in the frontend.
I already wrote a custom module with an AjaxController to achieve the adding to cart part, but I know struggle with setting the custom price.
My script looks like this:
$_prod = json_decode(Mage::app()->getRequest()->getPost('zapfsaeule_product'));
$id = 347; // there is only this one bundle product added to the cart viar this scipt, so a static id is enough.
$params = array(
'product' => $id,
'related_product' => null,
'bundle_option' => array(
6 => 17, // static options for testing purpouses
5 => 13), //
'qty' => 1 // static qty for testing as well
);
$cart = Mage::getSingleton('checkout/cart');
$product = new Mage_Catalog_Model_Product();
$product->load($id);
$cart->addProduct($product, $params);
$cart->save();
Mage::getSingleton('checkout/session')->setCartWasUpdated(true);
$this->getResponse()->setBody('true'); // setting response to true, because its an ajax request.
$this->getResponse()->setHeader('Content-type', 'text/plain');
That's the code for adding the product.
For setting the price I tried the approach as mentioned in this thread on stackexchange:
https://magento.stackexchange.com/questions/4318/dynamically-calculated-prices-save-before-add-to-cart
But it didn't work. I guess the event observed here doesn't occur in my case, because I wrote a custom script.
But then there still would be the problem, IF the observer approach would work, how would I pass the calculated price to the observer?
I hope you understand the problem and can help me solve it.
Thanks in advance!
Best regards,
Martin
Reading through Mage_Checkout_Model_Cart::addProduct(), there doesn't appear to be a way to set the item's price from the parameters. Instead, you'll need to add the product, then grab the resulting item, and set its price:
$cart->addProduct($product, $params)
->save();
// grab the corresponding item
$item = $cart->getQuote()->getItemByProduct($product);
// set its custom price
$item->setOriginalCustomPrice($customPrice)
->save();
Haven't had the time to try this out, but it should be the right idea. Make sure that you set the original_custom_price field (using setOriginalCustomPrice()), not one of the other prices. The other prices are recalculated during the totals process.
This comes pretty late, but I just stumbled upon this.
I got it to work like this:
$cart = Mage::getSingleton('checkout/cart');
$cart->addProduct($product, 1); // 1 = qty. Pass your qty and params.
$item = $cart->getQuote()->getItemByProduct($product);
$item->setCustomPrice(0); // or some other value
$item->setOriginalCustomPrice(0); // or some other value
$item->getProduct()->setIsSuperMode(true); // this is crucial
$cart->save();
Mage::getSingleton('checkout/session')->setCartWasUpdated(true);
If the params don't work, fetch the returned item from $cart->addProduct and change the price on the item before saving the cart.
$item = $cart->addProduct(...);
$item->setCustomPrice(...); {or whatever price attribute you like to set}
$cart->save();

Mage::init('default') causing error in Module

I have test php script running outside of Magento that will add an item to the cart. Works great. This code was found here and used by many people in quite a few posts. When I place this code into an existing module, the item is not added, from a fresh session. If I go to the store and add a regular product (have an item in my cart) the module will add the item properly. I Know the code to add the item works. The problem I have is with creating the FIRST instance of a cart.
This code works just fine if already have a normal magento product in my cart:
// this section of code only works if the customer already has a cart item added (cart established)
// for some reason this script fails when no cart exists
$session = Mage::getSingleton('customer/session');
// Get cart instance
$cart = Mage::getSingleton('checkout/cart');
$cart->init();
$productId=971;
$productInstance = Mage::getModel('catalog/product')->load($productId);
$param = array(
'product' => $productId,
'qty' => $rfqdata['option_quantity'],
'options' => array(
27 => $rfqdata['option_layers'], // Layers
26 => $rfqdata['option_thickness'], // Thickness
25 => $rfqdata['option_length'], // Length
24 => $rfqdata['option_width'], // Width
23 => $rfqdata['option_color'], // Color
22 => $rfqdata['option_finish'], // Finish
29 => $rfqdata['option_rush'], // Rush
30 => 'tbd' // RFQ Number
)
);
$request = new Varien_Object();
$request->setData($param);
$cart->addProduct($productInstance, $param);
$session->setCartWasUpdated(true);
$cart->save();
This somehow causes an error, and the module addtocart action is not completed. I cannot find any useful error messages. I have searched 100s of pages on stack, google, and I can find nothing to resolve this issue. Obviously my module is worthless if it doesn't work from page load 1.
I tried to post this before and got no response. I really need some help. If you cannot answer, can you tell me where I can find paid Magento support?
here is the solution, it was very hard to find too....
if(empty($quote)){
$checkout = Mage::getSingleton('checkout/session');
$quote = $checkout->getQuote();
$session = Mage::getSingleton('customer/session');
if($session->isLoggedIn()) {
// look up customer
$customerSession = $session->getCustomer();
$customer = Mage::getModel('customer/customer')->load($customerSession->getId());
$quote->assignCustomer($customer);
$quote->setIsMultiShipping(false);
}
$quote->save();
}

Wordpress Woocommerce - use update_post_meta to add product attributes

The products in my clients website require certain attributes which I have added via Products -> Attributes in the Wordpress administration. In this import script I'm coding I need to use the function update_post_meta($post_id, $meta_key, $meta_value) to import the proper attributes and values.
Currently I have the function like so:
update_post_meta( $post_id, '_product_attributes', array());
However I'm not sure how to properly pass along the attributes and their values?
Right so it took me a while to figure it out myself but I finally managed to do this by writing the following function:
// #param int $post_id - The id of the post that you are setting the attributes for
// #param array[] $attributes - This needs to be an array containing ALL your attributes so it can insert them in one go
function wcproduct_set_attributes($post_id, $attributes) {
$i = 0;
// Loop through the attributes array
foreach ($attributes as $name => $value) {
$product_attributes[$i] = array (
'name' => htmlspecialchars( stripslashes( $name ) ), // set attribute name
'value' => $value, // set attribute value
'position' => 1,
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
// Example on using this function
// The attribute parameter that you pass along must contain all attributes for your product in one go
// so that the wcproduct_set_attributes function can insert them into the correct meta field.
$my_product_attributes = array('hdd_size' => $product->hdd_size, 'ram_size' => $product->ram_size);
// After inserting post
wcproduct_set_attributes($post_id, $my_product_attributes);
// Woohay done!
I hope this function will help other people if they need to import multiple attributes pro-grammatically in WooCommerce!
I tried Daniel's answer, and it didn't work for me. It might be that the Wordpress/Woocommerce code has changed since, or perhaps I didn't quite understand how to do it, but either way that code did nothing for me. After a lot of work using it as a base, however, I came up with this snippet of code and put it on my theme's functions.php:
function wcproduct_set_attributes($id) {
$material = get_the_terms( $id, 'pa_material');
$material = $material[0]->name;
// Now update the post with its new attributes
update_post_meta($id, '_material', $material);
}
// After inserting post
add_action( 'save_post_product', 'wcproduct_set_attributes', 10);
With this, I can take what I set as "material" on my WooCommerce install as a custom attribute and add it to the formal meta as _material. This in turn allows me to use another snippet of code so the WooCommerce search function extends to meta fields, meaning I can search for a material in the WooCommerce search field and have all items with that material appear.
I hope this is useful to somebody.
#Daniels's answer works, won't decide on right or wrong, however if you want to add the values as a taxonomy term under attributes you have to adapt the code as below (set is_taxonomy = 1). Otherwise Woocommerce sees it as custom meta field(?). It still adds the value under attributes. This will only work for strings. For values that are arrays the code has to be adapted.
Additionally it uses the wp_set_object_terms that #Anand suggests as well. I was using that, because all the documentation I could find led to believe that had to be used. However if one only uses the wp_set_object_terms then I couldn't see the attributes in the edit product screen. Using the information from both answers and reading on the subject resulted in the solution.
You will need to tweak the code for things such as product variations.
/*
* Save Woocommerce custom attributes
*/
function save_wc_custom_attributes($post_id, $custom_attributes) {
$i = 0;
// Loop through the attributes array
foreach ($custom_attributes as $name => $value) {
// Relate post to a custom attribute, add term if it does not exist
wp_set_object_terms($post_id, $value, $name, true);
// Create product attributes array
$product_attributes[$i] = array(
'name' => $name, // set attribute name
'value' => $value, // set attribute value
'is_visible' => 1,
'is_variation' => 0,
'is_taxonomy' => 1
);
$i++;
}
// Now update the post with its new attributes
update_post_meta($post_id, '_product_attributes', $product_attributes);
}
Then call the function:
$custom_attributes = array('pa_name_1' => $value_1, 'pa_name_2' => $value_2, 'pa_name_3' => $value_3);
save_wc_custom_attributes($post_id, $custom_attributes);
Thank you for posting the code Daniel & Anand. It helped me a great deal.
Don't know if this is the "correct" way to do this... But I needed a function to add ACF repeater fields with a date value as a attribute on post save, so this was the function I came up with:
add_action( 'save_post', 'ed_save_post_function', 10, 3 );
function ed_save_post_function( $post_ID, $post, $update ) {
//print_r($post);
if($post->post_type == 'product')
{
$dates = get_field('course_dates', $post->ID);
//print_r($dates);
if($dates)
{
$date_arr = array();
$val = '';
$i = 0;
foreach($dates as $d)
{
if($i > 0)
{
$val .= ' | '.date('d-m-Y', strtotime($d['date']));
}
else{
$val .= date('d-m-Y', strtotime($d['date']));
}
$i++;
}
$entry = array(
'course-dates' => array(
'name' => 'Course Dates',
'value' => $val,
'position' => '0',
'is_visible' => 1,
'is_variation' => 1,
'is_taxonomy' => 0
)
);
update_post_meta($post->ID, '_product_attributes', $entry);
}
}
}
Hope this helps someone.

Categories