Based on "Add a checkbox on single product pages that adds an additional cost in Woocommerce" answer code, I am trying to add an "extra warranty" option to my products (checkbox in product page):
/*
* add warrenty
*/
// Backend: Additional pricing option custom field
add_action( 'woocommerce_product_options_pricing', 'wc_cost_product_field' );
function wc_cost_product_field() {
woocommerce_wp_text_input( array(
'id' => '_warrenty_price',
'class' => 'wc_input_price short',
'label' => __( 'Warrenty', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')'
));
}
// Backend: Saving product pricing option custom field value
add_action( 'woocommerce_admin_process_product_object', 'save_product_custom_meta_data', 100, 1 );
function save_product_custom_meta_data( $product ){
if ( isset( $_POST['_warrenty_price'] ) )
$product->update_meta_data( '_warrenty_price', sanitize_text_field($_POST['_warrenty_price']) );
}
// Front: Add a text input field inside the add to cart form on single product page
add_action('woocommerce_single_product_summary','add_warrenty_price_option_to_single_product', 2 );
function add_warrenty_price_option_to_single_product(){
global $product;
if( $product->is_type('variable') || ! $product->get_meta( '_warrenty_price' ) ) return;
add_action('woocommerce_before_add_to_cart_button', 'product_option_custom_field', 30 );
}
function product_option_custom_field(){
global $product;
$active_price = (float) $product->get_price();
$warrenty_price = (float) $product->get_meta( '_warrenty_price' );
$warrenty_price_html = strip_tags( wc_price( wc_get_price_to_display( $product, array('price' => $warrenty_price ) ) ) );
$active_price_html = wc_price( wc_get_price_to_display( $product ) );
$disp_price_sum_html = wc_price( wc_get_price_to_display( $product, array('price' => $active_price + $warrenty_price ) ) );
echo '<div class="hidden-field">
<p class="form-row form-row-wide" id="warrenty_option_field" data-priority="">
<span class="woocommerce-input-wrapper"><span class="war-title"> ' . __("Warrenty price:", "Woocommerce") .
'</span><label class="checkbox"><input type="checkbox" class="input-checkbox " name="warrenty_option" id="warrenty_option" value="1"> Add Warrenty for ' . $warrenty_price_html .
'</label></span></p>
<input type="hidden" name="warrenty_price" value="' . $warrenty_price . '">
<input type="hidden" name="active_price" value="' . $active_price . '"></div>';
// Jquery: Update displayed price
?>
<script type="text/javascript">
jQuery(function($) {
var cb = 'input[name="warrenty_option"]'
pp = 'p.price';
// On change / select a variation
$('form.cart').on( 'change', cb, function(){
if( $(cb).prop('checked') === true )
$(pp).html('<?php echo $disp_price_sum_html; ?>');
else
$(pp).html('<?php echo $active_price_html; ?>');
})
});
</script>
<?php
}
// Front: Calculate new item price and add it as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_product_data', 10, 3);
function add_custom_product_data( $cart_item_data, $product_id, $variation_id ) {
if (isset($_POST['warrenty_option']) && !empty($_POST['warrenty_option'])) {
$cart_item_data['new_price'] = (float) ($_POST['active_price'] + $_POST['warrenty_price']);
$cart_item_data['warrenty_price'] = (float) $_POST['warrenty_price'];
$cart_item_data['active_price'] = (float) $_POST['active_price'];
$cart_item_data['unique_key'] = md5(microtime().rand());
}
return $cart_item_data;
}
// Front: Set the new calculated cart item price
add_action('woocommerce_before_calculate_totals', 'extra_price_add_custom_price', 20, 1);
function extra_price_add_custom_price($cart) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach($cart->get_cart() as $cart_item) {
if (isset($cart_item['new_price']))
$cart_item['data']->set_price((float) $cart_item['new_price']);
}
}
// Front: Display option in cart item
add_filter('woocommerce_get_item_data', 'display_custom_item_data', 10, 2);
function display_custom_item_data($cart_item_data, $cart_item) {
if (isset($cart_item['warrenty_price'])) {
$cart_item_data[] = array(
'name' => __("Extra Warrenty", "woocommerce"),
'value' => strip_tags( '+ ' . wc_price( wc_get_price_to_display( $cart_item['data'], array('price' => $cart_item['warrenty_price'] ) ) ) )
);
}
return $cart_item_data;
}
It's work fine and the price is calculated in the payment.
The problem is that the field value doesn't appear in the order details table (and email notifications). So I don't have a way to know if the customer paid for the warranty or not (except calculated the final price of the product).
What should I add to the code so that the field will appear in the order details and mails?
You just need this little peace of code to display this warranty option everywhere:
// Save warranty as order item custom meta data and display it everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_product_warranty', 10, 4 );
function save_order_item_product_warranty( $item, $cart_item_key, $values, $order ) {
if( isset($values['warrenty_price']) && $values['warrenty_price'] > 0 ) {
$key = __("Extra Warrenty", "woocommerce");
$value = strip_tags( '+ '. wc_price( wc_get_price_to_display( $values['data'], array('price' => $values['warrenty_price']) ) ) );
$item->update_meta_data( $key, $value );
}
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
In order received page (and all other order pages):
In admin order pages:
In email notifications:
add_action( 'woocommerce_admin_order_data_after_order_details', 'warrenty_price_order_meta_general' );
function warrenty_price_order_meta_general( $order ){ ?>
<br class="clear" />
<h4>Gift Order Edit</h4>
<?php
/*
* get all the meta data values we need
*/
$_warrenty_price = get_post_meta( $order->get_id(), '_warrenty_price', true );
?>
<div class="address">
<p><strong>Warranty</strong></p>
<?php
if( $_warrenty_price ) :
?>
<p><strong>Price:</strong> <?php echo $_warrenty_price ?></p>
<?php
endif;
?>
</div>
<?php } ?>
For Email
add_action('woocommerce_email_order_meta', 'warrenty_price_email_order_meta', 10, 3);
function warrenty_price_email_order_meta($order_obj, $sent_to_admin, $plain_text) {
$warrenty_price = get_post_meta($order_obj->get_id(), '_warrenty_price', true);
if (empty($warrenty_price))
return;
if ($plain_text === false) {
echo '<h2>Warranty</h2>
<ul>
<li><strong>Price:</strong> ' . $warrenty_price . '</li>
</ul>';
} else {
echo "Warranty\n
Price: $warrenty_price";
}
}
Related
In Woocommerce I have a variable products with some variations and some variation has its own REGULAR price and SALE price.
Also I have three types of users with separated prices:
Regular Customer,
Wholesaler-1,
Wholesaler-2.
I would like when user:
is logged in,
Customer: the sale price will be the active price but also show the regular price.
Wholesaler 1 and 2: the custom price will be the active price but also show the regular price.
is not logged in, the regular price will be the active price.
Inspired mainly by Enable Wholesale prices in Woocommerce 3 answer code, here is my code attempt:
// Add custom field to VARIATIONS option pricing
add_action( 'woocommerce_variation_options_pricing', 'w4dev_add_variation_options_pricing', 20, 3 );
function w4dev_add_variation_options_pricing( $loop, $variation_data, $post_variation )
{
$value1 = get_post_meta( $post_variation->ID, '_wholesale_price_1', true );
$value2 = get_post_meta( $post_variation->ID, '_wholesale_price_2', true );
$symbol = ' (' . get_woocommerce_currency_symbol() . ')';
$key_1 = '_wholesale_price_1[' . $loop . ']';
$key_2 = '_wholesale_price_2[' . $loop . ']';
echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
<label>' . __( "Big Dealer Price", "woocommerce" ) . $symbol . '</label>
<input type="text" size="5" name="' . $key_1 .'" value="' . esc_attr( $value1 ) . '" />
</p></div>';
echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
<label>' . __( "Small Dealer Price", "woocommerce" ) . $symbol . '</label>
<input type="text" size="5" name="' . $key_2 .'" value="' . esc_attr( $value2 ) . '" />
</p></div>';
}
// Save "Wholesale Price" custom field to VARIATIONS
add_action( 'woocommerce_save_product_variation', 'w4dev_save_product_variation_wholesale_price', 20, 2 );
function w4dev_save_product_variation_wholesale_price( $variation_id, $i )
{
if ( isset( $_POST['_wholesale_price_1'][$i] ) )
{
update_post_meta( $variation_id, '_wholesale_price_1', floatval( $_POST['_wholesale_price_1'][$i] ) );
}
if ( isset( $_POST['_wholesale_price_2'][$i] ) )
{
update_post_meta( $variation_id, '_wholesale_price_2', floatval( $_POST['_wholesale_price_2'][$i] ) );
}
}
// Variable product price range
add_filter('woocommerce_variation_prices_price', 'w4dev_custom_variation_price', 90, 3 );
add_filter('woocommerce_variation_prices_regular_price', 'w4dev_custom_variation_price', 90, 3 );
add_filter('woocommerce_product_variation_get_regular_price', 'w4dev_custom_price', 90, 2 );
add_filter('woocommerce_product_variation_get_price', 'w4dev_custom_price', 90, 2 );;
function w4dev_custom_variation_price( $price, $variation, $product )
{
if (is_user_logged_in())
{
$level = get_user_meta(get_current_user_id(), 'wholesale_level', true);
switch ($level)
{
case 1: $key = '_wholesale_price_1'; break;
case 2: $key = '_wholesale_price_2'; break;
default:
if( get_post_meta( $variation->get_id(), '$key', true ) )
$price = get_post_meta( $variation->get_id(), '$key', true );
}
}
else
{
return $price;
}
return get_post_meta($variation->get_id(), $key, true);
}
This is showing only regular and sale price instead of users specific prices.
You need to set the customer sale price as a custom price in your case, so that means adding an additional custom field in the product… Also that means that you will not use WooCommerce Sale price and you will keep it empty on your product variations. This will allow you to display:
for non logged users: The default WooCommerce regular price
for logged in customers: A custom sale price (with the regular price strikethrough)
for Wholesale users: A custom wholesale price (with the regular price strikethrough)
To finish variable price range are cached so you need some additional code to make it work, without killing your website performances.
The code:
// Add custom fields to variations option pricing
add_action( 'woocommerce_variation_options_pricing', 'add_variation_wholesale_options_pricing', 20, 3 );
function add_variation_wholesale_options_pricing( $loop, $variation_data, $post_variation )
{
$value1 = get_post_meta( $post_variation->ID, '_wholesale_price_1', true );
$value2 = get_post_meta( $post_variation->ID, '_wholesale_price_2', true );
$value3 = get_post_meta( $post_variation->ID, '_customer_price', true );
$symbol = ' (' . get_woocommerce_currency_symbol() . ')';
$key_1 = '_wholesale_price_1[' . $loop . ']';
$key_2 = '_wholesale_price_2[' . $loop . ']';
$key_3 = '_customer_price[' . $loop . ']';
// Customer price (will be the sale price)
echo '<div class="variable_customer-price"><p class="form-row form-row-first">
<label>' . __( "Customer Price", "woocommerce" ) . $symbol . '</label>
<input type="text" size="5" name="' . $key_3 .'" value="' . esc_attr( $valu3 ) . '" />
</p></div>';
// Wholesale 1 price
echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
<label>' . __( "Big Dealer Price", "woocommerce" ) . $symbol . '</label>
<input type="text" size="5" name="' . $key_1 .'" value="' . esc_attr( $value1 ) . '" />
</p></div>';
// Wholesale 2 price
echo '<div class="variable_wholesale-price"><p class="form-row form-row-first">
<label>' . __( "Small Dealer Price", "woocommerce" ) . $symbol . '</label>
<input type="text" size="5" name="' . $key_2 .'" value="' . esc_attr( $value2 ) . '" />
</p></div>';
}
// Save variations wholesale prices custom fields values
add_action( 'woocommerce_save_product_variation', 'save_product_variation_wholesale_price', 20, 2 );
function save_product_variation_wholesale_price( $variation_id, $i )
{
if ( isset( $_POST['_wholesale_price_1'][$i] ) )
{
update_post_meta( $variation_id, '_wholesale_price_1', floatval( $_POST['_wholesale_price_1'][$i] ) );
}
if ( isset( $_POST['_wholesale_price_2'][$i] ) )
{
update_post_meta( $variation_id, '_wholesale_price_2', floatval( $_POST['_wholesale_price_2'][$i] ) );
}
if ( isset( $_POST['_customer_price'][$i] ) )
{
update_post_meta( $variation_id, '_customer_price', floatval( $_POST['_customer_price'][$i] ) );
}
}
// Variable product price ramge
add_filter('woocommerce_variation_prices_price', 'wholesale_variation_price', 900, 2 );
add_filter('woocommerce_variation_prices_sale_price', 'wholesale_variation_price', 900, 2 );
// Product variations (of a variable product)
add_filter('woocommerce_product_variation_get_price', 'wholesale_variation_price', 900, 2 );
add_filter('woocommerce_product_variation_get_sale_price', 'wholesale_variation_price', 900, 2 );
function wholesale_variation_price( $price, $object )
{
if ( is_user_logged_in() ) {
$level = (int) get_user_meta( get_current_user_id(), 'wholesale_level', true );
// For Wholesale user levels 1 and 2
if( in_array($level, [1, 2]) ) {
$new_price = (float) get_post_meta( $object->get_id(), '_wholesale_price_' . $level, true );
$price = empty($new_price) ? $price : $new_price;
}
// For customers
else {
$new_price = (float) get_post_meta( $object->get_id(), '_customer_price', true );
$price = empty($new_price) ? $price : $new_price;
}
}
return $price;
}
// Handling custom variable price range caching
add_filter( 'woocommerce_get_variation_prices_hash', 'wholesale_variation_performances_caching_prices', 99, 1 );
function wholesale_variation_performances_caching_prices( $hash ) {
if ( is_user_logged_in() ) {
$level = (int) get_user_meta( get_current_user_id(), 'wholesale_level', true );
// For Wholesale user levels 1 and 2
if( in_array($level, [1, 2]) ) {
$hash[] = 'level_' . $level;
}
// For customers
else {
$hash[] = 'level_0'; // Set the user level to zero here
}
}
return $hash;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
related:
Enable Wholesale prices in Woocommerce 3
Change product prices via a hook in WooCommerce 3
We have added second price for variable products with this code and it works just fine.
// Backend Variation - Add / Display MRSP Field
add_action( 'woocommerce_variation_options_pricing', 'add_variation_options_pricing_msrp', 10, 3 );
function add_variation_options_pricing_msrp( $loop, $variation_data, $variation ){
woocommerce_wp_text_input( array(
'id' => '_msrp_'.$loop,
'wrapper_class' => 'form-row form-row-first',
'class' => 'short wc_input_price',
'label' => __( 'Цена за комплект', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')',
'value' => wc_format_localized_price( get_post_meta( $variation->ID, '_msrp', true ) ),
'data_type' => 'price',
) );
}
// Backend Variation - Save MRSP Field value
add_action( 'woocommerce_save_product_variation','save_variation_options_pricing_msrp',10 ,2 );
function save_variation_options_pricing_msrp( $variation_id, $loop ){
if( isset($_POST['_msrp_'.$loop]) )
update_post_meta( $variation_id, '_msrp', wc_clean( wp_unslash( str_replace( ',', '.', $_POST['_msrp_'.$loop] ) ) ) );
}
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '<div class="woocommerce_msrp">' . __( 'Комплект: ', 'woocommerce' ) .
'<span class="msrp-price">' . wc_price( $msrp ) . '</span></div>' . $data['price_html'];
}
return $data;
}
On frontend it looks like this (when colour is selected):
This is how it looks on frontend
Now we need a little modification and I dont know how to do it:
I need to add small text before price (on screenshot its 87.18p.) The same as it is on the top price.
I need to move top price to bottom and to move bottom price to top.
I believe that I need to add some code (similar to this):
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '<div class="woocommerce_msrp">' . __( 'Комплект: ', 'woocommerce' ) .
'<span class="msrp-price">' . wc_price( $msrp ) . '</span></div>' . $data['price_html'];
}
return $data;
But I'm not a programmer...
I would appreciate any help on this, thank you.
Firs since your not a programmer I explane whats happening using command lines in your the code:
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '
<div class="woocommerce_msrp">' //wrapper box
. __( 'Комплект: ', 'woocommerce' ) //This is a wil prinnt a label with the text 'Комплект'
.'<span class="msrp-price">' // html label
. wc_price( $msrp )// your new price
. '</span>'//end html label
.'</div>' //end wrapper
. $data['price_html']; // default price of product
}
return $data;
}
Then for adding a symbol before your price you simply add the sybol to the span, like this:
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] = '
<div class="woocommerce_msrp">' //wrapper box
. __( 'Комплект: ', 'woocommerce' ) //This is a wil prinnt a label with the text 'Комплект'
.'<span class="msrp-price"> ------SYMBOL HERE----- ' // html label and symbol
. wc_price( $msrp )// your new price
. '</span>'//end html label
.'</div>' //end wrapper
. $data['price_html']; // default price of product
}
return $data;
}
Then finaly switching the prices is done by switching them in the code. So your finel product will look like this:
// Frontend Variation - MRSP display
add_filter( 'woocommerce_available_variation', 'display_variation_msrp', 10, 3 );
function display_variation_msrp( $data, $product, $variation ) {
if( $msrp = $variation->get_meta('_msrp') ) {
$data['price_html'] =
$data['price_html'] // default price of product
.'<div class="woocommerce_msrp">' //wrapper box
. __( 'Комплект: ', 'woocommerce' ) //This is a wil prinnt a label with the text 'Комплект'
.'<span class="msrp-price"> ------SYMBOL HERE----- ' // html label and symbol
. wc_price( $msrp )// your new price
. '</span>'//end html label
.'</div>'; //end wrapper
}
return $data;
}
Hope this wil help you and understand what's going on :-) !
Based on "Add a custom checkbox in WooCommerce checkout which value shows in admin edit order", I am trying to display custom radio buttons fields only if customer state is NewYork to let customer pick a delivery time in checkout page by choosing a delivery time option. Then admin could see the chosen delivery time in admin order edit pages.
This image will explain everything:
Here is my code attempt (with one checkbox for testing):
$user_state = get_user_meta( get_current_user_id(), 'billing_state')
if($user_state=='NY'){
add_action( 'woocommerce_review_order_before_submit', 'my_custom_checkout_field' );
function my_custom_checkout_field() {
echo '<div id="my_custom_checkout_field">';
woocommerce_form_field( 'my_field_name', array(
'type' => 'checkbox',
'class' => array('input-checkbox'),
'label' => __('My custom checkbox'),
'required'
), WC()->checkout->get_value( 'my_field_name' ) );
echo '</div>';
}
// Save the custom checkout field in the order meta, when checkbox has been checked
add_action( 'woocommerce_checkout_update_order_meta', 'custom_checkout_field_update_order_meta', 10, 1 );
function custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['my_field_name'] ) )
update_post_meta( $order_id, 'my_field_name', $_POST['my_field_name'] );
}
// Display the custom field result on the order edit page (backend) when checkbox has been checked
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
$my_field_name = get_post_meta( $order->get_id(), 'my_field_name', true );
if( $my_field_name == 1 )
echo '<p><strong>My custom field: </strong> <span style="color:red;">Is enabled</span></p>';
}}
But the custom field value isn't displayed. Any help is appreciated.
First you need to include your state condition (New York) inside the function that display your custom radio buttons on checkout page:
if( WC()->customer->get_shipping_state() == 'NY' ) {
// Do something for customers from "New York"
}
To make this possible Ajax and WC_Session is required, because checkout page is Ajax refreshed and it will not keep the customer choice.
So I have revisited all your existing code:
// Custom setting function: Here define your delivery options for "New york"
function get_newyork_delivery_options(){
return array(
'9am-2pm' => __('9 AM - 2 PM'),
'2pm-6pm' => __('2 PM - 6 PM'),
'6pm-9pm' => __('6 PM - 9 PM'),
);
}
// Display delivery custom radio buttons field in checkout for "New york" state
add_action( 'woocommerce_review_order_after_shipping', 'display_delivery_choice_field', 20 );
function display_delivery_choice_field(){
// Only for "New York" state
if( WC()->customer->get_shipping_state() == 'NY' ) :
$choice = WC()->session->get('delivery_choice');
// Display the radio buttons
echo '<tr class="delivery-options">
<th>' . __("Delivery time") . '<br><em>(' . __("for New York") . ')</em></th>
<td><span class="woocommerce-input-wrapper">';
foreach ( get_newyork_delivery_options() as $key => $label ) {
$checked = $choice == $key ? 'checked="checked"' : '';
$field_id = 'delivery_time' . $key;
echo '<label for="' . $field_id . '" class="radio " style="display:block">
<input type="radio" class="input-radio " id="' . $field_id . '" name="delivery_time" value="' . $key . '" ' . $checked . '> ' . $label;
echo '</label>';
}
echo '</span></td>
<tr>';
endif;
}
// jQuery - Ajax script
add_action( 'wp_footer', 'checkout_delivery_script' );
function checkout_delivery_script() {
// Only on Checkout
if( is_checkout() && ! is_wc_endpoint_url() ) :
if( WC()->session->__isset('delivery_choice') )
WC()->session->__unset('delivery_choice')
?>
<script type="text/javascript">
jQuery( function($){
if (typeof wc_checkout_params === 'undefined')
return false;
$('form.checkout').on('change', 'input[name="delivery_time"]', function(){
var delivery = $(this).val();
$.ajax({
type: 'POST',
url: wc_checkout_params.ajax_url,
data: {
'action': 'delivery_choice',
'delivery_choice': delivery,
},
success: function (result) {
$('body').trigger('update_checkout');
},
});
});
});
</script>
<?php
endif;
}
// Get Ajax request and saving to WC session
add_action( 'wp_ajax_delivery_choice', 'get_delivery_choice' );
add_action( 'wp_ajax_nopriv_delivery_choice', 'get_delivery_choice' );
function get_delivery_choice() {
if ( isset($_POST['delivery_choice']) ) {
WC()->session->set('delivery_choice', esc_attr( $_POST['delivery_choice'] ) );
echo WC()->session->get('delivery_choice');
}
die();
}
// Save the chosen delivery time as order meta data
add_action('woocommerce_checkout_create_order', 'custom_checkout_field_added_as_order_meta', 10, 2 );
function custom_checkout_field_added_as_order_meta( $order, $data ) {
if ( isset( $_POST['delivery_option'] ) )
$order->add_meta_data( '_delivery_time', esc_attr( $_POST['delivery_time'] ) );
}
// Display the chosen delivery time on order totals lines everywhere (except admin)
add_action('woocommerce_get_order_item_totals', 'display_bacs_option_on_order_totals', 10, 3 );
function display_bacs_option_on_order_totals( $total_rows, $order, $tax_display ) {
if ( $delivery_time = $order->get_meta('_delivery_time') ) {
$sorted_total_rows = [];
foreach ( $total_rows as $key_row => $total_row ) {
$sorted_total_rows[$key_row] = $total_row;
if( $key_row === 'shipping' ) {
$sorted_total_rows['delivery_time'] = [
'label' => __( "Delivery time", "woocommerce"),
'value' => esc_html( get_newyork_delivery_options()[$delivery_time] ),
];
}
}
$total_rows = $sorted_total_rows;
}
return $total_rows;
}
// Display the chosen delivery option on admin order edit page for new york state
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'display_custom_field_on_order_edit_pages', 10, 1 );
function display_custom_field_on_order_edit_pages( $order ){
if( $key = $order->get_meta( '_delivery_time' ) ) {
$label = get_newyork_delivery_options()[$key];
echo '<p><strong>Delivery <em>(New York)</em>: </strong> <span style="color:green;">' . $label . '</span></p>';
}
}
Code goes in function.php file of the active child theme (or active theme). Tested and works.
In woocommerce, I am using the following code to display an input text field on admin product edit pages, that allow me to add an additonal pricing option to the product:
add_action( 'woocommerce_product_options_pricing', 'wc_cost_product_field' );
function wc_cost_product_field() {
woocommerce_wp_text_input( array( 'id' => 'repair_price', 'class' => 'wc_input_price short', 'label' => __( 'Repair Cost', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')' ) );
}
add_action( 'save_post', 'wc_cost_save_product' );
function wc_cost_save_product( $product_id ) {
// stop the quick edit interferring as this will stop it saving properly, when a user uses quick edit feature
if (wp_verify_nonce($_POST['_inline_edit'], 'inlineeditnonce'))
return;
// If this is a auto save do nothing, we only save when update button is clicked
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return;
if ( isset( $_POST['repair_price'] ) ) {
if ( is_numeric( $_POST['repair_price'] ) )
update_post_meta( $product_id, 'repair_price', $_POST['repair_price'] );
} else delete_post_meta( $product_id, 'repair_price' );
}
Now on the product page (in the front end) I need a checkbox "Repair cost $20", that will appear when the product custom field pricing option is filled with some price.
If customer add this option, it will add an additional cost of $20 on the product and it should also be reflected on the cart and checkout pages.
Any help will be appreciated.
In the following code, I have revisited a bit your actual code and added all necessary code to enable the checkbox option in single product page if the pricing option in the product is filled (for non variable products type that are not on sale).
When the option is selected by the customer, the product price is increased and when added to cart the price change is reflected in cart and checkout pages (see the screenshots at the end).
The code:
// Backend: Additional pricing option custom field
add_action( 'woocommerce_product_options_pricing', 'wc_cost_product_field' );
function wc_cost_product_field() {
woocommerce_wp_text_input( array(
'id' => '_repair_price',
'class' => 'wc_input_price short',
'label' => __( 'Repair Cost', 'woocommerce' ) . ' (' . get_woocommerce_currency_symbol() . ')'
));
}
// Backend: Saving product pricing option custom field value
add_action( 'woocommerce_admin_process_product_object', 'save_product_custom_meta_data', 100, 1 );
function save_product_custom_meta_data( $product ){
if ( isset( $_POST['_repair_price'] ) )
$product->update_meta_data( '_repair_price', sanitize_text_field($_POST['_repair_price']) );
}
// Front: Add a text input field inside the add to cart form on single product page
add_action('woocommerce_single_product_summary','add_repair_price_option_to_single_product', 2 );
function add_repair_price_option_to_single_product(){
global $product;
if( $product->is_type('variable') || ! $product->get_meta( '_repair_price' ) ) return;
add_action('woocommerce_before_add_to_cart_button', 'product_option_custom_field', 30 );
}
function product_option_custom_field(){
global $product;
$active_price = (float) $product->get_price();
$repair_price = (float) $product->get_meta( '_repair_price' );
$repair_price_html = strip_tags( wc_price( wc_get_price_to_display( $product, array('price' => $repair_price ) ) ) );
$active_price_html = wc_price( wc_get_price_to_display( $product ) );
$disp_price_sum_html = wc_price( wc_get_price_to_display( $product, array('price' => $active_price + $repair_price ) ) );
echo '<div class="hidden-field">
<p class="form-row form-row-wide" id="repair_option_field" data-priority="">
<span class="woocommerce-input-wrapper"><label class="checkbox"> ' . __("Repair Option:", "Woocommerce") .
' <input type="checkbox" class="input-checkbox " name="repair_option" id="repair_option" value="1"> + ' . $repair_price_html .
'</label></span></p>
<input type="hidden" name="repair_price" value="' . $repair_price . '">
<input type="hidden" name="active_price" value="' . $active_price . '"></div>';
// Jquery: Update displayed price
?>
<script type="text/javascript">
jQuery(function($) {
var cb = 'input[name="repair_option"]'
pp = 'p.price';
// On change / select a variation
$('form.cart').on( 'change', cb, function(){
if( $(cb).prop('checked') === true )
$(pp).html('<?php echo $disp_price_sum_html; ?>');
else
$(pp).html('<?php echo $active_price_html; ?>');
})
});
</script>
<?php
}
// Front: Calculate new item price and add it as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_product_data', 10, 3);
function add_custom_product_data( $cart_item_data, $product_id, $variation_id ) {
if (isset($_POST['repair_option']) && !empty($_POST['repair_option'])) {
$cart_item_data['new_price'] = (float) ($_POST['active_price'] + $_POST['repair_price']);
$cart_item_data['repair_price'] = (float) $_POST['repair_price'];
$cart_item_data['active_price'] = (float) $_POST['active_price'];
$cart_item_data['unique_key'] = md5(microtime().rand());
}
return $cart_item_data;
}
// Front: Set the new calculated cart item price
add_action('woocommerce_before_calculate_totals', 'extra_price_add_custom_price', 20, 1);
function extra_price_add_custom_price($cart) {
if (is_admin() && !defined('DOING_AJAX'))
return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 )
return;
foreach($cart->get_cart() as $cart_item) {
if (isset($cart_item['new_price']))
$cart_item['data']->set_price((float) $cart_item['new_price']);
}
}
// Front: Display option in cart item
add_filter('woocommerce_get_item_data', 'display_custom_item_data', 10, 2);
function display_custom_item_data($cart_item_data, $cart_item) {
if (isset($cart_item['repair_price'])) {
$cart_item_data[] = array(
'name' => __("Repair option", "woocommerce"),
'value' => strip_tags( '+ ' . wc_price( wc_get_price_to_display( $cart_item['data'], array('price' => $cart_item['repair_price'] ) ) ) )
);
}
return $cart_item_data;
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
Addition based on this answer: Display product optional cost in Woocommerce in order details
Allow to save the repair price as order item meta data and display it everywhere on orders and email notifications:
// Save chosen seats to each order item as custom meta data and display order items Warrenty everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_product_waranty', 10, 4 );
function save_order_item_product_waranty( $item, $cart_item_key, $values, $order ) {
if( isset($values['repair_price']) && $values['repair_price'] > 0 ) {
$key = __("Repair option", "woocommerce");
$value = strip_tags( '+ '. wc_price( wc_get_price_to_display( $values['data'], array('price' => $values['repair_price']) ) ) );
$item->update_meta_data( $key, $value );
}
}
Code goes in function.php file of your active child theme (or active theme). tested and works.
We're using the following script to allow users to enter a custom price for their gift card purchase on this page: http://oceanapoke.staging.wpengine.com/pages/gift-card/
The problem is that the custom price is no longer totally correctly in the cart itself with the recent WooCommerce 3.0.8 update.
Troubleshooting this is way outside my wheelhouse. Is there anyone that can point me in the right direction?
function wpr_custom_price() {
if ( !class_exists( 'woocommerce' ) && !class_exists( 'rpgc_woocommerce' ) )
return;
}
add_action('plugins_loaded ', 'wpr_custom_price', 20 );
// Adds the box to enter in the cost of the giftcard.
function wpr_add_remove_field() {
$currency_symbol = get_woocommerce_currency_symbol();
$currency_pos = get_option( 'woocommerce_currency_pos' );
_e('Enter Gift Card Value');
?>
<br />
<?php
switch ( $currency_pos ) {
case 'left' :
echo '<strong>' . $currency_symbol . '</strong> <input
name="rpgc_price" id="rpgc_price" placeholder="' . __('0.00',
WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-bottom:5px;
width: 100px;">';
break;
case 'right' :
echo '<input name="rpgc_price" id="rpgc_price" placeholder="' .
__('0.00', WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-
bottom:5px; width: 100px;"><strong> ' . $currency_symbol . '</strong>';
break;
case 'left_space' :
echo '<strong>' . $currency_symbol . ' </strong> <input
name="rpgc_price" id="rpgc_price" placeholder="' . __('0.00',
WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-bottom:5px;
width: 100px;">';
break;
case 'right_space' :
echo '<input name="rpgc_price" id="rpgc_price" placeholder="' .
__('0.00', WPR_CP_CORE_TEXT_DOMAIN ) . '" class="input-text" style="margin-
bottom:5px; width: 100px;"> <strong> ' . $currency_symbol . '</strong>';
break;
}
}
add_action( 'rpgc_before_all_giftcard_fields', 'wpr_add_remove_field', 10 );
// Removes the display of the price on a gift card product
function wpr_remove_price( $price, $post ) {
$is_giftcard = get_post_meta( $post->id, '_giftcard', true );
if ( $is_giftcard == "yes" )
$price = "";
return $price;
}
add_filter( 'woocommerce_get_price_html', 'wpr_remove_price', 10, 2 );
**// Saves the Gift card amount on adding it to the cart
function wpr_add_cart_item($data) {
if ( isset( $_POST['rpgc_price'] ) )
$data['Price'] = (double) woocommerce_clean( $_POST['rpgc_price'] );
return $data;
}
add_filter('rpgc_giftcard_data', 'wpr_add_cart_item', 10, 1);
// Replaces the $0 price of the Gift card with the amount entered by the
customer
function wpr_add_custom_price( $cart_object ) {
foreach ( $cart_object->cart_contents as $key => $value ) {
if( isset( $value["variation"]["Price"] ) )
$value['data']->price = $value["variation"]["Price"];
}
}
add_action( 'woocommerce_before_calculate_totals', 'wpr_add_custom_price' );
// Updates the price in the Mini Cart
function wpr_minicart_price ( $price, $cart_item, $cart_item_key ){
$is_giftcard = get_post_meta( $cart_item [ "product_id" ], '_giftcard', true
);
if ( $is_giftcard == "yes" ) {
$price = woocommerce_price( $cart_item ["variation"]["Price"] );
}
return $price;
}
add_filter('woocommerce_cart_item_price','wpr_minicart_price', 10, 3);
add_filter('woocommerce_add_to_cart_validation',
'my_custom_checkout_field_process', 10, 2);
function my_custom_checkout_field_process( $state, $product_id ) {
$is_giftcard = get_post_meta( $product_id, '_giftcard', true );
if ( $is_giftcard == "yes" ) {
// Check if set, if its not set add an error.
if ( ! $_POST['rpgc_price'] ) {
wc_add_notice( __( 'Please enter a price for the gift card.' ),
'error' );
$state = false;
}
}
return $state;
}**
/**
* Load the Text Domain for i18n
*
* #return void
* #access public
*/
function rpgc_custprice_loaddomain() {
load_plugin_textdomain( 'rpgc-customprice', false, dirname( plugin_basename(
__FILE__ ) ) . "/languages" );
}
add_action( 'init', 'rpgc_custprice_loaddomain' );
?>
Replace this line $value['data']->price = $value["variation"]["Price"]; with this
$value['data']->set_price( $value["variation"]["Price"] ); because in the new version we only get an object with the product through that object. We can call the set_price() function to set the current price.