Appearance
File Uploads
Build a file upload form with preview, validation, and server-side handling using the File Upload widget.
Database Table
Create a documents table:
| Column | Type |
|---|---|
id | int |
title | varchar |
description | text |
file_url | varchar |
file_name | varchar |
file_size | int |
uploaded_by | int |
created_at | datetime |
UI Layout
Form Container
├── Heading ("Upload Document")
├── Text Input (name: "title", label: "Document Title", required: true)
├── Textarea (name: "description", label: "Description")
├── File Upload (name: "file", label: "Choose File",
│ accept: ".pdf,.doc,.docx,.xls,.xlsx",
│ maxSize: 5242880)
└── Submit Button ("Upload")File Upload Widget Configuration
| Property | Value | Description |
|---|---|---|
name | file | The form field name. |
accept | .pdf,.doc,.docx,.xls,.xlsx | Allowed file types. |
maxSize | 5242880 | Max file size in bytes (5 MB). |
The File Upload widget handles:
- File selection via a browse button.
- Client-side file type and size validation.
- File preview (image files show a thumbnail; other files show the filename).
- Upload to the WordPress media library via the REST API.
- Returns the attachment URL and metadata to the form.
Action Pipeline (onSubmit)
Context
→ Require Auth (logged_in)
→ Rate Limit (maxRequests: 10, windowSeconds: 60, scope: "user")
→ Validate
→ Sanitize
→ Set Field (uploaded_by = current user id)
→ Set Field (created_at = now())
→ Save Row (tableId: documents)
→ OutputValidate Rules
json
[
{ "field": "title", "rule": "required" },
{ "field": "title", "rule": "max_length", "value": "255" },
{ "field": "file_url", "rule": "required" }
]Sanitize Fields
json
[
{ "field": "title", "method": "strip_tags" },
{ "field": "title", "method": "trim" },
{ "field": "description", "method": "esc_html" },
{ "field": "description", "method": "trim" },
{ "field": "file_url", "method": "trim" },
{ "field": "file_name", "method": "strip_tags" },
{ "field": "file_size", "method": "to_int" }
]Set Fields
uploaded_by:
fieldName: "uploaded_by"
expression: "user_meta('ID')"created_at:
fieldName: "created_at"
expression: "now()"Displaying Uploaded Documents
Data Source Pipeline
Table Query (documents, orderBy: "created_at", order: "DESC")
→ ResultDisplay Layout
Repeater (documents data source)
└── Container (flex, row, gap: 12px)
├── Text ("`{ {row.title}}`")
├── Text ("`{ {number_format(row.file_size / 1024, 0)}}` KB")
├── Text ("`{ {date_format(row.created_at, 'M j, Y')}}`")
└── Button ("Download", link: "`{ {row.file_url}}`", target: "_blank")Image Upload Variant
For image uploads with preview:
File Upload (name: "image",
accept: ".jpg,.jpeg,.png,.gif,.webp",
maxSize: 10485760,
preview: true)After upload, the file_url contains the WordPress media URL. Display with:
Image (src: "`{ {row.file_url}}`")Variations
Multiple file uploads
Add multiple File Upload widgets with different names:
File Upload (name: "document", label: "Document")
File Upload (name: "cover_image", label: "Cover Image", accept: ".jpg,.png")Both URLs are available in the form context.
Restrict uploads by role
Require Auth (capability: "upload_files")The upload_files capability is assigned to Authors and above by default.
Delete uploaded file
Create a delete action pipeline that also removes the WordPress media attachment:
Context → Require Auth → Delete Row (tableId: documents) → OutputWARNING
Always validate file types on the server side, not just the client. The accept attribute on the File Upload widget provides a hint to the browser, but the actual file type validation should happen during the WordPress media upload process.
TIP
Files are uploaded to the WordPress media library, which handles storage, thumbnail generation (for images), and CDN compatibility. The file_url stored in your database table points to the WordPress media URL.