Provide attribution with a link if you share any of these snippets. For example, if you're a YouTuber and do a video on Templater and show off a command you found here, you should mention where you got it and provide a link in the video description.
Say you have a frontmatter key status
and you want to setup a button that will progress the value from one status to the next.
<%*
const file = tp.file.find_tfile(tp.file.title);
const {update} = app.plugins.plugins["metaedit"].api;
const status = tp.frontmatter.status;
if (status === "In Progress") {
await update("status","Complete",file);
}
if (status === "Backlog") {
await update("status", "In Progress", file);
}
-%>
I use this snippet in my new file template to quickly name my notes. The newTitle
variable can be used later in the note to get the note title.
<%*
const title = tp.file.title
if (title.includes("Untitled")) {
const newTitle = await tp.system.prompt("File Name")
await tp.file.rename(newTitle)
}
-%>
This snippet takes the selected text, which it assumes is a task, and converts the empty checkbox to [>]
. You could reuse it to do any text manipulation on a selection.
<%*
const selection = tp.file.selection();
if (selection) {
const replace = selection.split("\n").map(select => {
if (select.includes("- [ ]")) {
select = select.replace("[ ]", "[>]");
}
return select;
}).join("\n");
tR += replace;
} else {
new Notice("Text must be selected");
};
%>
Let's get fancy. This snippet updates a frontmatter key due
with the date supplied in a prompt using the MetaEdit plugin. The date supplied can be in natural language like "next Friday" and we use the Natural Language Dates plugin to convert it to "YYYY-MM-DD" format.
<%*
const file = tp.file.find_tfile(tp.file.title)
const {update} = app.plugins.plugins["metaedit"].api
const nlInput = await tp.system.prompt("What Date")
const date = app.plugins.plugins["nldates-obsidian"].parseDate(nlInput).formattedString
await update("due", date, file)
%>
Read the contents of the note, find the line with the content you want to change (in this example it is an inline meta field) and write back to the file with the updated line.
<%*
const content = tp.file.content.split("/n").map(line => {
if (line.includes("status:")) {
line = "status: :green_square:"
}
return line
}).join("\n")
const file = tp.file.find_tfile(tp.file.title)
await app.vault.modify(file, content)
%>
Use a suggester to select a file from all the files in your vault. Then append some text to the selected file.
<%*
const files = app.vault.getMarkdownFiles()
const select = await tp.system.suggester(f => f.basename, files)
await app.vault.append(file, 'some text to append')
%>
Using a keyword $ARG
we can quickly replace some text in a template note before using it to create a new file.
<%*
const arg = tp.frontmatter.arg
const template = await tp.file.include("[[Template]]")
const final = template.replace("$ARG",arg) //$ARG is put in the template where you want to replace with the argument
tp.file.create_new(final, "New Note")
%>
Gets all the files in your vault and returns a random one. You could further filter this down to files in a specific folder.
<%*
const files = app.vault.getFiles()
const random = Math.floor(Math.random() * (files.length - 1))
const randomNote = files[random]
%>
Today's random note is [[<% randomNote.basename %> ]]
Sure you could use tp.frontmatter
, but sometimes you want to read from the metadataCahe
directly. This snipped uses a Set
, which is just a fancy array where all the values are unique (no duplicates)
const tags = Array.from(new Set(Object.values(app.metadataCache.metadataCache).filter(cache => cache.frontmatter).map(cache => cache.frontmatter.tags)))
Gets all the tags in your vault. Shows a suggester to pick a tag, If "Make New" is chosen it shows a prompt to make a new tag. The final output is inserted into the note.
<%*
const tags = Object.keys(app.metadataCache.getTags())
let selection = await tp.system.suggester([...tags, "Make New"], [...tags, "Make New"])
if (selection === "Make New") {
selection = await tp.system.prompt("new tag")
}
tR += selection
%>
Say you've got a note and it has a bunch of links, but none of those links resolve to created notes yet. This snippet will create all those files.
const currentFile = tp.file.find_tfile(tp.file.title)
const links = app.metadataCache.getFileCache(currentFile)?.links
if (links) {
links.forEach(link => {
await tp.file.create_new("", link.name)
})
}
This involves a bunch of math, but the output is pretty cool! A text calendar with daily notes links.
| sun | mo | tu | we | th | fr | sat |
|:--:|:--:|:--:|:--:|:--:|:--:|:--:|
<%*
const days = parseInt(moment().daysInMonth()) + parseInt(moment().startOf("month").format("d"))
const table = []
table.push("|")
for (let i = 0; i < days; i++) {
if (i > 0 && i % 7 === 0) {
table.push("\n|")
}
table.push(`[[${moment().day(i).format("YYYY-MM-DD")}]]|`)
}
tR += table.join("")
%>
looks for tasks under a ## Header
and returns them. You could add this to your daily notes template to always move tasks ahead.
<%*
const previousDay = tp.file.find_tfile(tp.date.now("YYYY-MM-DD", -1)) // get the TFile of yesterday's note
const previousDayContent = await app.vault.read(previousDay) // read the contents of that note
const header = "## The Header" // replace with whatever the header is
const headerIndex = previousDayContent.split("\n").indexOf(header) // turn the content of the note into an array and find the index of the header
const tasks = previousDayContent.split("\n").splice(headerIndex, 6) //splice starts at the index and deletes the number of items in the array based on the second value provide. It returns the deleted items.
tasks.shift() // removes the first element of the array which is the header
tR += tasks.join("\n") //turn the array back into a string and return it to the note
%>
I probably wouldn't use this method anymore, but keeping it around as an example.
<%*
const exists = app.vault.adapter.exists("/Folder")
if (exists) {
await tp.file.move("")
} else {
await app.vault.adapter.mkdir("/Folder")
await tp.file.move("")
}
%>
This snippet creates an object dataview
that contains key/value pairs of any inline meta within the note it is run. For example if you had a meta value foo:: bar
, dataview.foo
would equal bar
<%*
const content = tp.file.content.split("\n")
const dataview = content.filter(line => line.match(/\w+\:\: \w+$/)).reduce((acc, line) => {
const [key, value] = line.split(":: ")
acc[key] = value
return acc
}, {})
%>
Show a suggester with different template options. Load in the selected template from the suggester. Check out that switch statement!
<%*
const choice = await tp.system.suggester(["Simple Note", "Book", "Music", "MOC"], ["Simple Note", "Book", "Music", "MOC"]);
let output = ""
switch(choice) {
case "Book":
output = await tp.file.include("[[-Book]]")
break;
case "Music":
output = await tp.file.include("[[-Music]]")
break
case "MOC":
output = await tp.file.include("[[-MOC]]")
break;
default:
new Notice("No Matching Template")
}
tR += output
%>
note: only works with folders in vault root. It won't find a nested folder. Requires MetaEdit plug.
Select a folder from a suggester, enter a key and value using a prompt and this will iterate over every note in the folder and update the specified meta key.
<%*
const {update} = app.plugins.plugins["metaedit"].api
const root = app.vault.getRoot()
const folders = root.children.filter(child => child.children)
const selectedFolder = await tp.system.suggester(e => e.name, folders, false, "Choose a Folder")
const metaKey = await tp.system.prompt("What Meta Key?")
const metaValue = await tp.system.prompt("Meta Value")
if (selectedFolder.children) {
selectedFolder.children.forEach(async (child) => {
const {frontmatter} = app.metadataCache.getCache(child.path)
const content = await app.vault.read(child)
if (frontmatter) {
if (Object.keys(frontmatter).includes(metaKey)) {
update(metaKey, metaValue, child)
} else {
const contentArray = content.split("\n")
contentArray.splice(1, 0, `${metaKey}: ${metaValue}`)
await app.vault.modify(child, contentArray.join("\n"))
}
} else {
const updatedContent = `---\n${metaKey}: ${metaValue}\n---`.concat(content)
await app.vault.modify(child, updatedContent)
}
})
} else {
new Notice("No Notes in Selected Folder")
}
%>
I honestly have no idea what this does and no recollection of writing it. Looks pretty fancy though!
<%*
const file = tp.file.find_tfile(tp.file.title)
const content = tp.file.content.split("\n")
const duplicateIds = []
content.filter(line => line.match(/^\[\^.*\]:/)).map(item => {
const [number, content] = item.split(":")
return {number, content}
}).reduce((acc, footnote) => {
if (!acc[0]) {
acc.push(footnote)
return acc
}
acc.forEach(item => {
if (item.content === footnote.content) {
duplicateIds.push({real: item.number, duplicate: footnote.number})
}
})
acc.push(footnote)
return acc
}, [])
const updatedContent = content.map(line => {
duplicateIds.forEach(({real, duplicate}) => {
if (line.includes(duplicate) && !line.startsWith(duplicate)) {
line = line.replace(duplicate, real)
}
if (line.startsWith(duplicate)) {
line = "$RENUM"
}
})
return line
}).filter(line => line !== "$RENUM").join("\n")
await app.vault.modify(file, updatedContent)
%>
Two techniques for only outputting a value if the day is a weekday. It expects your note title to have the format YYYY-MM-DD -- dddd
but the first example could be easily adapted for other formats.
<%*
const date = moment(tp.file.title, "YYYY-MM-DD -- dddd").day()
console.log(date)
if (date < 6) {
tR += "School:: "
}
-%>
<%*
const dow = tp.file.title.split("-- ")[1]
console.log(dow)
if (!dow.includes("Saturday") && !dow.includes("Sunday")) {
tR +="School:: "
}
-%>