I've already had this code on functions.php
This code is to add a new field on each product variation to have datetime input field, so variations would automatically expired when the current date is past the input date.
// 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_date_expire[' . $variation->ID . ']',
'class' => '_text_field_date_expire',
'type' => 'datetime-local',
'label' => __( 'Date of Expiration', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Expiration of Each Product Variation', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_text_field_date_expire', true )
)
);
}
//Save New Fields for Variation
function save_variation_settings_fields( $post_id ) {
// Text Field
$text_field = $_POST['_text_field_date_expire'][ $post_id ];
if( ! empty( $text_field ) ) {
update_post_meta( $post_id, '_text_field_date_expire', esc_attr( $text_field ) );
}
}
This is to add a new field on each variation of Wocommerce.
What I am trying to do is to get each "_text_field_date_expire" meta so I could delete expired variation for each of the products..
How do I get each woocommerce variation ID on functions.php so I could add a rule that it will expire when it is already past the current date right now?
var_dump(get_post_meta( $variation_id , '_text_field_date_expire', true ));
This code is the one that I will use to get the datetime field, but not sure how I could get each $variation_id field?
Try this one:
$args = array(
'post_type' => 'product_variation',
'post_status' => array( 'private', 'publish' ),
'numberposts' => -1,
'orderby' => 'menu_order',
'order' => 'asc',
'post_parent' => get_the_ID() // get parent post-ID
);
$variations = get_posts( $args );
foreach ( $variations as $variation ) {
// get variation ID
$variation_ID = $variation->ID;
// get variations meta
$product_variation = new WC_Product_Variation( $variation_ID );
// get variation featured image
$variation_image = $product_variation->get_image();
// get variation price
$variation_price = $product_variation->get_price_html();
get_post_meta( $variation_ID , '_text_field_date_expire', true );
}
Hope this will helps you. For more information:
How To Get Product Variations & Meta – WooCommerce
How to get the Variation ID in a Woocommerce product
In WooCommerce 3+, it's $variation->get_id() from $variation function argument, which is an instance of the WC_Product_Variation.
The method get_id() is inherited from WC_Data class.
So in your code it should be instead:
'id' => '_text_field_date_expire[' . $variation->get_id() . ']',
Since WooCommerce 3, All WC_Product properties can't be accessed directly. Instead, you need to use the available methods.
Also in your hooked function save_variation_settings_fields() you are declaring 2 arguments, so there is one missing. It should be:
//Save New Fields for Variation// Save Variation Settings
add_action( 'woocommerce_save_product_variation', 'save_variation_settings_fields', 10, 2 );
function save_variation_settings_fields( $variation_id, $i ) {
// Text Field
$text_field = $_POST['_text_field_date_expire'][ $variation_id ];
if( ! empty( $text_field ) ) {
update_post_meta( $variation_id, '_text_field_date_expire', esc_attr( $text_field ) );
}
}
See the source code for woocommerce_save_product_variation action hook
Related
I have been able to add a custom text input field to the variations of my variable products using the following code:
// Add custom text input field to admin Product Data > Variations
add_action( 'woocommerce_variation_options_pricing', 'add_custom_field_to_variations', 10, 3 );
function add_custom_field_to_variations( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input( array(
'id' => 'custom_field[' . $loop . ']',
'class' => 'short',
'label' => __( 'product size', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, 'custom_field', true )
) );
}
// Save custom field on product variation save
add_action( 'woocommerce_save_product_variation', 'save_custom_field_variations', 10, 2 );
function save_custom_field_variations( $variation_id, $i ) {
$custom_field = $_POST['custom_field'][$i];
if ( isset( $custom_field ) )
update_post_meta( $variation_id, 'custom_field', esc_attr( $custom_field ) );
}
// Store custom field value into variation data
add_filter( 'woocommerce_available_variation', 'add_custom_field_variation_data' );
function add_custom_field_variation_data( $variations ) {
$variations['custom_field'] = '<div class="woocommerce_custom_field">Custom Field: <span>' .
get_post_meta( $variations[ 'variation_id' ], 'custom_field', true ) . '</span></div>';
return $variations;
}
The code works and save inputed variation values (see the screenshot below).
Now here is my code attempt to get and display custom field value in additional information tab:
function yourprefix_woocommerce_display_product_attributes($variation_data, $variations){
$variation_data['custom_field'] = [
'label' => __('size', 'text-domain'),
'value' => get_post_meta($variations->ID, 'custom_field', true),
];
return $variation_data;
}
add_filter('woocommerce_display_product_attributes', 'yourprefix_woocommerce_display_product_attributes', 10, 2);
But it does not show the value I entered in variation.
Any help is appreciated.
Your code is a bit outdated, and there are some mistakes and missing things: Some additional jQuery code is required to display the selected variation "Size" custom field value in additional Information tab.
You should always name custom field field key with an explicit slug.
Here is the complete revisited code:
// Admin Product > Variations: Display an input text field
add_action( 'woocommerce_variation_options_pricing', 'add_admin_product_variations_custom_field', 10, 3 );
function add_admin_product_variations_custom_field( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input( array(
'id' => 'size[' . $loop . ']',
'class' => 'short',
'label' => __( 'product size', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_size', true )
) );
}
// Admin Product > Variations: Save input text field submited value
add_action( 'woocommerce_admin_process_variation_object', 'save_admin_product_variations_custom_field', 10, 2 );
function save_admin_product_variations_custom_field( $variation, $i ) {
if ( isset($_POST['size'][$i]) ) {
$variation->update_meta_data( '_size', sanitize_text_field($_POST['size'][$i]) );
}
}
// Frontend Variable products: Link variation custom field value
add_filter( 'woocommerce_available_variation', 'set_available_variation_custom_field', 10, 3 );
function set_available_variation_custom_field( $variation_data, $product, $variation ) {
return array_merge( $variation_data, array(
'size' => $variation->get_meta('_size'),
) );
}
// Frontend Variable products > additional information tab: Display "Size" label with an empty value
add_filter( 'woocommerce_display_product_attributes', 'Display_custom_field_label_with_empty_value', 10, 3 );
function Display_custom_field_label_with_empty_value( $product_attributes, $product ) {
$product_attributes[ 'size' ] = array(
'label' => __('Size', 'text-domain'),
'value' => '',
);
return $product_attributes;
}
// Variable Product (jQuery): Selected variation displays custom field value
add_action( 'woocommerce_before_variations_form', 'custom_variations_js_script' );
function custom_variations_js_script() {
wc_enqueue_js( "jQuery( function($){
var sizeObj = $('tr.woocommerce-product-attributes-item--size > td');
$('form.variations_form').on('show_variation', function(event, data){
sizeObj.text(data.size);
}).on('hide_variation', function(){
sizeObj.text('');
})
});" );
}
Code goes in functions.php file of the active child theme (or active theme). Tested and works.
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:
I need to be able to add admin data to subscription product variations (Woo Subscriptions extension) in order to pass this data on to fulfilment centres when an order is placed.
The issue I have is getting these values out from the product and passing them into the order and email notifications such that they can be properly exported, added to shipping labels and emailed via the various woo notifications.
I have custom meta fields added to variations on a subscription product. I can add data into these and they save data properly into the database on the correct variation ID. No problem there.
I can show custom test data on the cart and checkout page and also save this data into the order as you'll see in the code.
For brevity, the code is reduced below but there are in fact 6 text fields:
// Add custom field inputs to each product variation
add_action( 'woocommerce_variation_options_pricing', 'add_custom_field_to_variations', 10, 3 );
function add_custom_field_to_variations( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input(
array(
'id' => '_dose_customer_field[' . $loop . ']',
'label' => __( 'Dose (Customer)', 'woocommerce' ),
'placeholder' => __('Enter the treatment dosage','woocommerce' ),
'desc_tip' => 'true',
'description' => __( 'Enter dosage info for this variation', 'woocommerce' ),
'class' => '',
'value' => get_post_meta( $variation->ID, '_dose_customer_field', true )
)
);
}
// Save custom field on product variation save
add_action( 'woocommerce_save_product_variation', 'save_custom_field_variations', 10, 2 );
function save_custom_field_variations( $variation_id, $i ) {
$_dose_customer_field = $_POST['_dose_customer_field'][$i];
if ( isset( $_dose_customer_field ) ) update_post_meta( $variation_id, '_dose_customer_field', esc_attr( $_dose_customer_field ) );
}
// Add metadata to cart item post.
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_fields_cart_item_data', 10, 2 );
function add_custom_fields_cart_item_data( $cart_item_data, $product_id ){
$cart_item_data['custom_data']['_dose_customer_field'] = 'TEST DATA' /* HOW TO GET DATA FROM CUSTOM FIELD HERE */
$cart_item_data['custom_data']['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'custom_data', $cart_item_data['custom_data'] );
return $cart_item_data;
}
// Display custom meta data on cart and checkout page.
add_filter( 'woocommerce_get_item_data', 'display_custom_fields_cart_item_data', 10, 2 );
function display_custom_fields_cart_item_data($item_data, $cart_item){
if( ! array_key_exists( 'custom_data', $cart_item ) )
return $item_data;
if( array_key_exists( '_dose_customer_field', $cart_item['custom_data'] ) )
$item_data[] = array(
'key' => __('Dose (Customer)', 'woocommerce'),
'value' => $cart_item['custom_data']['_dose_customer_field']
);
return $item_data;
}
// Add metadata to the order.
add_action('woocommerce_checkout_create_order_line_item', 'save_custom_fields_as_order_item_meta', 20, 4);
function save_custom_fields_as_order_item_meta($item, $cart_item_key, $values, $order) {
if( ! isset($values['custom_data']) )
return;
$text_domain ='woocommerce';
if( array_key_exists('_dose_customer_field', $values['custom_data']) ){
$item->update_meta_data( __('Dose (Customer)', $text_domain), $values['custom_data']['_dose_customer_field'] );
}
}
// Frontend & emails: Display data on notifications
add_action( 'woocommerce_order_item_meta_start', 'vp_order_item_display_commodity_code', 10, 4 );
function vp_order_item_display_commodity_code( $item_id, $item, $order, $plain_text ) {
// Not on admin
//if( is_admin() ) return;
if( $value = $item->get_meta('_dose_customer_field') ) {
$value = '<strong>' . __("Dose (Customer)", "woocommerce") . ':</strong> ' . esc_attr( $value );
// On orders
if( is_wc_endpoint_url() )
echo '<div class="vp-ccode"><small>' . $value . '</small></div>';
// On Emails
else
echo '<div>' . $value . '</div>';
}
}
So everything is working except getting the data from the custom fields. It seems odd that I have to create a new array (here called 'custom_data') and add it to the cart_item_data, when the data is already available on the product variation, albeit private.
My question is how do get the metadata within add_custom_fields_cart_item_data()? Is this even the correct approach?
Many thanks
As this custom data exist for the product, you can get it easily and save it as order item custom data (so it will be displayed everywhere):
The complete code (changed the 2 last functions):
// Add custom field inputs to each product variation
add_action( 'woocommerce_variation_options_pricing', 'add_custom_field_to_variations', 10, 3 );
function add_custom_field_to_variations( $loop, $variation_data, $variation ) {
woocommerce_wp_text_input(
array(
'id' => '_dose_customer_field[' . $loop . ']',
'label' => __( 'Dose (Customer)', 'woocommerce' ),
'placeholder' => __('Enter the treatment dosage','woocommerce' ),
'desc_tip' => 'true',
'description' => __( 'Enter dosage info for this variation', 'woocommerce' ),
'class' => '',
'value' => get_post_meta( $variation->ID, '_dose_customer_field', true )
)
);
}
// Save custom field on product variation save
add_action( 'woocommerce_save_product_variation', 'save_custom_field_variations', 10, 2 );
function save_custom_field_variations( $variation_id, $i ) {
$_dose_customer_field = $_POST['_dose_customer_field'][$i];
if ( isset( $_dose_customer_field ) ) update_post_meta( $variation_id, '_dose_customer_field', esc_attr( $_dose_customer_field ) );
}
// Display custom meta data on cart and checkout page.
add_filter( 'woocommerce_get_item_data', 'display_custom_fields_cart_item_data', 10, 2 );
function display_custom_fields_cart_item_data( $item_data, $cart_item ) {
if( $value = $cart_item['data']->get_meta( '_dose_customer_field' ) )
$item_data[] = array(
'key' => __('Dose (Customer)', 'woocommerce'),
'value' => $value
);
return $item_data;
}
// Add metadata to the order item (and display it everywhere).
add_action('woocommerce_checkout_create_order_line_item', 'save_custom_fields_as_order_item_meta', 10, 4);
function save_custom_fields_as_order_item_meta( $item, $cart_item_key, $values, $order ) {
if( $meta_value = $values['data']->get_meta( '_dose_customer_field' ) )
$item->update_meta_data( __('Dose (Customer)', 'woocommerce'), $meta_value );
}
Code goes in functions.php file of your active child theme (or active theme). It should work.
I need to replace checkboxes fields with a unique select field to display product categories term names that I get from a child term ID, in admin product variation settings (for my variable products only).
So woocommerce_wp_checkbox() function will be replaced by woocommerce_wp_select() instead.
Here is my WORKING code for checkboxes:
<?php
// Woocommerce Product meta
// 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 );
// Add fields
function variation_settings_fields( $loop, $variation_data, $variation ) {
// Characteristics
$args = array( 'type' => 'product', 'taxonomy' => 'product_cat', 'child_of' => 20 );
$categories = get_categories( $args );
foreach ($categories as $cat) {
woocommerce_wp_checkbox( array(
"id" => $cat->name .'_['. $variation->ID .']',
"label" => __(" " . $cat->name, "woocommerce" ),
"value" => get_post_meta( $variation->ID, $cat->name .'_', true ),
)
);
}
?>
<?php
}
// Save
function save_variation_settings_fields( $post_id ) {
// Characteristics
$args = array( 'type' => 'product', 'taxonomy' => 'product_cat', 'child_of' => 20 );
$categories = get_categories( $args );
foreach ($categories as $cat) {
$checkbox = isset( $_POST[$cat->name . '_'][ $post_id ] ) ? 'yes' : 'no';
update_post_meta( $post_id, $cat->name . '_', $checkbox );
}
}
?>
How can I replace the checkboxes by a dropdown (OR eventually radio buttons)?
Any help is really appreciated.
In your actual code there is some mistakes like using get_categories() to get product category custom taxonomy terms. Instead just use get_terms()…
The below code will enable a select field instead of multiple checkboxes. The select value is well saved.
The revisited code:
// Add Variation settings custom field
add_action( 'woocommerce_product_after_variable_attributes', 'add_product_category_variation_field', 11, 3 );
function add_product_category_variation_field( $loop, $variation_data, $variation ) {
// Get product categories that are child of term = 20
$terms = get_terms( array('taxonomy' => 'product_cat', 'child_of' => 20 ) );
$options = []; // Initializing
// Loop through each wp_term object and set term names in an array
foreach ($terms as $term) {
$term_name = __( $term->name, "woocommerce" );
$options[$term_name] = $term_name;
}
// The select field
woocommerce_wp_select( array(
'id' => '_product_category',
'name' => "_product_category_$loop",
'label' => __("product categories", "woocommerce" ),
'options' => $options,
'value' => get_post_meta( $variation->ID, '_product_category', true ),
) );
}
// Save Variation settings custom field
add_action( 'woocommerce_save_product_variation', 'save_product_category_variation_field', 11, 2 );
function save_product_category_variation_field( $variation_id, $loop ){
if( isset($_POST["_product_category_$loop"]) )
update_post_meta( $variation_id, '_product_category', esc_attr( $_POST["_product_category_$loop"] ) );
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
I've added a custom field for each woocommerce product variation.
I've added a datetime input field. Then I will need to auto delete the variation when the datetime value is already past. So auto expire the woocommerce product variation.
This is my code for adding the custom input field.
// 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_date_expire[' . $variation->ID . ']',
'class' => '_text_field_date_expire',
'type' => 'datetime-local',
'label' => __( 'Date of Expiration', 'woocommerce' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Expiration of Each Product Variation', 'woocommerce' ),
'value' => get_post_meta( $variation->ID, '_text_field_date_expire', true )
)
);
}
//Save New Fields for Variation
function save_variation_settings_fields( $post_id ) {
// Text Field
$text_field = $_POST['_text_field_date_expire'][ $post_id ];
if( ! empty( $text_field ) ) {
update_post_meta( $post_id, '_text_field_date_expire', esc_attr( $text_field ) );
}
}
How could I get the input field value per each variations and echo it, so I could use the value for another function and delete the variations automatically?
you can get custom woocommerce product variation field by using get_post_meta() function
echo get_post_meta( $post->ID, '_text_field_date_expire', true );