To change the Add to Cart button position in WooCommerce, move woocommerce_template_single_add_to_cart to a different priority on the woocommerce_single_product_summary action. By default it sits at priority 30, after the excerpt and before the product meta.
I was asked to do this on a client site I built, and the same method works for any element in the product summary.
Move the Add to Cart Button
Add this to your child theme’s functions.php file. It moves the button from priority 30 to 15, between the price and the short description:
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
add_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 15 );
remove_action() only works when the priority matches the one used to add the callback, so the first line must say 30.
Default woocommerce_single_product_summary Priorities
The action runs inside the .summary div in templates/content-single-product.php. These are the callbacks WooCommerce registers in includes/wc-template-hooks.php:
| Priority | Callback | Output |
|---|---|---|
| 5 | woocommerce_template_single_title |
Product title |
| 10 | woocommerce_template_single_rating |
Star rating |
| 10 | woocommerce_template_single_price |
Price |
| 20 | woocommerce_template_single_excerpt |
Short description |
| 30 | woocommerce_template_single_add_to_cart |
Add to Cart form |
| 40 | woocommerce_template_single_meta |
SKU, categories, tags |
| 50 | woocommerce_template_single_sharing |
Sharing template |
| 60 | WC_Structured_Data::generate_product_data |
Product schema data, no visible output |
Rating and price share priority 10. Callbacks with the same priority run in the order they were added, and the rating is added first.
How It Works
WordPress runs callbacks on an action from the lowest priority number to the highest. Pick a number between two neighbours to place the button between them:
- Above the title: priority 1 to 4.
- Right after the price: 11 to 19.
- After the product meta: 41 to 49.
woocommerce_template_single_add_to_cart() does not print the button itself. It fires woocommerce_{product_type}_add_to_cart, and WooCommerce hooks a function to that action for each core type, such as woocommerce_simple_add_to_cart and woocommerce_variable_add_to_cart. Those load the templates in single-product/add-to-cart/.
Moving the parent function moves the form for every product type at once. For a wider view of these actions, see WooCommerce Hooks: Interactive Visual Guide for Every Page.
Shop and Archive Pages
Product loops on the shop and category pages use a different action. There the button comes from woocommerce_template_loop_add_to_cart on woocommerce_after_shop_loop_item at priority 10. This moves it above the product image:
remove_action( 'woocommerce_after_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 10 );
add_action( 'woocommerce_before_shop_loop_item', 'woocommerce_template_loop_add_to_cart', 5 );
Choose loop positions carefully. The product link opens on woocommerce_before_shop_loop_item at 10 and closes on woocommerce_after_shop_loop_item at 5, and anything hooked in between ends up inside that link. The button is also a link, and nested links are invalid HTML.
Block Themes and Page Builders
These hooks apply to classic templates. In a block theme the Single Product template is built from blocks, so drag the Add to Cart with Options block to a new spot in the Site Editor instead.
WooCommerce still fires the classic actions in block templates for compatibility, and removes only its own callbacks at their default priorities. Re-adding the add to cart function at a new priority there can print a second button.
Page builders like Elementor also use their own widgets, so check which system renders your product page first.
FAQs
Common questions about the Add to Cart button position and its hook:
woocommerce_single_product_summary action. It runs after the short description (20) and before the product meta (40).
woocommerce_template_single_add_to_cart to woocommerce_after_single_product_summary. The product tabs run there at 10, so priority 5 puts the button above the tabs and 11 below them.