> For the complete documentation index, see [llms.txt](https://kb.craftformswp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://kb.craftformswp.com/documentation/changelog.md).

# Changelog

Everything that changed in each CraftForms release, newest first.

## 2.1.4

* **Added:** help popups for fields. Write some text in a field's new "Help popup" panel and a "?" appears next to its label; visitors click it to read the text in a popup. Basic HTML works (links, bold, lists, images). The popup closes on Esc or a click outside, and works inside Repeater rows
* **Added:** a "Placeholder" setting for Select fields, shown until a choice is made (e.g. "Choose…" instead of "— Select —"). It appears when the field has no default value
* **Added:** the `craftforms_starter_dirs` filter. A plugin can add its own folder of form, email template, PDF template, catalog item or WooCommerce product starters, and they are listed and imported beside the shipped ones. A file with the same name as a shipped starter replaces it
* **Improved:** when a visitor tries to send a form with errors, the page now scrolls to the first field that needs fixing and puts the cursor in it
* **Improved:** the Add to Cart block now puts the Quantity field and the button in one row that wraps on narrow screens, with a narrower quantity box and the button text on one line. The WooCommerce product starters use the same row
* **Fixed:** a 1-column Table smart variable set to "closest" or "closest up" gave its default value instead of the matching row in the cart and on submit, so prices built from it (e.g. a width price list) were missing there
* **Fixed:** an option in a Linked smart variable with no price could make the price formula fail when the form was sent, and the form or add to cart was refused. An empty price now counts as the variable's default value, as it already did on the page
* **Fixed:** "&" and other special characters in validation and error messages showed as "\&amp;"
* **Fixed:** is\_date\_between() in a formula didn't read dates written as DD/MM/YYYY on the page (for example from a Datepicker set to that format), while the server did. The price on the page could then differ from the one worked out on submit, and the form was refused
* **Fixed:** words\_count() counted words differently on the page and on submit ("don't" was 1 word on the page, 2 on the server), so a price per word could make the form be refused. The page now counts like the server: every run of letters and digits is a word

## 2.1.3

* **Fixed:** when a number field and a Range Slider kept equal with Field Links had different steps (e.g. the field in steps of 1, the slider in steps of 5), both were forced onto the bigger step, so the field's up/down arrows could not change it. The field you change now keeps its value and the other one moves to its own nearest step
* **Fixed:** a slider with a step the linked number field doesn't accept (e.g. 2.5 next to a field in steps of 1) put values like 32.5 into the field, which then showed as invalid (red) and blocked sending the form. The field now gets the nearest value it accepts (33)
* **Fixed:** a Range Slider whose drag was interrupted by the browser (e.g. a touch gesture taken over by scrolling) could stay "dragging", and a linked field could no longer move it

## 2.1.2

* **Improved:** a number field linked to a Range Slider with Field Links now follows the slider while it is being dragged, not only when the mouse button is released. Formulas and prices already updated while dragging
* **Improved:** Field Links opened from a field's settings shows only that field's links. The form's other links are behind "Show N other links in this form", so the panel stays about the field you are editing (they open by themselves when one of them has a problem)
* **Fixed:** emptying a Range Slider's "Default Value" box saved nothing usable, and the slider started at 50 on the page. An empty box now means the slider's Min ("Default To": its Max), as the help text under the box says. Sliders saved this way before 2.1.2 still start at 50 until their default is set and the form is saved again

## 2.1.1

* **Fixed:** Range Slider "Step" saved a typed value with 0.001 added (5 became 5.001), so slider values and the prices calculated from them were off. Steps saved this way are corrected automatically
* **Fixed:** an underscore could not be typed at the end of a field name (e.g. on the way to "length\_cm"); it was removed on every keystroke
* **Fixed:** Field Links opened from a field's settings now lists that field's links apart from the form's other links, so adding a link for one field no longer means editing (and losing) another field's link by mistake

## 2.1.0

* **Security:** logged-out visitors can no longer read form, email and PDF template settings through the WordPress REST API (webhook URLs, recipients, email bodies); logged-in users without CraftForms access see only the title
* **Security:** hosted Stripe and PayPal checkouts are marked paid only when the amount, currency and order match; the unused public Stripe checkout-session route is removed
* **Security:** forms priced from the page's post meta now verify the page they were shown on, so a visitor can't submit with another page's (cheaper) price
* **Security:** WooCommerce starters, WooCommerce import and the Uni CPO import need the "edit products" permission, and can only change products the user may edit
* **Security:** merge tags typed by a visitor into a field are no longer expanded in email subjects, From and To, emails or PDFs
* **Security:** changing an SMTP server's host, port or username requires re-entering its password; managing SMTP servers needs the Settings permission
* **Security:** the forms list's Description column is escaped; "Required Request Headers" can no longer be skipped by faking the Referer/Origin header
* **Security:** embed codes for a catalog item are signed. Older unsigned embed codes keep working and are reported (admin notice, one email, a warning on the Embed tab) so you can replace them and turn on "Require signed embeds"
* **Security:** PDF rendering no longer fetches images from private or internal addresses, and reads local files only from font and theme folders
* **Fixed:** Stripe charged zero-decimal currencies (JPY, KRW…) 100 times the price
* **Added:** CraftForms clears your page cache once after an update that changes form markup (WP Rocket, W3 Total Cache, WP Super Cache, LiteSpeed, SiteGround, WP Engine and more); if no cache plugin answers, an admin notice asks you to clear it
* **Added:** Filter & Search for Radio and Checkboxes fields. A search box and filter dropdowns (e.g. colour, pattern) above long lists of options; the picked option always stays visible. Filter values are set per option and can be overridden per WooCommerce product and catalog item. The list scrolls after 315px by default, and the editor previews the filtering
* **Added:** Generate options from WooCommerce products (PRO). Fill a Radio or Checkboxes field from a product category, with image, price and filter values taken from product attributes; merge into the existing options or replace them
* **Changed:** option images load lazily at the smallest size that fits the box, so fields with hundreds of image options load fast
* **Added:** Overview page. Once a form has a submission or an order, the CraftForms dashboard shows key numbers (submissions, orders, revenue, bookings), what needs attention and upcoming bookings; the setup wizard stays one click away
* **Added:** "Build price from options" in the price formula editor: writes the formula from the prices of the form's option fields
* **Added:** token picker in the email and PDF template editors, the price formula and InfoBlocks, and a preview of email and PDF templates with data from a real submission. Shorter tokens: {{field.name}}, {{form.price}}, {{form.priceFormatted}}, {{form.currency}}; existing {{email.\*}} tokens keep working
* **Added:** when a form uses PRO blocks on the Free version or with an expired license, the form shows "temporarily unavailable" to visitors instead of half working, admins see why on the page, and the form editor shows a notice. PRO blocks show "(PRO)" in their title
* **Changed:** admin screens share one look: dates and prices follow your site's settings, status badges, pagination and wide tables scroll on small screens. Orders can be opened by link (?order=ID)
* **Changed:** "Re Init" and "Debug" moved to the block's Advanced panel; the "Analytics" panel is renamed "Track Submissions"
* **Added:** Catalog Search (PRO). A block, the \[craftforms\_search] shortcode and an embed code for other websites: visitors pick dates and guests and see which booking items are free, each linking to its booking page with the dates filled in. Items booked by time (treatments, boat trips, meeting rooms) list that day's free times, each opening the booking form with the time picked. Only items with room for the party are found: places left on shared items, the capacity of a room booked as a whole. Checks every night's places, stay rules, closed and blocked dates, imported calendars and the availability window. Fast and cached; a booking or item change updates results at once
* **Added:** Catalog Search, Bricks Builder element ("CraftForms Catalog Search")
* **Added:** the Catalog Search date field shows a placeholder ("Select dates" / "Select a date")
* **Changed:** Catalog Search picks dates with the CraftForms booking calendar; its embed code now loads the current version of the search on its own, so it never needs re-pasting after an update
* **Added:** "Search result link" on booking catalog items: the page the item is placed on (automatic), a page you choose, or a web address for static and hosted websites
* **Added:** the Order Summary lists what a product order bought: the item, quantity and the options picked. Product orders now save their items
* **Added:** Order Summary upgrade (PRO). The thank-you page block now shows booking dates, generated documents, "Add to calendar" (.ics) and "Print"; a Pending payment switches to Paid on its own while the provider confirms it; Default, Modern and Builderius CSS styles; and it works on other websites (hosted forms, static sites) with an embed code. Pages with an order reference are never cached and don't pass it to other sites
* **Fixed:** the booking calendar's month names and days were unreadable on dark-mode sites (they took the page's light text colour on the calendar's white background)
* **Added:** Settings → Field Message Translations now also lists the Catalog Search and Order Summary texts, per language, including plural forms ("1 night" / "5 nights", three forms for Polish and Ukrainian). Embedded searches take the site's texts at runtime
* **Fixed:** booking calendar months were narrower than their column (squashed) in the popup
* **Fixed:** a booking calendar picking a date range crashed when the item had no stay rules
* **Fixed:** \[craftforms\_static\_form] could load embed.js over http on an https site
* **Fixed:** a hosted checkout (Stripe Checkout, PayPal, Mollie, Square) the buyer walked away from kept the stock or places its order reserved for good. Unpaid hosted checkouts now give them back: Stripe sessions expire after an hour (and the new checkout.session.expired webhook event releases them at once), other gateways after a day. If the payment page can't be opened, the order is cancelled straight away
* **Fixed:** a single-date booking calendar whose window is one day (an event on 14 November) opened on the month before, with no bookable day in view, and jumped back there when the page reflowed after a date was picked
* **Fixed:** single-date booking calendars asked to "select a date and time" when only a date is booked
* **Changed:** switching a Catalog item to Single Date (Events / Drop-ins) opens every weekday instead of Monday to Friday, and the item warns when a fixed-date Availability Window has no open day
* **Fixed:** the Order Summary's empty and "not found" messages had their CSS class outside the class attribute
* **Added:** "Builderius CSS" style for forms and for the search, for sites on the Builderius CSS framework (TemplateCraft templates). The framework styles fields and buttons; option cards, the booking calendar, time slots, repeaters and messages take its colours and spacing
* **Fixed:** cancelling a booking or product order could fail to give places back when the item's capacity had been raised after the booking (a database error, nothing released)
* **Fixed:** the QR Code / Barcode block could be inserted in forms and pages, where it shows nothing; it's offered in PDF templates only
* **Fixed:** catalog items booked by time slot hid "Search result link" and said they can't be searched, although Catalog Search finds them; hosted sites couldn't link them at all
* **Fixed:** Filter & Search with a vertical options layout spread long lists into extra columns instead of scrolling
* **Added:** {{submission.ip}} tag for emails, PDFs and webhooks: the IP address the form was submitted from, the same one saved with the submission. Listed in the token picker under "Submitter IP address"
* **Changed:** reaching the plan's limit of embed websites now says "website limit" instead of "embed domain limit"
* **Fixed:** PDFs generated for WooCommerce orders left form-field tags ({{field.width}}, file links…) empty on stores using High-Performance Order Storage (HPOS); only interactive-element images came through
* **Fixed:** cancelling a product order from an item without stock tracking could add stock if tracking was turned on later
* **Fixed:** catalog items lost their Conditional and User role smart variables on save (they became empty expressions)
* **Added:** Submission label for exposed smart variables on WooCommerce products and catalog items, as on forms: the value then shows in the cart, orders and submissions
* **Added:** "Dynamic" smart variables (post meta or a site option) on WooCommerce products (reads the product's own meta) and catalog items
* **Fixed:** a one-date booking calendar filled from a link showed the date twice ("2026-10-22 - 2026-10-22")
* **Fixed:** cancelling or refunding a booking from the Orders screen gave back one place on every date including the checkout day. It now gives back exactly what the booking took: a room booked as a whole is free again, and the next guest's arrival day is left alone
* **Fixed:** a "Fixed date" availability window on a catalog item lost its date when saved
* **Fixed:** the server now refuses a single-date or whole-day booking on an unavailable date, and a room booked as a whole when part of it is already taken, instead of failing later at reservation
* **Fixed:** embedded forms on other websites could keep old CSS and JavaScript from the browser cache after a plugin update; the files are now versioned like on WordPress pages
* **Added:** form preview. "Preview form in new tab" in the form editor's Preview menu, and an eye icon on the Forms screen, show the form on your site in your theme without putting it on a page. Unsaved changes are autosaved and shown. A bar at the bottom says which version you see and that submissions are real. Forms used by one catalog item preview with that item; with several, pick one in the bar
* **Added:** Field Links (PRO). Update a field when the visitor changes another: keep two fields equal (e.g. a number box and a slider), or set a field with a formula, such as converting sizes when the unit changes or keeping width and height at a fixed ratio. "previous." gives the value from before the change. Managed in the form sidebar (Field Links) and from each field's settings. In a "keep equal" pair both fields start with the value of the field picked first, and stay within the values both accept (a slider at 5 next to a box with a minimum of 10 moves to 10)
* **Changed:** values of fields hidden or disabled by Field Conditions no longer show in InfoBlocks and dynamic labels ({{field.name}} is empty while the field is hidden), matching prices, smart variables and the submission, which already ignored them
* **Added:** "Disable valid field highlight" on the Form block (Validation Feedback panel). Turn it on to drop the green "valid" state; fields with a problem are still marked. Works with the Default and Modern form styles
* **Changed:** the Form block's "Global Colors" panel is now "Validation Feedback", with clearer names: Valid state color, Invalid state color, Error message color
* **Fixed:** a number field changed with its up/down arrows never showed the valid (green) or invalid (red) state. Chrome only marks a field as edited after typing; CraftForms now also marks it on any change the visitor makes
* **Fixed:** field blocks could be switched to the Flow or Constrained layout, which have no settings for a field, and on themes without theme.json the Layout panel then disappeared so the field couldn't be switched back. Fields now stay on the Flex (stack) layout (option groups and repeater groups can still use Grid), and fields saved with Flow or Constrained are set back to a vertical stack when opened in the editor

## 2.0.2

* **Added:** "User role" smart variables (PRO). Give a variable a different value per user role, e.g. wholesale customers pay wc\_price \* 0.8 and everyone else pays wc\_price. Pick roles from a list (plus "Guest" and "Any logged-in user"); the first matching rule wins. The value is chosen on the server, so a page never shows another role's price and the price is re-checked on submit. Works in forms, WooCommerce products and Catalog items. A role that isn't registered on the site is flagged in the editor and simply skipped
* **Added:** "contains" and "does not contain" operators in Field Conditions, Flow conditions and WooCommerce product conditions, for text fields. Not case-sensitive
* **Added:** search box on the Forms and Catalog screens. Type part of a form's or catalog item's name to filter the list. On the Catalog screen it works together with the type and status filters
* **Added:** search box and status filter on the Email Logs screen. Search by recipient or subject, and show only successful or failed emails. The list now has "To" and "Subject" columns
* **Changed:** the table smart variable's "Closest up" lookup is now labelled "smallest row/column ≥ value", which is what it has always done
* **Fixed:** "Update configuration" (editing a WooCommerce cart item) no longer overflows or breaks inside the Add to Cart button; the button widens across the free grid columns instead
* **Fixed:** abandoned form capture no longer saves what a visitor typed into a password field
* **Fixed:** the cached copy of a form used for embeds was rendered as the logged-in author, so {{user.\*}} tags could show the author's name and email to visitors. It is now rendered as a guest
* **Fixed:** smart variables set to show in submissions (and in emails as {{email.variable\_name}}) were saved with the value the visitor's browser sent, which could be changed. They now use the value worked out on the server; the browser's value is only used when the server can't calculate it. Prices were always checked on the server
* **Fixed:** buttons in email templates lost their link, background and padding in the sent email
* **Fixed:** formulas using date() or strtotime() didn't calculate in the browser while the visitor filled in the form; they only worked on submit
* **Fixed:** a visitor could get around the submission rate limits by sending a made-up address in the X-Forwarded-For header. The IP address saved with each submission is now the same one the rate limits use. Proxy headers are only trusted when the site turns them on (see "Submission limits and spam protection" in the docs). Behind Cloudflare or a load balancer, submissions may now show the proxy's address until this is set up
* **Fixed:** when a form sends several emails, the delay between them (to avoid mail-server rate limits) was skipped before the first deferred email

## 2.0.1

* **Fixed:** saving a form after editing its Field Conditions could fail with "Updating failed. disableSubmitRules is not a valid property of Object.", even when the form had no "Block submission" rule

## 2.0.0

* **Added:** email-marketing integrations for Mailchimp, Brevo, FluentCRM and MailPoet, included in the free version. Connect an account once under Settings → Integrations, then add a "Mailchimp" (or Brevo, FluentCRM, MailPoet) action to any form. Audiences, lists, tags and contact fields load live from your account, and the field mapping fills itself in by matching names (email, first name, phone…). Double opt-in, updating existing contacts and tags are supported. Someone who unsubscribed is never subscribed again by filling in a form
* **Added:** integration connections. Add several named accounts (e.g. one Mailchimp account per brand) and pick one per action. API keys are encrypted in the database and never shown again in full. Form editors can pick a connection but can't see its key. FluentCRM and MailPoet need no connection, only the plugin active on the same site
* **Added:** integration Activity log (Settings → Integrations → Activity) shows every contact sent, what was sent and why a call failed, with a "Retry now" button. It is included in WordPress's personal-data export and erase tools. Entries are kept for 30 days
* **Added:** automatic retries for failed integrations (PRO). A contact that couldn't be sent because the service was down is retried after 1, 5 and 30 minutes
* **Added:** "Run only if" on every submit action. Run an action only when a choice field has a certain value, e.g. subscribe to Mailchimp only when "Send me the newsletter" is ticked, or email the wedding team only when "Wedding" was picked. The action card shows the condition
* **Added:** Flows (PRO), a visual flow builder under CraftForms → Flows. Build the steps on a canvas, with Yes / No condition branches and an "If it fails" branch for each action (e.g. "if Mailchimp fails, email the office"). Conditions can use the form's fields, the logged-in user's role and the submission number. Point one or more forms at a flow and choose whether it runs after the form's own actions or replaces them. Automatic steps (catalog orders, WooCommerce add-to-cart) always run. Flows run after the visitor's response by default, so visitors don't wait for emails, PDFs or third-party services
* **Added:** WooCommerce order flows (PRO). Start a flow when an order is placed or changes status (e.g. to Completed), for all orders, only orders with CraftForms-configured items, or only orders without them. Conditions can check the order total, item count, payment method, billing/shipping country, customer role, coupons and more. A flow can send your own branded order email and switch off the WooCommerce email it replaces, so customers never get two, with a "Send WooCommerce email" step as a fallback. Order flows run in the background through WooCommerce's scheduled actions
* **Added:** flow Runs log showing every run, its result and the exact path it took, with the error for any failed step. Runs are kept for 30 days
* **Added:** flow export and import (.craftflow\.json). Imported flows are always drafts. Email and PDF templates, SMTP servers, files and integration connections are matched by name on the new site. A form exported with a flow brings the flow along
* **Added:** Order Items block for email and PDF templates (PRO). One block lists the order's products, the options the customer chose, quantities, prices and totals. Works in WooCommerce order flows, order PDFs and forms that create a catalog order, and prints nothing when there's no order. In WooCommerce order flows also available as {{order.items\_table}}, {{order.items\_list}} and {{order.totals\_table}}
* **Added:** {{order.\*}} dynamic tags in email and PDF templates for WooCommerce orders (PRO): customer, billing and shipping details, payment and shipping method, customer note, every amount, and links to view, pay for or edit the order
* **Added:** {{user.\*}} tags in submit actions (id, email, login, display name, role) for the logged-in person who submitted the form. They are worked out by WordPress on the server, so a visitor can't fake them with a form field
* **Improved:** the actions library has a search box and is grouped into sections (Core, Email marketing), so the right action is quick to find as the list grows
* **Improved:** PDF documents set up for WooCommerce order statuses through code/CLI (the `craftforms_pdf_order_status_map` option) are moved into WooCommerce order flows on update, so they can be seen and edited. Documents keep being generated as before, and the old setting is kept as a backup
* **Improved:** stored secrets (payment keys, integration keys) now use stronger AES-256-GCM encryption. Existing keys keep working
* **Improved:** translations updated in all seven languages, including Flows and Integrations
* **Fixed:** importing a form whose content or settings contained "&" or other special characters stored them as codes (e.g. "u0026")
* **Fixed:** an imported form without block settings could fail to load its form block
* **Fixed:** email templates, PDF templates, SMTP servers and other references whose names contain "&" or an apostrophe weren't found on import
* **Developers:** new `craftforms_register_integration_providers` hook to add your own email-marketing or CRM driver, and `craftforms_feature_enabled` keys to withhold features on hosted setups: `submit_action:<slug>` (actions), `integration:<slug>` (integration services), `flows` (the whole Flows builder), `flow_trigger:<slug>` (flow triggers) and `integration_auto_retry` (automatic retries)

## 1.9.1

* **Added:** "Edit configuration" link on WooCommerce cart items configured with a CraftForms form. It reopens the product with the customer's choices already filled in, and the "Update configuration" button changes that cart item in place instead of adding a new one. Works in the cart page (classic and block), the Mini-cart block and classic mini-carts such as theme side carts and the Elementor Menu Cart, and is switched on for all products automatically. Uploaded files, repeater rows, booking dates and the image cropper's framing (crop, flip, black & white, sepia) come back too; the customer can keep, remove or replace uploaded files. Not available for repeaters that contain a file upload or a booking picker
* **Added:** images uploaded through a form can now appear in PDF and email templates. Add an Image block, choose Insert from URL and use the field's image tag (e.g. {{email.photo.image\_url}}; {{email.photo.2.image\_url}} for the second file). PDFs embed the image directly from protected storage, so it never gets a public URL. If the field is left empty, the image is simply left out
* **Added:** file upload fields now appear in the Dynamic Data panel of email and PDF templates, with tags for the file name, the image and the download link
* **Added:** Signature field. Customers sign with a mouse or finger; the signature is saved as an image with the submission and can be placed in PDFs and emails with {{email.\<field>.image\_url}}
* **Added:** Google Analytics 4 tracking per form (form settings → Analytics). A successful submission sends an event to GA4 / Google Tag Manager, and a failed one sends "\<name>\_error"
* **Added:** customers can use their own photo in the Image Cropper and Picture Frame. Connect a File Upload field (block setting "Connected Upload", or "Customer's photo" in the WooCommerce Active Element) and the chosen photo replaces the shop image in the preview. "Edit configuration" from the cart brings the photo back
* **Added:** pictures made by the Image Cropper, Layered Image and Picture Frame on regular (non-WooCommerce) forms are saved as files with the submission and can be used in email and PDF templates; order PDFs can show them for WooCommerce orders too
* **Added:** new starters. WooCommerce products: Picture Frame Configurator, Frame Your Own Photo, Canvas Photo Print, Photo Wallpaper Mural and Sofa in a Room. Forms (without WooCommerce, each with a catalog item for checkout): Framed Print Order, Framed Photo Order, Canvas Print Order, Wallpaper Mural Order and Sofa Configurator, plus a Curtain & Rug Room Visualiser quote form
* **Improved:** the Image Cropper and Picture Frame blocks placed on a WooCommerce product page use the product's image
* **Improved:** after a crop is applied, changing the width or height to a different shape reopens the crop box at the new proportions, so the photo can be cropped again. Submitting with the crop box open applies it
* **Improved:** translations updated in all seven languages (German, Spanish, Finnish, Italian, Polish, Ukrainian, Bulgarian), including the new Signature field, GA4 and photo-upload settings
* **Fixed:** on forms with a file upload, ticked checkboxes (and multi-select choices) reached the server as a single value when a file was attached. Price rules depending on them were miscalculated, so "Add to cart" failed with "Price verification failed", and conditional fields depending on them were lost
* **Fixed:** with themes or builders that print the product gallery themselves (e.g. Astra Pro gallery layouts, Elementor's Product Images widget), the WooCommerce gallery was shown and the CraftForms image preview appeared below it. The preview now replaces the gallery
* **Fixed:** a product configured with a CraftForms form could be added to the cart without its options, at the plain WooCommerce price, through WooCommerce's own add-to-cart routes (?add-to-cart= links, the AJAX shop button, block Add to cart buttons). This is how bots and card-testing scripts place orders. Such additions are now refused with a link to the product page, and any unconfigured line already in a cart is removed before checkout
* **Fixed:** a field shown by a Field Condition on a checkbox group (e.g. "show Engraving text when Engraving is ticked") appeared and could be filled in, but its value was dropped on submit, so it never reached the cart, order or submission. "Any of", "all of" and "none of" conditions on checkboxes were also evaluated the wrong way round on submit. Existing forms are corrected automatically on update
* **Fixed:** on products with their own Field Conditions (Product data → CraftForms), a field those conditions showed could still be dropped on submit, because the submission was checked against the form's own conditions instead of the product's
* **Fixed:** saving a product with the classic Update button, a dynamic-SKU stock change after an order, or a WooCommerce bundle import could erase the product's CraftForms settings when a formula or text contained a double quote, and turned characters such as × or é into codes like u00d7
* **Fixed:** submissions created from WooCommerce orders stored customer text with double quotes or accented characters incorrectly
* **Fixed:** PDF templates with a custom page size and Landscape orientation were generated with the width and height swapped (e.g. 99 × 210 mm instead of 210 × 99 mm)
* **Fixed:** exporting a form with an Image Cropper block left the image behind, so the imported form pointed to the original site's image
* **Fixed:** WooCommerce Layered Image ignored its "Save composited preview" setting
* **Fixed:** a Chart could not read some smart variables, Value Presets changed the letter case of field names, and a new Picture Frame block showed no frame or mount until one was chosen
* **Fixed:** a JavaScript error ("debouncedValidation is not a function") on some pages when another element updated the form before it had finished loading

## 1.9.0

* **Added:** Mollie payment gateway — Hosted Checkout with iDEAL, Bancontact, cards, bank transfer and the other methods enabled on your Mollie profile; no webhook setup needed
* **Added:** Square payment gateway — Hosted Checkout (Square Payment Links) or card fields right in the form, with the card held until stock or the booking is confirmed
* **Improved:** the Add Payment Connection screen now shows the fields, webhook URL and events each gateway needs
* **Added:** availability periods for bookings — different opening times and slot times per season or for specific date ranges, including whole-day (date-only) availability
* **Added:** remaining places shown on time slots ("2 left" / "Sold out") instead of busy times silently disappearing from the calendar
* **Added:** "Block submission" condition — stop a form being submitted while a combination is invalid (e.g. width + depth + height over a limit)
* **Added:** catalog item export and import, plus ready-made catalog starters
* **Improved:** iCal export feed and booking email invites now carry the booked time for appointment and meeting-room bookings, instead of an all-day entry
* **Improved:** an imported iCal feed now blocks only the times its events cover — all-day events still close the whole day — and repeating events are honoured
* **Improved:** imported calendars are fetched right after a catalog item is saved, not only on the hourly schedule
* **Improved:** security hardening
* **Improved:** Dynamic Validation values are evaluated as real expressions on both sides, so "300 - width - depth" computes instead of being read as 300
* **Fixed:** on stores whose currency isn't USD, Stripe/PayPal embedded payments on forms linked to a Catalog item failed with "Payment currency does not match", and orders were saved in USD
* **Fixed:** events imported from an external calendar did not block appointment time slots at all
* **Fixed:** events removed from an imported calendar stayed blocked; removing them now frees the time at the next sync

## 1.8.4

* **Fixed:** fatal error on form submission when another plugin (e.g. ACPT) bundles an incompatible psr/cache version — bundled libraries are now namespace-prefixed to prevent conflicts

## 1.8.3

* **Improved:** minor UI improvements
* **Improved:** string translations
* **Added:** "Files" file management UI

## 1.8.2

* **Security:** fixed an important bug in price calculation — the final price is now always determined and verified on the server, and re-verified before checkout and order creation. Updating is recommended for any site using price formulas.
* **Improved:** if a price formula cannot be evaluated on the server, the submission is refused with a clear message and the reason is written to the error log, instead of the form falling back to a price calculated in the browser
* **Improved:** WooCommerce cart items are re-priced from the form definition before totals are calculated, so a stale or altered cart price cannot reach an order
* **Fixed:** "Order again" and cart re-pricing now resolve linked Smart Variables the same way the form itself does, so forms using them are priced correctly on those paths

## 1.8.1

* **Security:** hardened the Send Email action's "Additional Headers" setting against mail header injection — header names are now validated against the allowed character set, control characters in header values are rejected, and From/Sender/Return-Path can no longer be set from this field (which bypassed the validated "From" setting)
* **Added:** loading indicator for embedded forms — a lightweight CSS spinner fills the embed container while the form loads instead of leaving it blank; it stays hidden on fast loads so it never flashes, and its colour, size, thickness and speed are customizable via CSS custom properties
* **Fixed:** the "CraftForms" marker on the Products list table was output as raw HTML after the product title; it now appears as a post state alongside "Draft"/"Pending"
* **Improved:** the mail helper now validates the From address before writing it to the email headers (defensive hardening — no known exploit path in current code)

## 1.8.0

* **Added:** bulk "Add images from Media Library" for Radio/Checkboxes image swatches
* **Added:** Ambient Scene block (PRO) — field-bound image regions over a background
* **Added:** GET-param prefill — `?fieldname=value` prefills a matching form field on load
* **Added:** Abandoned-form capture (silent submissions) with admin status filter and CSV export
* **Added:** Dynamic Data Binding for Smart Variables ("Dynamic (bound)" kind)
* **Added:** Dynamic Data picker for taxonomy terms
* **Added:** Multi-account payment connections for Stripe/PayPal — named, reusable connections (like SMTP Servers), multiple accounts/live+test side by side
* **Added:** Flexible/continuous time-duration booking mode (PRO) for back-to-back slot booking
* **Added:** visual split-day marker for same-day turnover (B\&B checkout=checkin) dates
* **Added:** "All Form Data" block for Email/PDF templates — table/list/paragraphs of all submitted fields, empty fields skipped automatically
* **Added:** Value Presets block (PRO) — one-click badge sets multiple field values at once
* **Fixed:** JS error ("insertBefore") in the File Upload field when the element is moved/reflowed by a theme or page-builder script after initial render
* **Fixed:** layered-image visual element (product pages) rendered a layer bound to a hidden field using that field's stale/default value, so e.g. a color-conditional pair of duplicate fields (one hidden by conditional logic) could show the wrong-color hardware regardless of the customer's actual selection

## 1.7.6

* **Fixed:** dynamic validation expression evaluation
* **Fixed:** it was impossible to not select a default option for Select field

## 1.7.5

* **Added:** Standard validation messages translation UI
* **Added:** "smart watch" form starter (non WC version)
* **Fixed:** properly init of abilities API available in the plugin
* **Fixed:** turnover-day bug for check-in/check-out days
* **Improved:** updated webhook context, added IP address
* **Improved:** admin UI for catalog/WC product settings

## 1.7.4

* **Fixed:** bug when the empty stock setting was not properly disabling the stock management

## 1.7.3

* **Fixed:** UI/UX issue leading to misconfiguration
* **Improved:** Uni CPO converter script

## 1.7.2

* **Fixed:** bug in fields conditional logic
* **Fixed:** bug in smart variables resolving
* **Fixed:** displaying datepicker in embedded form
* **Fixed:** bug of payment success/order fail because of stock in embedded payment form
* **Added:** payment form mapping tool; payment info in orders
* **Added:** refund action for orders

## 1.7.1

* **Fixed:** bug with redirect URL compilation
* **Added:** pre-fill form from GET params (get param equals to form field names)

## 1.7.0

* **Added:** PayPal payment gateway
* **Added:** optional appointemnt .ics attachment for booking related email
* **Added:** 2 bookings form starters and 2 WC product starters
* **Added:** dynamic form data in "return on submit" url
* **Improved:** Uni CPO -> CraftForms migration script
* **Improved:** accuracy of styles used in embed form
* **Fixed:** using payment block with embedded form

## 1.6.1

* **Added:** filter to media library to display attachment uploaded with CF forms
* **Added:** Finnish translation (Suomi)
* **Fixed:** displaying correct cart item thumbnail
* **Fixed:** handling of composite image preview
* **Fixed:** issue with dependencies used in other plugins

## 1.6.0

* **Added:** "Locked WP mode" setting
* **Added:** new interactive element Frames Editor
* **Improved:** adding form through shortcode plus connecting form to WC product to display it on any page
* **Improved:** double booking prevention by implementing atomic pattern for writing data
* **Fixed:** bug of adding product to cart
* **Fixed:** bug with multi file upload

## 1.5.3

* **Added:** examples of form emdbed for astro and hugo
* **Fixed:** an issue with stripes width setting for Cropper element
* **Improved:** form editing - blocks are added to Form block automatically

## 1.5.2

* **Fixed:** Astra theme related wrong order for price tag element
* **Added:** new settings for price tag custom formatting
* **Improved:** UI related to products/catalog items

## 1.5.1

* **Fixed:** Displaying the form using Elementor's 'add to cart' widget
* **Improved:** Uni CPO migration failed with radio option type 'text' and pricing setup migration

## 1.5.0

* **Added:** new booking type 'seasonal' (catalog item functionality)
* **Added:** Order analytics
* **Added:** form field labels can use dynamic tags
* **Improved:** displaying WC taxes next to the product price
* **Fixed:** 'order again' functionality

## 1.4.1

* **Added:** new wp hook 'craftforms\_pre\_submit'
* **Improved:** Column 'Used In' now shows form usage in WC products
* **Improved:** Uni CPO migration script

## 1.4.0

* **Added:** Interactive elements
* **Added:** Image conditional logic
* **Added:** PDF Builder — design PDF templates and auto-generate documents from form submissions
* **Added:** Attach generated PDFs to submissions, WooCommerce orders, and emails
* **Added:** QR code / barcode form block
* **Added:** Migrate from Uni CPO (importer for existing Uni CPO products)
* **Added:** Translations for German, Spanish, Italian, Polish and Ukrainian
* **Fixed:** various UI and stability improvements

## 1.3.4

* **Fixed:** issue with some starters not being imported correctly in some languages
* **Added:** MU WP install full support

## 1.3.3

* **Updated:** radio/checkbox option blocks; added 'Card' swatch
* **Updated:** Pipe/Stickers starters
* **Added:** Added new starter Print Boards
* **Added:** New starter "Custom Table"
* **Added:** Export submissions to CSV
* **Added:** Export orders to CSV
* **Fixed:** bugs/issues in the UI of admin pages

## 1.3.2

* **Fixed:** PHP error required a non-existent file in the FREE version

## 1.3.1

* **Fixed:** WP Abilities API guard for older versions

## 1.3.0

* **Added:** repeater form field
* **Added:** colorpicker form field
* **Added:** range slider form field
* **Added:** new WC specific starters
* **Added:** Error messages style setting
* **Added:** Encrypting Stripe API keys in DB
* **Added:** dynamic SKU and stock management functionality

## 1.2.1

* **Added:** 8 starter forms and email templates
* **Fixed:** JS error related to datepicker
* **Fixed:** issue related to loading inline embedded payment fields

## 1.2.0

* **Added:** form embed functionality
* **Added:** WC integration
* **Added:** new form debug tool
* **Fixed:** duplicating forms messes with unique form ID

## 1.1.5

* **Fixed:** bug related to saving "Redirect Url" setting
* **Fixed:** correct render of catalog ID for connected form

## 1.1.4

* **Improved:** booking related settings, added from/until number of days datepicker availability
* **Added:** Elementor and Bricks native widgets/elements
* **Added:** submit action "Webhook"
* **Fixed:** a bug in the file upload field

## 1.1.3

* **Improved:** the accessibility of the forms
* **Fixed:** custom headers now automatically allowed for CORS for forms enabled for external submissions

## 1.1.2

* **Fixed:** "modern" styles for some field types
* **Fixed:** (PRO) bug in form submission and proper deducting stock level/booking availability

## 1.1.1

* **Fixed:** styling issue in Gutenberg;
* **Fixed:** bug in 'linked' smart variable when used with checkboxes;

## 1.1.0

* **Added:** commerce functionality, booking, new starters, styles, blocks and functionality

## 1.0.0

* Initial Release
