# Hugo

> A Hugo partial and shortcode that render an Ikiform form from site params, in layouts and in Markdown content.

Hugo builds plain HTML, and a plain form post is all Ikiform needs, so there is no JavaScript to add. The one Hugo-specific catch is Markdown: Hugo's renderer drops raw HTML from content files unless you turn on `markup.goldmark.renderer.unsafe`, and a pasted form turns into `<!-- raw HTML omitted -->`. A shortcode keeps the HTML in a template instead.

## Set it up

### Step 1: Add the form id to your config

`hugo.toml`:

```toml
baseURL = "https://example.com/"

[params.ikiform]
formId = "frm_xxxxxxxxxxxxxxxx"
thanks = "/thanks/"
```

`baseURL` must be your real `https:` address. The partial turns `thanks` into an absolute URL with it, and Ikiform only follows `https:` redirects.

### Step 2: Create the partial

`layouts/_partials/ikiform-form.html`:

```html
{{ $id := .id | default site.Params.ikiform.formId }}
{{ $thanks := .thanks | default site.Params.ikiform.thanks }}
<form class="ikiform" action="https://ikiform.com/f/{{ $id }}" method="post">
  <label>Email <input name="email" type="email" autocomplete="email" required></label>
  <label>Message <textarea name="message" rows="5"></textarea></label>
  {{ with .subject }}<input type="hidden" name="_subject" value="{{ . }}">{{ end }}
  {{ with $thanks }}<input type="hidden" name="_redirect" value="{{ . | absURL }}">{{ end }}
  <input name="_gotcha" type="text" tabindex="-1" autocomplete="off" hidden>
  <button type="submit">{{ .button | default "Send" }}</button>
</form>
```

Always call it with a `dict`, even an empty one. Every key is optional and falls back to the site params.

### Step 3: Wrap it in a shortcode

`layouts/_shortcodes/ikiform.html`:

```html
{{ partial "ikiform-form.html" (dict "id" (.Get "id") "subject" (.Get "subject") "button" (.Get "button")) }}
```

Hugo 0.146 moved templates to `layouts/_partials` and `layouts/_shortcodes`. On older versions, use `layouts/partials` and `layouts/shortcodes`.

### Step 4: Use it

In any content file:

`content/contact.md`:

```text
---
title: Contact
---

Questions about pricing? Write to us.

{{< ikiform subject="Pricing question" >}}
```

Or in a layout, for a form on every page:

`layouts/_partials/footer.html`:

```html
<footer>
  {{ partial "ikiform-form.html" (dict "subject" "Footer enquiry") }}
</footer>
```

Add a `content/thanks.md` page for the redirect. Ikiform follows `_redirect` only when the form has allowed domains that include your site; without them, visitors see Ikiform's thank-you page. See [Rules for _redirect](https://ikiform.com/docs/html.md#redirect-rules).

## Allowed domains

List your production domain plus every place you preview the built site.

| Where the form runs | Add to Allowed domains |
| --- | --- |
| `hugo server` | `localhost`. It matches `http://localhost:1313`: Ikiform compares the host name only, never the port. |
| Your domain | `example.com`, which also covers `www.example.com` |
| Netlify | `your-site.netlify.app`. Deploy previews (`deploy-preview-12--your-site.netlify.app`) and branch deploys (`branch--your-site.netlify.app`) are not subdomains of it, so add the exact preview host while you test one. |
| Cloudflare Pages | `your-project.pages.dev`. Preview URLs such as `abc123.your-project.pages.dev` are subdomains of it, so they already match. |
| GitHub Pages | `username.github.io`. Project sites at `username.github.io/repo` use the same host, so one entry covers them all. |

- Never add `netlify.app`, `pages.dev` or `github.io` on its own. Every site on that host would match, including other people's.

## Test checklist

1. Run `hugo server`, open the page and view the source. You should see the `<form>`, not `<!-- raw HTML omitted -->`.
2. Submit locally with `localhost` in allowed domains. You'll land on Ikiform's thank-you page, because `absURL` gives an `http://localhost` address and only `https:` redirects are followed.
3. Deploy a preview, submit from it, and confirm the submission is listed in Ikiform and not marked spam.
4. Submit on your production domain and confirm you land on `/thanks/`.

## Troubleshooting

| What you see | Why | Fix |
| --- | --- | --- |
| `<!-- raw HTML omitted -->` where the form should be | The form was pasted straight into Markdown | Use the shortcode. |
| Hugo fails with `template for shortcode "ikiform" not found` | The shortcode file is in a folder your Hugo version doesn't read | Use `layouts/_shortcodes` on 0.146 and later, `layouts/shortcodes` before that. |
| Ikiform's thank-you page instead of `/thanks/` in production | No allowed domains, or `baseURL` is `http:` | Add your domain and set `baseURL` to your `https:` address. |
| `404 not_found` after submit | `params.ikiform.formId` is missing, so the action ends in `/f/` | Set the form id in `hugo.toml`. |
| Submissions arrive under the spam filter with `origin_mismatch` | The page that posted isn't on the form's allowed domains | Add the host from the table above. With **Reject** chosen, the same posts get `403 origin_not_allowed` instead. |

## Related

- [Jekyll](https://ikiform.com/docs/guides/jekyll.md): An include, and GitHub Pages setup.
- [Eleventy](https://ikiform.com/docs/guides/eleventy.md): A shortcode for Nunjucks, Liquid and Markdown.
- [HTML forms](https://ikiform.com/docs/html.md): Redirects, reserved fields and the honeypot.
- [Allowed domains](https://ikiform.com/docs/spam.md#allowed-domains): How origins are matched, and what a mismatch does.
