Woocommerce custom checkout form

You can overwrite woocommerce templates placing them in your theme. To overwrite e.g. form-billing.php template, place it in yourtheme/woocommerce/checkout/form-billing.php directory.

You can also add filter to overwrite form field rendering function. Or even overwrite whole function.

To add new fields refer to WooCommerce documentation.

I’m pasting code from documentation for adding fields to not leave answer only with link:

/**
 * Add the field to the checkout
 */
add_action( 'woocommerce_after_order_notes', 'wpse_287663_custom_checkout_field' );

function wpse_287663_custom_checkout_field( $checkout ) {

    echo '<div id="custom_checkout_field"><h2>' . __('My Field') . '</h2>';

    woocommerce_form_field( 'field_name', array(
        'type'          => 'text',
        'class'         => array('my-field-class form-row-wide'),
        'label'         => __('Fill in this field'),
        'placeholder'   => __('Enter something'),
        ), $checkout->get_value( 'field_name' ));

    echo '</div>';
}

/**
 * Process the checkout
 */
add_action('woocommerce_checkout_process', 'wpse_287663_custom_checkout_field_process');

function wpse_287663_custom_checkout_field_process() {
    // Check if set, if its not set add an error.
    if ( ! $_POST['field_name'] )
        wc_add_notice( __( 'Please enter something into this new shiny field.' ), 'error' );
}

/**
 * Update the order meta with field value
 */
add_action( 'woocommerce_checkout_update_order_meta', 'wpse_287663_custom_checkout_field_update_order_meta' );

function wpse_287663_custom_checkout_field_update_order_meta( $order_id ) {
    if ( ! empty( $_POST['field_name'] ) ) {
        update_post_meta( $order_id, 'My Field', sanitize_text_field( $_POST['field_name'] ) );
    }
}

/**
 * Display field value on the order edit page
 */
add_action( 'woocommerce_admin_order_data_after_billing_address', 'wpse_287663_custom_checkout_field_display_admin_order_meta', 10, 1 );

function wpse_287663_custom_checkout_field_display_admin_order_meta($order){
    echo '<p><strong>'.__('My Field').':</strong> ' . get_post_meta( $order->id, 'My Field', true ) . '</p>';
}