Skip to content

Everything for WordPress, web development — and beyond

🛒 How to add a "More details" button next to "Add to cart" in WooCommerce

🛒 How to add a "More details" button next to "Add to cart" in WooCommerce

The standard WooCommerce shop page shows a single button under each product: "Add to Cart". For most stores, this is enough. But if you sell products that require research before purchase, a single "Add to Cart" button falls short. Shoppers want to open the product page first, read the description, check the specifications, and then add to cart from there.

The problem is that WooCommerce offers no built-in setting for "add a Read More button next to Add to Cart". Plugins for this task are either bloated with unnecessary features or conflict with your theme. That leaves the proven path: custom code in functions.php.

Below is a step-by-step guide. You will get two buttons on the shop page: "Read More" (links to the product page) and "Add to Cart" (works as usual). We will also cover the edge case for out-of-stock products.

💡 Quick overview:

  • Remove the default "Add to Cart" button via remove_action
  • Add a custom "Read More" button linking to the product page
  • Return the "Add to Cart" button to a new position next to "Read More"
  • Fix duplicate buttons for out-of-stock products with jQuery
  • Code goes into the child theme's functions.php, safe and plugin-free

How WooCommerce renders buttons on the shop page

WooCommerce outputs the "Add to Cart" button via the woocommerce_after_shop_loop_item hook. This hook fires in each product card within the WP_Query loop on the shop page. The function responsible for adding the button is woocommerce_template_loop_add_to_cart with priority 10.

The hook is attached to an action. To change the button set, we work with it directly: remove the default handler and add our own. No edits to WooCommerce templates are required, and the theme remains updatable.

Step 1: remove the default "Add to Cart" button

The first step is to unhook the woocommerce_template_loop_add_to_cart function. Place this code in your child theme's functions.php or via the Code Snippets plugin:

1/* Remove the standard Add to cart button */
2function remove_loop_button() {
3 remove_action(
4 'woocommerce_after_shop_loop_item',
5 'woocommerce_template_loop_add_to_cart',
6 10
7 );
8}
9add_action( 'init', 'remove_loop_button' );

We wrap remove_action in a function and attach it to the init hook. You cannot call remove_action directly in functions.php because WooCommerce may not have initialized its hooks by the time the theme loads. The init hook guarantees that all actions are already registered.

After inserting this code, the shop page will lose the "Add to Cart" button. Do not worry: in the next step, we will bring it back, now paired with "Read More".

Step 2: add a custom "Read More" button

The "Read More" button is a link to the product page, styled like a standard WooCommerce button. We use $product->get_permalink() to get the URL and do_shortcode for the wrapper:

1/* Add a More details button */
2add_action(
3 'woocommerce_after_shop_loop_item',
4 'replace_add_to_cart'
5);
6function replace_add_to_cart() {
7 global $product;
8 $link = $product->get_permalink();
9 echo do_shortcode(
10 '<a href="' . esc_url( $link ) . '" class="button addtocartbutton">Read More</a>'
11 );
12}

The function hooks into the same woocommerce_after_shop_loop_item action with the default priority of 10. It retrieves the $product object via global, gets the product page URL, and outputs a link with the button class. WooCommerce automatically picks up button styles from the active theme.

Note the esc_url() call: escaping the URL is mandatory for security. You can replace the addtocartbutton class with your own if you want custom styles.

Step 3: return the "Add to Cart" button alongside

The "Add to Cart" button is still needed on the shop page; without it, shoppers cannot add products to the cart directly. But now it must appear AFTER the "Read More" button. To achieve this, we register the native handler with priority 20 (after our button with priority 10):

1/* Restore the Add to cart button */
2add_action( 'after_setup_theme', 'lets_add_cart_button' );
3function lets_add_cart_button() {
4 add_action(
5 'woocommerce_after_shop_loop_item',
6 'woocommerce_template_loop_add_to_cart',
7 20
8 );
9}

We wrap add_action in the after_setup_theme hook for the same reason as the removal: WooCommerce may not be loaded by the time functions.php runs. Priority 20 places "Add to Cart" strictly after "Read More" (priority 10).

Result: under each product on the shop page, you now have two buttons. First "Read More", then "Add to Cart".

The video demonstrates an alternative approach that adds custom buttons to individual products and to the entire shop page. The principle of working with hooks is the same as we covered above.

What goes wrong with out-of-stock products

The code above works perfectly for products that are in stock. But for out-of-stock items, a conflict arises: WooCommerce automatically replaces the "Add to Cart" button with "Read More" for such products. The result is TWO "Read More" buttons in a row: our custom one and the WooCommerce replacement.

The issue is not with our code logic; this is how the WooCommerce core is designed. The standard woocommerce_template_loop_add_to_cart function renders a "Read More" link instead of the "Add to Cart" button for out-of-stock items. Our custom "Read More" button remains, so we get a duplicate.

Step 4: remove the extra button with jQuery

The most straightforward way to remove the duplicate button is jQuery. The script finds the link containing the text "Read More" that sits inside the standard WooCommerce span container and removes it:

1/* Remove the duplicate More details button for out-of-stock items */
2jQuery( document ).ready( function( $ ) {
3 $( 'a.button.product_type_simple.ajax_add_to_cart:contains("Read More")' ).remove();
4
5 $( 'button.button.woof_reset_search_form' ).on( 'click', function() {
6 $( 'a.button.product_type_simple.ajax_add_to_cart:contains("Read More")' ).remove();
7 });
8});

The script does two things. First, on page load, it removes all links with the product_type_simple class that contain the text "Read More". Second, it attaches a handler to the WooCommerce filter reset button (woof_reset_search_form) because after AJAX filtering, the DOM updates and duplicates reappear.

Place the jQuery code in a separate .js file and enqueue it via wp_enqueue_script in functions.php, or paste it into the "Custom JavaScript" field of your theme or a plugin like Simple Custom CSS and JS.

Alternative approach: a filter instead of removal

If you prefer to avoid jQuery, there is a more elegant method: the woocommerce_product_is_in_stock filter. It checks product availability before outputting the custom button:

1/* Do not show the More details button for unavailable items */
2add_action(
3 'woocommerce_after_shop_loop_item',
4 'replace_add_to_cart_conditional',
5 10
6);
7function replace_add_to_cart_conditional() {
8 global $product;
9
10 if ( ! $product->is_in_stock() ) {
11 return;
12 }
13
14 $link = $product->get_permalink();
15 echo do_shortcode(
16 '<a href="' . esc_url( $link ) . '" class="button addtocartbutton">Read More</a>'
17 );
18}

The $product->is_in_stock() method returns false for out-of-stock products, so our button simply does not render. WooCommerce displays its own "Read More" for such products. For in-stock items, both buttons work as intended. This approach is cleaner: no JS, fewer filter conflicts.

Which variant to choose depends on your store. jQuery is more universal (works with any filtering plugins), while the PHP filter is lighter and faster.

⁉️🤔 Frequently asked questions

The code does not work, and the buttons do not appear. What is wrong?

First, make sure the code is in the CHILD theme's functions.php, not the parent theme (the parent gets overwritten on updates). Second, verify that WooCommerce is active and updated to the latest version. Third, check whether your theme overrides the woocommerce_after_shop_loop_item hook. Some themes completely replace the product card template, and WooCommerce hooks do not fire in it.

Can I change the "Read More" button text to something else?

Yes. In the replace_add_to_cart() function, replace the string 'Read More' in the <a> tag attributes with whatever text you need, for example "View", "Select", or "Description". The text is static and does not affect functionality.

Why does the jQuery selector use product_type_simple?

Because WooCommerce assigns different classes to buttons depending on product type: product_type_simple for simple products, product_type_variable for variable ones. If your store has out-of-stock variable products, add a second selector for product_type_variable or use a more general a.button.ajax_add_to_cart.

Is it safe to insert PHP code into functions.php?

It is safe under two conditions. First, back up your functions.php before editing (or use a child theme so the original remains intact). Second, insert code via FTP/SFTP or the admin's "Appearance → Theme Editor" rather than through snippet plugins with autoloading. If a syntax error occurs, WordPress will show a white screen, and restoring the file is easier via FTP.

The buttons do not look like my theme's native buttons. How do I style them?

The button class in the <a> tag provides basic WooCommerce styles. If the button still looks different, your theme probably overrides button selectors more specifically (for example, .products .button instead of just .button). Copy the CSS classes from the native "Add to Cart" button using your browser inspector and add them to the class attribute of your custom link.

What to use in 2026: code or a plugin?

The choice between custom code and a plugin depends on three factors. If you are tweaking a single button on the shop page and want to avoid plugin bloat, the code from this article is sufficient. It adds zero weight in the admin, creates no extra database queries, and does not break on WooCommerce updates (the woocommerce_after_shop_loop_item and woocommerce_template_loop_add_to_cart hooks have been stable since version 3.0).

However, if you need to change button behavior on different pages or for different product categories, plugins are worth considering: YITH WooCommerce Customize My Account Page offers a visual button editor, and WooCommerce Product Add-Ons lets you add custom fields before purchase.

Start with code. It is free, transparent, and fully under your control. If you need more later, move to plugins, now with a clear understanding of exactly which features you need.