JetFormBuilder Media Upload Field with Progress Bar & Compression

The redesigned JetFormBuilder media upload field, with a drag-and-drop box, a per-file progress bar and image compression, is not built into JetFormBuilder. It is a free PHP snippet by Qubadi on GitHub. You paste it into a code snippets plugin, give your Media Field the CSS class media_image, and control the design from a new JFB Media Field page in the dashboard.
Before you use the snippet on a live site, apply the two fixes in this guide. The first stops its CSS from hiding the default preview area and size note on every other Media Field. The second closes an unused public upload endpoint. If you only want a better-looking field, JetFormBuilder's own Style Manager may be enough. If you want official drag and drop with image resizing and vendor support, the paid Drag & Drop File Upload add-on is the better fit.
- Snippet, Style Manager or add-on: which one you need
- What the snippet adds to the Media Field
- How to install the snippet
- Settings and defaults
- File limits still come from JetFormBuilder and the server
- Two fixes before you go live
- Common problems
Snippet, Style Manager or add-on: which one you need
You have three ways to get a modern media upload field in JetFormBuilder. Pick based on what you need beyond looks.
| Option | Cost | What you get | Best for |
|---|---|---|---|
| JetFormBuilder Style Manager | Free, in core | The New Style Manager arrived in JetFormBuilder 3.6.0. Version 3.6.6 added extra style settings for the Media Field. Appearance only: no compression, no progress bar. | Matching the field to your brand |
| Qubadi's snippet | Free | Custom upload box, drag and drop or a plain button, per-file progress and remove icon, optional image compression (desktop browsers only) | A free modern UI when you are comfortable maintaining a snippet |
| Drag & Drop File Upload add-on | Paid PRO add-on, from $49 | Drag-n-drop UI, optional WP Media Library UI for logged-in users, max image width/height and image quality (1–100), upload on form submit or instant upload, max files, max file size, allowed MIME types, and saving files on the server or as base64 | Client sites that need support and all file rules in one place |
Whatever you choose, update JetFormBuilder to the latest version (3.6.7 at the time of writing). Recent releases fixed Media Field security issues: 3.6.5.2 escapes Media field previews to prevent XSS, 3.6.6 fixed unauthenticated arbitrary Media Library attachment deletion, and 3.6.6.1 added a Media field access check. We cover the paid route in our guide to the JetFormBuilder Drag & Drop File Upload add-on, and a CSS-only approach in how to style JetFormBuilder file upload fields for a modern look.
What the snippet adds to the Media Field
Design you control from the dashboard
The default "Choose file" input is replaced by a responsive upload box. The author says over 90% of the design can be changed from the backend, so you rarely need your own CSS. You can set:
- Button colors, text and alignment
- Padding, margin, border color and border radius
- Error background, error text color and error font size
Drag and drop or a plain button
The Upload Style setting has two options: Drag and Drop (Default) and Choose File Button Only. Use the button-only style if your audience is mostly on phones, where dragging files rarely happens.
Per-file progress bar
Each selected file appears as its own item with a preview (image thumbnail or document icon), a 0–100% progress bar and a remove icon, so visitors can drop a wrong file before they submit.
Know what the bar measures. The script uses XMLHttpRequest upload.onprogress to send each file to admin-ajax.php with the action jfbm_probe. That handler only returns the file's name, type and size, then discards the file. The real upload happens when the form is submitted. So the bar shows a real network upload, but of a test copy, and every file crosses the network twice.
Optional image compression
Compression is off by default. When you turn it on, you set a max width, a max height and a quality value, and large images are scaled down before submit. Keep Original Dimensions re-encodes the image without resizing it. Two limits apply:
- Quality below 60 is treated as 60. The script uses
Math.max(quality/100, 0.6). - The author notes that compression works on desktop browsers only, not on mobile phones.
How to install the snippet
- Update JetFormBuilder to the latest version. If the site is live, test on a staging copy first. We have not confirmed how the snippet behaves on every JetFormBuilder release, and JetFormBuilder's markup can change between versions.
- Open Qubadi's gist JetFormbuilder Choose file ( mediafield ) + drag and drop + progressbar + image compression and copy the full PHP code.
- In a code snippets plugin such as Code Snippets or WPCode, create a new PHP snippet, paste the code and set it to run everywhere. Do not activate it yet.
- Apply the two fixes in Two fixes before you go live.
- Activate the snippet. A top-level JFB Media Field menu item with an upload icon appears in the dashboard (page heading "JFB Media Field Styling"). Only users with the
manage_optionscapability, normally administrators, can see it. - Open JFB Media Field. Note the Target CSS Class (default
media_image), pick an Upload Style, set your colors and texts, and save. - Open your form in JetFormBuilder, select the Media Field, and go to Block settings → Advanced → CSS class name. Enter the same class without a dot, for example
media_image. - Save the form.
- Open the form page in a private browser window. With the defaults you should see an upload box with "Click to Upload" in purple (#8b5cf6) above a grey "or drag and drop". Add a file, watch its bar reach 100%, submit the form and check that the file arrived.
Step 7 is the one people miss. The snippet's JavaScript only rebuilds Media Fields that carry the target class. Without it, the field keeps its default input. Until you apply Fix 1, though, the snippet's CSS hides the default preview area and size note on every Media Field. After Fix 1 you can restyle one Media Field and leave the others alone.
Settings and defaults
The snippet stores everything in a single option, jfbm_settings, split into four sections: Design, Translations, Error Messages and Image Compression. The defaults are:
| Setting key | Default |
|---|---|
target_css_class | media_image |
upload_style | drag_drop |
button_bg_color, primary_color | #8b5cf6 |
upload_text | Click to Upload |
sub_text | or drag and drop |
box_padding | 40px 20px |
box_border_radius | 12px |
filename_trim_length | 20 |
scroll_threshold | 6 |
error_bg_color | #fecaca |
error_font_size | 14px |
enable_compression | 0 (off) |
max_width, max_height | 4096 |
quality | 85 |
keep_original_dimensions | 0 (off) |
Texts accept placeholders: {count} in the status text, {max} in the max-files error, {name} and {size} in the max-size error, and {type} in the file-type error. Translate these strings in the Translations and Error Messages sections if your form is not in English.
File limits still come from JetFormBuilder and the server
The snippet changes how the field looks and what messages it shows. It does not set the rules. Max files, max file size and allowed file types are still configured in the Media Field's own settings in JetFormBuilder. Since JetFormBuilder 3.6.3, choosing a User Access option in the Media Field settings is required.
Your server sets a hard ceiling too. PHP's upload_max_filesize caps each file, and post_max_size caps the whole form submission, including all files together. Because compression does not run on phones, a visitor's full-size phone photos are sent as they are. Set the field limit and the server limits with that in mind.
Two fixes before you go live
Fix 1: stop hiding the default UI on other Media Fields
The snippet's wp_head style block hides parts of JetFormBuilder's Media Field on every page, not only on the field with the target class: the preview area (.jet-form-builder-file-upload__content), the max-size note (.jet-form-builder-file-upload__message) and the field's error containers. Any other Media Field on the site loses its file previews and size hint.
In the snippet's style block, find the rules under the comments /* Hide JFB default UI we replace */ and /* Hide JFB default file field errors; show only our styled ones */. Replace those rules with this scoped version:
.field-type-media-field:has(.<?php echo esc_attr($s['target_css_class']); ?>) .jet-form-builder-file-upload__content{all:unset!important;display:none!important}
.field-type-media-field:has(.<?php echo esc_attr($s['target_css_class']); ?>) .jet-form-builder-file-upload__message{display:none!important}
.field-type-media-field:has(.<?php echo esc_attr($s['target_css_class']); ?>) .jet-form-builder-file-upload__errors:not(.jfbm-error-message),
.field-type-media-field:has(.<?php echo esc_attr($s['target_css_class']); ?>) .jet-form-builder__field-error:not(.jfbm-error-message){display:none!important}It reads the target class from the same $s settings array the style block already uses. If your copy names that variable differently, use its name. JetFormBuilder puts the CSS Class Name on the <input> itself, so the rules use :has() to find the field row that contains it. :has() works in all current browsers. Now the default preview area, size note and errors are hidden only on the field you restyled, where the snippet shows its own UI and messages.
Fix 2: remove the unused public upload endpoint
The current revision still registers an upload handler for logged-in users and for guests, even though its own comment says it is no longer invoked:
add_action('wp_ajax_jfbm_upload','jfbm_upload_handler');
add_action('wp_ajax_nopriv_jfbm_upload','jfbm_upload_handler');Anyone who is not logged in can call it and save files into /wp-content/uploads/jfbm-temp/, a folder that is publicly reachable. The nonce it checks is printed in every page's head, so it is not a real barrier.
The cleanest fix is to delete those two lines and the whole jfbm_upload_handler function from the snippet. Then check /wp-content/uploads/ with FTP or your host's file manager and delete the jfbm-temp folder if it exists.
If you would rather keep Qubadi's code untouched, for example so you can paste a future revision as is, add this second PHP snippet instead. It detaches the endpoint without editing the original. In Code Snippets or WPCode, paste it without an opening PHP tag. In a child theme's functions.php, paste it below the existing opening tag.
Code
/**
* Hardening for Qubadi's JFB Media Field snippet.
* Detaches the legacy jfbm_upload AJAX endpoint (logged-in and guest)
* that the current revision still registers but no longer uses.
* The jfbm_probe endpoint used by the progress bar is not touched.
*/
add_action( 'admin_init', 'bmc_jfbm_remove_legacy_upload_endpoint', 1 );
function bmc_jfbm_remove_legacy_upload_endpoint() {
// admin-ajax.php fires admin_init before any wp_ajax_* hook runs,
// so the handler is removed before WordPress dispatches the request.
if ( ! wp_doing_ajax() ) {
return;
}
remove_action( 'wp_ajax_jfbm_upload', 'jfbm_upload_handler' );
remove_action( 'wp_ajax_nopriv_jfbm_upload', 'jfbm_upload_handler' );
}How the hardening snippet works and how to test it
Add it as its own PHP snippet set to run everywhere, next to Qubadi's snippet, or put it in your child theme's functions.php. WordPress's admin-ajax.php fires admin_init before it runs any wp_ajax_ or wp_ajax_nopriv_ hook. The function runs at priority 1 on that hook and removes the legacy handler, so WordPress finds nothing registered for jfbm_upload and answers with 0 and HTTP status 400. The wp_doing_ajax() check keeps it from doing anything on normal admin pages. The jfbm_probe action stays in place, so the progress bar keeps working.
To test it, send a request as a logged-out visitor from your terminal (replace the domain):
curl -i -X POST -d "action=jfbm_upload" https://example.com/wp-admin/admin-ajax.phpYou should get HTTP/1.1 400 (or HTTP/2 400) and a body of 0. If you get any other response, your copy registers the endpoint in a different way. Delete the two add_action lines and the handler function directly instead.
Then test Fix 1: open a form whose Media Field does not have the target class, choose a file and check that JetFormBuilder's own preview and size note appear.
Common problems
- The field still looks like the default "Choose file" input. The CSS class is missing or does not match. Compare Block settings → Advanced → CSS class name with the Target CSS Class on the JFB Media Field page, make sure there is no dot in the block setting, save the form, and clear your page cache.
- Other Media Fields lost their file previews or "Maximum file size" note. This is the unscoped CSS. Apply Fix 1.
- Visitors see "Upload failed" but uploads work for you when logged in. The snippet prints its nonce in the page head. On a fully page-cached site the cached nonce goes stale, the probe request gets "Invalid nonce", and the file shows as failed. Exclude your form pages from page caching in your caching plugin or at your host.
- Compression does nothing on a phone. That matches the author's note: compression runs on desktop browsers only. Phone photos upload at full size, so check your Media Field size limit and the PHP limits.
- Lowering quality below 60 does not shrink files further. The script never uses a quality below 60. Reduce max width and max height instead.
- Uploads feel slow on large files. Each file is sent twice: once for the progress bar test, once on submit. Turn on compression for desktop users and keep the field's max file size reasonable.
- The progress bar reaches 100% but the form rejects the file. The real check happens on submit. The file is larger than the Media Field limit or the server's
upload_max_filesizeorpost_max_size, or its type is not allowed in the field settings. - The snippet stopped working after a JetFormBuilder update. It depends on JetFormBuilder's field markup and class names. Check the gist for a newer revision and retest on staging before each update.
One optional hardening step: the snippet registers its settings without a sanitize_callback. Only administrators can change them and the values are escaped on output, so the risk is low. If several people have admin access, adding a sanitize callback is a sensible extra.
With the class in place and both fixes applied, the snippet gives you a branded drag-and-drop upload field with per-file progress and desktop image compression at no cost. When you need resizing on every device, instant uploads or Media Library access, move to the paid add-on. If you would rather have someone build and test this on your site, post a request on BoostMyCroco.
Frequently Asked Questions
Does JetFormBuilder compress images natively?
Why is my custom JetFormBuilder media upload design not showing?
Why do my other Media Fields show no file previews after adding the snippet?
Is the snippet's progress bar showing the real upload?
Do I need the paid add-on to get drag and drop in JetFormBuilder?
Sources
- JetFormbuilder Choose file ( mediafield ) + drag and drop + progressbar + image compression · GitHub (gist.github.com)
- JetFormBuilder — Dynamic Blocks Form Builder (wordpress.org)
- Drag & Drop File Upload Add-on — JetFormBuilder (jetformbuilder.com)
- Drag & Drop File Upload for WordPress (jetformbuilder.com)


