> 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/form-building/embedding-forms-with-shortcodes.md).

# Embedding Forms With Shortcodes

CraftForms registers **two** shortcodes. Both render a form you have built in the CraftForms editor, but they serve different targets:

| Shortcode                  | Renders                                                                             | Use it for                                                                                                |
| -------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------- |
| `[craftforms]`             | The form **inline**, server-side (`do_blocks()`)                                    | Any WordPress page/post/widget/page-builder that runs PHP                                                 |
| `[craftforms_static_form]` | A lightweight **embed placeholder** that fetches the live form over REST at runtime | Static-site exports / headless front ends (Astro, Hugo, [Builderius](https://builderius.io/) static site) |

***

### `[craftforms]` — inline render <a href="#craftforms--inline-render" id="craftforms--inline-render"></a>

Renders the selected form directly into the page and force-enqueues exactly the assets that form needs (Stripe, PayPal, file upload, booking datepicker, etc.). This is the universal embed path for page builders that can't drop in WordPress post content — paste it into Builderius' Shortcode module, a Bricks/Elementor shortcode/text element, a Gutenberg Shortcode block, or a widget.

#### Attributes <a href="#attributes" id="attributes"></a>

| Attribute      | Default | Required | Description                                                                                                                                                                            |
| -------------- | ------- | :------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `form`         | —       |     ✅    | Form **post ID**. Nothing renders if missing/empty.                                                                                                                                    |
| `catalog-item` | `0`     |          | Catalog **resource ID** (PRO). Scopes the form's field options, pricing formula, smart-variable overrides and booking availability to that catalog resource. Ignored on the free plan. |
| `product`      | `0`     |          | WooCommerce **product ID** (PRO + WooCommerce). Renders the form as that product's add-to-cart form on **any** page — see below.                                                       |

#### Examples <a href="#examples" id="examples"></a>

```
[craftforms form="42"]
[craftforms form="42" catalog-item="7"]
[craftforms form="42" product="99"]
```

#### `product` — add to cart from anywhere <a href="#product--add-to-cart-from-anywhere" id="product--add-to-cart-from-anywhere"></a>

On a WooCommerce single-product page, a connected CraftForms form automatically replaces the default add-to-cart form. The `product` attribute lets you place that **same add-to-cart form on any other page** (landing page, custom builder layout, a different post). Submitting it adds the product to the cart with the form's computed price, custom fields, dynamic SKU, weight/dimensions and generated preview — identical to the product page.

Requirements — the product must be:

1. a **simple** product,
2. **connected to the same form** (on its product-data tab) you pass in `form`.

If the pair doesn't satisfy these, **the form still renders** **without** add-to-cart functionality (which means the the form submission will not lead to adding the product to cart; so a contact/quote form degrades gracefully), and logged-in editors see an HTML comment explaining why. A forged or mismatched `product` id can never add an unrelated product — the server re-validates the form↔product connection on submit.

`catalog-item` and `product` are independent paths; when `product` resolves to a valid connected form it takes over the render, so combining both is not needed.

***

### `[craftforms_static_form]` — headless / static-site embed (PRO) <a href="#craftforms_static_form--headless--static-site-embed-pro" id="craftforms_static_form--headless--static-site-embed-pro"></a>

Instead of baking the form HTML (with a soon-stale nonce and a `/wp-json/` URL) into the page, this emits a placeholder `<div data-craftforms-embed="KEY">` plus a one-time `embed.js` loader. On the visitor's browser, `embed.js` fetches the current form markup, pricing logic and (for booking) availability from your WordPress backend over REST. The output is therefore safe to **freeze into a static export** and keeps working against a [locked-down backend](/documentation/for-developers/headless-backend-mode.md).

Returns nothing on the free plan.

#### Attributes <a href="#attributes-1" id="attributes-1"></a>

| Attribute      | Default | Description                                                                                                                |
| -------------- | ------- | -------------------------------------------------------------------------------------------------------------------------- |
| `key`          | `''`    | Embed key from **Settings → Embed**. Takes precedence over `form`.                                                         |
| `form`         | `''`    | Form reference — post **ID, UUID, or REST name**. When `key` is empty, its registered embed key is resolved automatically. |
| `resource-id`  | `''`    | Catalog **resource ID** for catalog pricing / booking availability.                                                        |
| `catalog-item` | `''`    | Alias of `resource-id` (used only when `resource-id` is empty).                                                            |

If no embed key can be resolved, logged-in editors get a guidance comment and the public page renders nothing.

#### Examples <a href="#examples-1" id="examples-1"></a>

```
[craftforms_static_form form="42"]
[craftforms_static_form key="a1b2c3…"]
[craftforms_static_form form="42" catalog-item="7"]
```

#### Catalog & booking over the embed <a href="#catalog--booking-over-the-embed" id="catalog--booking-over-the-embed"></a>

When `resource-id` / `catalog-item` is supplied, the backend **re-renders the form live with that resource applied** before returning it, so the static embed behaves the same as the inline shortcode:

* **Catalog pricing/options:** the catalog price formula, merged option values and smart-variable overrides are baked into the returned HTML — what the shopper sees matches what they're charged on submit.
* **Booking:** the datepicker receives its resource binding, booking window, schedule and availability/slots endpoints, so remaining-capacity checks work.

Availability is refreshed on discrete events — datepicker init, relevant field changes, this form's own successful submit, and once more right before Stripe/PayPal payment — plus an authoritative capacity re-check server-side on submit. There is **no** live cross-user polling; a slot another visitor just took becomes visible on the next of those events (or a reload).

#### Hardened backends <a href="#hardened-backends" id="hardened-backends"></a>

All CraftForms REST URLs baked into the embed — form submission **and** the booking datepicker's availability/slots endpoints — are emitted in `?rest_route=` form, so the embed works even when `/wp-json/` is blocked at the server level.

#### WooCommerce note <a href="#woocommerce-note" id="woocommerce-note"></a>

There is intentionally **no** `product` (add-to-cart) support in the static embed — a static site has no WooCommerce cart. Use `[craftforms product="…"]` (inline) on a WordPress page for add-to-cart.

***

### Readiness at a glance <a href="#readiness-at-a-glance" id="readiness-at-a-glance"></a>

| Form type                            | `[craftforms]` (inline) | `[craftforms_static_form]` (embed) |
| ------------------------------------ | :---------------------: | :--------------------------------: |
| Simple contact                       |            ✅            |                  ✅                 |
| Product form, self-contained pricing |            ✅            |                  ✅                 |
| Catalog-connected pricing/options    |            ✅            |                  ✅                 |
| Booking (catalog resource)           |            ✅            |                  ✅                 |
| WooCommerce add-to-cart (`product`)  |       ✅ (any page)      |     — (no cart on static sites)    |

***

### Page builders <a href="#page-builders" id="page-builders"></a>

* **Builderius / Bricks / Elementor / Gutenberg /** **Etch:** drop `[craftforms form="…"]` into a shortcode/text module.
* **Bricks** and **Elementor** additionally ship a native **"CraftForms Form"** element/ widget (form selector + catalog-item control) — use it instead of the shortcode there if you prefer a visual control. Builderius uses the shortcode.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://kb.craftformswp.com/documentation/form-building/embedding-forms-with-shortcodes.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
