On WooCommerce, I would like a custom add to cart button redirection for specific categories to contact us page (when customer click on the add to cart button in single product pages).
This is my code:
add_filter( 'woocommerce_add_to_cart_redirect', 'rv_redirect_to_url' );
function rv_redirect_to_url() {
global $woocommerce, $post;
$product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) );
$rv_woo_redirect_url = get_post_meta( $product_id, '_rv_woo_product_custom_redirect_url', true );
if ( ! empty( $rv_woo_redirect_url ) ) {
wp_redirect( esc_url( $rv_woo_redirect_url ) ); exit;
}
}
How can I change my code to get it working only for defined product categories?
Updated (the right custom url when it's a defined product category)
Using a custom function hooked in woocommerce_add_to_cart_redirect filter hook, that will redirect customer when a product is added to cart (for defined product category(ies)):
add_filter( 'woocommerce_add_to_cart_redirect', 'conditional_add_to_cart_redirection', 99, 1 );
function conditional_add_to_cart_redirection( $url ) {
// ==> HERE define your product category or categories in the array
$category = array( 'clothing', 'music' );
if ( ! isset( $_REQUEST['add-to-cart'] ) ) return $url; // Very important!
// When it's available (on add to cart click), get the product ID
$product_id = absint( $_REQUEST['add-to-cart'] );
// Get the custom url from product post meta data
$custom_url = get_post_meta( $product_id, '_rv_woo_product_custom_redirect_url', true );
// Exit to normal, If the custom URL redirection is not set in the product
if( empty( $custom_url ) ) return $url;
// Custom redirection only for your defined product category(ies)
if( has_term( $category, 'product_cat', $product_id ) ){
// Clear add to cart notice (with the cart link).
wc_clear_notices();
$url = $custom_url; // Updated here
}
return $url;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Code is tested on Woocommerce 3+ and works
Add to cart redirection will not work with ajax add to cart on shop and archives pages. So you will have to choose between that 2 options for shop and archives pages:
Disable ajax add-to-cart on shop and archives pages ( WC settings > Products > Display ).
Add the following code to replace the add to cart button, by a button linked to the product:
This 2nd option seems to be the best (as this is conditional on some products only):
// Conditionally changing add to cart button link and text on shop and archives
add_filter( 'woocommerce_loop_add_to_cart_link', 'replacing_add_to_cart_button', 10, 2 );
function replacing_add_to_cart_button( $button, $product ) {
if( $product->is_type( 'variable-subscription' ) || $product->is_type( 'variable' ) ) return $button;
// ==> HERE define your product category or categories in the array
$category = array( 'clothing', 'music' );
// Check that the custom url from product post meta data is not empty
$custom_url = get_post_meta( $post->ID, '_rv_woo_product_custom_redirect_url', true );
if( empty( $custom_url ) ) return $button;
// Check if the current product has a defined product category(ies)
if( ! has_term( $category, 'product_cat', $post->ID ) ) return $button;
$button_text = __( 'View product', 'woocommerce' );
$button = '<a class="button" href="' . $product->get_permalink() . '">' . $button_text . '</a>';
return $button;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Code is tested on Woocommerce 3+ and works
If the product is not meant to be purchased outright, then I would filter woocommerce_is_purchasable and replace the add to cart button with a button-styled link to your contact form.
function so_46395830_not_purchasable( $is_purchasable, $product ) {
$rv_woo_redirect_url = $product->get_meta( '_rv_woo_product_custom_redirect_url', true );
if ( ! empty( $rv_woo_redirect_url ) ) {
add_action( 'woocommerce_single_product_summary', 'so_46395830_redirect_to_contact' );
}
return $is_purchasable;
}
add_filter( 'woocommerce_is_purchasable', 'so_46395830_not_purchasable', 10, 2 );
function so_46395830_redirect_to_contact( $url ) {
global $product;
$rv_woo_redirect_url = $product->get_meta( '_rv_woo_product_custom_redirect_url', true );
echo sprintf( '<a class="button" href="%s">%s</a>', esc_url( $rv_woo_redirect_url ), __( 'Contact Us for Info', 'your-plugin-textdomain' ) );
}
Related
The following code add a custom field to admin product settings to manage guest checkout at product level:
// Display Guest Checkout Field
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_custom_general_fields' );
function woo_add_custom_general_fields() {
global $woocommerce, $post;
echo '<div class="options_group">';
// Checkbox
woocommerce_wp_checkbox( array(
'id' => '_allow_guest_checkout',
'wrapper_class' => 'show_if_simple',
'label' => __('Checkout', 'woocommerce' ),
'description' => __('Allow Guest Checkout', 'woocommerce' )
) );
echo '</div>';
}
// Save Guest Checkout Field
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
$woocommerce_checkbox = isset( $_POST['_allow_guest_checkout'] ) ? 'yes' : 'no';
update_post_meta( $post_id, '_allow_guest_checkout', $woocommerce_checkbox );
}
// Enable Guest Checkout on Certain products
add_filter( 'pre_option_woocommerce_enable_guest_checkout', 'enable_guest_checkout_based_on_product' );
function enable_guest_checkout_based_on_product( $value ) {
if ( WC()->cart ) {
$cart = WC()->cart->get_cart();
foreach ( $cart as $item ) {
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) == 'yes' ) {
$value = "yes";
} else {
$value = "no";
break;
}
}
}
return $value;
}
But it doesn't work actually. What I am doing wrong? How can I fix it?
I am trying to allow guest purchases for specific products. The admin custom field display and save custom field value is working (the 2 first functions), But login/register never comes up on checkout page, even if there are products in cart that doesn't allow guest checkout.
The filter hook enable_guest_checkout_based_on_product doesn't exist anymore and has been replaced by another hook a bit different.
So your code is going to be:
add_filter( 'woocommerce_checkout_registration_required', 'change_tax_class_user_role', 900 );
function change_tax_class_user_role( $registration_required ) {
if ( ! WC()->cart->is_empty() ) {
$registration_required = false; // Initializing (allowing guest checkout by default)
// Loop through cart items
foreach ( WC()->cart->get_cart() as $item ) {
// Check if there is any item in cart that has not the option "Guest checkout allowed"
if ( get_post_meta( $item['product_id'], '_allow_guest_checkout', true ) !== 'yes' ) {
return true; // Found: Force checkout user registration and exit
}
}
}
return $registration_required;
}
Code goes in functions.php file of your active child theme (or active theme). It should works.
Related continuation: Redirection for non checkout guest allowed in WooCommerce
I wish to make multiple specific subscription products skip the cart and go straight to checkout. I found the following code here (only for one product), which skips it for one product using the product ID, but unable to adapt it for multiple products. Tried also various other methods, but none seem to work for Woocommerce 4.51
How to skip cart page on woocomerce for certain products only?
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout' );
function woo_redirect_checkout() {
global $woocommerce;
$desire_product = '73458';
//Get product ID
$product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $_POST['add-to-cart'] );
//Check if current product is subscription
if ( $product_id == $desire_product ){
$checkout_url = $woocommerce->cart->get_checkout_url();
return $checkout_url;
exit;
} else {
$cart_url = $woocommerce->cart->get_cart_url();
return $cart_url;
exit;
}
}
The woocommerce_add_to_cart_redirect filter gives you access to the product object of the product that was added to the cart. So you can check for the subscription product type:
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout', 10, 2 );
function woo_redirect_checkout( $url, $product ) {
return $product->get_type() == 'subscription' ? wc_get_checkout_url() : $url;
}
Now all products that are of type subscription get redirected to the checkout instead of the cart.
If you do not want all your subscription products to redirect to the checkout but only subscriptions in certain categories, you can first retrieve the product categories from the product object and see if they match one of the categories defined in the $checkout_cats array:
add_filter( 'woocommerce_add_to_cart_redirect', 'woo_redirect_checkout', 10, 2 );
function woo_redirect_checkout( $url, $product ) {
//Define your categories here
$checkout_cats = array( 'Music', 'Posters' );
if ( $product->get_type() == 'subscription' ) {
$terms = get_the_terms( $product->get_id(), 'product_cat' );
if ( !empty( $terms ) ) {
foreach ( $terms as $term ) {
if ( in_array( $term->name, $checkout_cats ) ) return wc_get_checkout_url();
}
}
}
return $url;
}
I'm trying to display custom product field checkout_name on the checkout page but I can't seem to figure out how. I'm following checkout hooks visual guide from here.
add_action( 'woocommerce_checkout_before_customer_details', 'custom_before_checkout_form', 10 );
function custom_before_checkout_form( $cart_data ){
$meta_key = 'checkout_name';
$product_id = $cart_item['product_id'];
$meta_value = get_post_meta( $product_id, $meta_key, true );
if( !empty( $cart_data ) )
$custom_items = $cart_data;
if( !empty($meta_value) ) {
$custom_items[] = array(
'key' => __('Store Name', 'woocommerce'),
'value' => $meta_value,
'display' => $meta_value,
);
}
return $custom_items;
}
Custom checkout fields need to be inside the checkout form. If not the field values are not posted on submission.
There is also some errors in your code. Try the following instead using a hook located inside the checkout form, just before billing fields (assuming that the custom product field checkout_name exist).
add_action( 'woocommerce_checkout_before_customer_details', 'custom_before_checkout_form' );
function custom_before_checkout_form(){
// Loop though cart items
foreach ( WC()->cart->get_cart() as $item ) {
// Get the WC_Product Object
$product = $item['data'];
echo '<div align="center">' . $product->get_meta( 'checkout_name' ) . '</div><br>';
}
}
Code goes in functions.php file of your active child theme (or active theme). It should better work.
I'm looking for the right code that hides the prices for some specific categories in Woocommerce.
I already have the code to hide the prices on de single product page:
add_action( 'wp', 'remove_prices_based_on_category' );
function remove_prices_based_on_category() {
// On product single pages
if ( is_product() ) {
remove_product_price( get_the_ID() );
}
}
function return_custom_price( $price, $instance ) {
$price = '<span style="color:red; font-size:12px;">Call our office <strong>516.695.3110</strong> for prices.</span>';
return $price;
}
add_action( 'woocommerce_before_shop_loop_item', 'remove_product_price', 5, 1 ); // for each product on product listing page/shop page.
function remove_product_price( $product_id ) {
$product_id = get_the_ID();
$hidden_price_category_ids = array( '27419','27421' ); // Add Product Category IDs for which the product price should be hidden.
$product_cat_ids = get_the_terms( $product_id, 'product_cat' ); // Getting all categories for this product.
$cat_ids = wp_list_pluck( $product_cat_ids, 'term_id' ); // Getting all category ids for this product.
$result = array_intersect( $hidden_price_category_ids, $cat_ids ); // Will match hidden price categories with product categories and the cat id in the array.
// If a hidden price category is found
if( !empty($result) ) {
add_filter( 'woocommerce_get_price_html', 'return_custom_price', 10, 2 );
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart' );
} else {
remove_filter( 'woocommerce_get_price_html', 'return_custom_price', 10, 2 );
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
add_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart' );
}
}
How can I do it for WooCommerce archive pages?
Your existing code is complicated, uncompleted and not really convenient. Try the following instead that will work for single product pages and archives pages too (as shop page).
It handles any kind of product, including variable products and their variations.
For defined product categories, it replace the price and disable add to cart button on related products.
The code:
// Custom conditional function that check for specific product categories
function check_for_defined_product_categories( $product_id ) {
// HERE your Product Categories where the product price need to be hidden.
$targeted_terms = array( '27419','27421' ); // Can be term names, slugs or Ids
return has_term( $targeted_terms, 'product_cat', $product_id );
}
// Custom function that replace the price by a text
function product_price_replacement(){
return '<span style="color:red; font-size:12px;">' . sprintf( __( "Call our office %s for prices."), '<strong>516.695.3110</strong>' ) . '</span>';
}
// Replace price by a text (conditionally)
add_filter( 'woocommerce_get_price_html', 'filter_get_price_html_callback', 10, 2 );
function filter_get_price_html_callback( $price, $product ){
if( check_for_defined_product_categories( $product->get_id() ) ) {
$price = product_price_replacement();
}
return $price;
}
// Hide prices and availiability on product variations (conditionally)
add_filter( 'woocommerce_available_variation', 'filter_available_variation_callback', 10, 3 ); // for Variations
function filter_available_variation_callback( $args, $product, $variation ) {
if( check_for_defined_product_categories( $product->get_id() ) ) {
$args['price_html'] = '';
$args['availability_html'] = '';
}
return $args;
}
// Disable add to cart button (conditionally)
add_filter( 'woocommerce_variation_is_purchasable', 'woocommerce_is_purchasable_filter_callback', 10, 2 );
add_filter('woocommerce_is_purchasable', 'woocommerce_is_purchasable_filter_callback', 10, 2 );
function woocommerce_is_purchasable_filter_callback( $purchasable, $product ) {
$product_id = $product->get_parent_id() > 0 ? $product->get_parent_id() : $product->get_id();
if( check_for_defined_product_categories( $product_id ) ) {
$purchasable = false;
}
return $purchasable;
}
Code goes in functions.php file of your active child theme (or active theme). Tested and work.
I work on site that use External products from Amazon, but want instead pointing users to that external URL, first to add to cart that product. I have this function, that change Default Button text for each product, to Add to cart.
function sv_wc_external_product_button( $button_text, $product ) {
if ( 'external' === $product->get_type() ) {
// enter the default text for external products
return $product->button_text ? $product->button_text : 'Add To Cart';
}
return $button_text;
}
add_filter( 'woocommerce_product_single_add_to_cart_text',
'sv_wc_external_product_button', 10, 2 );
But this function not add product to cart.
How to make this function to Add selected product to cart?
Thanks.
Updated 2020
This is a complete different way with simple products and a custom field external link.
In this answer we will use simple products instead of external products.
We add an "External URL" custom field in product option settings and we save the data.
Add a custom field on general product option settings for simple products only :
add_action( 'woocommerce_product_options_general_product_data', 'simple_product_with_external_url' );
function simple_product_with_external_url() {
global $product_object;
echo '<div class="options_group show_if_simple hidden">';
// External Url
woocommerce_wp_text_input( array(
'id' => '_ext_url_cust',
'label' => 'External Url',
'description' => 'Custom external URL',
'desc_tip' => 'true',
'placeholder' => 'Enter here your custom external URL'
) );
echo '</div>';
}
Save the custom field data if it's a simple product and not empty:
add_action( 'woocommerce_admin_process_product_object', 'save_simple_product_with_external_url' );
function save_simple_product_with_external_url( $product ) {
if( $product->is_type('simple') && isset($_POST['_ext_url_cust']) ) {
$product->update_meta_data( '_ext_url_cust', sanitize_url($_POST['_ext_url_cust']) );
}
}
2) This will not work on shop pages and archives pages, if we don't set in WooCommerce the cart redirection when adding a product to cart.
So we will replace add-to-cart button (just for our simple products with a custom link redirection) on shop pages and archives pages by a linked custom button to single product pages.
Replacing add-to-cart button in shop pages and archives pages (for simple products with custom external url):
add_filter( 'woocommerce_loop_add_to_cart_link', 'quantity_inputs_for_woocommerce_loop_add_to_cart_link', 10, 2 );
function quantity_inputs_for_woocommerce_loop_add_to_cart_link( $html, $product ) {
$external_url = $product->get_meta('_ext_url_cust');
if ( ! empty($external_url) ) {
$html = sprintf( '%s', $product->get_permalink(), __("Read More", "woocommerce") );
}
return $html;
}
3) If the custom field value is not empty, the product is added to cart first and then redirected to the external URL (our custom field value in single product pages)
External URL redirection after adding to cart (when custom field is not empty in simple products):
add_filter( 'woocommerce_add_to_cart_redirect', 'redirect_simple_product_with_external_url' );
function redirect_simple_product_with_external_url( $url ) {
if( isset($_REQUEST['add-to-cart']) && absint( $_REQUEST['add-to-cart'] ) > 0 )
return get_post_meta( absint( $_REQUEST['add-to-cart'] ), '_ext_url_cust', true );
return $url;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works on WooCommerce version 3+
Use https://stackoverflow.com/a/44036965/3730754 instead.
You should try to use woocommerce_product_add_to_cart_url filter hook to change the add-to-cart link (here for grouped products), this way:
add_filter( 'woocommerce_product_add_to_cart_url', 'override_external_product_url', 10, 2 );
function override_external_product_url( $url, $product ){
if ( 'external' === $product->get_type() ) {
//Get product ID -- WooCommerce compatibility
if ( method_exists( $product, 'get_id' ) ) {
$product_id = $product->get_id();
} else {
$product_id = $product->id;
}
// custom add to cart url example
$url = home_url( "/product/?add-to-cart=$product_id");
}
return $url;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Update: But this will not add to cart this external product before redirecting to an external url even if it works displaying the add-to-cart url (as add-to-cart is ajax driven).
I fixed myself. For External products, to replace default "Buy This Product" with other generic text, add this functions into functions.php file into theme:
add_filter( 'woocommerce_product_add_to_cart_text' ,
'wpf_custom_add_cart_text_archive',11);
function wpf_custom_add_cart_text_archive() {
global $product;
$product_type = $product->product_type;
switch ( $product_type ) {
case 'external':
return __( 'Add to Cart', 'woocommerce' );
break;
case 'grouped':
return __( 'View products', 'woocommerce' );
break;
case 'simple':
return __( 'Add to cart', 'woocommerce' );
break;
case 'variable':
return __( 'Select options', 'woocommerce' );
break;
default:
return __( 'Read more', 'woocommerce' );
}
}
add_filter( 'woocommerce_product_single_add_to_cart_text',
'wpf_custom_add_cart_text',11);
and this one:
function wpf_custom_add_cart_text() {
return __( 'Add to Cart', 'woocommerce' );
}
to replace text everywhere.