--- title: "Add a file upload to WooCommerce checkout: a plugin you can build today" description: Custom products need customer files at checkout. This small plugin adds an upload field and attaches the file directly to the WooCommerce order. source: https://steem.dev/blog/woocommerce-file-upload-checkout-plugin published: 2026-09-29 updated: 2026-09-29 alternative_to: WooCommerce Product Add-Ons site: Steem — AI WordPress plugin generator --- # Add a file upload to WooCommerce checkout: a plugin you can build today Print shops, embroidery businesses, sign makers, and anyone selling made-to-order products share a problem at checkout: the customer places an order, and then the artwork, logo, or specification arrives separately in email. Two separate streams, one job. When you are running twenty custom orders in a day, the risk of attaching the wrong file to the wrong order grows with each one. WooCommerce Product Add-Ons, the official Woo extension, handles file uploads as one of several input types. At $49 per year it also ships with date pickers, color swatches, pricing adjustments per option, a character counter for personalisation fields, and a drag-and-drop builder for configuring all of it. If you sell three products and each one needs a single file from the customer, you are paying for and maintaining infrastructure you will never touch. A plugin that adds one checkbox to the product screen and one file input to the checkout page does the job. The file attaches to the order, the admin sees a download link on the order edit screen, and the artwork lives where the order lives. ## What one build covers - A checkbox on the product data panel to mark a product as requiring a file upload at checkout - A file input added to the checkout form when a qualifying product is in the cart, with validation blocking submission if the field is empty - The uploaded file saved to the WordPress media library and attached to the WooCommerce order post - A download link on the order edit screen so the admin can access the file without leaving wp-admin - Works alongside any theme and does not require changes to checkout templates ## What it does not cover - Per-line-item file uploads when multiple custom products are in the same cart - Multiple file uploads per order - File type or size validation beyond WordPress media library defaults - Artwork review, proof approval, or revision workflows - High-Performance Order Storage compatibility: the file meta box uses the classic shop_order screen ## The prompt ```text Build a WordPress plugin called Simple WooCommerce File Upload. Plugin Name: Simple WooCommerce File Upload. Description: Adds a file upload field to WooCommerce checkout for products that require customer artwork or files. Single PHP file. Requires WooCommerce. Add a tab to the WooCommerce product data panel using woocommerce_product_data_tabs. Tab key swfu, label File Upload, icon dashicons-upload. Output the tab panel content using woocommerce_product_data_panels: wrap in a div with id product-data-swfu, output one field using woocommerce_wp_checkbox with id _swfu_require_upload, label Require file upload at checkout, desc_tip false. On woocommerce_process_product_meta, save _swfu_require_upload via update_post_meta: value 'yes' if the POST key is set, 'no' otherwise. Hook into woocommerce_before_order_notes. Loop WC()->cart->get_cart(). For each item, call wc_get_product passing the product_id. If get_meta('_swfu_require_upload') returns 'yes', set a $requires_upload flag to true and break. If the flag is true, output: a div class form-row form-row-wide containing a label with for=swfu_file and text File to upload with a span class required containing an asterisk, and an input type=file id=swfu_file name=swfu_file. After the div, output wp_nonce_field with action swfu_upload and name swfu_nonce. Hook into woocommerce_checkout_process. Loop the cart and check for any product with _swfu_require_upload yes. If found, check whether $_FILES['swfu_file'] is empty or has a non-zero error value. If either condition is true, call wc_add_notice with message Please upload the required file before placing your order and type error. Hook into woocommerce_checkout_order_processed with priority 10, accepting three arguments: $order_id, $posted_data, $order. Verify wp_verify_nonce on $_POST['swfu_nonce'] with action swfu_upload. If the nonce fails or $_FILES['swfu_file'] is not set or has a non-zero error, return early. Call wp_handle_upload passing $_FILES['swfu_file'] as the first argument and ['test_form' => false] as the second. If the result array has a url key and no error key: get the filename via basename of $result['file']. Call wp_check_filetype with $result['file'] to get type. Call wp_insert_attachment with post_mime_type set to $result['type'], post_title set to sanitize_file_name of the filename, post_content empty string, post_status inherit, post_parent set to $order_id, and $result['file'] as the second argument. If the returned attachment ID is not a WP_Error, call wp_generate_attachment_metadata and wp_update_attachment_metadata. Then call update_post_meta on $order_id three times: key _swfu_attachment_id value the attachment ID, key _swfu_upload_url value $result['url'], key _swfu_upload_name value the filename. Add a meta box using add_meta_box: id swfu_order_file, title Customer File, callback swfu_render_order_file_box, screen shop_order, context side. In the callback, get $attachment_id from get_post_meta $post->ID _swfu_attachment_id true. Get $upload_url from get_post_meta _swfu_upload_url true. Get $upload_name from get_post_meta _swfu_upload_name true. If $attachment_id is not empty, output a paragraph containing an anchor with href set to esc_url(wp_get_attachment_url($attachment_id)), target _blank, and link text esc_html($upload_name). Else if $upload_url is not empty, output a paragraph containing an anchor with href esc_url($upload_url), target _blank, and link text esc_html($upload_name). Else output a paragraph with text No file uploaded. ``` ## Why file uploads belong in the order, not in email When a customer emails artwork separately, there is a gap between the order record and the files needed to fulfil it. You rely on a subject line, a name match, or memory to connect them. Some orders have several email threads: the original, a revision, a confirmation. The correct version of the file is in there somewhere. Attaching the file to the WooCommerce order closes that gap. Anyone looking at the order in wp-admin sees the order and the file in one place, without switching to a mailbox or a shared drive. The file is there when the order is there and gone when the order is deleted. The friction this removes is small per order and real across a week. A shop handling fifty custom orders a week has fifty opportunities for a file to arrive disconnected from its order. One admin screen with everything on it removes that exposure without changing anything about how customers shop. ## What the plugin adds and where it stores things A tab on the WooCommerce product data panel holds a single checkbox: Require file upload at checkout. Ticking this on a product tells the plugin that the checkout form should show a file input whenever that product is in the cart. At checkout, if any cart item has the flag set, a file input appears in the form. The field is required: submitting without a file shows an error and the order cannot be placed. This keeps the file from being skipped by accident without burdening customers ordering products that do not need one. When the order is created, the plugin uploads the file to the WordPress media library attached to the order post and saves the download URL to order meta. The order edit screen shows a link to download the file. No separate screen, no extra menu item. ## What to do when a customer needs to upload more than one file This plugin adds one upload field per order. If a customer orders three custom products in a single cart, they upload one file. For most small custom product businesses, one file per order covers the common case: a customer ordering an embroidered hat uploads their logo once. If your orders involve multiple distinct files regularly, say a separate vector logo and a separate layout proof, the plugin is not the right tool. WooCommerce Product Add-Ons handles per-line-item uploads with multiple fields per product. A practical middle ground: if you routinely need two files, ask Steem to extend the plugin with a second upload field labelled specifically for your workflow. That is a short follow-up prompt once the base plugin is working. ## When to buy WooCommerce Product Add-Ons instead If upload pricing matters, for example a print job with more pages costs more, Product Add-Ons attaches pricing rules to uploaded files. This plugin has no pricing logic at all. If you sell many product types each requiring a different upload configuration, the visual field builder in Product Add-Ons is worth the annual cost. Maintaining distinct upload requirements across twenty products inside a settings screen is harder than a builder designed for it. If you are already paying for Product Add-Ons for other reasons, file upload is bundled and there is no reason to run a separate plugin alongside it. The case for building your own is narrowest when you are already a paying customer of the thing it replaces. ## Questions ### What happens if the customer skips the upload? The checkout blocks submission and shows an error. The order cannot be placed until a file is uploaded. If you want the upload to be optional, remove the woocommerce_checkout_process check and the required marker from the field label. ### Where does the file go? Into the WordPress media library, attached to the order post. It appears under Media in wp-admin but is not publicly visible. Anyone with wp-admin access can open the order and download it from the Customer File meta box. ### Does this work with the WooCommerce block checkout? No. The field hooks into the classic checkout form. Block checkout uses a different extension system. To add an upload field to block checkout, a separate approach using the Cart and Checkout Blocks extensibility API is needed. Ask Steem to build a block checkout version once the classic version is running. ### What file types are accepted? Any type WordPress allows by default: images, PDFs, Office documents, and similar. WordPress blocks some types for security. To allow SVG, AI, or EPS files, a filter on upload_mimes is needed. Ask Steem to add that filter if your workflow requires it. ### Can the customer see the file they uploaded in their order history? Not in this build. The file is visible in wp-admin only. To show it on the My Account order page, a hook into woocommerce_order_details_after_order_table reading the _swfu_upload_url meta would do it. Ask Steem to add that as a follow-up prompt. --- Source: https://steem.dev/blog/woocommerce-file-upload-checkout-plugin Build this plugin: https://steem.dev/app