I would like to have a specific WooCommerce product where customers can put in their own price/value for a giftcard. I have found a very nice script that almost does the trick if you create a simple product with price value 0, but there are three issues I can't fix:
.single-product.postid-241982 div.product p.price {display: none;}
add_action( 'woocommerce_before_add_to_cart_button', 'bbloomer_product_price_input', 9 );
function bbloomer_product_price_input() {
global $product;
if ( 241982 !== $product->get_id() ) return;
woocommerce_form_field( 'set_price', array(
'type' => 'text',
'required' => true,
'label' => 'Set price ' . get_woocommerce_currency_symbol(),
));
}
add_filter( 'woocommerce_add_to_cart_validation', 'bbloomer_product_add_on_validation', 9999, 3 );
function bbloomer_product_add_on_validation( $passed, $product_id, $qty ) {
if ( isset( $_POST['set_price'] ) && sanitize_text_field( $_POST['set_price'] ) == '' ) {
wc_add_notice( 'Set price is a required field', 'error' );
$passed = false;
}
return $passed;
}
add_filter( 'woocommerce_add_cart_item_data', 'bbloomer_product_add_on_cart_item_data', 9999, 2 );
function bbloomer_product_add_on_cart_item_data( $cart_item, $product_id ) {
if ( 241982 !== $product_id ) return $cart_item;
$cart_item['set_price'] = sanitize_text_field( $_POST['set_price'] );
return $cart_item;
}
add_action( 'woocommerce_before_calculate_totals', 'bbloomer_alter_price_cart', 9999 );
function bbloomer_alter_price_cart( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) ) return;
if ( did_action( 'woocommerce_before_calculate_totals' ) >= 2 ) return;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
if ( 241982 !== $product->get_id() ) continue;
$cart_item['data']->set_price( $cart_item['set_price'] );
}
}
There are some mistakes and missing things in your code. Try the following instead:
// Remove specific product displayed price on archive pages
add_action( 'woocommerce_after_shop_loop_item_title', 'remove_loop_specific_product_displayed_price', 1 );
function remove_loop_specific_product_displayed_price(){
global $product;
// Only for specific product ID
if ( 241982 == $product->get_id() ) {
// Remove price
remove_action('woocommerce_after_shop_loop_item_title', 'woocommerce_template_loop_price', 10 );
}
}
// Remove specific product displayed price in single product
add_action( 'woocommerce_single_product_summary', 'remove_specific_product_displayed_price', 1 );
function remove_specific_product_displayed_price() {
global $product;
// Only for specific product ID
if ( 241982 == $product->get_id() ) {
// Remove price
remove_action('woocommerce_single_product_summary', 'woocommerce_template_single_price', 10 );
}
}
// Replace loop add to cart button with a link to the product page
add_filter( 'woocommerce_loop_add_to_cart_link', 'replace_specific_product_add_to_cart_link', 100, 3 );
function replace_specific_product_add_to_cart_link( $button, $product, $args ) {
// Only for specific product ID
if ( 241982 == $product->get_id() ) {
$button = sprintf( '<a href="%s" class="%s" %s>%s</a>',
esc_url( $product->get_permalink() ),
esc_attr( 'button' ),
isset( $args['attributes'] ) ? wc_implode_html_attributes( $args['attributes'] ) : '',
esc_html__( 'Set a price', 'woocommerce' )
);
}
return $button;
}
// Display price input field on specific single product
add_action( 'woocommerce_before_add_to_cart_button', 'display_product_price_input_field', 9 );
function display_product_price_input_field() {
global $product;
// Only for specific product ID
if ( 241982 == $product->get_id() ) {
woocommerce_form_field( 'custom_price', array(
'type' => 'text',
'label' => sprintf(__('Set price (%s)', 'woocommerce'), get_woocommerce_currency_symbol()),
'required' => true,
));
}
}
// Add to cart field validation (Accept only a numerical value greater than zero)
add_filter( 'woocommerce_add_to_cart_validation', 'sov_product_add_on_validation' );
function sov_product_add_on_validation( $passed ) {
if ( isset($_POST['custom_price']) ) {
// Replace "," with "." for float numbers
$custom_price = str_replace(',', '.', esc_attr($_POST['custom_price']));
if ( empty($custom_price) || ! is_numeric($custom_price) || ! ($custom_price > 0) ) {
wc_add_notice( 'Set price is a required field (only accepts a numerical value greater than zero)', 'error' );
$passed = false;
}
}
return $passed;
}
// Add custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 10, 2 );
function filter_add_cart_item_data( $cart_item_data, $product_id ) {
if ( isset($_POST['custom_price']) ) {
// Replace "," with "." for float numbers
$custom_price = str_replace(',', '.', esc_attr($_POST['custom_price']));
$cart_item_data['custom_price'] = floatval($custom_price);
$cart_item_data['unique_key'] = md5(microtime().rand());
}
return $cart_item_data;
}
// Display the correct cart item custom price html
add_filter( 'woocommerce_cart_item_price', 'filter_cart_displayed_price', 10, 2 );
function filter_cart_displayed_price($price, $cart_item) {
if ( isset($cart_item['custom_price']) ) {
$args = array('price' => floatval($cart_item['custom_price']));
if ('incl' === get_option('woocommerce_tax_display_cart')) {
$product_price = wc_get_price_including_tax($cart_item['data'], $args);
} else {
$product_price = wc_get_price_excluding_tax($cart_item['data'], $args);
}
return wc_price($product_price);
}
return $price;
}
// Set cart item custom price
add_action( 'woocommerce_before_calculate_totals', 'set_price_before_calculate_totals' );
function set_price_before_calculate_totals( $cart ) {
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( isset($cart_item['custom_price']) ) {
$cart_item['data']->set_price( $cart_item['custom_price'] );
}
}
}
Code goes in functions.php file of your child theme (or in a plugin). Tested and works.
Note: Some themes make their own customizations, so something different could be needed to remove the displayed price in WooCommerce archives and single product pages.