Building sites based on WordPress & WooCommerce can sometimes lead you to create custom solutions that you never thought you would have to or that such a request was ever to be made. A friend of mine, Goran Jakovljević from wpgens.com, had a similar situation. He had to move the whole shipping methods area away from the table and into somewhere else. In this tutorial, I will show you how to customize WooCommerce checkout pages with understanding and also how to move other parts around.

We are going to get into two specific parts of customizing the checkout page. First, we will move the shipping address & notes to the bottom of the page and have the order details (total) appear on the right side (next to the billing address). Second, we will move the shipping methods from the table and move it up above the product list.

If you don’t like to read a lot, you can watch it here: 

First Steps: Making a Child Theme

When you want to customize WooCommerce checkout pages, you will probably have to use a child theme (or another plugin). In this tutorial, I will also use a child theme.

When you install a new WordPress site, you will get the Twenty Seventeen theme and we will use that as our parent theme. Go to your wp-content/themes folder and create a new folder child17. Inside that folder, create a style.css and copy this code there:

Now, go to the admin dashboard and activate that theme (be sure to have the Twenty Seventeen available there also).

Before we go further, let’s make sure that we have the right CSS from the parent theme so create the file functions.php and add this:

How to Customize WooCommerce Checkout Pages

It is pretty easy to change and override WooCommerce templates. With the same approach we will use here to customize WooCommerce checkout pages, you can customize any other WooCommerce parts.

When you want to overwrite a WooCommerce template, just create a folder woocommerce in your theme and then start following the same path that WooCommerce has for each template inside the folder templates.

Replacing Shipping Details with Order Totals

Now that we have a child theme and understand how to override a WooCommerce template, we are ready to proceed.

To re-order the shipping details and order totals, you need to create a folder checkout inside woocommerce folder in your child theme. Then add a file form-checkout.php and copy the whole file contents from the plugin woocommerce/templates/checkout/form-checkout.php.

We will do now something really simple. If you look closely to that template, you will see that the billing and shipping details are wrapped inside .col-2set. We want that placed above and then wrap the order details into a .col-2. Check it out here:

If you want to see the complete file, you can check it out here.

So simple, right? You could do some more advanced stuff, but that is up to you!

Moving Shipping Methods Somewhere Else

The previous parts was really simple, right? Let’s now move the shipping methods above the products. How to do that?

If you check the checkout-form.php for order review, you will see there is an action woocommerce_checkout_order_review. This action will include a file checkout/review-order.php.

So, what should we do? Let’s create a new file in our child theme, woocommerce/checkout/review-order.php. After that, go to WooCommerce and copy the code from that template (woocommerce/templates/checkout/review-order.php).

Then, find the shipping methods code that will look like this:

Once you found that, select it all, copy it and DELETE IT. Yes, remove it from that template. We don’t need it, but keep it in the clipboard (don’t copy other stuff).

Now, we will go to our previous template checkout-form.php and find the #order_review.

After that, copy the shipping methods code above it. You probably think that you are done, right? Wrong.

Fixing the Shipping Methods Refresh Issue

Now, since the shipping methods are in their own custom table, they won’t be refreshed if you change the address. To be able to view that issue, you will have to add at least 2 shipping zones. Add them inside WooCommerce Settings. I have 2 shipping zones, first is Everywhere with 2 different shipping methods and the second one is Croatia with a free shipping method. Be sure to put Everywhere as the last option.

Open the checkout page (with at least 1 product in the cart). The shipping methods will be correct on the page load. But if you try to change the address, let’s say from Croatia to United States, you won’t see the refreshed shipping methods.

How to fix that? We will use fragments.

Fragments are JSON objects retrieved from AJAX responses and each fragment consists of:

  • key – class or id which we can use to target an element
  • value – new HTML that we will put into that place

When we change our details on the checkout page, WooCommerce performs an AJAX request to our website and retrieves a new order total. You can check what it does inside woocommerce/includes/class-wc-ajax.php. For the checkout page purposes, you might be interested in checking out the method update_order_review.

On the front side, when the AJAX response is retrieved, WooCommerce goes through each fragment and uses the key to target an element through jQuery. After that, it replaces it with the value. How is that done? You can check the GitHubcheckout.js on WooCommerce.

Refactoring the Shipping Methods

To add our own fragment, we first need to wrap the shipping methods in a custom table since Shipping Methods HTML is actually a table row tr. This table will also have a custom class (our fragment key).

Adding our own Fragment HTML

If you look closely to the method update_order_review, you will see that the fragments are filtered with woocommerce_update_order_review_fragments. We will use that filter to add our own fragment. Open the file functions.php and add this:

In here, we are adding the complete custom shipping table (with the custom class) and we are adding that HTML to the key .my-custom-shipping-table.

Now, when the AJAX is processed, the WooCommerce will get our old table HTML with $('.my-custom-shipping-table') and replace it with the new HTML.

Conclusion

Extending or overriding WooCommerce is really simple because it is built with the WordPress Plugin API. What you have to have in mind when changing the checkout page, cart or any other WooCommerce template, is JavaScript. If a template can change through JavaScript, be sure to test it. If something is not working, then probably something will have to be included or excluded (through PHP or JavaScript).

Book WooCommerce for Developer to buy

Become a Sponsor

Posted by Igor Benic

Web Developer who mainly uses WordPress for projects. Working on various project through Codeable & Toptal. Author of several ebooks at https://leanpub.com/u/igorbenic.

31 Comments

  1. Do you also do this as a contractor? I am considering adding a checkout option to my website, but don’t have the time to deal with this level of customization myself, but the standard plugin, is too product oriented (I have a service).

    Reply

    1. Hi Alison, I do but I am currently too busy and could not take on any more projects. I can suggest you going to Codeable.io and submitting your project. Should be able to get a developer working with you in several hours or a day.

      Reply

  2. Great guide Igor. Thanks for sharing.

    Reply

  3. Really helpful, Thank you so much for sharing.

    Reply

    1. No problem! Will try to make more on customizing WooCommerce.

      Reply

  4. Hey Igor,
    this is really great article.

    Just more curious, How about carrying out the entire process of purchase in some modal popup using Ajax in WordPress?

    is this possible that user can complete the entire purchase process without reloading page?

    Regards,

    Reply

    1. It would depend on the gateway also. If that gateway does not require a redirection to their page, then you might be able to do that. You would just have to see how the checkout works. I have not tried it yet so I can’t tell you exactly how to do it. If WooCommerce does not support that with their hooks, then you might have to create everything almost from scratch.

      Reply

  5. Please how do I override the default :
    do_action( ‘woocommerce_review_order_after_order_total’ );

    Also where is the location of the default implementation.

    Thanks in advance for your support

    Reply

    1. Hi, which default implementation? If you mean where that is located, then you can view that inside the template woocommerce/templates/checkout/review-order.php. I would not advise you to remove that since other plugins might use that action to add their information. But you could do a search inside the wp-content folder for that action and then see which functions, that are hooked inside, you want to remove (override).

      Reply

  6. An amazing tutorial and very helpful! I wondered what it would take to put the shipping method on a sidebar, it doesn’t have to be a widget but maybe some html, how would I then register that in the session? Any help appreciated. Cheers

    Reply

    1. You would need to have a widget which would then render those shipping methods. And then change the container of those shipping methods in the AJAX fragments as I’ve did here.

      Reply

  7. Hi Igor,
    I see you are very familiar with WC.

    I need to place order directly from card, skipping checkout page. How to do that?

    All customers are automatically logged as guest. All payments are after delivery. That is a restaurant ordering site.

    Thanks in advance for your help

    Reply

    1. If you’re to skip the checkout page, you should still have a way to get the information for shipping (delivery) so this should be on the cart page.

      The template for the cart can have the whole checkout form right on there if done correctly and it may include only the delivery address which you would need.

      The payment gateway can be configured to be cash on delivery so the order will be created automatically.

      Reply

      1. Thank you for the quick response!

        I have no delivery outside of the restaurant. Delivery is to the table number.
        The customer sits on the table, make a order, the waiter bring him a order and take a cash. All is very simple. No names, no shipment, no payment. Only order and table number.

        Reply

  8. You are awesome! Saved my life. Thanks for the great article.

    Reply

  9. Hi !
    Thank you for your info Igor.

    I’m having a small bug that I think it’s the theme i’m using. My fields in Cart and Checkout form are all unformatted. I’m trying to change this but I can’t. Do you know what should I do?

    Thanks a lot!
    Best, Diogo

    Reply

    1. Hi Diogo, they seem fine to me.

      Reply

  10. Igor, I am trying to customize my order/delivery food service site’s WC checkout page. I would like to disable shipping in the WC settings so I can use custom fields on the checkout page to get the delivery information I want. Can’t figure a way to add the charge in at checkout this way. And so with shipping enabled, I can hide the shipping fields while still displaying the custom fields and alas, charge a flat rate for delivery. However, there is an annoying “Ship to a different address?” checkbox section I’d like to replace with “Delivery Information.” Any thoughts on how?

    Reply

  11. Hi Igor,

    I want to confine Shipping Country to always match Billing Country in the “ship to a different address?” section based on which Billing Country is used.

    As an example, if a customers billing country is United States, I only want orders to be able to shipped within the United States. The can use a different shipping address but it must be within the United States.

    I want to do the same with some other countries, like Romania, Hungary etc as I need to cut down on credit card fraud.

    But I want to leave other countries open, such as Australia and New Zealand.

    Is there a plug-in or a way you can code this?

    Thanks

    Reply

    1. Hi Charlie, there should be plugins out there. For example, this one: https://wordpress.org/plugins/woo-checkout-field-editor-pro/. You can check it out for free and see if you like how it works.
      Probably, most of such plugins will offer this conditional scenario you need as a premium offer. If you are a developer, you can try to look into customizing checkout fields tutorials. This should be fairly simple code to achieve something like that since the checkout fields are reloaded on country change (I think so), you could filter out the checkout billing country field as needed.

      Reply

      1. Thanks Igor

        Reply

  12. Hi Igor,
    I have a problem please help me.
    On checkout page I would like to swap the “Payment mode” és “Shipping method” position.
    But i am not a programmer and i don’t understand all. 🙁
    Please can you help me how can i do it?
    What files and what codes do i change for it?
    You can see here what i talk about.:
    https://www.screencast.com/t/DxIRsL2rCv
    I use child theme.

    Thanks, Attila

    Reply

    1. Hi Attila,

      you can follow the same steps as in this tutorial except the place where you paste the shipping methods code.

      You can then copy the template woocommerce/templates/checkout/payment.php and add the shipping methods code after the payment gateways. Right above <div class="form-row place-order">

      Reply

      1. Hi Igor,
        Thank you so much.
        So I was able to solve it. 🙂
        But now, unfortunately, the “total field” is not at the bottom of the table.
        How can I move the “total field” to the bottom of the table?
        (Above the “terms & condition” fields.)

        You can see here:
        https://www.screencast.com/t/zEFQZXSXtem

        Thanks, Attila

        Reply

  13. Hello, great article that resolves my problem. But I have a question. I use a child theme so I have replace the file review-order.php in woocommerce/checkout folder. I have deleted the portion of the code of shipping method and replace it in form-checkout.php.
    The shipping method appears right in the portion of the page, but the review order doesn’t change (so appears twice).
    Substantially the field in child theme does not replace the original in woocommerce.

    Thanks
    Gaetano

    Reply

    1. Were all files that were changed placed inside of the woocommerce folder in your child theme (following the correct folder structure)?

      If the review order does not change, but appears twice (or sometimes even more on each refresh) it means that the woocommerce is replacing a class in HTML that is not the whole order-review but maybe only a part of it.

      Be sure that the fragment class for the order review (you can view the fragment class on AJAX preview call in the developer tools of the browser) is the class on the container of the whole order review.

      Reply

  14. Hi Igor,

    This is a fantastic article! Thanks a lot for sharing. I don’t know about coding. I would like to know if there’s any way to change the “Shipping” title on the checkout page to “delivery”?

    Thanks.

    Reply

  15. Thanks for this tutorial. Helped me a lot with my current e-shop.
    After moving shipping to new location it kind of looks weird not having “Shipping” before the “Total” price.
    Is there a way to show selected shipping in order totals, before “Total” price?

    Thank you in advance!

    Reply

    1. Hi Dan, I got the same question. Have you found a solution to this one?

      Thanks!

      Reply

Leave a reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.