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
/** 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
/** 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
/** 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'] ) );
}
}

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.