How to Add a File Upload Field to the WooCommerce Checkout Page

How to Add a File Upload Field to the WooCommerce Checkout Page
On this page
  1. Why a Direct File Input Doesn't Work at Checkout
  2. Step 1: Add the File Input and Ajax Upload Script
  3. Step 2: Handle the Ajax Upload
  4. Step 3: Save the File URL to the Order
  5. Troubleshooting
  6. Frequently Asked Questions
  7. Conclusion

You can add a file upload field to the WooCommerce checkout page by uploading the file via Ajax before the order is placed, then attaching the resulting file URL to the order as a hidden field value — a plain HTML file input alone doesn’t submit correctly through checkout.

Why a Direct File Input Doesn’t Work at Checkout

  • WooCommerce’s checkout form submission doesn’t handle multipart file uploads the way a standard form might
  • The reliable workaround is uploading the file separately via Ajax the moment it’s selected, before “Place Order” is even clicked
  • Once uploaded, only the resulting file URL (a simple string) needs to travel with the order — not the file itself
  • This pattern works for application forms, custom design files, or any document a customer needs to submit with their order

Step 1: Add the File Input and Ajax Upload Script

PHP
/** Add a file upload field to checkout, uploading via Ajax on file selection */
add_action( 'woocommerce_after_order_notes', 'add_checkout_file_upload_field' );

function add_checkout_file_upload_field() {
    echo '<p class="form-row">
        <label for="order_attachment">Attachment (PDF) <abbr class="required" title="required">*</abbr></label>
        <input type="file" id="order_attachment" name="order_attachment" accept=".pdf" required>
        <input type="hidden" name="order_attachment_url" />
    </p>';

    wc_enqueue_js( "
        jQuery('#order_attachment').on('change', function() {
            if (this.files.length) {
                var formData = new FormData();
                formData.append('order_attachment', this.files[0]);

                jQuery.ajax({
                    url: wc_checkout_params.ajax_url + '?action=upload_checkout_attachment',
                    type: 'POST',
                    data: formData,
                    contentType: false,
                    processData: false,
                    success: function(response) {
                        jQuery('input[name=\"order_attachment_url\"]').val(response);
                    }
                });
            }
        });
    " );
}

Step 2: Handle the Ajax Upload

PHP
/** Handle the checkout file upload via WordPress's upload functions */
add_action( 'wp_ajax_upload_checkout_attachment', 'process_checkout_attachment_upload' );
add_action( 'wp_ajax_nopriv_upload_checkout_attachment', 'process_checkout_attachment_upload' );

function process_checkout_attachment_upload() {
    if ( empty( $_FILES['order_attachment'] ) ) {
        wp_die();
    }

    $uploaded = wp_upload_bits(
        $_FILES['order_attachment']['name'],
        null,
        file_get_contents( $_FILES['order_attachment']['tmp_name'] )
    );

    echo esc_url( $uploaded['url'] );
    wp_die();
}

Step 3: Save the File URL to the Order

PHP
/** Attach the uploaded file URL to the order and show it in admin/emails */
add_action( 'woocommerce_checkout_create_order', 'save_checkout_attachment_to_order' );

function save_checkout_attachment_to_order( $order ) {
    if ( ! empty( $_POST['order_attachment_url'] ) ) {
        $order->update_meta_data( '_order_attachment_url', esc_url_raw( $_POST['order_attachment_url'] ) );
    }
}
Add a file upload field to the WooCommerce checkout page: the page before adding the code
Before
Add a file upload field to the WooCommerce checkout page: the page after adding the code
After

Troubleshooting

File Doesn’t Upload Before Checkout Submits

Confirm the hidden field actually receives the returned URL before “Place Order” is clicked — a fast double-click or extremely quick submission could theoretically beat the Ajax response; consider disabling the submit button until the upload completes for a fully robust implementation.

Restricted File Types Get Rejected

If customers need to upload a file type WordPress blocks by default, pair this with an upload_mimes filter to allow that specific extension, scoped narrowly for security.

Frequently Asked Questions

Is this file upload secure for guest checkouts?

The wp_ajax_nopriv_ hook allows guests to trigger the upload, so add file type and size validation server-side (not just the browser’s accept attribute, which is easily bypassed) to keep this safe.

Where does the uploaded file get stored?

wp_upload_bits() saves it to the standard WordPress uploads directory, the same location used for Media Library files.

Can I make the upload optional instead of required?

Yes — remove the required attribute from the file input, and add a check in the order-save function so it simply skips attaching a URL when none was uploaded.

Conclusion

File uploads at WooCommerce checkout require an Ajax workaround rather than a direct form field, since checkout submission doesn’t handle multipart uploads natively. Add server-side file type validation on top of the browser’s accept attribute, since that alone isn’t a real security control. Getting this right is really what add a file upload field to the woocommerce checkout page comes down to.

See also How to Turn a WooCommerce Checkout Field Into a Dropdown. Then read How to Customize WooCommerce Checkout Fields.

Prefer no code? All-in-One Utilities Woo Add-on adds over 50 WooCommerce features, so you can switch them on without code.

Leave a Reply

Schedule a call