Skip to content

Commit a1df06f

Browse files
committed
docs: add comprehensive WordPress plugin guide
- docs/WORDPRESS_PLUGIN.md: full guide covering installation (self-hosted + WordPress.com), configuration (settings page, Test Connection), usage (shortcode with all attributes and examples, Gutenberg block step-by-step), architecture explanation (JS vs iframe modes, data flow), troubleshooting (common issues with solutions), uninstalling, file structure reference, and security (attribute sanitization table) - docs/EMBEDDING.md: cross-reference to new WordPress plugin guide - CHANGELOG.md: v0.60.0 updated with WordPress plugin docs - README.md: embeddable forms feature highlight
1 parent 412b62e commit a1df06f

File tree

2 files changed

+229
-1
lines changed

2 files changed

+229
-1
lines changed

docs/EMBEDDING.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ The iframe will not auto-resize in this mode. Set an appropriate `min-height` fo
9191

9292
## WordPress Plugin
9393

94-
The **DFW Forms** WordPress plugin provides a shortcode and Gutenberg block for easy embedding.
94+
The **DFW Forms** WordPress plugin provides a shortcode and Gutenberg block for easy embedding. For full installation, configuration, troubleshooting, and security details, see the **[WordPress Plugin Guide](WORDPRESS_PLUGIN.md)**.
9595

9696
### Installation
9797

@@ -165,6 +165,7 @@ Anonymous embed submissions are rate-limited to prevent spam. Configure rate lim
165165

166166
## Related Docs
167167

168+
- [WordPress Plugin Guide](WORDPRESS_PLUGIN.md) — full plugin installation, usage, troubleshooting, and security
168169
- [Payments](PAYMENTS.md) — payment collection in embedded forms
169170
- [Shared Option Lists](SHARED_OPTION_LISTS.md) — centrally managed choice lists
170171
- [Workflows](WORKFLOWS.md) — approval workflows that process embed submissions

docs/WORDPRESS_PLUGIN.md

Lines changed: 227 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
1+
# WordPress Plugin — DFW Forms
2+
3+
The **DFW Forms** WordPress plugin lets you embed Django Forms Workflows forms on any WordPress page or post using a shortcode or Gutenberg block. All form rendering, validation, and submission happens on your DFW server — WordPress only hosts the iframe container.
4+
5+
## Prerequisites
6+
7+
Before using the plugin, you need:
8+
9+
1. A running Django Forms Workflows server accessible via HTTPS (e.g. `https://forms.example.com`)
10+
2. At least one form with **embed_enabled** checked (Django Admin → Form Definition → API & Embedding → Embed enabled)
11+
3. For public forms, **requires_login** should be unchecked so anonymous visitors can submit
12+
13+
## Installation
14+
15+
### Self-hosted WordPress (WordPress.org)
16+
17+
1. Download or clone the `wordpress/dfw-forms/` folder from the [django-forms-workflows repository](https://github.com/opensensor/django-forms-workflows).
18+
2. Copy the entire `dfw-forms/` folder into your WordPress installation at `/wp-content/plugins/`:
19+
20+
```
21+
wp-content/
22+
└── plugins/
23+
└── dfw-forms/
24+
├── dfw-forms.php
25+
├── includes/
26+
├── blocks/
27+
├── assets/
28+
├── uninstall.php
29+
└── readme.txt
30+
```
31+
32+
3. In WordPress admin, go to **Plugins** and activate **DFW Forms**.
33+
34+
### WordPress.com
35+
36+
- **Business plan or higher**: Upload via **Plugins → Add New → Upload Plugin** (zip the `dfw-forms/` folder first). Use `mode="iframe"` in shortcodes since WordPress.com may strip external `<script>` tags.
37+
- **Free / Personal / Premium plans**: Custom plugins are not supported. Use the [plain iframe method](EMBEDDING.md#iframe-fallback) in a Custom HTML block instead.
38+
39+
## Configuration
40+
41+
After activation, go to **Settings → DFW Forms**:
42+
43+
1. Enter your **DFW Server URL** — the base URL without a trailing slash (e.g. `https://forms.example.com`).
44+
2. Click **Test Connection** to verify the server is reachable.
45+
3. Click **Save Changes**.
46+
47+
The settings page also shows a quick-reference table of all shortcode attributes.
48+
49+
## Usage
50+
51+
### Method 1: Shortcode
52+
53+
Add the `[dfw_form]` shortcode to any page, post, or widget area:
54+
55+
```
56+
[dfw_form slug="contact-us"]
57+
```
58+
59+
#### Shortcode attributes
60+
61+
| Attribute | Required | Default | Description |
62+
|-----------|----------|---------|-------------|
63+
| `slug` | **Yes** || Form slug from your DFW server |
64+
| `server` | No | Settings value | Override the global server URL for this specific form |
65+
| `theme` | No || `light` or `dark` |
66+
| `accent_color` | No || Hex color for primary buttons (e.g. `#0d6efd`) |
67+
| `min_height` | No | `300` | Minimum iframe height in pixels |
68+
| `loading_text` | No | `Loading form...` | Text shown while the form loads |
69+
| `mode` | No | `js` | `js` (auto-resize) or `iframe` (plain fallback) |
70+
| `on_submit` | No || JavaScript function name called after successful submission |
71+
| `on_load` | No || JavaScript function name called when the form finishes loading |
72+
73+
#### Examples
74+
75+
Basic embed:
76+
```
77+
[dfw_form slug="contact-us"]
78+
```
79+
80+
Dark theme with custom accent color:
81+
```
82+
[dfw_form slug="feedback" theme="dark" accent_color="#ff6600"]
83+
```
84+
85+
Taller form with iframe fallback (for WordPress.com):
86+
```
87+
[dfw_form slug="application" min_height="800" mode="iframe"]
88+
```
89+
90+
With JavaScript callback for analytics:
91+
```
92+
[dfw_form slug="survey" on_submit="trackFormSubmission"]
93+
```
94+
95+
```html
96+
<script>
97+
function trackFormSubmission(data) {
98+
// data.submissionId is available
99+
gtag('event', 'form_submit', {
100+
form_slug: data.formSlug,
101+
submission_id: data.submissionId
102+
});
103+
}
104+
</script>
105+
```
106+
107+
Using a different server for one form:
108+
```
109+
[dfw_form slug="external-form" server="https://other-server.example.com"]
110+
```
111+
112+
### Method 2: Gutenberg Block
113+
114+
1. In the WordPress block editor, click **+** (Add Block).
115+
2. Search for **DFW Form**.
116+
3. Enter the form slug and click **Embed Form**.
117+
4. The block shows a **live preview** of the form inside the editor.
118+
5. Use the **block sidebar** (Settings panel on the right) to configure:
119+
- **Form Slug** — change the embedded form
120+
- **Theme** — Default, Light, or Dark
121+
- **Accent Color** — hex color for buttons
122+
- **Minimum Height** — slider from 100 to 1200px
123+
- **Embed Mode** — JS (auto-resize) or iframe (plain fallback)
124+
125+
The block renders server-side using the same shared rendering logic as the shortcode, so the output is identical.
126+
127+
### Multiple forms on one page
128+
129+
Both methods support multiple forms on the same page. Each instance gets a unique container and operates independently:
130+
131+
```
132+
[dfw_form slug="contact-us"]
133+
134+
[dfw_form slug="feedback" theme="dark"]
135+
136+
[dfw_form slug="newsletter-signup" accent_color="#28a745"]
137+
```
138+
139+
## How it works
140+
141+
Understanding the architecture helps with troubleshooting:
142+
143+
1. **JS mode** (`mode="js"`, the default): The plugin outputs a `<div>` container and a `<script>` tag pointing to `dfw-embed.js` on your DFW server. When the page loads, the script creates an `<iframe>` inside the container pointing to `https://your-server/forms/<slug>/embed/`. A `ResizeObserver` inside the iframe detects content height changes and sends `dfw:resize` messages via `postMessage` to the parent page, which adjusts the iframe height automatically.
144+
145+
2. **iframe mode** (`mode="iframe"`): The plugin outputs a plain `<iframe>` tag directly. No JavaScript is involved — the iframe has a fixed `min-height`. This is the fallback for environments that strip external scripts.
146+
147+
In both modes, **no form data passes through WordPress**. The iframe points directly to your DFW server, and all form validation, submission, file uploads, and payment processing happen server-side on the DFW server.
148+
149+
## Troubleshooting
150+
151+
### Form doesn't appear
152+
153+
- Verify the form slug is correct — it must match exactly (check Django admin → Form Definitions → slug field)
154+
- Ensure **embed_enabled** is checked on the form in Django admin
155+
- Ensure the form **is_active** is checked
156+
- Check that the DFW server URL in WordPress settings is correct and reachable (use the **Test Connection** button)
157+
- Check the browser console for errors (F12 → Console)
158+
159+
### Form appears but can't be submitted
160+
161+
- For public forms, ensure **requires_login** is unchecked in Django admin
162+
- Check that your DFW server uses HTTPS — the embed view sets `SameSite=None; Secure` on the CSRF cookie, which requires HTTPS
163+
- If using a Content Security Policy on your WordPress site, add your DFW server to the `frame-src` directive:
164+
```
165+
Content-Security-Policy: frame-src https://forms.example.com;
166+
```
167+
168+
### Form doesn't auto-resize (JS mode)
169+
170+
- Check the browser console for `postMessage` errors
171+
- Verify the DFW server URL uses the correct protocol (http vs https)
172+
- Some WordPress security plugins block inline scripts — try `mode="iframe"` as a workaround
173+
174+
### WordPress.com specific
175+
176+
- External `<script>` tags may be stripped on some plans — always use `mode="iframe"` on WordPress.com
177+
- The Gutenberg block works on Business plans and above
178+
- Free/Personal/Premium plans: use the [plain iframe method](EMBEDDING.md#iframe-fallback) in a Custom HTML block
179+
180+
## Uninstalling
181+
182+
Deactivating the plugin removes the shortcode and block registration. Deleting the plugin (via WordPress admin or by removing the `dfw-forms/` folder) also cleans up the `dfw_forms_server_url` option from the WordPress database via the `uninstall.php` hook.
183+
184+
## Plugin file structure
185+
186+
```
187+
dfw-forms/
188+
├── dfw-forms.php # Main plugin file, activation + registration
189+
├── includes/
190+
│ ├── class-dfw-render.php # Shared HTML rendering (JS + iframe modes)
191+
│ ├── class-dfw-settings.php # Settings page (Settings → DFW Forms)
192+
│ └── class-dfw-shortcode.php # [dfw_form] shortcode handler
193+
├── blocks/
194+
│ └── dfw-form/
195+
│ ├── block.json # Gutenberg block metadata + attributes
196+
│ ├── edit.js # Block editor component (no build step)
197+
│ ├── render.php # Server-side render for the block
198+
│ └── editor.css # Editor-specific styles
199+
├── assets/
200+
│ ├── css/admin.css # Admin settings page styles
201+
│ └── js/admin.js # Test Connection button logic
202+
├── uninstall.php # Cleanup on plugin deletion
203+
└── readme.txt # WordPress.org-style readme
204+
```
205+
206+
## Security
207+
208+
All shortcode attributes are sanitized:
209+
210+
| Attribute | Sanitization |
211+
|-----------|-------------|
212+
| `slug` | `sanitize_title()` — only lowercase alphanumeric and hyphens |
213+
| `server` | `esc_url()` — must be a valid URL |
214+
| `theme` | Whitelist: `light`, `dark`, or empty |
215+
| `accent_color` | Regex: must match `#[0-9a-fA-F]{3,8}` |
216+
| `min_height` | `absint()` — positive integer only |
217+
| `loading_text` | `sanitize_text_field()` — strips tags and encoding |
218+
| `on_submit` / `on_load` | Regex: valid JS identifier chars only (`[a-zA-Z_$][a-zA-Z0-9_$.]*`) |
219+
| `mode` | Whitelist: `js` or `iframe` |
220+
221+
The plugin does not execute any user-supplied JavaScript directly. Callback names are validated but only passed as `data-*` attributes — the `dfw-embed.js` script on the DFW server handles the actual function lookup via `window[callbackName]`.
222+
223+
## Related docs
224+
225+
- [Embedding Guide](EMBEDDING.md) — JS loader, iframe fallback, postMessage protocol
226+
- [Payments](PAYMENTS.md) — payment collection in embedded forms
227+
- [Workflows](WORKFLOWS.md) — approval workflows triggered by embed submissions

0 commit comments

Comments
 (0)