I'd like to have the checkout billing form on two columns. Is there a way to wrap half of the fields in a div and the other hald in another so that it's easy to use a float or flexbox?

The form is invoked in form-billing.php via woocommerce_form_field in a forEach loop, but I'm clueless as to where I could find the form template itself to modify it.

I'm also aware that a woocommerce_checkout_fields filter exists, but that doesn't seem helpful to wrap fields in some divs.

  • i believe this is the template file you are looking for github.com/woocommerce/woocommerce/blob/3.8.0/templates/… - This template can be overridden by copying it to yourtheme/woocommerce/checkout/form-checkout.php.
    – 7uc1f3r
    Mar 24, 2020 at 21:42
  • in the following folder github.com/woocommerce/woocommerce/tree/3.8.0/templates/… you will find the other files, if necessary
    – 7uc1f3r
    Mar 24, 2020 at 21:43
  • Thank you for your answer. Actually, form-checkout is one level up before form-billing. What I'd like to do is have form billing to two cols, not billing and shipping next to each other. What I can't figure out is how to modify what's outputed by woocommerce_form_field](github.com/woocommerce/woocommerce/blob/3.8.0/templates/…) in the forEach.
    – Buzut
    Mar 25, 2020 at 21:42
  • @7uc1f3r My bad, I had mistakenly mentioned woocommerce_before_checkout_billing_form in my question whereas I was referring to woocommerce_form_field, I've edited the question to correct it.
    – Buzut
    Mar 25, 2020 at 21:44

2 Answers 2


woocommerce_form_field in the foreach loop


refers to


So you can adapt the following code to your needs

function change_woocommerce_field_markup( $field, $key, $args, $value ) {
    //  Remove the .form-row class from the current field wrapper
    $field = str_replace('form-row', '', $field);

    //  Wrap the field (and its wrapper) in a new custom div, adding .form-row so the reshuffling works as expected, and adding the field priority
    $field = '<div class="form-row single-field-wrapper" data-priority="' . $args['priority'] . '">' . $field . '</div>';

    return $field;
add_filter( 'woocommerce_form_field', 'change_woocommerce_field_markup', 10, 4 );


In the template file (form-billing.php), in the foreach loop. Add div(s) with an if statement where needed.

  • Awesome, thanks for the tip :)
    – Buzut
    Mar 28, 2020 at 11:44
  • I know remember what the issue is: eventhough I distribute fields within two different divs, the checkout JS kicks in place them in the first one…
    – Buzut
    Apr 1, 2020 at 8:52

My question was wrong because I had forgotten some things I had tried earlier. Splitting the form field within two divs is easy task:

// form-billing.php
<div class="woocommerce-billing-fields__field-wrapper">
        $fields = $checkout->get_checkout_fields('billing');
        $fields_half_count = round(count($fields) / 2);
        $i = 0;

        echo '<div class="one">';
        foreach ($fields as $key => $field) {
            if ($i++ == $fields_half_count) echo '</div><div class="two">';
            woocommerce_form_field($key, $field, $checkout->get_value($key));
        echo '</div>';

Now the issue is that the when the checkout JS kicks in, it rearranges all fields and places them in one div.

One could disable it, but it's used to get shipping rates based on shipping country, manages the fields based on country too (US has states, Spain has provinces etc…), so disabling it isn't really an option.

The only workaround I've found so far is to use the CSS column-count: 2 on .woocommerce-billing-fields__field-wrapper to have the browser display it on two columns.

The layout isn't perfect, but it's the best option I've found so far. Otherwise, one needs to use a custom JS to handle the work done by the WooCommerce checkout JS.

Not the answer you're looking for? Browse other questions tagged or ask your own question.