Skip to main content

Template Variables & Defaults

Every template type exposes its own context variables. This page is the full reference — all variables for the four template types, plus the built-in default templates you can start from. For syntax and workflow, see the Template Guide; for filters, see Template Filters.

1. Zotero Source Note Template

Controls the body of Source Notes for Zotero library items. Context is { item, settings }.

item — Zotero Item

VariableTypeDescription
item.keystringZotero item key
item.versionnumberItem version number, used for incremental update detection
item.libraryIDnumberLibrary ID
item.citationKeystringCitation key (e.g., from Better BibTeX); empty string if not set
item.itemTypestringItem type ("journalArticle", "book", etc.)
item.titlestringTitle
item.parentItemstringParent item key; empty string for top-level items
item.creatorsArray<{ name: string }>Creator list, name is the combined full name
item.datestring | nullPublication date string (raw value from Zotero)
item.yearstring | nullFour-digit year extracted from item.date, or null if not extractable
item.dateAddedstringISO timestamp when the item was added to Zotero
item.dateModifiedstringISO timestamp of last modification
item.accessDatestring | nullLast access date
item.abstractNotestring | undefinedAbstract
item.publicationTitlestring | undefinedJournal / conference name
item.publisherstring | undefinedPublisher
item.placestring | undefinedPlace of publication
item.volumestring | undefinedVolume
item.issuestring | undefinedIssue
item.pagesstring | undefinedPage range
item.seriesstring | undefinedSeries name
item.seriesNumberstring | undefinedSeries number
item.editionstring | undefinedEdition
item.urlstring | undefinedURL
item.DOIstring | undefinedDOI
item.ISBNstring | undefinedISBN
item.ISSNstring | undefinedISSN
item.tagsArray<{ tag, type? }>Tag list
item.itemPathsstring[]Collection path array for the item (e.g., ["Research/ML"])
item.attachmentsAttachmentContext[]Child attachment list (PDFs, etc.)
item.annotationsAnnotationContext[]Annotations directly on the item (only for standalone attachment items)
item.attachmentAnnotationsAnnotationContext[]Flattened summary of all annotations across all attachments
item.notesNoteContext[]Zotero child note list
item.relatedItemsRelatedItemContext[]Zotero "Related" item list

item.attachments[] — Attachment Sub-Objects

VariableTypeDescription
attachment.keystringAttachment item key
attachment.libraryIDnumberLibrary ID
attachment.parentItemstringKey of the parent top-level item
attachment.filenamestringFilename (e.g., "paper.pdf")
attachment.contentTypestringMIME type (e.g., "application/pdf")
attachment.tagsArray<{ tag, type? }>Tags
attachment.dateAddedstringISO timestamp
attachment.dateModifiedstringISO timestamp
attachment.annotationsAnnotationContext[]Annotation list on this attachment

item.notes[] — Child Notes

VariableTypeDescription
note.keystringNote item key
note.libraryIDnumberLibrary ID
note.titlestringNote title (first line, or empty)
note.parentItemstringParent item key
note.notestringFull note HTML (Zotero ProseMirror format)
note.tagsArray<{ tag, type? }>Tags
note.dateAddedstringISO timestamp
note.dateModifiedstringISO timestamp

From Zotero's Related tab (dc:relation). Each entry corresponds to a relation URI. key and libraryID are always parsed from the URI; other fields are populated only when the related item exists in the local database.

VariableTypeDescription
rel.keystringZotero item key of the related item
rel.libraryIDnumberLibrary ID parsed from the relation URI
rel.resolvedbooleanWhether the item is in the local database (false = cross-library / unsynced / deleted)
rel.titlestring | undefinedTitle (only when resolved)
rel.itemTypestring | undefinedItem type (only when resolved)
rel.citationKeystring | undefinedCitation key (only when resolved)
rel.notePathstring | undefinedPath to the item's Source Note in the vault (only when resolved)

Cross-library or unsynced related items still appear in the list (resolved: false), useful for placeholder display. Filter with {% if rel.resolved %} or {% if rel.title %}.

item.annotations[] / attachment.annotations[] — Annotations

VariableTypeDescription
annotation.keystringAnnotation item key
annotation.libraryIDnumberLibrary ID
annotation.parentItemstring | undefinedKey of the owning attachment
annotation.typestringType: "highlight", "note", "image", "ink"
annotation.authorNamestring | undefinedAnnotation author
annotation.textstring | nullHighlighted text (> and < already escaped)
annotation.commentstring | undefinedAnnotation comment (already Markdown-converted: <b>**, <i>*, <sub>/<sup> stay inline HTML)
annotation.colorstring | undefinedHex color (e.g., "#ffd400")
annotation.pageLabelstring | undefinedPage label
annotation.tagsArray<{ tag, type? }>Tags
annotation.dateAddedstringISO timestamp
annotation.dateModifiedstringISO timestamp
annotation.rawAnnotationJSONRaw annotation object, for use with the process_nav_info filter

settings — Plugin Configuration

ZotFlowSettings exposed in full. Commonly used:

VariableTypeDescription
settings.annotationImageFolderstringAnnotation image output dir
settings.sourceNoteFolderstringDefault Source Note directory

Default Template

When no custom template is configured, the following built-in template is used:

---
citationKey: {{ item.citationKey | json }}
title: {{ item.title | json }}
itemType: {{ item.itemType | json }}
creators: [{% for c in item.creators %}"{{ c.name }}"{% unless forloop.last %}, {% endunless %}{% endfor %}]
publication: {{ item.publicationTitle | default: item.publisher | json }}
date: {{ item.date | json }}
year: {{ item.year }}
url: {{ item.url | json }}
doi: {{ item.DOI | json }}
tags: [{% for t in item.tags %}"#{{ t.tag | replace: " ", "_" }}"{% unless forloop.last %}, {% endunless %}{% endfor %}]
---
{%- capture quote_string %}{{ newline }}> {% endcapture -%}
{%- capture quote_string_2 %}{{ newline }}> >{% endcapture -%}
# {{ item.title }}
{%- if item.abstractNote -%}
## Abstract
> {{ item.abstractNote | replace: newline, quote_string }}

{%- endif -%}
{%- if item.attachments.length > 0 -%}
## Attachments
{%- for attachment in item.attachments -%}
- [{{ attachment.filename }}]({{ attachment | attachment_link }})
{%- endfor -%}

{%- endif -%}
## Notes
{%- if item.notes.length > 0 -%}
{%- for note in item.notes -%}
{{ note.note | html2md | wrap_editable: "NOTE", note.key }}

{%- endfor -%}
{%- endif -%}
{%- if item.attachments.length > 0 and item.attachmentAnnotations.length > 0 -%}
## Annotations
{%- for attachment in item.attachments -%}
{%- if attachment.annotations.length > 0 -%}
### {{ attachment.filename }}
{%- for annotation in attachment.annotations -%}
> [!zotflow-{{ annotation.type }}-{{ annotation.color }}] [{{ attachment.filename }}, p.{{ annotation.pageLabel }}]({{ annotation | annotation_link }})
{%- if annotation.type == "ink" or annotation.type == "image"-%}
> > ![[{{settings.annotationImageFolder}}/{{ annotation.key }}.png]]
{%- else -%}
> > {{ annotation.text | replace: newline, quote_string_2 }}
{%- endif -%}
>
> {{ annotation.comment | wrap_editable: "ANNO", annotation.key | replace: newline, quote_string }}
> {% if annotation.tags and annotation.tags.length > 0 -%} {% for t in annotation.tags %}#{{ t.tag | replace: " ", "_" }}{% unless forloop.last %} {% endunless %}{% endfor %} {%- endif %}
^{{ annotation.key }}

{%- endfor -%}
{%- endif -%}
{%- endfor -%}
{%- endif -%}
{%- if item.attachments.length == 0 and item.itemType == "attachment" and item.annotations.length > 0 -%}
## Annotations
{%- for annotation in item.annotations -%}
> [!zotflow-{{ annotation.type }}-{{ annotation.color }}] [{{ item.title }}, p.{{ annotation.pageLabel }}]({{ annotation | annotation_link }})
{%- if annotation.type == "ink" or annotation.type == "image"-%}
> > ![[{{settings.annotationImageFolder}}/{{ annotation.key }}.png]]
{%- else -%}
> > {{ annotation.text | replace: newline, quote_string_2 }}
{%- endif -%}
>
> {{ annotation.comment | wrap_editable: "ANNO", annotation.key | replace: newline, quote_string }}
> {% if annotation.tags and annotation.tags.length > 0 -%} {% for t in annotation.tags %}#{{ t.tag | replace: " ", "_" }}{% unless forloop.last %} {% endunless %}{% endfor %} {%- endif %}
^{{ annotation.key }}

{%- endfor -%}
{%- endif -%}
  1. Frontmatter — Outputs citationKey, title, itemType, creators, publication, date, year, url, doi, tags
  2. Title# Title
  3. Abstract — Rendered in blockquote format
  4. Attachments — List of clickable links (via attachment_link filter, opening in ZotFlow reader by default)
  5. Child notes — Each note rendered with html2md | wrap_editable as an editable region
  6. Annotations — Grouped by attachment, rendered with [!zotflow-<type>-<color>] callouts, annotation comments wrapped as editable regions, tags displayed on a dedicated line below the comment

2. Local Source Note Template

Controls Source Notes for vault-local files (PDF/EPUB/HTML). Context is { item, settings, path }.

item — Local File

VariableTypeDescription
item.namestringFull filename (e.g., "paper.pdf")
item.pathstringVault-relative path (e.g., "Articles/paper.pdf")
item.extensionstringExtension (e.g., "pdf")
item.basenamestringFilename without extension (e.g., "paper")
item.annotationsLocalAnnotation[]Annotation list from the local reader

item.annotations[] — Local Annotations

VariableTypeDescription
annotation.keystringAnnotation ID
annotation.libraryIDnumberAlways 0 (local file)
annotation.typestring"highlight", "note", "image", "ink"
annotation.authorNamestring | undefinedAnnotation author
annotation.textstring | nullHighlighted text
annotation.commentstring | undefinedUser comment
annotation.colorstring | undefinedColor
annotation.pageLabelstring | undefinedPage label
annotation.tagsArray<{ tag, type? }>Tags
annotation.dateAddedstring | undefinedISO timestamp
annotation.dateModifiedstring | undefinedISO timestamp
annotation.rawAnnotationJSONRaw object, for use with the process_raw_anno_json filter

path / settings

  • path — Same as item.path
  • settings — Shares the same ZotFlowSettings object as the Zotero template

Default Template

Output logic is similar to the Zotero template but simpler: no metadata fields (local files lack Zotero metadata), only title and annotation list. Annotation comments are wrapped as editable regions — edits in the note are written back to the .zf.json sidecar. wrap_editable (including "PERSIST" regions) works in local templates too; read-only/external annotations are rendered as plain locked text automatically.

---
zotflow-locked: {{true}}
zotflow-local-attachment: [[{{ path }}]]
---
{%- capture quote_string %}{{ newline }}> {% endcapture -%}
{%- capture quote_string_2 %}{{ newline }}> >{% endcapture -%}
# {{ item.basename }}
{%- if item.annotations.length > 0 -%}
## Annotations
{%- for annotation in item.annotations -%}

> [!zotflow-{{ annotation.type }}-{{ annotation.color }}] [[{{item.path}}#page={{ annotation.pageLabel }}#annotation={{ annotation.key | process_nav_info }}|{{ item.name }}, p.{{ annotation.pageLabel }}]]
{%- if annotation.type == "ink" or annotation.type == "image"-%}
> > ![[{{settings.annotationImageFolder}}/{{ annotation.key }}.png]]
{%- else -%}
> > {{ annotation.text | replace: newline, quote_string_2 }}
{%- endif -%}
>
> {{ annotation.comment | wrap_editable: "ANNO", annotation.key | replace: newline, quote_string }}
{%- if annotation.tags and annotation.tags.length > 0 -%}
>
> {% for t in annotation.tags %}#{{ t.tag | replace: " ", "_" }}{% unless forloop.last %} {% endunless %}{% endfor %}
{%- endif -%}
^{{ annotation.key }}

{%- endfor -%}
{%- endif -%}

3. Citation Templates

Control the rendered output for citation insertion. Five slots:

SlotOutputTrigger scenario
Pandoc[@key] format citationDrag / suggest / copy with Pandoc selected
Wikilink[[notePath|label]] format linkDrag / suggest / copy with Wikilink selected
Footnote ReferenceInline [^key] markerInline part of a Footnote citation
Footnote DefinitionFootnote definition at doc endDefinition part of a Footnote citation
CitekeyBare @keyDirect output, no template rendering

Citation Context Variables

VariableTypeDescription
item.keystringZotero item key
item.citationKeystringCitation key (falls back to item.key if empty)
item.titlestringTitle
item.creatorsArray<{ name }>Creator list
item.datestringPublication date
item.itemTypestringItem type
item.urlstring | undefinedURL
item.DOIstring | undefinedDOI
item.publicationTitlestring | undefinedJournal / conference name
item.publisherstring | undefinedPublisher
item.volumestring | undefinedVolume
item.issuestring | undefinedIssue
item.pagesstring | undefinedPage range
item.tagsArray<{ tag }>Tags
item.*Other Zotero item fields are also available
notePathstringVault-relative path to the Source Note
annotationsArrayCurrently selected annotations (empty array when none selected)

annotations[] sub-fields: annotation.key, annotation.type, annotation.text, annotation.comment, annotation.color, annotation.pageLabel, annotation.tags, annotation.dateAdded, annotation.dateModified.

Use annotations.size to check whether annotations are selected, and annotations | map: 'pageLabel' to extract page numbers.

Default Citation Templates

Pandoc:

[@{{ item.citationKey | default: item.key }}{% if annotations.size > 0 %}{% assign pages = annotations | map: 'pageLabel' | compact | uniq | join: ', ' %}{% if pages != empty %}, pp. {{ pages }}{% endif %}{% endif %}]

Example output: [@smith2024, pp. 3, 7]

Footnote Reference:

[^{{ item.citationKey | default: item.key }}]

Example output: [^smith2024]

Footnote Definition:

{%- if item.creators.length > 1 -%}
{{ item.creators[0].name }} et al.
{%- elsif item.creators.length == 1 -%}
{{ item.creators[0].name }}
{%- else -%}
Unknown Author
{%- endif -%}, *{{ item.title }}* ({{ item.date | slice: 0, 4 }}).

Example output: Smith et al., *Deep Learning for NLP* (2024).

Wikilink:

{%- if annotations.size > 0 -%}
{%- for annotation in annotations -%}
[[{{ notePath }}#^{{ annotation.key }}|{{ item.creators[0].name | default: "Unknown" }} ({{ item.date | slice: 0, 4 }}), p. {{ annotation.pageLabel }}]]
{%- if forloop.last == false %}, {% endif -%}
{%- endfor -%}
{%- else -%}
[[{{ notePath }}|{{ item.creators[0].name | default: "Unknown" }} ({{ item.date | slice: 0, 4 }})]]
{%- endif -%}

4. Path Templates

Control where Source Note files land in your vault. Each path segment is automatically sanitized (illegal characters removed, reserved names handled).

Library Path Variables

VariableTypeDescription
keystringZotero item key
citationKeystringCitation key
libraryIDnumberLibrary ID
itemTypestringItem type
titlestringTitle
creatorsArray<{ name }>Creator list
datestringPublication date
yearstringFour-digit year extracted from date
libraryNamestringLibrary display name
publicationTitlestringJournal / conference name
publisherstringPublisher
tagsArray<{ tag }>Tags
itemPathsstring[]Collection paths
*Other Zotero metadata fields available

Local Path Variables

VariableTypeDescription
basenamestringFilename without extension
namestringFull filename
pathstringVault-relative path
extensionstringExtension (without dot)

Default Path Templates

Library: Source/{{libraryName}}/@{{citationKey | default: title | default: key}} Example output: Source/My Library/@smith2024

Local: Source/Local/@{{basename}} Example output: Source/Local/@myPaper

Path Template Tips

  • / creates directory hierarchy: References/{{year}}/{{citationKey}}
  • @ prefix is a visual convention (distinguishes Source Notes from regular notes), not mandatory
  • | default: chain fallback: {{citationKey | default: title | default: key}}
  • Collection path: {{itemPaths[0]}} to use the first collection path