

Discover more from Obsidian Ninja
Obsidian Templater Functions You Need To Know About
These will save time and make it fun to use obsidian
Templates can be incredibly useful tools for enhancing your productivity and efficiency. They give you a predefined structure and format, that can help you save your time and effort.
Templates is a useful plugin for Obsidian but the Templater community plugin is a more advanced and powerful one.
It allows you to insert variables and functions in your notes to automate a lot of manual work. This can create a powerful workflow that can help you streamline your workflow process.
In this article, we’ll go through some of the most useful templater functions for Obsidian.
Templater functions in this list will range from simple functions to more advanced functions. These are compiled by going through Templater’s documentation, reddit, & Obsidian Forum.
Automatically move notes to a particular folder
Do you manually move your notes into different folders for organization? I mean why? This templater function can do it for you.
<% await tp.file.move("/002 RESOURCES/" + tp.file.title) %>
It will be moved inside the 002 RESOURCES folder inside your vault.
Add a daily quote
Want to start your day with inspiration? This function will add a new quote to your daily note from the web.
<% tp.web.daily_quote() %>
Add a Random Picture
Want to add a visual element on your notes? This will add a random picture to your note from the web.
Just a random picture: <% tp.web.random_picture() %>
Random picture with size: <% tp.web.random_picture("600x400") %>
Random picture with size+ query: <% tp.web.random_picture("600x400", "mountains") %>
Templater functions for Daily Notes
These functions can be used to automatically add dates to your daily notes and navigate between yesterday’s and tomorrow’s daily notes. This can help you create a nice chain of links in graph view.
This can also be used to make task queries easier.
For daily notes
Today's date: <% tp.date.now("YYYY-MM-DD") %>
Yesterday's date: <% tp.date.now("YYYY-MM-DD", -1) %>
Tomorrow's date: <% tp.date.now("YYYY-MM-DD", 1) %>
This works in most cases but if you are creating daily notes for future dates ahead of time. This won’t work properly.
You can take advantage of the note’s title.
For future daily notes
Today's date: <% moment(tp.file.title, "YYYY-MM-DD") %>
Yesterday's date: <% fileDate = moment(tp.file.title, 'YYYY-MM-DD').subtract(1, 'd').format('YYYY-MM-DD') %>
Tomorrow's date: <% fileDate = moment(tp.file.title, 'YYYY-MM-DD').add(1, 'd').format('YYYY-MM-DD') %>
Day of the year
This function will show you the day of the year.
<% moment(tp.file.title, 'YYYY-MM-DD').format("DDD[/365]") %>
Templater functions for periodic notes
This will be useful for creating a structured and well-organized periodic notes template in Obsidian.
This week: <%tp.date.now("gggg-[W]ww")%>
This month: <%tp.date.now("YYYY-MM")%>
Navigating between different periodic notes
Weeks
Next Week: [[<% moment(tp.file.title, "ww YYYY").add(1, "weeks").format("gggg-[W]ww") %>]]
Last Week: [[<% moment(tp.file.title, "ww YYYY").subtract(1, "weeks").format("gggg-[W]ww") %>]]
Months
Next month: [[<% moment(tp.file.title, 'YYYY-MM').add(1, 'months').format("YYYY-MM|MMMM YYYY") %>]]
Previous Month: [[<% moment(tp.file.title, 'YYYY-MM').subtract(1, 'months').format("YYYY-MM|MMMM YYYY") %>]]
Year
This Year: <% moment(tp.file.title, 'YYYY').format("YYYY") %>
Last Year: [[<% moment(tp.file.title, 'YYYY').subtract(1, 'years').format("YYYY") %>]]
Next Year: [[<% moment(tp.file.title, 'YYYY').add(1, 'years').format("YYYY") %>]]
Add file creation date:
File creation date: <% tp.file.creation_date() %>
File modification date: <%+ tp.file.last_modified_date() %>
Add file title
Want to add the file title as H1 in the note. Add this to your template
# <% tp.file.title %> ` `
Add content from metadata
Want to include what’s already in the note’s metadata to the note content? Use this function.
For example, if you have a note with the following YAML frontmatter:
---
alias: This is an alias
type: literature
---
If you want to show the content of metadata in the content of your note, use this template:
File's metadata alias: <% tp.frontmatter.alias %>
Note's type: <% tp.frontmatter["type"] %>
Insert callout template
This is a really useful template. This might save you a lot of time and make Obsidian more fun. With this function, you can automatically add a callout without the hassle.
A popup will open when the templater function is triggered. You get a popup with the following options:
Choose the callout type
Choose whether you want the callout to be expanded or folded
Add the title of the callout
Add the content of the callout
<%*
const callouts = {
note: '🔵 ✏ Note',
info: '🔵 ℹ Info',
todo: '🔵 🔳 Todo',
tip: '🌐 🔥 Tip / Hint / Important',
abstract: '🌐 📋 Abstract / Summary / TLDR',
question: '🟡 ❓ Question / Help / FAQ',
quote: '🔘 💬 Quote / Cite',
example: '🟣 📑 Example',
success: '🟢 ✔ Success / Check / Done',
warning: '🟠 ⚠ Warning / Caution / Attention',
failure: '🔴 ❌ Failure / Fail / Missing',
danger: '🔴 ⚡ Danger / Error',
bug: '🔴 🐞 Bug',
};
const type = await tp.system.suggester(Object.values(callouts), Object.keys(callouts), true, 'Select callout type.');
const fold = await tp.system.suggester(['None', 'Expanded', 'Collapsed'], ['', '+', '-'], true, 'Select callout fold option.');
const title = await tp.system.prompt('Title:', '', true);
let content = await tp.system.prompt('Content (New line -> Shift + Enter):', '', true, true);
content = content.split('\n').map(line => `> ${line}`).join('\n')
const calloutHead = `> [!${type}]${fold} ${title}\n`;
tR += calloutHead + content
-%>
Really cool. Like, it totally blew my mind when I first knew about this.
Insert Table of Contents
Navigating through long-form notes is hard. But not anymore. This templater function will create a table of content with a link to different sections of the note.
Clicking on the content will take you to the same section on the note.
---
>[!SUMMARY]+ Table of Contents
<%*
// Amended from: https://github.com/SilentVoid13/Templater/discussions/888
// Another alternative method of getting headers from file (uses different way to get current file reference):
//const outlineArray = await app.metadataCache.getFileCache(await tp.file.find_tfile(await tp.file.title)).headings;
// Change to 1 to output useful debugging info in console (Ctrl + Shift + i)
// Most often outputs a breakdown of system commands to check they are working.
var deBug = 0;
// Get header level where TOC should stop from user
let header_limit = await tp.system.prompt("Show Contents Down to Which Header Level (1-6)?", "3");
// Get headers from file
if ( deBug == 1) { console.log("tp.config.active_file \n\n", tp.config.active_file) };
if ( deBug == 1) { console.log("tp.config.active_file.name \n\n", tp.config.active_file.name) };
if ( deBug == 1) { console.log("app.workspace.activeLeaf.view.file \n\n",app.workspace.activeLeaf.view.file) };
if ( deBug == 1) { console.log("this.app.workspace.getActiveFile \n\n",await this.app.workspace.getActiveFile()) };
const activeFile = await this.app.workspace.getActiveFile();
if ( deBug == 1) { console.log("this.app.metadataCache.getFileCache(activeFile)) \n\n",await this.app.metadataCache.getFileCache(activeFile)) };
const mdCache = await this.app.metadataCache.getFileCache(activeFile);
if ( deBug == 1) { console.log("mdCache.headings \n\n",mdCache.headings) };
const mdCacheListItems = mdCache.headings;
// Build TOC from headers
let TOC = "";
mdCache.headings.forEach( item => {
var header_text = item.heading;
var header_level = item.level;
if ( deBug == 1) { console.log("array item header info \n\n",header_text, " (level:", header_level,")") };
// Wikilinks style output:
//let file_title= tp.file.title;
//let header_url = header_text;
//let header_link = `[[${file_title}#${header_url}|${header_text}]]`
// Non-wikilinks style output:
let file_title= tp.file.title.replace(/ /g, '%20'); // Replace spaces in file names with '%20'
let header_url = header_text.replace(/ /g, '%20'); // Replace spaces in urls with '%20'
let header_link = `[${header_text}](${file_title}.md#${header_url})`;
// Only output headers if level below specified limit
if ( header_level <= header_limit) {
TOC += `>${' '.repeat(header_level - 1) + '- ' + header_link + "\n"}`;
};
})
if ( deBug == 1) { console.log("TOC \n\n",TOC) };
%><% TOC %>
---
Automatic periodic Note Creation
This templater function will automatically create a weekly, monthly, quarterly, and yearly file that exists for the current date. Periodic notes will be created using the appropriate templates.
In the following code, configure templates name for your weekly, monthly, quarterly, and monthly file.
<%*
let wk = tp.date.now('GGGG-[W]WW');
let mnth = tp.date.now('MM MMMM');
let qrtr = tp.date.now('Qo [Quarter]');
let yr = tp.date.now('YYYY');
let template = '';
if (!tp.file.exists(wk)) {
template = tp.file.find_tfile('Periodic Note - Weekly');
await tp.file.create_new(template, wk);
};
if (!tp.file.exists('[[Personal/Journal/' + yr + '/' + qrtr + '/' + mnth + '/' + mnth + ']]')) {
template = tp.file.find_tfile('Periodic Note - Monthly');
await tp.file.create_new(template, yr + '/' + qrtr + '/' + mnth + '/' + mnth);
};
if (!tp.file.exists('[[Personal/Journal/' + yr + '/' + qrtr + '/' + qrtr + ']]')) {
template = tp.file.find_tfile('Periodic Note - Quarterly');
await tp.file.create_new(template, yr + '/' + qrtr + '/' + qrtr);
};
if (!tp.file.exists('[[Personal/Journal/' + yr + '/' + yr + ']]')) {
template = tp.file.find_tfile('Periodic Note - Yearly');
await tp.file.create_new(template, yr + '/' + yr);
};
%>
Create a countdown timer in a daily note
Want to use your daily note for keeping an eye on important dates? This templater function will help you do that.
Add the desired date and the name of the event. And add it to the top on your daily notes.
<%*
const elixirConfDate = new Date('2023-05-05');
const now = new Date();
const diff = elixirConfDate - now;
const days = Math.floor(diff / (1000 * 3600 * 24));
%><% days %> days until my event!
Better Kindle Highlights
I read a lot of books purchased outside of the Amazon store on my Kindle. And Kindle doesn’t support syncing highlights from those books.
I either have to go back to Kindle and review my highlights or have to get clippings.txt file.
This is a better way to manage your Kindle highlights in this scenario.
Add the clippings.txt file to your vault as .md file. Run this template in that file.
It will extract the highlights from clippings which will be stored on your clipboard. Create a new note and add them over there.
<%*
const editor = this.app.workspace.activeLeaf?.view?.editor;
if(!editor) return;
const linecount = editor.lineCount();
const titles = [];
let titleNext = true
for(i=0;i<linecount;i++) {
const line = editor.getLine(i);
if(line.startsWith(`==========`)) {
titleNext = true;
} else if(titleNext) {
titleNext = false;
if(!titles.includes(line)) {
titles.push(line);
}
}
}
const title = await tp.system.suggester(titles, titles,false,"Select book from list");
const output = [];
let page = 0;
let includeLine = false;
let row = 0;
let data = ``;
titleNext = true;
for(i=0;i<linecount;i++) {
const line = editor.getLine(i).trim();
if(line.startsWith(`==========`)) {
if (includeLine) output.push([page,data]);
titleNext = true;
includeLine = false;
} else if(titleNext) {
titleNext = false;
includeLine = (line === title);
row = 0;
}
if (includeLine && row === 1) {
const p = line.match(/(\d+)/);
page = p ? parseInt(p[0]) : -1;
data = line.startsWith("- Your Note")?`> [!note]`:``;
}
if (includeLine && row > 1 && line !== "" && line !== "\n") {
if (line.match(/^\d+\.\d+\.\d+./)) {
data = `#### ${line}`;
} else if (line.match(/^\d+\.\d+./)) {
data = `### ${line}`;
} else if (line.match(/^\d+./)) {
data = `## ${line}`;
} else {
data += `\n> ${line}`;
}
}
row++;
}
window.navigator.clipboard.writeText(
"# "+title+"\n\n" +
output
.sort((a,b)=>a[0]>b[0]?1:-1)
.map(x =>x[1].startsWith(`##`) ? `${x[1]}\n` : `${x[1]} ^${x[0]}\n`)
.join("\n") +
"\n"
);
new Notice ("Extracted kindle highlights are available on the clipboard.",4000);
%>
Basic Note Template
I never had thought of creating a basic note template until now. But this template from blitz-blitz changed my mind. I’m creating something similar for myself as well.
I really liked the philosophy of this template. Adding topics, themes, and related notes at the time of creation makes it easier for us to understand the context of the note.
Also when you come back to review notes, it's easy to make connections, in your brain as well as your second brain.
The dataview query for linked mentions makes it more useful.
---
tags: basic, new
aliases:
date created: <% tp.date.now() %>
---
%%
I add file links after topics, themes, and related
Why I use topics, themes, and related:
1. It gives me the flexibility of adding context and not having to include it directly in the note's content
2. I create quite a bit of short, quick notes and so the ability to quickly add connections comes in handy a lot
3. I can come back to the note and add more connections very easily later on.
4. The added connections improves the graph view's ability to navigate, explore, and discover connections between your notes.
%%
topics:
themes:
related:
--
%%
templater plugin code to return the note's title when the template is inserted into the note
%%
### [[<% tp.file.title %>]]
-
---
see also:
%%
returns list of linked mentions that are not present in the current note
%%
```dataview
list
from [[#this.file.name]] and
!outgoing([[#this.file.name]])
```