WP add to cart and save item meta programmatically [duplicate] - wordpress

This question already has answers here:
Woocommerce Ajax add to cart programmatically
(2 answers)
Closed 1 year ago.
I want to add product along with meta data in cart with programming.
Here is my code. But its not adding any meta data but only adding product in cart.
$genre = 10;
$item_id = WC()->cart->add_to_cart( $product_id, 1, false, false, [ 'genre_id' => $genre, 'genre' => 'Test' ] );
WC()->cart->cart_contents[$item_id]['genre_id'] = $genre;
WC()->cart->cart_contents[$item_id]['genre'] = 'Test';
WC()->cart->calculate_totals();
WC()->cart->set_session();
WC()->cart->maybe_set_cart_cookies();
Also added few hooks, that are also not adding meta data.
add_action( 'woocommerce_before_calculate_totals', 'change_cart_item_price', 30, 1 );
function change_cart_item_price( $cart ) {
foreach ( $cart->get_cart() as $cart_item ) {
//if( isset($cart_item['genre_id']) ){
$cart_item['data']->add_meta_data( 'genre_id', $cart_item['genre_id'] );
$cart_item['data']->add_meta_data( 'genre', 'Test' );
//}
}
}
add_filter( 'woocommerce_get_item_data', function ( $item_data, $cart_item_data ) {
//if( isset( $cart_item_data['genre'] ) ) {
$item_data[] = array(
'key' => 'Genre',
'value' => 'Test'
);
//}
return $item_data;
}, 10, 2 );
add_action( 'woocommerce_checkout_create_order_line_item', function( $item, $cart_item_key, $values, $order ) {
//if( isset( $values['genre'] ) ) {
$item->add_meta_data(
'Genre',
'Test',
true
);
//}
}, 10, 4 );
Can you please verify where I'm wrong. I got these code from online search.

You can use below action/filter to add additional data to cart item:
//Add custom cart item data
function zwtadd_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
if( isset( $_POST['what_is_being_promoted'] ) ) {
$cart_item_data['zwt_field'] = sanitize_text_field( $_POST['genre_id'] );
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'zwtadd_cart_item_data', 10, 3 );
//Display custom item data in the cart
function zwt_get_item_data( $item_data, $cart_item_data ) {
if( isset( $cart_item_data['zwt_field'] ) ) {
$item_data[] = array(
'key' => __( 'Genre id', 'text-domain' ),
'value' => wc_clean( $cart_item_data['zwt_field'] )
);
}
return $item_data;
}
add_filter( 'woocommerce_get_item_data', 'zwt_get_item_data', 10, 2 );
//Add custom meta to order
function zwt_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if( isset( $values['zwt_field'] ) ) {
$item->add_meta_data(__( 'Genre id', 'text-domain' ), $values['zwt_field'], true);
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'zwt_checkout_create_order_line_item', 10, 4 );
Above code will add data to cart item, display data to cart and same will display in the order.

Related

Save multiple datas in order WooCommerce

I have two customs fields in my product (image and texte), I all ready show it in the cart but when the order is complete, i can't find how can I show both in the admin order (I can show one of two ^^)
Here is the code :
// Add custom fields data as the cart item custom data
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_fields_data_as_custom_cart_item_data', 10, 2 );
function add_custom_fields_data_as_custom_cart_item_data($cart_item, $product_id){
if( isset($_FILES['image']) && !empty($_FILES['image']) && !empty($_POST['nom_pp']) ) {
$upload = wp_upload_bits( $_FILES['image']['name'], null, file_get_contents( $_FILES['image']['tmp_name'] ) );
$filetype = wp_check_filetype( basename( $upload['file'] ), null );
$upload_dir = wp_upload_dir();
$upl_base_url = is_ssl() ? str_replace('http://', 'https://', $upload_dir['baseurl']) : $upload_dir['baseurl'];
$base_name = basename( $upload['file'] );
$cart_item['file_upload'] = array(
'guid' => $upl_base_url .'/'. _wp_relative_upload_path( $upload['file'] ), // Url
'file_type' => $filetype['type'], // File type
'file_name' => $base_name, // File name
'title' => ucfirst( preg_replace('/\.[^.]+$/', '', $base_name ) ), // Title
);
$cart_item['nom_pp'] = $_POST['nom_pp'];
$cart_item['unique_key'] = md5( microtime().rand() ); // Avoid merging items
}
return $cart_item;
}
// Display custom cart item data in cart (optional)
add_filter('woocommerce_get_item_data', 'njengah_custom_item_data', 10, 2);
function njengah_custom_item_data($cart_item_data, $cart_item) {
if ( isset($cart_item['file_upload']['title']) ){
$cart_item_data[] = array(
'name' => __( 'Mon image ', 'woocommerce' ),
'value' => str_pad($cart_item['file_upload']['title'], 16, 'X', STR_PAD_LEFT) . '…',
);
}
if ( isset($cart_item['nom_pp']) ){
$cart_item_data[] = array(
'name' => __( 'Nom du papier peint ', 'woocommerce' ),
'value' => $cart_item['nom_pp'],
);
}
return $cart_item_data;
}
// Save Image data as order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'njengah_field_update_order_item_meta', 20, 4 );
function njengah_field_update_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset($values['file_upload']) && isset($values['nom_pp']) ){
$item->update_meta_data($item, '_img_file', $values['file_upload']);
$item->update_meta_data($item, '_nom_pp', $values['nom_pp']);
}
}
// Admin orders: Display a linked button + the link of the image file
add_action( 'woocommerce_after_order_itemmeta', 'njengah_image_link_after_order_itemmeta', 10, 3 );
function njengah_image_link_after_order_itemmeta( $item_id, $item, $product ) {
// Only in backend for order line items (avoiding errors)
if( is_admin() && $item->is_type('line_item') && $file_data = $item->get_meta('_img_file') && $file_data = $item->get_meta('_nom_pp') ){
echo '<p>'.__("Voir l'image") . '</p>'; // Optional
echo '<p><code>'.$file_data['guid'].'</code></p>'; // Optional
echo '<p>'.$file_data['nom_pp'].'</p>'; // Optional
}
}
I think I need to edit the order meta data, but I don't know how can I do it :)

Update WooCommerce order status if product custom field is set

I need to automatically set a certain order status (different than processing) when getting a new order.
This is achieved by this function:
add_action('woocommerce_thankyou','change_order_status');
function change_order_status( $order_id ) {
if ( ! $order_id ) { return; }
$order = wc_get_order( $order_id );
if( 'processing'== $order->get_status() ) {
$order->update_status( 'wc-custom-status' );
}
}
This totally works. Now I only need this to happen when a product has a customization.
The way to customize a product is filling an input field before adding to cart. The input is attached to the item data:
// Add custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_cart_item_data', 10, 2 );
function add_custom_cart_item_data( $cart_item_data, $product_id ){
if( isset($_POST['custom_text']) ) {
$cart_item_data['custom_text'] = sanitize_text_field( $_POST['custom_text'] );
$cart_item_data['unique_key'] = md5( microtime().rand() ); // Make each item unique
}
return $cart_item_data;
}
Then the custom text is retrieved and displayed in cart and in the order data using this:
// Display custom cart item data on cart and checkout
add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 10, 2 );
function display_custom_cart_item_data( $cart_item_data, $cart_item ) {
if ( !empty( $cart_item['custom_text'] ) ){
$cart_item_data[] = array(
'name' => __('Customization', 'woocommerce'),
'value' => $cart_item['custom_text'] // Already sanitized field
);
}
return $cart_item_data;
}
// Save and display custom item data everywhere on orders and email notifications
add_action( 'woocommerce_checkout_create_order_line_item', 'add_product_custom_field_as_order_item_meta', 10, 4 );
function add_product_custom_field_as_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset($values['custom_text']) ) {
$item->update_meta_data('Add on', $values['custom_text'] );
}
}
I'm trying using the if ( isset($values['custom_text']) ) part as a trigger of the function to change the order status only if the product add on is set and other similar methods (like if ( !empty( $cart_item['custom_text'] ) ) but I'm not sure this is the way to go:
add_action('woocommerce_thankyou','change_order_status');
function change_order_status( $order_id ) {
if ( ! $order_id ) {return;}
$order = wc_get_order( $order_id );
if ( isset($values['custom_text']) ) {
if( 'processing'== $order->get_status() ) {
$order->update_status( 'wc-custom-status' );
}
}
}
This above does nothing. Am I anywhere near it with this approach?
EDIT: I tried this too
add_action('woocommerce_thankyou','change_order_status');
function change_order_status( $order_id ) {
if ( ! $order_id ) {return;}
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item_id => $item ) {
$allmeta = $item->get_meta_data();
if ( isset($values['custom_text']) ) {
if( 'processing'== $order->get_status() ) {
$order->update_status( 'wc-custom-status' );
}
}
}
}
Your code contains some unnecessary steps as well as some shortcomings
For example, the woocommerce_add_cart_item_data hook contains 3 arguments versus 2
So you get:
// Add custom cart item data
function filter_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
// Isset and NOT empty
if ( isset ( $_POST[ 'custom_text' ] ) && ! empty ( $_POST[ 'custom_text' ] ) ) {
$cart_item_data['custom_text'] = sanitize_text_field( $_POST['custom_text'] );
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 10, 3 );
// Display custom cart item data on cart and checkout
function filter_woocommerce_get_item_data( $cart_data, $cart_item = null ) {
if ( isset ( $cart_item['custom_text'] ) ) {
$cart_data[] = array(
'name' => __( 'Customization', 'woocommerce' ),
'value' => $cart_item['custom_text']
);
}
return $cart_data;
}
add_filter( 'woocommerce_get_item_data', 'filter_woocommerce_get_item_data', 10, 2 );
// Add the information as meta data so that it can be seen as part of the order
// Save and display custom item data everywhere on orders and email notifications
function action_woocommerce_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if ( isset ( $values['custom_text'] ) ) {
$item->update_meta_data( 'custom_text', $values['custom_text'] );
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'action_woocommerce_checkout_create_order_line_item', 10, 4 );
// On thankyou page
function action_woocommerce_thankyou( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Only when the current order status is 'processing'
if ( $order->get_status() == 'processing' ) {
// Loop trough
foreach ( $order->get_items() as $item ) {
// Get meta
$value = $item->get_meta( 'custom_text' );
// NOT empty
if ( ! empty ( $value ) ) {
// Update status (change to desired status)
$order->update_status( 'cancelled' );
// Stop loop
break;
}
}
}
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );
Currently it is just checking if the value exists, to compare it effectively
Change
// NOT empty
if ( ! empty ( $value ) ) {
// Update status
$order->update_status( 'cancelled' );
// Stop loop
break;
}
To
// Compare
if ( $value == 'some value' ) ) {
// Update status
$order->update_status( 'cancelled' );
// Stop loop
break;
}

Wordpress add meta key to Cart item

as I am trying to add one extra data so that I can fetch and filter the data according to the meta after successfull payment. Let me explain using code.
$cart_data = array(
'product_id' => $product_id,
'payment_type' => 'subscription',
'**what_is_being_promoted**' => $promoting,
);
WC()->cart->add_to_cart($product_id, 1, null, null, $cart_item_data);
now i would like to read the key 'what_is_being_promoted' in classifier_update_user_data_upon_payment hook.
how to achieve that.
You can use below filters/action to add additional data to cart item:
//Add custom cart item data
function zwtadd_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
if( isset( $_POST['what_is_being_promoted'] ) ) {
$cart_item_data['zwt_field'] = sanitize_text_field( $_POST['what_is_being_promoted'] );
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'zwtadd_cart_item_data', 10, 3 );
//Display custom item data in the cart
function zwt_get_item_data( $item_data, $cart_item_data ) {
if( isset( $cart_item_data['zwt_field'] ) ) {
$item_data[] = array(
'key' => __( 'Is promoted', 'text-domain' ),
'value' => wc_clean( $cart_item_data['zwt_field'] )
);
}
return $item_data;
}
add_filter( 'woocommerce_get_item_data', 'zwt_get_item_data', 10, 2 );
//Add custom meta to order
function zwt_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if( isset( $values['zwt_field'] ) ) {
$item->add_meta_data(__( 'Is promoted', 'text-domain' ), $values['zwt_field'], true);
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'zwt_checkout_create_order_line_item', 10, 4 );
Above code will add data to cart item, display data to cart and same will display in the order.

Add custom select field with validation to WooCommerce checkout page if certain products are in cart

I wish to add a custom select field with validation to the WooCommerce checkout page if certain products are in cart.
With my current code I retrieve the value of my custom WooCommerce form field. However, it display "array" at the order page.
I have an select field which have an option of 1 and 0. Upon selection of the select field, i want it to display either 1 or 0 at the order page but im unable to do so.
Please guide me on what should i do with my current codes:
//AMBASSADOR CUSTOM CHECKOUT FIELDS, CONTENT add marketplace for sameday TEST
add_action( 'woocommerce_after_checkout_billing_form', 'aym_custom_checkout_field' );
function aym_custom_checkout_field( $checkout ) {
//Check if Product in Cart
$prod_in_cart_17563 = aym_is_conditional_product_in_cart_17563( 212 );
if ( $prod_in_cart_17563 === true ) {
$domain = 'wocommerce';
$default = 'Y';
woocommerce_form_field( '_my_field_name', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Market Place - Please Select Y to complete this order' ),
'required' => true,
'options' => array(
'Y' => __('1'),
'N' => __('0')
),'default' => $default),
$checkout->get_value( '_my_field_name' ) );
}
}
//AMBSSADOR BUNDLE add marketplace for same day pa rt 2
function aym_is_conditional_product_in_cart_17563( $product_id ) {
//Check to see if user has product in cart
global $woocommerce;
//flag no product in cart
$prod_in_cart_17563 = false;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id === $product_id ) {
//product is in cart!
$prod_in_cart_17563 = true;
}
}
return $prod_in_cart_17563;
}
//process orders in order page
// Custom checkout fields validation
add_action( 'woocommerce_checkout_process', 'custom_checkout_field_process' );
function custom_checkout_field_process() {
if ( isset($_POST['_my_field_name']) && empty($_POST['_my_field_name']) )
wc_add_notice( __( 'Please fill in "My 1st new field".' ), 'error' );
}
// Save custom checkout fields the data to the order
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_meta', 10, 2 );
function custom_checkout_field_update_meta( $order, $data ){
if( isset($_POST['_my_field_name']) && ! empty($_POST['_my_field_name']) )
$order->update_meta_data( '_my_field_name', sanitize_text_field( $_POST['_my_field_name'] ) );
}
/**
* Update the order meta with field value
**/
add_action('woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta');
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ($_POST['_my_field_name']) update_post_meta( $order_id, 'My Field', esc_attr($_POST['_my_field_name']));
}
// View fields in Edit Order Page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_value_admin_order', 10, 1 );
function display_custom_fields_value_admin_order( $order ){
// Display the delivery option
if( $delivery_option = $order->get_meta('_my_field_name') )
echo '<p><strong>'.__('Delivery type').':</strong> ' . $delivery_option . '</p>';
}
// Display field value on the order edit page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta( $order ) {
if( $selectoption = $order->get_meta('_my_field_name') ) {
//$value = wc_get_hearaboutus_options()[$selectoptions];
$meta= get_post_meta( $post->ID, $selectoption, true );
$myvalues = unserialize( $meta );
echo '<p><strong>'.__('Market_Place').':</strong> ' . $myvalues . '</p>';
}
}
I have partly rewritten / modified your code with some (extra) features
The ability to check for multiple product IDs in the shopping cart
The custom field is only added if a certain product id is in the shopping cart
The possibility to check out if the custom field is not present (product ID is NOT in cart)
No possibility to checkout as long as the value 'Y' is not selected from the custom select menu (Product ID is IN cart)
Explanation via comment tags added in the code
// Add custom 'select' field after checkout billing form (if product ID is in cart)
function action_woocommerce_after_checkout_billing_form( $checkout ) {
// Check if Product in Cart
// Multiple product IDs can be entered, separated by a comma
$product_in_cart = is_product_in_cart( array( 212, 30, 815 ) );
// True
if ( $product_in_cart ) {
$domain = 'woocommerce';
$default = 'Y';
woocommerce_form_field( '_my_field_name', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Market Place - Please Select Y to complete this order', $domain ),
'required' => true,
'options' => array(
'Y' => __( 'Y', $domain ),
'N' => __( 'N', $domain ),
),
'default' => $default,
), $checkout->get_value( '_my_field_name' ) );
}
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );
// Function to check if a certain product ID is in cart
function is_product_in_cart( $targeted_ids ) {
// Flag no product in cart
$flag = false;
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids
if ( in_array( $cart_item['product_id'], $targeted_ids ) ) {
// Product is in cart
$flag = true;
// Break loop
break;
}
}
}
return $flag;
}
// Custom checkout 'select' field validation
function action_woocommerce_checkout_process() {
// Isset
if ( isset( $_POST['_my_field_name'] ) ) {
$domain = 'woocommerce';
$my_field_name = $_POST['_my_field_name'];
// Empty
if ( empty ( $my_field_name ) ) {
wc_add_notice( __( 'Please Select Y to complete this order', $domain ), 'error' );
}
// NOT empty but value is 'N'
if ( ! empty ( $my_field_name ) && $my_field_name == 'N' ) {
wc_add_notice( __( 'Please Select Y to complete this order', $domain ), 'error' );
}
}
}
add_action( 'woocommerce_checkout_process', 'action_woocommerce_checkout_process', 10, 0 );
// Save custom checkout 'select' field
function action_woocommerce_checkout_create_order( $order, $data ) {
// Isset
if ( isset( $_POST['_my_field_name'] ) ) {
$my_field_name = $_POST['_my_field_name'];
// NOT empty & equal to 'Y'
if ( ! empty( $my_field_name ) && $my_field_name == 'Y' ) {
$order->update_meta_data( '_my_field_name', sanitize_text_field( $my_field_name ) );
}
}
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );
// Display the custom 'select' field value on admin order pages after billing adress
function action_woocommerce_admin_order_data_after_billing_address( $order ) {
$domain = 'woocommerce';
// Get meta
$my_field_name = $order->get_meta( '_my_field_name' );
// NOT empty
if ( ! empty ( $my_field_name ) ) {
echo '<p><strong>' . __( 'Delivery type', $domain ) . ':</strong> ' . $order->get_meta( '_my_field_name' ) . '</p>';
}
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'action_woocommerce_admin_order_data_after_billing_address', 10, 1 );
// Display the custom 'select' field value on 'order received' and 'order view' pages (frontend)
function action_woocommerce_order_details_after_order_table( $order ) {
$domain = 'woocommerce';
// Get meta
$my_field_name = $order->get_meta( '_my_field_name' );
// NOT empty
if ( ! empty ( $my_field_name ) ) {
echo '<p><strong>' . __( 'Delivery type', $domain ) . ':</strong> ' . $order->get_meta( '_my_field_name' ) . '</p>';
}
}
add_action( 'woocommerce_order_details_after_order_table', 'action_woocommerce_order_details_after_order_table', 10, 1 );

Woocommerce - Calculate Exta Fee Based on Amount of People

I've added in a function for a custom field on the product general options:
// Add Custom Field to Product under General
function create_extra_fee_field() {
$args = array(
'id' => 'park_fee',
'label' => __( 'Natl Park Entrance Fee', 'tranq-lsx-child' ),
'class' => 'tranq-custom-field',
'desc_tip' => true,
'description' => __( 'This sets the Fee that will be added to the car.', 'tranq-lsx-child' ),
);
woocommerce_wp_text_input( $args );
}
add_action( 'woocommerce_product_options_general_product_data', 'create_extra_fee_field' );
// Save Custom Field Data
function save_extra_fee_field( $post_id ) {
$product = wc_get_product( $post_id );
$title = isset( $_POST['park_fee'] ) ? $_POST['park_fee'] : '';
$product->update_meta_data( 'park_fee', sanitize_text_field( $title ) );
$product->save();
}
add_action( 'woocommerce_process_product_meta', 'save_extra_fee_field' );
I would like to add this as an extra fee to the Cart Totals which multiplied based on the amount of Person/People that were selected from the Woocommerce Bookings.
Something like this:
// Calculate Extra Fee Based on Amount of People.
add_action('woocommerce_cart_calculate_fees' , 'add_custom_fees');
function add_custom_fees( WC_Cart $cart ){
$park_fee = get_post_meta($item['product_id'] , 'park_fee', true);
foreach( $cart->get_cart() as $item ){
$fees += $item[ 'park_fee' ] * 14706;
}
if( $fees != 0 ){
$cart->add_fee( 'Park Fee', $fees);
}
}
How do I go about in achieving this? Any Links to a walkthrough would be greatly appreciated.
I've added this and it seems to work:
// Add Custom Field to Cart Totals
function woo_add_cart_fee() {
global $woocommerce;
foreach( WC()->cart->get_cart() as $cart_item ){
// Get the WC_Product object (instance)
$product = $cart_item['data'];
$product_id = $product->get_id(); // get the product ID
$custom_field_value = get_post_meta( $product->get_id(), 'park_fee', true );
$person = array_sum( $cart_item['booking']['_persons'] );
}
$additional_fee_name = "Natl Park Entrance Fee";
$extra_fee = $custom_field_value * $person;
$addedFee = false;
// first check to make sure it isn’t already there
foreach ( $woocommerce->cart->get_fees() as $_fee )
{
if ($_fee->id == sanitize_title($additional_fee_name) )
{
$_fee->amount = (float) esc_attr( $extra_fee );
}
}
if (!$addedFee)
{
$woocommerce->cart->add_fee( __($additional_fee_name, "woocommerce"),
$extra_fee, $additional_fee_taxable );
}
}
add_action( "woocommerce_before_calculate_totals", "woo_add_cart_fee" );

Resources