Woocommerce add to cart with custom price - wordpress

I've seen many examples of adding an item to the WC cart with a customer price, but none dynamically. I am trying to do in a shortcode function that receives a POST variables....
if (isset($_POST['wmnf_add_donation'])) {
global $woocommerce;
$cart_object = $woocommerce->cart;
$custom_price = ($_POST['donation_amount'] > 0 ? $_POST['donation_amount'] : 0);
$target_product_id = 65986;
$cart_object->add_to_cart($target_product_id, "1");
foreach ( $cart_object->cart_contents as $key => $value ) {
if ( $value['product_id'] == $target_product_id ) {
$value['data']->price = $custom_price;
}
}
}
This adds the item to the cart of course, but the price is zero and I realize I need to somehow save this array back to the WC cart data. Is this method even possible or can it only be done via a filter or action hook? If so, how can I save the changed array back to the cart contents or make it work to add the one item with its posted price? Any guidance greatly appreciated.
Thanks for that answer doublesharp, I was not able to get it to work as described because the form was posting to the page with my shortcode, which has my form, instead of posting directly to the cart. The $_POST was not being seen and the product ended up zero. I did find another approach, but having a problem using wp_redirect. I changed the above shortcode to this:
if (isset($_POST['wmnf_add_donation'])) {
global $woocommerce;
$custom_price = ($_POST['donation_amount'] > 0 ? $_POST['donation_amount'] : 0);
$target_product_id = 65986;
$_SESSION['donation_amount'] = $custom_price;
$woocommerce->cart->add_to_cart($target_product_id, "1");
wp_redirect( site_url() . '/gifts/swag-bag/');
}
Then I added the following filters to functions.php:
add_filter('woocommerce_get_price','donation_price', 10, 2);
add_filter('woocommerce_get_regular_price','donation_price', 10, 2);
add_filter('woocommerce_get_sale_price','donation_price', 10, 2);
function donation_price($price, $productd){
if($productd->id == '65986'){
$price = $_SESSION['donation_amount'];
}
return $price;
}
This does not work except when wp_redirect is commented out, hence, not redirecting. The above redirects to the cart, but its empty. If I comment out the wp_redirect line and then manually go to the cart, the product is there with my custom price. Actually, I would like to apply a custom price and redirect directly to the checkout page instead of the cart, if possible?

You can use the woocommerce_before_calculate_totals action hook to modify the contents of the cart, including the product prices.
add_action( 'woocommerce_before_calculate_totals', 'before_calculate_totals' );
function before_calculate_totals( $_cart ){
// loop through the cart_contents
foreach ( $_cart->cart_contents as $cart_item_key => &$item ) {
// you will need to determine the product id you want to modify, only when the "donation_amount" is passed
if ( $item['id'] == 65986 && isset( $_POST['donation_amount'] ) ){
// custom price from POST
$custom_price = $_POST['donation_amount'] > 0 ? $_POST['donation_amount'] : 0;
// save to the cart data
$item['data']->price = $custom_price;
// new versions of WooCommerce may require (instead of line above)...
// $item['data']->set_price($custom_price);
}
}
}

Related

WooCommerce function that disables an admin user to reduce the product stock quantity

I would like to add a function that is triggered every time that the stock quantity of a product will be changed in the admin product page, such that this function will not allow any reduce of the stock value - but only increase.
This is to prevent an admin user to reduce the stock quantity of the products.
Of course, this function should not be triggered if a product will be in an order, since then of course I would like the stock quantity to be reduced.
I tried the following function in the functions.php but unfortunately did not work.
Since I'm new to woocommerce and php, any ideas that could provide a solid solution to the problem?
// get old and new product stock quantity
function get_old_and_new_product_quantity_stock( $sql, $product_id_with_stock, $new_stock, $operation ) {
$product = wc_get_product( $product_id_with_stock );
$old_stock_quantity = $product->get_stock_quantity();
$new_stock_quantity = $new_stock;
echo $old_stock_quantity, $new_stock_quantity;
if ($new_stock_quantity < $old_stock_quantity) {
$new_stock = $old_stock_quantity;
$new_stock_quantity = $old_stock_quantity;
}
return $sql;
}
add_filter( 'woocommerce_update_product_stock_query', 'get_old_and_new_product_quantity_stock', 10, 4 );
You can use the update_post_meta action hook to check if the new value is less than the previous value and display error message.
This will work for quick edit and for product edit page. But the wp_die on product page will look bad so use the javascript to prevent submitting on product edit page (there was another question about it yesterday)
Be sure to test this snippet and create some orders that will reduce the stock automatically. I added is_admin() check but please do a good test.
add_action( 'update_post_meta', 'prevent_reducing_stock_metadata', 10, 4 );
function prevent_reducing_stock_metadata( $meta_id, $post_id, $meta_key, $meta_value ) {
// Check if the meta key is _stock and the new value is less than the previous value
if ( '_stock' == $meta_key && $meta_value < get_post_meta( $post_id, '_stock', true ) ) {
// Check if this is an update from the WordPress admin area
if ( is_admin() ) {
wp_die( __( 'Error: You cannot reduce the stock level for this product.' ), 'error' );
}
}
}

Remove specific meta_data from product on woocommerce checkout

so - I have a couple of meta_data which I don't want to get transmitted. Actually with this snippet I am able to do this on woocommerce order view. As I have connected an ERP this won't work there.
add_filter( "woocommerce_order_item_get_formatted_meta_data","unset_specific_order_item_meta_data", 10, 2);
function unset_specific_order_item_meta_data($formatted_meta, $item){
foreach( $formatted_meta as $key => $meta ){
if( in_array( $meta->key, array("length", "surface", "amount") ) )
unset($formatted_meta[$key]);
}
return $formatted_meta;
}
Is there a way to achieve this with woocommerce_checkout_update_order_meta? So that the specific meta_data (like length, surface, amount) isn't in the order in the first place?
The woocommerce_checkout_update_order_meta hook is meant to save custom meta data, unsetting meta data doesn't work here. However you can use delete_meta_data like this:
add_action("woocommerce_checkout_update_order_meta", "custom_woocommerce_checkout_update_order_meta", 10, 2);
function custom_woocommerce_checkout_update_order_meta($order_id, $data) {
$order = wc_get_order($order_id);
if ($order) {
$meta_data_keys = array("length", "surface", "amount");
foreach ($meta_data_keys as $meta_data_key) {
$order->delete_meta_data($meta_data_key);
}
}
}

URL to product page with quantity inputed - WooCommerce

I am trying to find a way to edit a product url in WooCommerce so that when visited a quantity is pre-selected for the quantity input, e.g. 2.
I know there is an add to cart url for it:
http://yourdomain.com/?add-to-cart=47&quantity=2
But was wondering if it was possible to just input the quantity on the product page with a similar URL.
Thanks for any ideas on the matter.
you can do it like this:
add_filter( 'woocommerce_quantity_input_args', 'custom_woocommerce_quantity_input_args' ); // Simple products
add_filter( 'woocommerce_available_variation', 'custom_woocommerce_quantity_input_args' ); // Variations
function custom_woocommerce_quantity_input_args( $args ) {
if ( isset( $_GET['qty'] ) && is_numeric($_GET['qty']) ) {
$args['input_value'] = $_GET['qty'];
}
return $args;
}
with that you can then do http://yourdomain.com/product/ship-your-idea/?qty=10.

WooCommerce Booking & Appointment Plugin: wrong price on cart and checkout page

The site I am developing is using the WooCommerce Booking & Appointment Plugin (http://www.tychesoftwares.com/store/premium-plugins/woocommerce-booking-plugin), I create a custom form to add mutiple products to cart at one time. Here is the code:
function booking_add_to_cart() {
if ($_POST && is_post_type_archive('product')) {
global $woocommerce;
if(is_array($_POST['qty']) && !empty($_POST['qty'])) {
$woocommerce->cart->empty_cart(); //Clear the cart
foreach ($_POST['qty'] as $product_id => $qty) {
$qty = intval($qty);
$product_id = intval($product_id);
if ($qty > 0 && $product_id > 0) {
$woocommerce->cart->add_to_cart($product_id, $qty); // Add product to cart individually.
}
}
$checkout_url = $woocommerce->cart->get_checkout_url();
wp_redirect( $checkout_url ); //Redirect to checkout page
}
}
}
add_action( 'template_redirect', 'booking_add_to_cart');
But there are something wrong with the prices on checkout page. Some of them are correct and some aren't.
The plugin is using three filters to modify the prices:
add_filter('woocommerce_add_cart_item_data', array('bkap_cart', 'bkap_add_cart_item_data'), 25, 2);
add_filter('woocommerce_get_cart_item_from_session', array('bkap_cart', 'bkap_get_cart_item_from_session'), 25, 2);
add_filter( 'woocommerce_get_item_data', array('bkap_cart', 'bkap_get_item_data_booking'), 25, 2 );
However it's not working correctly in the custom form I created. Can anyone help me with this? Thanks in advance.

Wordpress variable, user created, woocommerce product

Basically I am interested in using woocommerce to sell a product . This product is a Print Order of a external printing service that I have implemented in a brand new plugin.
What I want now is after the order, is to be able to put that "order" in the buy cart, and buy it normally as just another woocommerce product.
The product has to be created on the fly, manually by a way of some function that I can use to create a product during a certain workflow point.
Can you help me to find a solution?
Using woocommerce or not!
What i understand from your requirement/comments is that you want to be able to dynamically create a product, which is bad idea. But here is my suggestion.
Lets say you have a simple product called "Print Job" with a price of $1 and with an id of 10. And i am supposing that your external printing service would send back a response with the order and the price of printing, lets say $64.
Once you recieve the response you can simply call add_product_to_cart(10), this will automatically add the print job product to your cart.
/************* functions.php ***************/
function add_product_to_cart($product_id) {
if ( ! is_admin() ) {
$found = false;
//check if product already in cart
if ( sizeof( WC()->cart->get_cart() ) > 0 ) {
foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id == $product_id )
$found = true;
}
// if product not found, add it
if ( ! $found )
WC()->cart->add_to_cart( $product_id );
} else {
// if no products in cart, add it
WC()->cart->add_to_cart( $product_id );
}
}
}
You also need to add this function in your functions.php, this function will override the price of the product i.e "Print Job" with the actual price of $64.
/******************* Functions.php ****************/
add_action( 'woocommerce_before_calculate_totals', 'override_printing_price' );
function override_printing_price( $cart_object ) {
$custom_price = 64;
foreach ( $cart_object->cart_contents as $key => $value ) {
$value['data']->price = $custom_price;
}
}

Resources