Alchemy cms

Core concept

Pages & Page Layouts

Every Page has a Page Layout that decides which Elements it may contain. Pages are versioned, can be scheduled, and can be restricted to certain roles.

config/alchemy/elements.yml
- name: concept_intro
  hint: true
  ingredients:
    - role: eyebrow
      type: Text
      hint: true
      default: :concept_intro_eyebrow
    - role: headline
      type: Headline
      as_element_title: true
      hint: true
      default: :concept_intro_headline
      settings:
        levels: [1, 2]
        sizes: [1, 2]
        anchor: from_value
    - role: lead
      type: Richtext
      hint: true
      default: :concept_intro_lead
      settings:
        tinymce:
          toolbar: "bold italic | alchemy_link unlink"
        sanitizer:
          tags: [p, br, strong, em, a]
          attributes: [href, target, rel, title]

Draft and publish

Every Page keeps two versions: a draft you edit and a public version visitors see. Publishing copies the draft over the public version, so work in progress never leaks โ€” and you can preview the draft in the admin any time.

  • Edit the draft freely.
  • Preview it privately.
  • Publish when it's ready.

config/alchemy/elements.yml
- name: prose
  hint: true
  ingredients:
    - role: headline
      type: Headline
      hint: true
      default: :prose_headline
      settings:
        levels: [2, 3]
        sizes: [2, 3]
    - role: text
      type: Richtext
      hint: true
      default: :prose_text
      settings:
        tinymce:
          toolbar: "bold italic | bullist numlist | alchemy_link unlink"
        sanitizer:
          tags: [p, br, strong, em, a, ul, ol, li]
          attributes: [href, target, rel, title]

Scheduled publishing. Give a Page a go-live date to publish it automatically at a future time, and an end date to retire it โ€” ideal for embargoed news or time-limited campaigns.

config/alchemy/elements.yml
- name: callout
  hint: true
  ingredients:
    - role: variant
      type: Select
      group: styling
      hint: true
      default: info
      settings:
        select_values:
          - ["Info", "info"]
          - ["Tip", "tip"]
          - ["Warning", "warning"]
    - role: text
      type: Richtext
      hint: true
      default: :callout_text
      settings:
        tinymce:
          toolbar: "bold italic | alchemy_link unlink"
        sanitizer:
          tags: [p, br, strong, em, a]
          attributes: [href, target, rel, title]

Restricted pages. Mark a Page as restricted and choose its permitted roles, so only signed-in users with those roles can see it โ€” perfect for members-only or internal content.

config/alchemy/elements.yml
- name: callout
  hint: true
  ingredients:
    - role: variant
      type: Select
      group: styling
      hint: true
      default: info
      settings:
        select_values:
          - ["Info", "info"]
          - ["Tip", "tip"]
          - ["Warning", "warning"]
    - role: text
      type: Richtext
      hint: true
      default: :callout_text
      settings:
        tinymce:
          toolbar: "bold italic | alchemy_link unlink"
        sanitizer:
          tags: [p, br, strong, em, a]
          attributes: [href, target, rel, title]

config/alchemy/page_layouts.yml

- name: article
  cache: false
  elements: [post_header, prose]

# A Page can also be scheduled and access-controlled:
#   public_on:       2026-09-01 09:00   # goes live
#   public_until:    2026-12-31 23:59   # retires automatically
#   restricted:      true               # signed-in visitors only
#   permitted_roles: [member]           # ...with one of these roles

config/alchemy/elements.yml
- name: code_sample
  hint: true
  ingredients:
    - role: caption
      type: Text
      hint: true
      default: :code_sample_caption
    - role: language
      type: Select
      hint: true
      default: yaml
      settings:
        select_values:
          - ["YAML", "yaml"]
          - ["Ruby", "ruby"]
          - ["ERB", "erb"]
          - ["HTML", "html"]
    - role: code
      type: Html
      hint: true
      default: :code_sample_code