File uploads are where WordPress form plugins tend to fall apart.
Not because uploading a file is technically hard. But because the moment you need a client to upload multiple documents — a signed contract, a proof of identity, a financial statement — the gaps in traditional form plugins become visible very quickly.
Files end up in the wrong place. They're hard to find. They're disconnected from the submission. They hit size limits. They fail silently on mobile.
This article covers what a proper file upload implementation looks like in a WordPress client portal, and why most form plugins get it wrong by design.
When a user submits a form with an attachment through Gravity Forms, WPForms, or similar plugins, the uploaded files typically land in a plugin-specific directory: /wp-content/uploads/gravity_forms/ or similar.
This creates three immediate problems:
1. Files are invisible to your client. The WordPress Media Library — the place your client knows how to navigate — is empty. The files exist somewhere on the server, but your client can't find them without going into the plugin's own interface.
2. Files are disconnected from the submission. The connection between "this file" and "this form submission" lives only in the plugin's custom database tables. Export those tables to CSV and you get a list of file paths, not the actual files. Move the files and the references break.
3. Files live in a plugin silo. If you deactivate the plugin, the files become orphaned. If the plugin's database tables get corrupted, you lose the link between submissions and their attachments.
The right approach is to route uploaded files into the native WordPress Media Library and attach them to a native WordPress object — in this case, a Custom Post Type that represents the submission.
Here's what this achieves:
Files are where your client expects them. The client logs into wp-admin, clicks Media, and sees all uploaded documents organized by date. No need to navigate to a plugin-specific screen.
Files are linked to their submission. Each submission is a WordPress post. The uploaded files are attached to that post as media attachments — the same relationship that exists between a featured image and a blog post. This is a native WordPress relationship that survives plugin updates, migrations, and exports.
Files survive plugin changes. If the plugin is ever deactivated or replaced, the files remain in the Media Library. They are WordPress content, not plugin content.
Client intake workflows often involve multiple large files: PDFs, scanned documents, photos of ID cards. Traditional form plugins struggle here for a different reason — the upload is processed in a single HTTP request, which is limited by PHP's upload_max_filesize and post_max_size settings.
A more robust approach handles each file as a separate request, independent of the main form submission. This means:
The form's REST endpoint accepts each file upload individually, attaches it to a draft submission, and the final "Submit" action simply commits the draft. The user experience is smooth; the server load is predictable.
Beyond storage, the operator experience matters. Your client (a lawyer, an accountant, an HR manager) needs to be able to open a submission and see everything: the contact details, the context provided, and the uploaded documents — all in one place.
The ideal submission view in wp-admin shows:
This is what a Custom Post Type submission model makes possible. Each submission is a WordPress post. The structured data lives in post meta. The files are attached media. The entire submission is self-contained, readable, and navigable with standard WordPress tools.
File uploads in a client portal are not an afterthought. They are often the primary reason the portal exists. A law firm isn't using your form to collect names — they're using it to collect signed documents and identification. An accountant isn't using it for contact details — they're using it for financial statements.
The storage model for those files needs to match the importance of the files themselves. Native WordPress Media Library storage, linked to native WordPress posts, is the only architecture that meets that bar.
→ See a working file upload portal — upload a test document and check where it lands in wp-admin.
Ready to stop fighting your theme’s CSS?
Drop any complex form into any WordPress theme — pixel-perfect, zero overrides, zero CSS conflicts.
See the decoupled architecture in action on our live demo — no signup required.