WooCommerce: Replace the Add to Cart Button on the Product Page

Are you looking to learn the basics of WooCommerce development?
My book "Learning WooCommerce Development by Example" will teach you what you need in a fast and friendly way!

On the WooCommerce single product page there is an “Add to cart” button

In most cases people will want the button to appear as they’ll want to make it as easy as possible to buy products in their store.

I have seen requests to remove the button though, and replace it with text such as “Call us for availability”.

There is a way to remove the button by calling remove_action but you have to be careful using this method as although it does remove the “Add to cart” button,  it can also remove other functionality.

Let’s take a look at how WooCommerce renders the “Add to cart” button and the best way to remove it.

The Process that WooCommerce Uses to add the “Add to cart” button to the Single Product Page

If I look at the single product page with the excellent “Query Monitor” plugin installed and bring up the diagnostics, it shows me the template that rendered the page

So we know that this is the template that has rendered the single product page, if we then look at the “single-product.php” file in the WooCommerce plug-in source we can see the following line

<?php wc_get_template_part( 'content', 'single-product' ); ?>

Because of the way that the wc_get_template_part function works the line above will cause it to look for the following template

wp-content/plugins/woocommerce/templates/content-single-product.php

Inside that template is the following code

<?php
/**
 * Hook: woocommerce_single_product_summary.
 *
 * @hooked woocommerce_template_single_title - 5
 * @hooked woocommerce_template_single_rating - 10
 * @hooked woocommerce_template_single_price - 10
 * @hooked woocommerce_template_single_excerpt - 20
 * @hooked woocommerce_template_single_add_to_cart - 30
 * @hooked woocommerce_template_single_meta - 40
 * @hooked woocommerce_template_single_sharing - 50
 * @hooked WC_Structured_Data::generate_product_data() - 60
 */
do_action( 'woocommerce_single_product_summary' );
?>

We can see from the code above that the woocommerce_single_product_summary action has a function named woocommerce_template_single_add_to_cart hooked to it, let’s take a look at the code for that function which we can find in wp-content/plugins/woocommerce/includes/wc-template-functions.php

/**
 * Trigger the single product add to cart action.
 */
function woocommerce_template_single_add_to_cart() {
    global $product;
    do_action( 'woocommerce_' . $product->get_type() . '_add_to_cart' );
}

As you can see from the code above the function calls an action that it creates the name of by concatenating the current product type in the middle of a couple of other strings, if we imagine that we are looking at a simple product then the action that will get called is  woocommerce_simple_add_to_cart

In the wp-content/plugins/woocommerce/includes/wc-template-hooks.php file the woocommerce_simple_add_to_cart action is hooked to a function that is also called woocommerce_simple_add_to_cart

add_action( 'woocommerce_simple_add_to_cart', 'woocommerce_simple_add_to_cart', 30 );

The woocommerce_simple_add_to_cart function can be found in the wp-content/plugins/woocommerce/includes/wc-template-functions.php

function woocommerce_simple_add_to_cart() {
    wc_get_template( 'single-product/add-to-cart/simple.php' );
}

As you can see from the code above, it uses the wc_get_template function to render the single-product/add-to-cart/simple.php template. It is this template that renders the add to cart button to the screen.

Now we know how the “Add to cart” button is added to the single product page we can write some code to remove it, it would be tempting to write something that used the remove_action function to remove the woocommerce_template_single_add_to_cart function from the woocommerce_single_product_summary action. The code would look something like this. Please note, this is just an example, it’s not the best way to solve the problem 

add_action('woocommerce_single_product_summary', 'hwn_remove_add_to_cart_using_remove_action', 2 );
function hwn_remove_add_to_cart_using_remove_action(){
    global $product;
    $tshirt_with_logo_product_id = 32;
    if ($product->get_id() == $tshirt_with_logo_product_id) {
        remove_action('woocommerce_single_product_summary','woocommerce_template_single_add_to_cart',30 );
    }
}

The code above hooks into the woocommerce_single_product_summary action using a low priority number, this allows it to remove the woocommerce_template_single_add_to_cart function before it fires. In the code above we add an if statement so the action is only removed if the current product has a specific id.

So what are the drawbacks of doing it this way?

The main drawback is that by removing the woocommerce_template_single_add_to_cart function we also remove any functions that are fired as part of that function, such as woocommerce_simple_add_to_cart , so if any other plugins or themes are hooked into that function their functionality will be removed when our code runs.

So what would be a better solution?

The answer to this lies in the single-product/add-to-cart/simple.php template, the following code is at the top of the template file

As you can se there is an if statement on line 22 that returns out of the template if the $product->is_purchasable() check returns false, if we could make a particular product not purchasable then we could get the code to drop out of the template and not write the “Add to cart” button to the screen.

Luckily, we can do this, if we look at the code for is_purchaseble() we can see it fires a filter with the tag woocommerce_is_purchasable

/**
 * Returns false if the product cannot be bought.
 *
 * @return bool
 */
public function is_purchasable() {
    return apply_filters( 'woocommerce_is_purchasable', $this->exists() && ( 'publish' === $this->get_status() || current_user_can( 'edit_post', $this->get_id() ) ) && '' !== $this->get_price(), $this);
}

If we hook into this filter then we can remove the “Add to cart” button by returning false and causing the template to return before it has added the “Add to cart” button to the screen, here’s how we could do it using the same product as we did in our remove_action example

function hwn_remove_add_to_cart_using_is_purchasable($product_purchasable,$product) {
    $tshirt_with_logo_product_id = 32;
    if( $product->get_id() == $tshirt_with_logo_product_id ) {
        return false;
    }
    return $product_purchasable;
}
add_filter('woocommerce_is_purchasable', 'hwn_remove_add_to_cart_using_is_purchasable',10,2);

If we add this snippet to our store then the “Add to cart” button will be removed for the specified product

and we won’t have had to any remove any functions from action hooks, so this change should play nicely with other custom code and plugins that we are using in our store.

So Now We’ve Finally Removed The Add To Cart Button , How Can We Replace It With Something Else?

We can do this by adapting the code we wrote to remove the action, if we change it to add an action just after the woocommerce_template_single_add_to_cart function is fired then it will add text to the single product screen just after where “Add to cart” button would normally be.

function hwn_remove_add_to_cart_using_remove_action(){
    global $product;
    $tshirt_with_logo_product_id = 32;
    if ($product->get_id() == $tshirt_with_logo_product_id) {
        add_action('woocommerce_single_product_summary','hwn_text_to_replace_add_to_cart_button',31 );
    }
}

function hwn_text_to_replace_add_to_cart_button(){
    echo "This product can not currently be purchased via our online store, please contact us for more details.";
}

add_action('woocommerce_single_product_summary', 'hwn_remove_add_to_cart_using_remove_action', 2 );

As you can see from the code above we use the add_action function to hook a function to the  woocommerce_single_product_summary action, we use the same if logic as we did previously so the action will only be added  if the single product screen is showing a certain product.

If we now add all our code together we get the following

function hwn_remove_add_to_cart_using_remove_action(){
    global $product;
    $tshirt_with_logo_product_id = 32;
    if ($product->get_id() == $tshirt_with_logo_product_id) {
        add_action('woocommerce_single_product_summary','hwn_text_to_replace_add_to_cart_button',31 );
    }
}

function hwn_text_to_replace_add_to_cart_button(){
    echo "This product can not currently be purchased via our online store, please contact us for more details.";
}

add_action('woocommerce_single_product_summary', 'hwn_remove_add_to_cart_using_remove_action', 2 );

function hwn_remove_add_to_cart_using_is_purchasable($product_purchasable,$product) {
    $tshirt_with_logo_product_id = 32;
    if( $product->get_id() == $tshirt_with_logo_product_id ) {
        return false;
    }
    return $product_purchasable;
}
add_filter('woocommerce_is_purchasable', 'hwn_remove_add_to_cart_using_is_purchasable',10,2);

If the code above is added to a store then it will remove the “Add to cart” button and also add the extra text the echoed in the hwn_text_to_replace_add_to_cart_button function

You could change the text echoed by the hwn_text_to_replace_add_to_cart_button function to be anything you like, or replace it with a contact form etc.

Final Thoughts

That’s ended up being quite a long post as I went through how the “Add to cart” button is added to the single product page and the different ways we can remove it. I’d be interested to know if you enjoy posts like this or if you’d  prefer shorter posts with code snippets. Please let me know what you think about that, and any other questions you have in the comments below.

Leave a Comment