Spintax Syntax Reference

Complete reference for spintax template markup.

Enumerations { }

Randomly selects one option from the list.

{option1|option2|option3}

Examples

{blue|grey|clear}
{|free|paid} plan                 ← empty option = sometimes nothing
{Acme {Pro|Lite}}                ← nested enumerations
{order {|#42-A} confirmed}       ← nesting with empty option

Rules

  • Delimiters: { and }
  • Separator: |
  • Supports nesting to arbitrary depth
  • Empty options are valid (produce empty string)
  • Resolution is from the innermost expression outward

Permutations [ ]

Selects N elements, shuffles them, and joins with separators.

Simple permutations

All elements included, space-separated:

[1|2|3|4]

Output examples: 1 4 3 2, 2 3 4 1, 3 2 4 1

With separator

Uniform separator specified in < > at the start:

[<, > 1|2|3|4]

Output examples: 2, 1, 4, 3, 4, 3, 2, 1

Important: No space between [ and <separator>.

Per-element separators

Each option can have its own separator defined with <sep> before the preceding |. The separator travels with its element during shuffle.

[<, > 1|2|3 < and >|4]

Output examples: 1, 3, 2 and 4, 3, 1, 2 and 4

Auto-spacing: Word separators like <and> or <or> are automatically padded with spaces, so <and> produces  and . Punctuation separators (<,>) are not padded.

Permutations with combinations

Configurable min/max element count and separators:

[<minsize=1;maxsize=3;sep=", ";lastsep=" and "> apple|plum|orange|apricot]

Output examples: apple, plum and orange, apple and apricot, orange

Configuration parameters

ParameterDefaultDescription
minsizecount of allMinimum number of elements to pick
maxsizecount of allMaximum number of elements to pick
sep" " (space)Separator between non-final items
lastsepsame as sepSeparator before the last element

Permutation rules

  • Delimiters: [ and ]
  • Config block <...> must immediately follow [
  • Config parameters are semicolon-separated
  • String values in config are quoted: sep=", "
  • Enumerations and permutations can be nested inside options
  • HTML elements can be options

Variables %var%

Defines a reusable variable that is substituted wherever it appears.

#set %VARIABLE_NAME% = value or spintax structure
#def %VARIABLE_NAME% = value or spintax structure

Examples

#set %name% = John
#set %greeting% = {Hello|Hi|Hey}
#set %items% = [<minsize=2;maxsize=3;sep=", ";lastsep=" and "> apples|oranges|bananas]
Some text with %name% and %greeting%, also %items%.

/# %greeting% above may differ between the two references — #set re-rolls.
   #def picks once and keeps it: #/
#def %tone% = {friendly|warm|upbeat}
A %tone% intro, and a %tone% outro — always the same word.

Variable rules

  • #set and #def must start at the beginning of a line
  • Variable names are enclosed in %: %name%
  • Variable names are alphanumeric + underscore
  • Values can contain any spintax syntax (enumerations, permutations, other variables)
  • #set variables are expanded when referenced, not when defined (lazy evaluation)
  • #set is a macro: its value is re-substituted — and any spintax inside it re-rolled — at every reference. #def resolves its value once per render and holds that result everywhere
  • #set and #def lines are stripped from output

Variable scopes in the WordPress plugin

The plugin supports three variable scopes. When the same name exists in multiple scopes, the strongest scope wins:

  1. Runtime variables (strongest) — passed via shortcode: [spintax slug="greeting" name="Alice"]
  2. Local variables — defined with #set or #def inside the template
  3. Global variables (weakest) — defined on the Settings page

Conditionals {?VAR?then|else}

Conditionals are spintax.net's distinctive extension to the GTW family. Where {a|b} is a uniform random pick that ignores variables, {?VAR?then|else} picks based on whether %VAR% has a value.

Use it for value-driven choices — show a free-tier line only when a free tier exists, render a pro-features block only when the user is on a paid plan, hide a CTA that does not apply.

The pre-pass runs before %var% expansion and before the random branch picker, so a falsy branch is fully discarded — nothing inside it is evaluated.

Forms

{?VAR?then}                ← truthy ⇒ then; falsy ⇒ empty
{?VAR?then|else}           ← truthy ⇒ then; falsy ⇒ else
{?!VAR?then|else}          ← inverted
{?HasFreeTier? — free tier available since %founded%|, trusted since %founded%}

Truthy and falsy

The rule is deliberately simpler than JavaScript — truthy = at least one non-whitespace character:

Value of %VAR%Truthy?
not declaredfalsy
empty stringfalsy
whitespace onlyfalsy
"0", "false"truthy (non-empty)
any other text or HTMLtruthy

Conditional rules

  • Variable names follow the same regex as %var% (case-insensitive)
  • The ! prefix inverts the check: {?!VAR?missing}
  • The first depth-0 | separates then from else; later top-level | stays literal in else
  • Nested conditionals evaluate outer-first — falsy branches short-circuit
  • Composite logic (&&, ||, comparisons) is not supported — pre-compute a guard variable in the assembler
  • Malformed forms ({??yes}, {?VAR}) never throw — the playground flags them as warnings
  • Deep dive: see the Conditional spintax guide for worked examples and anti-patterns

Plurals {plural %n%: one|many}

Picks the grammatically correct word form for a number. The count goes before the colon, the forms after it, separated by |.

The form is chosen by the render locale, not by the template — so how many forms you must supply depends on that locale. English needs two, Russian needs three.

{plural %n%: form1|form2}          ← 2-form locale (en, de, es…)
{plural %n%: form1|form2|form3}    ← 3-form locale (ru, uk, sr…)
#def %LangCount% = 5
supports %LangCount% {plural %LangCount%: language|languages}
← supports 5 languages

Forms per locale

The locale is matched on its language subtag, so ru-RU and ru behave identically:

LocaleFormsSelected by
ru, uk, be, sr, hr, bs31 · 2–4 · 5 and up
every other locale, incl. en2exactly 1 · everything else

Supply the wrong number of forms and the engine reports plural.arity and leaves the block visible with fullwidth braces — a silent wrong plural never ships.

Plural rules

  • The opener is literal, including the space: {plural . {plural: x} and {pluralN: x} are not plural blocks
  • The colon is mandatory — it separates the count from the forms
  • The count is a %Var% reference or a literal integer; variables in the count are substituted before the form is chosen
  • Negative counts use the absolute value; 0 takes the "everything else" form
  • A count variable must be #def, not #set#set is a macro, so a value like {1|4|9} is still unresolved spintax when the plural is decided and the whole block renders empty. The playground flags this as plural.count-macro
  • A non-numeric or undefined count erases the block rather than guessing
  • Deep dive: see the Plural spintax guide for the Russian 3-form rules and worked examples

Includes #include

Embeds another template at the directive's position.

#include "hero-text"

Include rules

  • Template reference is in double quotes
  • Resolves by template slug or numeric ID
  • Included templates can contain their own variables and spintax
  • Recursive includes are supported
  • Circular references are detected and blocked
  • Child templates inherit global and runtime variables but not parent's #set / #def locals

Comments /#...#/

Text between comment markers is stripped from the output before any other processing.

/#
  This is a comment section.
  It can span multiple lines.
  It won't appear in output.
#/

Comment rules

  • Start delimiter: /#
  • End delimiter: #/
  • Can span multiple lines
  • Cannot be nested
  • Removed before any other processing

Nesting

All syntax elements can be nested within each other to arbitrary depth:

{option1|[<, > sub1|sub2|sub3]|option3}

[<minsize=2;maxsize=3;sep=", ";lastsep=" and "> {red|blue} apples|{big|small} oranges|bananas]

#set %var% = {a|[b|c]}

Post-Processing

The engine applies automatic text correction after generation:

  1. Shield URLs, emails, domains, decimals, and abbreviations from capitalization
  2. Collapse duplicate spaces and tabs
  3. Remove whitespace before punctuation (, . ! ?)
  4. Add space after punctuation where missing
  5. Capitalize first letter of the output (skipping HTML tags)
  6. Capitalize after sentence-ending punctuation
  7. Capitalize after block-level HTML tags
  8. Capitalize after line breaks
  9. Restore shielded placeholders

Syntax Summary

FeatureSyntaxBehavior
Enumeration{a|b|c}Pick one random option
Permutation[a|b|c]Pick N, shuffle, join
Separator[<sep> a|b|c]Permutation with uniform separator
Per-element sep[<,> a|b <x>|c]Permutation with custom separators
Combinations[<config> a|b|c]Permutation with min/max count
Variable#set %var% = valReusable substitution
Variable (roll once)#def %var% = valResolved once per render
Conditional{?VAR?then|else}Render then if truthy, else if falsy
Plural{plural %n%: one|many}Agree the word form with the number, by locale
Include#include "slug"Embed another template
Comment/#...#/Stripped from output

The syntax is compatible with the Generating The Web (GTW) standard.