Skip to content

Metadata Transforms

Brett Terpstra edited this page Dec 12, 2025 · 1 revision

Metadata Transforms

Metadata transforms allow you to modify metadata values using the [%key:transform] syntax. Transforms can be chained together, and many accept optional parameters.

Metadata Sources

Metadata can come from three sources (merged in priority order):

  1. Command-line: --meta KEY=VALUE (highest priority)
  2. Document: Metadata embedded in the document (YAML, MMD, or Pandoc format)
  3. External file: --meta-file FILE (lowest priority)

See Command Line Options for details on --meta-file and --meta flags.

Basic Usage

The basic syntax is [%key:transform] where key is a metadata key and transform is one of the available transforms:

---
title: hello world
---

# [%title:upper]
<!-- Outputs: # HELLO WORLD -->

Transforms can be chained using colons:

---
title: hello world
---

# [%title:title:split( ):first]
<!-- Outputs: # Hello -->

Enabling Transforms

Metadata transforms are enabled by default in unified mode. For other modes, use the --transforms flag:

apex document.md --transforms

To disable transforms (even in unified mode), use --no-transforms.

Case Transforms

upper

Converts the value to uppercase.

---
title: hello world
---

[%title:upper]
<!-- Outputs: HELLO WORLD -->

lower

Converts the value to lowercase.

---
title: HELLO WORLD
---

[%title:lower]
<!-- Outputs: hello world -->

title

Converts the value to title case (capitalizes first letter of each word).

---
title: hello world
---

[%title:title]
<!-- Outputs: Hello World -->

capitalize

Capitalizes only the first letter of the value.

---
title: hello world
---

[%title:capitalize]
<!-- Outputs: Hello world -->

String Manipulation

trim

Removes leading and trailing whitespace.

---
title: "  hello world  "
---

[%title:trim]
<!-- Outputs: hello world -->

slug / slugify

Converts the value to a URL-friendly slug (lowercase, spaces and special characters replaced with hyphens).

---
title: My Great Post!
---

[%title:slug]
<!-- Outputs: my-great-post -->

replace(OLD,NEW) / replace(regex:PATTERN,REPLACEMENT)

Replaces occurrences of OLD with NEW. Supports both simple string replacement and regex patterns.

---
url: http://example.com
---

[%url:replace(http:,https:)]
<!-- Outputs: https://example.com -->

Regex replacement:

---
text: Hello 123 World
---

[%text:replace(regex:[0-9]+,N)]
<!-- Outputs: Hello N World -->

substring(START,END) / substr(START,END)

Extracts a substring. Supports negative indices (from end).

---
title: Hello World
---

[%title:substr(0,5)]
<!-- Outputs: Hello -->

[%title:substr(-5)]
<!-- Outputs: World (last 5 characters) -->

truncate(LENGTH,SUFFIX)

Truncates the value to the specified length, optionally appending a suffix.

---
title: This is a very long title
---

[%title:truncate(15,...)]
<!-- Outputs: This is a very... -->

reverse

Reverses the order of characters in the value.

---
text: Hello
---

[%text:reverse]
<!-- Outputs: olleH -->

Array Transforms

split(DELIMITER)

Splits a string into an array using the specified delimiter (default: space).

---
tags: tag1,tag2,tag3
---

[%tags:split(,)]
<!-- Outputs: tag1 (first element as representation) -->
<!-- Use with :first, :last, :slice, or :join to work with the array -->

join(DELIMITER)

Joins an array into a string using the specified delimiter.

---
tags: tag1,tag2,tag3
---

[%tags:split(,):join( | )]
<!-- Outputs: tag1 | tag2 | tag3 -->

first

Returns the first element of an array.

---
tags: tag1,tag2,tag3
---

[%tags:split(,):first]
<!-- Outputs: tag1 -->

last

Returns the last element of an array.

---
tags: tag1,tag2,tag3
---

[%tags:split(,):last]
<!-- Outputs: tag3 -->

slice(START,LENGTH)

Extracts a slice from an array. If applied to a non-array value, splits the string into individual characters.

---
tags: tag1,tag2,tag3
---

[%tags:split(,):slice(0,2):join(,)]
<!-- Outputs: tag1,tag2 -->

---
text: Hello
---

[%text:slice(0,5)]
<!-- Outputs: Hello (characters 0-5) -->

Utility Transforms

default(VALUE)

Returns the specified default value if the metadata value is empty.

---
desc: ""
---

[%desc:default(No description)]
<!-- Outputs: No description -->

escape / html_escape

Escapes HTML special characters (&, <, >, ", ').

---
title: A & B
---

[%title:html_escape]
<!-- Outputs: A &amp; B -->

basename

Extracts the filename from a path.

---
image: /path/to/image.jpg
---

[%image:basename]
<!-- Outputs: image.jpg -->

urlencode

URL-encodes the value.

---
search: hello world
---

[%search:urlencode]
<!-- Outputs: hello%20world -->

urldecode

URL-decodes the value.

---
search: hello%20world
---

[%search:urldecode]
<!-- Outputs: hello world -->

prefix(VALUE)

Adds a prefix to the value.

---
url: example.com
---

[%url:prefix(https://)]
<!-- Outputs: https://example.com -->

suffix(VALUE)

Adds a suffix to the value.

---
title: Hello
---

[%title:suffix(!)]
<!-- Outputs: Hello! -->

remove(STRING)

Removes all occurrences of the specified string.

---
title: Hello'World
---

[%title:remove(')]
<!-- Outputs: HelloWorld -->

repeat(COUNT)

Repeats the value the specified number of times.

---
sep: -
---

[%sep:repeat(3)]
<!-- Outputs: --- -->

Formatting Transforms

format(FORMAT_STRING)

Formats a numeric value using sprintf-style formatting.

---
price: 42.5
---

[%price:format($%.2f)]
<!-- Outputs: $42.50 -->

length

Returns the length of the value as a string.

---
text: Hello
---

[%text:length]
<!-- Outputs: 5 -->

pad(WIDTH,CHAR)

Pads the value to the specified width with the specified character (default: space).

---
number: 42
---

[%number:pad(5,0)]
<!-- Outputs: 00042 -->

contains(STRING)

Returns "true" if the value contains the specified string, "false" otherwise.

---
tags: javascript,html,css
---

[%tags:contains(javascript)]
<!-- Outputs: true -->

Date/Time Transforms

strftime(FORMAT)

Formats a date using strftime-style format strings. Parses dates in formats like YYYY-MM-DD, YYYY-MM-DD HH:MM, or YYYY-MM-DD HH:MM:SS.

---
date: 2024-03-15
---

[%date:strftime(%Y)]
<!-- Outputs: 2024 -->

[%date:strftime(%B %d, %Y)]
<!-- Outputs: March 15, 2024 -->

Transform Chaining

Multiple transforms can be chained together using colons. Each transform operates on the result of the previous transform:

---
title: hello world
---

[%title:title:split( ):first]
<!--
  1. title -> "Hello World"
  2. split( ) -> ["Hello", "World"] (array)
  3. first -> "Hello"
-->

Example with dates:

---
date: 2024-03-15 14:30
---

[%date:strftime(%Y)]
<!-- Outputs: 2024 -->

Notes

  • Transforms are case-sensitive
  • Array transforms (split, join, first, last, slice) work together - use split to create an array, then apply other array transforms
  • The slice transform automatically converts non-array strings into character arrays if needed
  • Regex patterns in replace support POSIX Extended Regular Expressions and can include character classes like [0-9]+
  • Date parsing supports common formats but may not handle all date string formats
  • Unknown transforms are ignored and return the original value

Quick Links

Clone this wiki locally