Sync newsletter custom checkbox between checkout and my account in WooCommerce - php

I would like to synhcronize a custom checkbox field in WooCommerce checkout page with a similar one in the My Account page (when the user is logged in).
Here's my code:
// Show a checkbox in checkout page and in My account > Details
add_action( 'woocommerce_edit_account_form', 'display_checkbox_in_account_page' );
add_action( 'woocommerce_after_order_notes', 'display_checkbox_in_account_page' );
function display_checkbox_in_account_page() {
woocommerce_form_field( 'newsletter-account', array(
'type' => 'checkbox',
'class' => array('form-row-wide'),
'label' => __( 'Subscribe to my newsletter', 'woocommerce' ),
), get_user_meta(get_current_user_id(), 'newsletter-account', true ) );
}
// Save checkbox value when saved in My account > Details
add_action( 'woocommerce_save_account_details', 'save_checkbox_value_from_account_details', 10, 1 );
function save_checkbox_value_from_account_details( $user_id ) {
$value = isset( $_POST['newsletter-account'] ) ? '1' : '0';
update_user_meta( $user_id, 'newsletter-account', $value );
}
Those two blocks of code work fine: if in My account > Details I checked the checkbox, the preference is saved and I can see a checked checkbox also in the checkout page.
Now the problem is that I need a way to obtain the same result when I edit my newsletter preference from the checkout page. I think I need to use the woocommerce_checkout_create_order but I haven't any idea on how to code this:
//Save the checkbox value when customer edit it from the checkout page
add_action( 'woocommerce_checkout_create_order', 'save_checkbox_value_from_checkout_page'. 10, 1 );
function save_checkbox_value_from_checkout_page() {
//some code here
}
Any suggestions are appreciated.

Updated
The hook woocommerce_checkout_create_order is for order meta data and what you need is to save/update your checkout newsletter-account field value as user meta data…
So is better to use dedicated woocommerce_checkout_update_customer hook.
Here is your complete code (tested and working):
add_action( 'woocommerce_edit_account_form', 'display_checkbox_in_account_page' );
add_action( 'woocommerce_after_order_notes', 'display_checkbox_in_account_page' );
function display_checkbox_in_account_page() {
woocommerce_form_field( 'newsletter-account', array(
'type' => 'checkbox',
'class' => array('form-row-wide'),
'label' => __( 'Subscribe to my newsletter', 'woocommerce' ),
), get_user_meta( get_current_user_id(), 'newsletter-account', true ) );
}
// Save/update checkbox value when saved in My account > Details
add_action( 'woocommerce_save_account_details', 'save_checkbox_value_from_account_details', 10, 1 );
function save_checkbox_value_from_account_details( $user_id ) {
$value = isset( $_POST['newsletter-account'] ) ? '1' : '0';
update_user_meta( $user_id, 'newsletter-account', $value );
}
// Save/update custom checkout field value as user meta data
add_action('woocommerce_checkout_update_customer','custom_checkout_checkbox_update_customer', 100, 2 );
function custom_checkout_checkbox_update_customer( $customer, $data ){
$value = isset( $_POST['newsletter-account'] ) ? '1' : '0';
update_user_meta( $customer->get_id(), 'newsletter-account', $value ); // Updated
}
Code goes in functions.php file of your active child theme (or active theme).
Now if you want to grab that information additionally to the order as order meta data you will use:
add_action('woocommerce_checkout_create_order','custom_checkout_checkbox_add_order_meta', 100, 2 );
function custom_checkout_checkbox_add_order_meta( $order, $data ){
$value = isset( $_POST['newsletter-account'] ) ? '1' : '0';
$order->update_meta_data( 'newsletter-account', $value );
}

Related

Save Custom Field Data to Cart and Order of a Woocommerce product variation

We managed to put a custom field for variation products following Remi Corson guide here
At this point, we are able to show the custom text field in the single product page when users select the variation, but this is not enough in the purchase process since we need to:
A) Display this text in Cart and Checkout
B) Save this information so it shows in Thank You Page, Emails and Admin Order Edit Page
Something similar to Save and display product custom meta on WooCommerce orders and emails, but with product variations instead of simple products.
This is the code we added to our functions.php to add the custom field to the product variations
// Add Variation Settings
add_action( 'woocommerce_product_after_variable_attributes', 'variation_settings_fields', 10, 3 );
// Save Variation Settings
add_action( 'woocommerce_save_product_variation', 'save_variation_settings_fields', 10, 2 );
/**
* Create new fields for variations
*
*/
function variation_settings_fields( $loop, $variation_data, $variation ) {
// Text Field
woocommerce_wp_text_input(
array(
'id' => '_text_field[' . $variation->ID . ']',
'label' => __( 'My Text Field', 'woocommerce' ),
'placeholder' => 'http://',
'desc_tip' => 'true',
'description' => __( 'Enter the custom value here.', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_text_field', true )
)
);
// Hidden field
woocommerce_wp_hidden_input(
array(
'id' => '_hidden_field[' . $variation->ID . ']',
'value' => 'hidden_value'
)
);
}
/**
* Save new fields for variations
*
*/
function save_variation_settings_fields( $post_id ) {
// Text Field
$text_field = $_POST['_text_field'][ $post_id ];
if( ! empty( $text_field ) ) {
update_post_meta( $post_id, '_text_field', esc_attr( $text_field ) );
}
// Hidden field
$hidden = $_POST['_hidden_field'][ $post_id ];
if( ! empty( $hidden ) ) {
update_post_meta( $post_id, '_hidden_field', esc_attr( $hidden ) );
}
}
// Add New Variation Settings
add_filter( 'woocommerce_available_variation', 'load_variation_settings_fields' );
/**
* Add custom fields for variations
*
*/
function load_variation_settings_fields( $variations ) {
// duplicate the line for each field
$variations['text_field'] = get_post_meta( $variations[ 'variation_id' ], '_text_field', true );
return $variations;
}
So the goal here is how can we show this custom field for each variation in the Cart and Checkout below the items (Something like the image below - Look at the Shipping delay notice)
And to save that custom field info that each variation has to the Thank You Page, Emails and Order Page (We did it for simple products with this code, but this doesn't work for variable ones)
// Save and display "Custom Field for Simple Products" on order items everywhere
add_filter( 'woocommerce_checkout_create_order_line_item', 'action_wc_checkout_create_order_line_item', 10, 4 );
function action_wc_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
// Get the Custom Field
$value = $values['data']->get_meta( 'custom_field_for_simple_products' );
if( ! empty( $value ) ) {
// Save it and display it
$item->update_meta_data( __( 'Custom Fields', 'woocommerce' ), $value );
}
}
Please help!!
Updated
There are some mistakes in your code… The following revisited code will solve your issue:
// Display Variation custom fields (admin)
add_action( 'woocommerce_product_after_variable_attributes', 'display_variation_setting_custom_fields', 10, 3 );
function display_variation_setting_custom_fields( $loop, $variation_data, $variation ) {
echo '<div>';
woocommerce_wp_text_input( array( // Text Field
'id' => "_text_field[$loop]",
'label' => __("My Text Field", "woocommerce"),
'placeholder' => "http://",
'desc_tip' => true,
'description' => __("Enter the custom value here.", "woocommerce"),
'wrapper_class' => 'form-row form-row-full',
'value' => get_post_meta( $variation->ID, '_text_field', true ),
) );
woocommerce_wp_hidden_input( array( // Hidden field
'id' => "_hidden_field[$loop]",
'value' => 'hidden_value',
) );
echo '</div>';
}
// Save Variation custom fields
add_action( 'woocommerce_save_product_variation', 'save_variation_custom_fields', 10, 2 );
function save_variation_custom_fields( $variation_id, $i ) {
// Save Text Field
if( isset( $_POST['_text_field'][$i] ) && ! empty( $_POST['_text_field'][$i] ) )
update_post_meta( $variation_id, '_text_field', sanitize_text_field( $_POST['_text_field'][$i] ) );
// Save Hidden Field
if( isset( $_POST['_hidden_field'][$i] ) && ! empty( $_POST['_hidden_field'][$i] ) )
update_post_meta( $variation_id, '_hidden_field', esc_attr( $_POST['_hidden_field'][$i] ) );
}
// Include our variation custom field
add_filter( 'woocommerce_available_variation', 'include_variation_custom_field', 10, 3) ;
function include_variation_custom_field( $data, $product, $variation ) {
$data['text_field'] = $variation->get_meta( '_text_field' );
return $data;
}
// Save and display "Custom Field for Simple Products" on order items everywhere
add_filter( 'woocommerce_checkout_create_order_line_item', 'action_wc_checkout_create_order_line_item_2', 10, 4 );
function action_wc_checkout_create_order_line_item_2( $item, $cart_item_key, $values, $order ) {
// Get the Custom Field
$value = $values['data']->get_meta( '_text_field' );
if( ! empty( $value ) ) {
// Save it and display it
$item->update_meta_data( __( 'Custom Field', 'woocommerce' ), $value );
}
}
Code goes in functions.php file of your active child theme (or active theme) . Tested and works.
Related: Save and display product custom meta on WooCommerce orders and emails
Somme screenshots
On admin product variations settings:
On order received page (thankyou):
On admin edit orders pages:

Woocommerce custom product field in checkout [duplicate]

This question already has an answer here:
Admin product pages custom field displayed in Cart and checkout
(1 answer)
Closed 5 years ago.
I have a seemingly simple task, that I can't, for the life of me, seem to figure out.
I have a custom field on the admin page of my Woocommerce products. I just need the value I set here to display in the Woocommerce Checkout page and email.
I have managed to get the field to display on the product page using the following code:
add_action( 'woocommerce_product_options_general_product_data', 'create_shipdate_custom_field' );
function create_shipdate_custom_field() {
woocommerce_wp_text_input( array(
'id' => '_shipdate',
'type' => 'text',
'label' => __('Shipping Date', 'woocommerce' ),
'description' => '',
'desc_tip' => 'true',
'placeholder' => __('i.e. 16 December 2017', 'woocommerce' ),
) );
}
// save the data value from this custom field on product admin tab
add_action( 'woocommerce_process_product_meta', 'save_shipdate_custom_field' );
function save_shipdate_custom_field( $post_id ) {
$wc_text_field = $_POST['_shipdate'];
if ( !empty($wc_text_field) ) {
update_post_meta( $post_id, '_shipdate', esc_attr( $wc_text_field ) );
}
}
function product_date() {
echo get_post_meta( get_the_ID(), '_shipdate', true );
}
add_action('woocommerce_single_product_summary', 'product_date', 30);
I am able to get static text to display on the checkout page, using the following code, but it just won't work with my custom field:
function emaildate() { echo "This will display fine"; }
add_action('woocommerce_order_item_meta_start', 'emaildate', 10, 1);
Thanks in advance for the help!
You are missing a couple of steps to have your custom value display on the cart/checkout pages, namely, storing the custom field in the cart and in the order as meta data. Here is the full code which should work as expected:
// create the custom field on product admin tab
add_action( 'woocommerce_product_options_general_product_data', 'create_shipping_custom_field' );
function create_shipping_custom_field() {
// Create a custom text field
woocommerce_wp_text_input( array(
'id' => '_shipdate',
'type' => 'text',
'label' => __('Shipping Date', 'woocommerce' ),
'description' => '',
'desc_tip' => 'true',
'placeholder' => __('i.e. 16 December 2017', 'woocommerce' ),
) );
}
// save the data value from this custom field on product admin tab
add_action( 'woocommerce_process_product_meta', 'save_shipping_custom_field' );
function save_shipping_custom_field( $post_id ) {
$wc_text_field = $_POST['_shipdate'];
if ( !empty($wc_text_field) ) {
update_post_meta( $post_id, '_shipdate', esc_attr( $wc_text_field ) );
}
}
// Store custom field in Cart
add_action( 'woocommerce_add_cart_item_data', 'store_shipping_custom_field', 10, 2 );
function store_shipping_custom_field( $cart_item_data, $product_id ) {
$ship_date = get_post_meta( $product_id , '_shipdate', true );
if( !empty($ship_date) ) {
$cart_item_data[ '_shipdate' ] = $ship_date;
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'date_shipping', $ship_date );
}
return $cart_item_data;
}
// Render meta on cart and checkout
add_filter( 'woocommerce_get_item_data', 'rendering_meta_field_on_cart_and_checkout', 10, 2 );
function rendering_meta_field_on_cart_and_checkout( $cart_data, $cart_item ) {
$custom_items = array();
// Woo 2.4.2 updates
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['_shipdate'] ) ) {
$custom_items[] = array( "name" => __( "Shipping Date", "woocommerce" ), "value" => $cart_item['_shipdate'] );
}
return $custom_items;
}
// Add the information in the order as meta data
add_action('woocommerce_add_order_item_meta','add_shipping_to_order_item_meta', 1, 3 );
function add_shipping_to_order_item_meta( $item_id, $values, $cart_item_key ) {
$prod_id = wc_get_order_item_meta( $item_id, '_product_id', true );
$shipdate = get_post_meta( $prod_id, '_shipdate', true );
wc_add_order_item_meta( $item_id, 'Shipping Date', $shipdate, true );
}

Woocommerce coupons adding custom checkbox

I've gotten far enough on this simple function in functions.php that let's me add a checkbox to coupons. However, once I save/update a coupon, my checkbox value (check/unchecked) doesn't get committed (so the checkbox is always unchecked). In other words, I can't get it to update the value to yes in the meta_value column in postmetas when I update/save. The checkbox is there, I just can't use it... highly frustrating! Any sugestions on what I'm doing wrong, please :)
function add_coupon_revenue_dropdown_checkbox() {
$post_id = $_GET['post'];
woocommerce_wp_checkbox( array( 'id' => 'include_stats', 'label' => __( 'Coupon check list', 'woocommerce' ), 'description' => sprintf( __( 'Includes the coupon in coupon check drop-down list', 'woocommerce' ) ) ) );
$include_stats = isset( $_POST['include_stats'] ) ? 'yes' : 'no';
update_post_meta( $post_id, 'include_stats', $include_stats );
do_action( 'woocommerce_coupon_options_save', $post_id );
}add_action( 'woocommerce_coupon_options', 'add_coupon_revenue_dropdown_checkbox', 10, 0 );
The part I'm trying to affect is:
wp-content/plugins/woocommerce/includes/admin/meta-boxes/class-wc-meta-box-coupon-data.php
The problem with your code is that you are attempting to save the value of the checkbox in the same function where you generate the html for it. This won't work. You need to break your current function into two parts that run on two different WooCommerce hooks.
The first is to display the actual checkbox:
function add_coupon_revenue_dropdown_checkbox() {
woocommerce_wp_checkbox( array( 'id' => 'include_stats', 'label' => __( 'Coupon check list', 'woocommerce' ), 'description' => sprintf( __( 'Includes the coupon in coupon check drop-down list', 'woocommerce' ) ) ) );
}
add_action( 'woocommerce_coupon_options', 'add_coupon_revenue_dropdown_checkbox', 10, 0 );
The second is to save the value of the checkbox when the submitted form is being processed.
function save_coupon_revenue_dropdown_checkbox( $post_id ) {
$include_stats = isset( $_POST['include_stats'] ) ? 'yes' : 'no';
update_post_meta( $post_id, 'include_stats', $include_stats );
}
add_action( 'woocommerce_coupon_options_save', 'save_coupon_revenue_dropdown_checkbox');

Set product custom field and display value in cart, checkout and view order

I've created a custom field for warranty in my products pages, via function.php.
add_action( 'woocommerce_product_options_general_product_data', 'test_custom_fields' );
function test_custom_fields() {
// Print a custom text field
woocommerce_wp_text_input( array(
'id' => '_warranty',
'label' => 'i.e. 15 years',
'description' => '',
'desc_tip' => 'true',
'placeholder' => 'i.e. 15 years'
) );
}
add_action( 'woocommerce_process_product_meta', 'test_save_custom_fields' );
function test_save_custom_fields( $post_id ) {
if ( ! empty( $_POST['_warranty'] ) ) {
update_post_meta( $post_id, '_warranty', esc_attr( $_POST['_warranty'] ) );
}
}
I would like to "duplicate" this custom field with key and value, in an self-generated custom field on the admin order page depending on products in cart/order (without plugin).
So, with this custom field on order page, I will finally be able to display "warranty" in my pdf invoice with WooCommerce PDF Invoice plugin.
Another explanation :
As admin, I fill _warranty value in "product1" page
When "product1" is in an order, on the admin order view, I would like to see a custom field containing "_warranty + value" from product1 page.
So, as admin, I could set {{_warranty}} in WooCommerce PDF Invoice plugin to display "Warranty : 15 years"
Many thanks for your help.
I have just tested the following case: show product meta in order items table in Order Details
But this does not give me a custom field, so I couldn't get my {{_warranty}} value width it.
What I am doing wrong?
How can I achieve this?
Thanks.
First: "Duplicating this custom field with key and value, in an self-generated custom field on the admin order page" is not the good approach.
To achieve what you are expecting, you have missed just some little things. You need to:
Store custom field in Cart (when product is added to cart)
Render this on cart and checkout pages
Add the information in the order as meta data (to make it part of the order)
With point 3 you will be able to get this on WooCommerce PDF Invoice plugin to display "Warranty : 15 years".
So the code you need is:
// create the custom field on product admin tab
add_action( 'woocommerce_product_options_general_product_data', 'create_warranty_custom_field' );
function create_warranty_custom_field() {
// Create a custom text field
woocommerce_wp_text_input( array(
'id' => '_warranty',
'type' => 'text',
'label' => __('Warranty', 'woocommerce' ),
'description' => '',
'desc_tip' => 'true',
'placeholder' => __('i.e. 15 years', 'woocommerce' ),
) );
}
// save the data value from this custom field on product admin tab
add_action( 'woocommerce_process_product_meta', 'save_warranty_custom_field' );
function save_warranty_custom_field( $post_id ) {
$wc_text_field = $_POST['_warranty'];
if ( !empty($wc_text_field) ) {
update_post_meta( $post_id, '_warranty', esc_attr( $wc_text_field ) );
}
}
// Store custom field in Cart
add_filter( 'woocommerce_add_cart_item_data', 'store_warranty_custom_field', 10, 2 );
function store_warranty_custom_field( $cart_item_data, $product_id ) {
$warranty_item = get_post_meta( $product_id , '_warranty', true );
if( !empty($warranty_item) ) {
$cart_item_data[ '_warranty' ] = $warranty_item;
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'days_manufacture', $warranty_item );
}
return $cart_item_data;
}
// Render meta on cart and checkout
add_filter( 'woocommerce_get_item_data', 'rendering_meta_field_on_cart_and_checkout', 10, 2 );
function rendering_meta_field_on_cart_and_checkout( $cart_data, $cart_item ) {
$custom_items = array();
// Woo 2.4.2 updates
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['_warranty'] ) ) {
$custom_items[] = array( "name" => __( "Warranty", "woocommerce" ), "value" => $cart_item['_warranty'] );
}
return $custom_items;
}
// Add the information in the order as meta data
add_action('woocommerce_add_order_item_meta','add_waranty_to_order_item_meta', 1, 3 );
function add_waranty_to_order_item_meta( $item_id, $values, $cart_item_key ) {
// Retrieving the product id for the order $item_id
$product_id = wc_get_order_item_meta( $item_id, '_product_id', true );
// Getting the warranty value for this product Id
$warranty = get_post_meta( $product_id, '_warranty', true );
// Add the meta data to the order
wc_add_order_item_meta($item_id, 'Warranty', $warranty, true);
}
Naturally, this goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works.
References:
WooCommerce : Add custom Metabox to admin order page
Admin product pages custom field displayed in Cart and checkout
There is an error at the end of the code, you call a variable $prod_id at first, and then $product_id. Correct and working code is:
// Add the information in the order as meta data
add_action('woocommerce_add_order_item_meta','add_waranty_to_order_item_meta', 1, 3 );
function add_waranty_to_order_item_meta( $item_id, $values, $cart_item_key ) {
// Retrieving the product id for the order $item_id
$prod_id = wc_get_order_item_meta( $item_id, '_product_id', true );
// Getting the warranty value for this product Id
$warranty = get_post_meta( $prod_id, '_warranty', true );
// Add the meta data to the order
wc_add_order_item_meta($item_id, 'Warranty', $warranty, true);
}

save select field on checkout page woocommerce

I'm new to WooCommerce.I'm unable to figure out where is problem here is my code
I have added a select field in billing form of checkout page.
Problem
records are not saving or updating on submitting. Problem is in Update the order meta with field value.value is not updating in database
// checkout page customization start
global $post, $woocommerce;
// Account select field
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
function custom_override_checkout_fields($fields) {
$fields['billing']['Account'] = array(
'type' => 'select',
'class' => array('billing form-row-wide'),
'label' => __('Choose an Account'),
'placeholder' => _x('Account', 'placeholder', 'woocommerce'),
'options' => array(
'' => __( 'Select Account','' ),
),
'required' => true,
);
return $fields;
}
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
global $woocommerce;
if (!$_POST['Account'])
$woocommerce->add_error( __('Please enter your Account.'.$_POST['Account']));
}
///**
Problem area
value is not updating in database
//* 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['Account']) update_post_meta( $order_id, 'Account', esc_attr($_POST['Account']));
}
/**
* Update the user meta with field value
**/
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta');
function my_custom_checkout_field_update_user_meta( $user_id ) {
if ($user_id && $_POST['Account']) update_user_meta( $user_id, 'Account', esc_attr($_POST['Account']) );
}
The functions look pretty accurate to me. Are you sure they aren't updating? Or perhaps you are having difficulty is displaying them.
I've tweaked them a bit. First, to use the $posted variabled that WooCommerce sends to the function, though this is trivial as $_POST should be the same. And secondly, you are using esc_attr() when you should be using sanitize_text_field(). The former is for displaying the data in an HTML attribute while the latter is for sanitizing before saving.
//* Update the order meta with field value
//**/
add_action('woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta', 10, 2 );
function my_custom_checkout_field_update_order_meta( $order_id, $posted ) {
if ( isset( $posted['Account'] ) ){
update_post_meta( $order_id, 'Account', sanitize_text_field( $posted['Account'] ) );
}
}
/**
* Update the user meta with field value
**/
add_action('woocommerce_checkout_update_user_meta', 'my_custom_checkout_field_update_user_meta', 10, 2 );
function my_custom_checkout_field_update_user_meta( $user_id, $posted ) {
if ( $user_id && isset( $posted['Account'] ) ){
update_user_meta( $user_id, 'Account', sanitize_text_field( $posted['Account'] ) );
}
}

Categories