domma-cms 1.6.60 → 1.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (168) hide show
  1. package/CHANGELOG.md +4349 -0
  2. package/README.md +1 -1
  3. package/admin/dist/domma/domma-tools.css +3 -3
  4. package/admin/dist/domma/domma-tools.min.js +3 -3
  5. package/admin/js/lib/effect-defs.js +1 -1
  6. package/admin/js/lib/effects-builder.js +2 -2
  7. package/admin/js/lib/mail-compose.js +1 -0
  8. package/admin/js/lib/page-editor-reference.js +5 -5
  9. package/admin/js/lib/shortcode-tags.js +1 -1
  10. package/admin/js/templates/call-new.html +1 -1
  11. package/admin/js/templates/docs/usage-shortcodes.html +39 -0
  12. package/admin/js/views/call-new.js +1 -1
  13. package/admin/js/views/contacts.js +15 -15
  14. package/admin/js/views/form-submissions.js +2 -2
  15. package/docs/DommaFeatures.md +3005 -0
  16. package/docs/MultiTenant.md +176 -0
  17. package/docs/api-reference.md +1667 -0
  18. package/docs/cache.md +96 -0
  19. package/docs/configuration.md +1811 -0
  20. package/docs/editions-and-licences.md +190 -0
  21. package/docs/getting-started.md +201 -0
  22. package/docs/guides/form-triggers.md +260 -0
  23. package/docs/guides/mongodb-storage-adapter.md +282 -0
  24. package/docs/guides/multi-page-forms.md +121 -0
  25. package/docs/images/scribe-composer.png +0 -0
  26. package/docs/markdown-shortcodes.md +1738 -0
  27. package/docs/pentest-report-2026-04-03.md +181 -0
  28. package/docs/plans/2026-02-28-admin-topbar-login-forms.md +349 -0
  29. package/docs/plans/2026-02-28-domma-ui-polish.md +286 -0
  30. package/docs/plans/2026-02-28-reset-seed-fresh-commands.md +520 -0
  31. package/docs/plans/2026-03-02-cookie-consent-design.md +86 -0
  32. package/docs/plans/2026-03-02-cookie-consent-plugin.md +453 -0
  33. package/docs/plans/2026-03-02-tooltip-sweep-and-back-to-top-plugin-design.md +126 -0
  34. package/docs/plans/2026-03-02-tooltip-sweep-back-to-top.md +427 -0
  35. package/docs/plans/2026-03-05-cookie-consent-btt-core.md +115 -0
  36. package/docs/plans/2026-03-05-custom-css-migrate-to-core-design.md +35 -0
  37. package/docs/plans/2026-03-05-custom-css-migrate-to-core.md +352 -0
  38. package/docs/plans/2026-03-05-scribe-script-shortcode.md +373 -0
  39. package/docs/plans/2026-03-05-user-types-design.md +139 -0
  40. package/docs/plans/2026-03-05-user-types-implementation.md +1035 -0
  41. package/docs/plans/2026-03-09-page-editor-view-cta-inserts-design.md +78 -0
  42. package/docs/plans/2026-03-09-page-editor-view-cta-inserts.md +388 -0
  43. package/docs/plans/2026-03-09-pro-documentation-design.md +80 -0
  44. package/docs/plans/2026-03-09-pro-documentation.md +1017 -0
  45. package/docs/plans/2026-06-10-core-project-design.md +240 -0
  46. package/docs/plugin-development.md +827 -0
  47. package/docs/recruitment-recipe.md +501 -0
  48. package/docs/scaffolding.md +312 -0
  49. package/docs/screenshots/calculator-floating.png +0 -0
  50. package/docs/screenshots/calculator-standard.png +0 -0
  51. package/docs/screenshots/email-settings.png +0 -0
  52. package/docs/screenshots/messages-count.png +0 -0
  53. package/docs/structure/user-types.md +107 -0
  54. package/docs/superpowers/plans/2026-05-25-admin-sidebar-via-menus.md +1112 -0
  55. package/docs/superpowers/plans/2026-06-08-navbar-mobile-drawer-and-menu-enrichment.md +1161 -0
  56. package/docs/superpowers/plans/2026-06-25-domma-docs-project.md +695 -0
  57. package/docs/superpowers/plans/2026-06-26-surveys-HANDOFF.md +68 -0
  58. package/docs/superpowers/plans/2026-06-26-surveys-pro-plugin.md +1902 -0
  59. package/docs/superpowers/plans/2026-08-19-collection-context-sort-export.md +1577 -0
  60. package/docs/superpowers/plans/2026-10-09-content-api.md +1192 -0
  61. package/docs/superpowers/specs/2026-03-12-form-followup-actions-design.md +152 -0
  62. package/docs/superpowers/specs/2026-03-12-page-editor-form-insert-and-per-page-theme-design.md +115 -0
  63. package/docs/superpowers/specs/2026-03-17-nav-hidden-items-design.md +85 -0
  64. package/docs/superpowers/specs/2026-03-19-accordion-insert-design.md +175 -0
  65. package/docs/superpowers/specs/2026-03-25-static-block-shortcode-design.md +153 -0
  66. package/docs/superpowers/specs/2026-03-25-text-shortcode-design.md +168 -0
  67. package/docs/superpowers/specs/2026-04-05-card-builder-design.md +315 -0
  68. package/docs/superpowers/specs/2026-04-06-insert-builders-design.md +278 -0
  69. package/docs/superpowers/specs/2026-04-06-layouts-design.md +226 -0
  70. package/docs/superpowers/specs/2026-04-07-blog-plugin-design.md +300 -0
  71. package/docs/superpowers/specs/2026-04-07-calendar-plugin-design.md +538 -0
  72. package/docs/superpowers/specs/2026-04-17-components-area-design.md +368 -0
  73. package/docs/superpowers/specs/2026-05-02-effects-slideover-overhaul-design.md +193 -0
  74. package/docs/superpowers/specs/2026-05-06-dashboard-rebuild-design.md +257 -0
  75. package/docs/superpowers/specs/2026-05-24-menus-design.md +466 -0
  76. package/docs/superpowers/specs/2026-05-25-admin-sidebar-via-menus-design.md +358 -0
  77. package/docs/superpowers/specs/2026-05-25-projects-design.md +380 -0
  78. package/docs/superpowers/specs/2026-06-08-navbar-mobile-drawer-and-menu-enrichment-design.md +292 -0
  79. package/docs/superpowers/specs/2026-06-08-sidebar-tools-plugins-folders-design.md +59 -0
  80. package/docs/superpowers/specs/2026-06-25-domma-docs-project-design.md +192 -0
  81. package/docs/superpowers/specs/2026-06-26-domma-charts-upstream-proposal.md +44 -0
  82. package/docs/superpowers/specs/2026-06-26-manager-scheduler-upstream-proposal.md +46 -0
  83. package/docs/superpowers/specs/2026-06-26-surveys-pro-plugin-design.md +206 -0
  84. package/docs/superpowers/specs/2026-07-02-shortcode-context-menu-design.md +96 -0
  85. package/docs/superpowers/specs/2026-08-19-collection-context-sort-export-design.md +330 -0
  86. package/docs/superpowers/specs/2026-09-22-dcms-marketplace-design.md +1150 -0
  87. package/docs/superpowers/specs/2026-10-09-content-api-design.md +325 -0
  88. package/docs/superpowers/specs/plans/2026-03-12-form-followup-actions.md +624 -0
  89. package/docs/superpowers/specs/plans/2026-03-12-page-editor-form-insert-and-per-page-theme.md +125 -0
  90. package/docs/superpowers/specs/plans/2026-03-17-nav-hidden-items.md +578 -0
  91. package/docs/superpowers/specs/plans/2026-03-19-accordion-insert.md +635 -0
  92. package/docs/superpowers/specs/plans/2026-03-25-text-shortcode.md +545 -0
  93. package/docs/superpowers/specs/plans/2026-04-05-card-builder.md +1970 -0
  94. package/docs/superpowers/specs/plans/2026-04-06-insert-builders.md +1049 -0
  95. package/docs/superpowers/specs/plans/2026-04-06-layouts.md +1015 -0
  96. package/docs/superpowers/specs/plans/2026-04-07-calendar-plugin.md +1526 -0
  97. package/docs/superpowers/specs/plans/2026-04-08-plugin-monetisation-split.md +242 -0
  98. package/docs/superpowers/specs/plans/2026-04-17-components-area.md +2038 -0
  99. package/docs/superpowers/specs/plans/2026-05-02-effects-slideover-overhaul.md +2335 -0
  100. package/docs/superpowers/specs/plans/2026-05-06-dashboard-rebuild.md +1999 -0
  101. package/docs/superpowers/specs/plans/2026-05-17-cache-system.md +1436 -0
  102. package/docs/superpowers/specs/plans/2026-05-24-menus.md +3096 -0
  103. package/docs/superpowers/specs/plans/2026-05-25-projects.md +2869 -0
  104. package/docs/superpowers/specs/plans/2026-09-22-marketplace-step2-consolidation.md +505 -0
  105. package/docs/superpowers/specs/plans/2026-09-22-marketplace-step3-catalogue-and-key.md +154 -0
  106. package/docs/superpowers/specs/plans/2026-09-22-tools-promotion.md +260 -0
  107. package/docs/theming.md +320 -0
  108. package/package.json +2 -2
  109. package/plugins/_lib/admin/mail/compose-window.js +3 -1
  110. package/plugins/_lib/admin/mail/identity.js +18 -3
  111. package/plugins/_lib/admin/mail/reader-view.js +32 -3
  112. package/plugins/blog/CLAUDE.md +4 -0
  113. package/plugins/blog/admin/lib/email.js +191 -0
  114. package/plugins/blog/admin/views/comments.js +3 -1
  115. package/plugins/blog/plugin.json +2 -2
  116. package/plugins/blog/plugin.public.js +1 -1
  117. package/plugins/blog/tests/email.test.js +69 -0
  118. package/plugins/booking/CLAUDE.md +4 -0
  119. package/plugins/booking/admin/lib/email.js +191 -0
  120. package/plugins/booking/admin/views/panels.js +7 -3
  121. package/plugins/booking/plugin.json +1 -1
  122. package/plugins/booking/tests/email.test.js +69 -0
  123. package/plugins/free-tier.lock.json +27 -19
  124. package/plugins/shopping-cart/CLAUDE.md +4 -0
  125. package/plugins/shopping-cart/admin/lib/email.js +191 -0
  126. package/plugins/shopping-cart/admin/views/orders.js +11 -3
  127. package/plugins/shopping-cart/plugin.json +2 -2
  128. package/plugins/shopping-cart/tests/email.test.js +69 -0
  129. package/plugins/support/CLAUDE.md +4 -0
  130. package/plugins/support/admin/lib/email.js +191 -0
  131. package/plugins/support/admin/views/desk.js +4 -1
  132. package/plugins/support/admin/views/inbox.js +6 -2
  133. package/plugins/support/plugin.json +2 -2
  134. package/plugins/support/tests/email.test.js +69 -0
  135. package/public/js/celebrations/core/canvas.js +1 -1
  136. package/public/js/celebrations/index.js +1 -1
  137. package/public/js/celebrations/licenses/ABeeZee-Regular-OFL.txt +93 -0
  138. package/public/js/celebrations/licenses/Allura-Regular-OFL.txt +93 -0
  139. package/public/js/celebrations/message-attrs.mjs +1 -0
  140. package/public/js/celebrations/themes/anniversary.js +1 -0
  141. package/public/js/celebrations/themes/autumn.js +1 -0
  142. package/public/js/celebrations/themes/birthday.js +1 -0
  143. package/public/js/celebrations/themes/butterfly-flight.js +1 -0
  144. package/public/js/celebrations/themes/calendar.js +1 -0
  145. package/public/js/celebrations/themes/chinese-new-year-dates.js +1 -0
  146. package/public/js/celebrations/themes/chinese-new-year.js +1 -0
  147. package/public/js/celebrations/themes/christmas.js +1 -1
  148. package/public/js/celebrations/themes/easter.js +1 -0
  149. package/public/js/celebrations/themes/garden-drawing.js +1 -0
  150. package/public/js/celebrations/themes/garden.js +1 -0
  151. package/public/js/celebrations/themes/graduation.js +1 -0
  152. package/public/js/celebrations/themes/greeting.js +1 -0
  153. package/public/js/celebrations/themes/make-it-rain.js +1 -0
  154. package/public/js/celebrations/themes/money-rain.js +1 -0
  155. package/public/js/celebrations/themes/new-year.js +1 -0
  156. package/public/js/celebrations/themes/occasion-drawing.js +1 -0
  157. package/public/js/celebrations/themes/occasions.js +1 -0
  158. package/public/js/celebrations/themes/rain-control.js +1 -0
  159. package/public/js/celebrations/themes/sparkler-font-data.js +1 -0
  160. package/public/js/celebrations/themes/sparkler-font.js +1 -0
  161. package/public/js/celebrations/themes/sparkler-writing.js +1 -0
  162. package/public/js/celebrations/themes/summer-garden.js +1 -0
  163. package/public/js/celebrations/themes/winter.js +1 -0
  164. package/public/js/celebrations/trait-data.mjs +1 -1
  165. package/public/js/effects.js +1 -1
  166. package/scripts/build.js +4 -0
  167. package/server/services/markdown.js +5 -2
  168. package/server/templates/page.html +1 -1
@@ -0,0 +1,282 @@
1
+ # MongoDB Storage Adapter (Pro Feature)
2
+
3
+ Domma CMS stores collection entries as JSON files by default. The MongoDB Storage Adapter is an optional Pro feature
4
+ that lets you store collection entries in a MongoDB database instead - with zero changes to the CMS admin interface.
5
+
6
+ ---
7
+
8
+ ## Why Use It
9
+
10
+ | Reason | Detail |
11
+ |-------------------|------------------------------------------------------------|
12
+ | **Scale** | Handle thousands of entries without directory I/O overhead |
13
+ | **Query power** | Rich filtering, sorting, and aggregation via MongoDB |
14
+ | **Mixed mode** | Some collections on MongoDB, others on file - your choice |
15
+ | **Seamless swap** | Change one line in `schema.json`; no code changes needed |
16
+
17
+ ---
18
+
19
+ ## Prerequisites
20
+
21
+ - MongoDB 6.0 or later (local or hosted - MongoDB Atlas works)
22
+ - Node.js 24+
23
+ - Domma CMS 0.4.0+
24
+
25
+ ---
26
+
27
+ ## Quick Setup
28
+
29
+ The fastest way to enable Pro mode:
30
+
31
+ ```bash
32
+ npm run pro enable
33
+ ```
34
+
35
+ This will:
36
+
37
+ 1. Copy `config/connections.json.example` → `config/connections.json`
38
+ 2. Prompt you for your MongoDB URI and database name
39
+ 3. Run `npm install mongodb`
40
+
41
+ Then restart the server and configure individual collections (see below).
42
+
43
+ ---
44
+
45
+ ## Manual Setup
46
+
47
+ If you prefer to configure manually:
48
+
49
+ ### 1. Copy the example connections file
50
+
51
+ ```bash
52
+ cp config/connections.json.example config/connections.json
53
+ ```
54
+
55
+ ### 2. Edit `config/connections.json`
56
+
57
+ ```json
58
+ {
59
+ "default": {
60
+ "type": "mongodb",
61
+ "uri": "mongodb://localhost:27017",
62
+ "database": "domma_cms",
63
+ "options": {}
64
+ }
65
+ }
66
+ ```
67
+
68
+ | Field | Description |
69
+ |------------|------------------------------------------------|
70
+ | `type` | Must be `"mongodb"` |
71
+ | `uri` | MongoDB connection string |
72
+ | `database` | Name of the database to use |
73
+ | `options` | Optional extra options passed to `MongoClient` |
74
+
75
+ > `config/connections.json` is gitignored - credentials stay local and are never committed.
76
+
77
+ ### 3. Install the mongodb package
78
+
79
+ ```bash
80
+ npm install mongodb
81
+ ```
82
+
83
+ ### 4. Restart the server
84
+
85
+ ```bash
86
+ npm start
87
+ ```
88
+
89
+ You should see connection log lines like:
90
+
91
+ ```
92
+ [connectionManager] Connected: default → domma_cms
93
+ ```
94
+
95
+ ---
96
+
97
+ ## Multiple Connections
98
+
99
+ You can define any number of named connections:
100
+
101
+ ```json
102
+ {
103
+ "default": {
104
+ "type": "mongodb",
105
+ "uri": "mongodb://localhost:27017",
106
+ "database": "domma_cms",
107
+ "options": {}
108
+ },
109
+ "atlas": {
110
+ "type": "mongodb",
111
+ "uri": "mongodb+srv://user:pass@cluster.mongodb.net",
112
+ "database": "domma_prod",
113
+ "options": {}
114
+ }
115
+ }
116
+ ```
117
+
118
+ Each collection then references a connection by name in its `schema.json`.
119
+
120
+ ---
121
+
122
+ ## Connections in the admin
123
+
124
+ Admins can edit `config/connections.json` on the **Database connections** tab of **Collections** (`GET`/`PUT /api/collections/connections`)
125
+ instead of by hand; URIs are masked on screen. Connections are opened at startup, so restart after adding or changing
126
+ one.
127
+
128
+ If a connection fails, collections on it fall back to file storage and the admin raises a critical **Database
129
+ unavailable** notification (source `core:storage`) naming the connection, so the empty lists are explained.
130
+
131
+ ---
132
+
133
+ ## Switching a Collection to MongoDB
134
+
135
+ Edit the collection's `schema.json` and add a `storage` block:
136
+
137
+ ```json
138
+ {
139
+ "slug": "products",
140
+ "title": "Products",
141
+ "fields": [...],
142
+ "storage": {
143
+ "adapter": "mongodb",
144
+ "connection": "default"
145
+ }
146
+ }
147
+ ```
148
+
149
+ | Field | Required | Default | Description |
150
+ |----------------------|----------|-------------|------------------------------------------|
151
+ | `storage.adapter` | Yes | `"file"` | Set to `"mongodb"` to use MongoDB |
152
+ | `storage.connection` | No | `"default"` | Named connection from `connections.json` |
153
+
154
+ The easier way is the collection editor's **Storage** tab (shown once a connection exists): choose the adapter and
155
+ connection and it moves the existing entries across for you (`POST /api/collections/:slug/migrate-storage`), with no
156
+ restart. Moved entries are created afresh in the new store, so they get **new ids and dates** - references to them
157
+ from other collections do not follow. When moving off file storage, the old `data.json` is kept as `data.json.bak`.
158
+
159
+ If you edit `schema.json` by hand instead, **restart the server**: the adapter registry caches each collection's
160
+ adapter, and only a save through the CMS (or a restart) clears it. A hand edit moves no entries.
161
+
162
+ ---
163
+
164
+ ## Switching Back to File-Based
165
+
166
+ Remove the `storage` block from `schema.json`:
167
+
168
+ ```json
169
+ {
170
+ "slug": "products",
171
+ "title": "Products",
172
+ "fields": [...]
173
+ }
174
+ ```
175
+
176
+ > **Important:** a hand edit does not move entries back to files. Use the Storage tab, which moves them (with new ids,
177
+ > as above), or export and re-import them.
178
+
179
+ ---
180
+
181
+ ## Mixed Mode
182
+
183
+ Collections can use different adapters independently:
184
+
185
+ ```
186
+ ┌─────────────────────────────────────────────┐
187
+ │ Domma CMS Collections │
188
+ ├──────────────────┬──────────────────────────┤
189
+ │ products │ → MongoAdapter (default) │
190
+ │ blog-posts │ → MongoAdapter (atlas) │
191
+ │ testimonials │ → FileAdapter │
192
+ │ roles │ → FileAdapter (always) │
193
+ └──────────────────┴──────────────────────────┘
194
+ ```
195
+
196
+ Preset collections - `roles`, `user-profiles`, `projects` and the rest defined in `server/services/presetCollections.js`
197
+ (notes, todo items, contacts and others) - always use the file adapter, whatever their `storage` block says
198
+ (`server/services/adapterRegistry.js`).
199
+
200
+ ---
201
+
202
+ ## How It Works Internally
203
+
204
+ | Component | File | Role |
205
+ |---------------------|--------------------------------------------|--------------------------------------------------------------------------|
206
+ | Connection Manager | `server/services/connectionManager.js` | Creates and caches `MongoClient` instances at startup |
207
+ | Adapter Registry | `server/services/adapterRegistry.js` | Reads `schema.json` and resolves the correct adapter per collection |
208
+ | File Adapter | `server/services/adapters/FileAdapter.js` | Default; reads/writes JSON files in `content/collections/` |
209
+ | Mongo Adapter | `server/services/adapters/MongoAdapter.js` | Reads/writes documents in MongoDB; prefixes collection names with `cms_` |
210
+ | Collections Service | `server/services/collections.js` | Orchestrates CRUD, delegates I/O to the resolved adapter |
211
+
212
+ ### Startup flow
213
+
214
+ 1. Server reads `config/connections.json` (if present)
215
+ 2. `connectionManager.initialise()` connects to all named MongoDB servers
216
+ 3. Each collection schema is read lazily on first request
217
+ 4. `adapterRegistry.getAdapter(slug)` resolves and caches the adapter
218
+
219
+ ### Request flow (entry read/write)
220
+
221
+ ```
222
+ API route → collections.js → adapterRegistry.getAdapter(slug)
223
+ │
224
+ ┌────────────────┴─────────────────┐
225
+ │ │
226
+ FileAdapter MongoAdapter
227
+ (content/collections/) (MongoDB via getDb())
228
+ ```
229
+
230
+ ---
231
+
232
+ ## Checking Status
233
+
234
+ ```bash
235
+ npm run pro status
236
+ ```
237
+
238
+ Example output (Pro enabled):
239
+
240
+ ```
241
+ Pro Mode Status
242
+ ───────────────
243
+ Mode : Pro (MongoDB)
244
+ mongodb : installed ✓
245
+
246
+ Connections (1):
247
+ • default
248
+ URI : mongodb://localhost:27017
249
+ Database : domma_cms
250
+ ```
251
+
252
+ MongoDB URIs with passwords are automatically masked (`****`).
253
+
254
+ ---
255
+
256
+ ## Disabling Pro Mode
257
+
258
+ ```bash
259
+ npm run pro disable
260
+ ```
261
+
262
+ This backs up `config/connections.json` to `config/connections.json.bak` and optionally uninstalls the `mongodb`
263
+ package. The server falls back to file-based storage on next restart.
264
+
265
+ To re-enable, run `npm run pro enable` or rename the backup:
266
+
267
+ ```bash
268
+ mv config/connections.json.bak config/connections.json
269
+ ```
270
+
271
+ ---
272
+
273
+ ## Troubleshooting
274
+
275
+ | Symptom | Cause | Fix |
276
+ |-----------------------------------------------------------|--------------------------------------------------------------------|-----------------------------------------------------------------|
277
+ | No `[connectionManager] Connected` log line | `config/connections.json` missing or mongodb not installed | Run `npm run pro enable` |
278
+ | `Failed to connect "default"` in logs | Wrong URI, MongoDB not running, or network issue | Check URI in `connections.json` and ensure MongoDB is reachable |
279
+ | `[adapterRegistry] Failed to load MongoAdapter` | `mongodb` package not installed or connection failed | Run `npm install mongodb`, check connection logs |
280
+ | Collection entries appear empty after switching | `schema.json` was edited by hand, which moves no entries | Switch with the editor's Storage tab, or export and re-import |
281
+ | `Unknown connection: "name"` error | Connection name in `schema.json` not defined in `connections.json` | Add the named connection to `connections.json` and restart |
282
+ | A preset collection (`roles`, …) ignores `storage` config | By design - system collections always use file storage | No fix needed; this is intentional |
@@ -0,0 +1,121 @@
1
+ # Multi-Page Forms (Wizards)
2
+
3
+ Any form in the Form Builder becomes a wizard by adding a **Page Break**. Fields before the
4
+ break are page one, fields after it are page two, and so on. The visitor moves through with
5
+ Previous / Next and submits from the last page.
6
+
7
+ There is no separate "wizard mode" to switch on - the page breaks are the switch.
8
+
9
+ ---
10
+
11
+ ## Building one
12
+
13
+ In **Forms → edit a form**, use **Add Page Break** between the fields you want to separate.
14
+ Each break carries two fields of its own:
15
+
16
+ | Field | Effect |
17
+ |-----------------|---------------------------------------------------------------|
18
+ | **Step Title** | Heading shown above that page |
19
+ | **Description** | Smaller line under the heading; leave blank to omit it |
20
+
21
+ The first page has no break before it, so it takes its heading from the form's own title.
22
+ Give it a different one by putting a page break at the very top - a break with nothing before
23
+ it re-titles the page that follows rather than creating an empty page of its own.
24
+
25
+ A break at the very end is ignored for the same reason: it would produce a final page holding
26
+ nothing but the button.
27
+
28
+ ---
29
+
30
+ ## Layout
31
+
32
+ Forms are laid out as a **grid** unless you choose otherwise, two columns by
33
+ default and three if you set Columns to 3 - those are the only two the renderer
34
+ produces. A field can be widened with its **Column Span**, or set to **Full
35
+ Width** to take the whole row.
36
+
37
+ Stacked and Inline are still there under **Settings → Layout** if a form reads
38
+ better one field per line.
39
+
40
+ **Settings → Submit Button Position** does not move a wizard's buttons: Previous
41
+ and Next / Finish stay at the two ends of the footer on every page, so the button
42
+ never jumps under the visitor's pointer between steps.
43
+
44
+ The rest of the **Submit Button** card does reach the footer: **Style** and
45
+ **Size** apply to Next and Finish, the icons to Finish only, and Previous takes
46
+ the size. A **second button** (Clear form or a Cancel link) is not shown on a
47
+ multi-step form - Clear on a later page could not clear the pages already
48
+ answered, and the footer already has Previous.
49
+
50
+ ---
51
+
52
+ ## What carries across pages
53
+
54
+ Everything the single-page form does is applied to each page as the visitor reaches it.
55
+
56
+ | Feature | Behaviour across pages |
57
+ |------------------------|-----------------------------------------------------------------------|
58
+ | **Layout / columns** | The form's Layout and Columns settings apply to every page |
59
+ | **Field spans** | A field set to span the full width does so on whichever page it is on |
60
+ | **Date fields** | Render as native date pickers on every page |
61
+ | **Icon / image fields**| Keep their Browse buttons and previews on every page |
62
+ | **Spacers** | Rendered in place on the page they belong to |
63
+ | **File uploads** | A file chosen on page one is still attached when page three submits |
64
+ | **Conditional logic** | A rule on page two can test an answer given on page one |
65
+ | **Spam protection** | The honeypot and timing check cover the submission, not just page one |
66
+
67
+ Answers are accumulated as the visitor advances, so going **Previous** and changing an answer
68
+ re-evaluates any rule that depends on it.
69
+
70
+ ---
71
+
72
+ ## Validation
73
+
74
+ Each page validates before it will let the visitor move on - required fields must be filled
75
+ and format rules must pass. The server re-checks everything on submit regardless of what the
76
+ browser allowed, including conditional requirements that depend on answers from other pages.
77
+
78
+ ---
79
+
80
+ ## Preview
81
+
82
+ The builder's live preview renders the wizard exactly as the public page does: same layout,
83
+ same page splitting, same titles. Stepping through the preview is a fair test of the real
84
+ thing. The preview submits to the real endpoint once the form has been saved, so test
85
+ submissions are stored like any other.
86
+
87
+ ---
88
+
89
+ ## Notes and limits
90
+
91
+ - **Don't name a field `website`.** It is the name used by the spam honeypot. The CMS steps
92
+ the honeypot aside if you do, but a clearer field name (`your_website`, `company_url`)
93
+ avoids the question entirely.
94
+ - **Field names must be unique across the whole form**, not just within a page. Two pages
95
+ using the same name will overwrite one another.
96
+ - A form made only of page breaks renders as a single empty page.
97
+
98
+ ---
99
+
100
+ ## Where a form is rendered from
101
+
102
+ Three different pieces of code render a form, depending on how it reaches the
103
+ page. They behave identically, but knowing which one is in play saves time when
104
+ something looks wrong:
105
+
106
+ | How the form got there | Rendered by |
107
+ |----------------------------------------|---------------------------------|
108
+ | `[form slug="…" /]` in page content | `public/js/site.js` |
109
+ | A hand-written `<div data-form="…">` | `public/js/forms.js` |
110
+ | The builder's live preview | `admin/js/views/form-editor.js` |
111
+
112
+ All three share `public/js/form-steps.mjs` for splitting a form into pages.
113
+
114
+ ---
115
+
116
+ ## Related
117
+
118
+ - [Form Triggers](form-triggers.md)
119
+
120
+ - `docs/configuration.md` - form settings schema
121
+ - Admin → Forms → Settings tab - layout, columns, honeypot, rate limit, and the Submit Button card (text, position, style, size, icons, second button)
Binary file