Cut note content and reinsert it into new specified location using templater

What I’m trying to do

I recently did an overhaul to the templates I am using to add metadata / frontmatter to my notes, however, the previous notes I had already created need updating.

So, I tried making a templater script (I have no clue what I am doing) to:

  1. Clear and update the frontmatter and tags.
  2. Format the note without deleting the important bits.
  3. Cut the content of the original note to reinsert it into itself after formatting it.

Things I have tried

There are multiple folders I wish to apply this to, for now, I started with my daily notes folder, I have searched and taken snippets of code from across multiple sources and have ended up with this:

<%*
//Links that helped me fix this annoying hurdle:
	// 1 - https://zachyoung.dev/posts/templater-snippets#update-frontmatter
	// 2 - https://github.com/SilentVoid13/Templater/issues/302
	// 3 - https://github.com/SilentVoid13/Templater/issues/1191
	// 4 - https://forum.obsidian.md/t/new-properties-and-templater-prompts-and-commands/66425/9?u=briandbecsi
	// 5 - https://www.reddit.com/r/ObsidianMD/comments/1b3hjoh/how_to_push_some_text_to_another_section_within/
	// 6 - https://forum.obsidian.md/t/how-do-i-replace-the-contents-of-a-file-with-templater-right-now-it-only-inserts-the-template-at-the-cursor-position/49311

// Reapply template instead of append (zachyoung)
await app.vault.modify(tp.file.find_tfile(tp.file.path(true)), "");

//## Update frontmatter (zachyoung)
	//Instead of reading the contents of the file and parsing it manually, it’s recommended to use `app.fileManager.processFrontMatter` from the Obsidian public api.
	//You must mutate the `frontmatter` object directly, do not try to copy the object first and then do mutations.

//## applying templater commands inside the properties' values instead of strings(Github issue forum)
	// When creating a new file, we would create a race condition between Templater and the native Obsidian APIs we're using here.
	// We can circumvent that with a very small delay.
setTimeout(() => {    app.fileManager.processFrontMatter(this.app.workspace.getActiveFile(), (frontmatter) => {
	// create a new property or update an existing one by name
		//updates title property
        frontmatter["title"] = `${tp.file.title}` 
        //updates creation date property
        frontmatter["creation date"] = `${tp.file.creation_date()}`
		//updates modification date property
		frontmatter["modification date"] =`${tp.file.last_modified_date("dddd Do MMMM YYYY HH:mm:ss")}`
		//updates file folder property
		frontmatter["file folder"] = `${tp.file.folder(true)}`
		//sets the tags property the following tag
		frontmatter["tags"] = `dailyNote`
    })
}, 1)
%>`This note was created at: <% tp.date.now("dddd Do MMMM YYYY HH:mm:ss") %>`

---

***↳*** <%*
// ## Append content in another file (zachyoung)
// Get contents of file
const file = tp.file.find_tfile(tp.file.path(true));
const content = await app.vault.read(file);
// Replace content
const newContent = content + "replace mewith me";
await app.vault.modify(file, content);
%>

---

<< Yesterday: [[<% tp.date.yesterday("YYYY-MM-DD") %> ]] | Tomorrow: [[<% tp.date.tomorrow("YYYY-MM-DD") %>]] >>

I want the content from the note that will be edited to be sectione off to be reinserted where the “↳” symbol is, but I couldn’t find a topic / discussion online with someone with this specific problem. So therefore I opened this topic here at the obsidian forum.

TLDR: I don’t know much about coding but I want to copy & paste with templater while also doing a bunch of other stuff

I don’t think I fully understand you, but does this do the trick?

<%*
async function updateNoteContent() {
    // Clear the content of the file
    const file = tp.file.find_tfile(tp.file.path(true));
    await app.vault.modify(file, "");

    // Update frontmatter
    setTimeout(() => {
        app.fileManager.processFrontMatter(this.app.workspace.getActiveFile(), (frontmatter) => {
            frontmatter["title"] = `${tp.file.title}`;
            frontmatter["creation date"] = `${tp.file.creation_date()}`;
            frontmatter["modification date"] = `${tp.file.last_modified_date("YYYY-MM-DDTHH:mm")}`;
            frontmatter["file folder"] = `${tp.file.folder(true)}`;
            frontmatter["tags"] = `dailyNote`;
        });
    }, 1);

    // Get the content of the file
    const content = await app.vault.read(file);

    // Remove the old frontmatter and lines with Yesterday and Tomorrow links
    const contentWithoutFrontmatterAndLinks = content.replace(/---[\s\S]*?---/, '').replace(/<< Yesterday: \[\[.*?\]\] \| Tomorrow: \[\[.*?\]\] >>/, '').trim();

    // Extract the date from the file title
    const fileTitle = tp.file.title;
    const fileDate = moment(fileTitle, "YYYY-MM-DD");

    // Calculate yesterday and tomorrow dates
    const yesterday = fileDate.clone().subtract(1, 'day').format("YYYY-MM-DD");
    const tomorrow = fileDate.clone().add(1, 'day').format("YYYY-MM-DD");

    // Define the new content with the placeholder for reinsertion
    const newContent = `---
title: ${tp.file.title}
creation date: ${tp.file.creation_date()}
modification date: ${tp.file.last_modified_date("YYYY-MM-DDTHH:mm")}
file folder: ${tp.file.folder(true)}
tags: dailyNote
---

This note was created at: ${tp.date.now("dddd Do MMMM YYYY HH:mm:ss")}

---

***↳*** ${contentWithoutFrontmatterAndLinks}

---

<< Yesterday: [[${yesterday}]] | Tomorrow: [[${tomorrow}]] >>
    `;

    // Replace the content of the file with the new content
    await app.vault.modify(file, newContent);
}

// Call the function
updateNoteContent();
%>
1 Like

You can also use this script if you see that it works well to copy the previous script to all the notes inside your daily notes folder, but you will have to put the previous script inside a note, add the place inside this script and make a backup of the daily notes as well.

<%*
const dailyNotesFolder = "daily notes";
const updateScriptPath = "Scripts/Update the old daily notes.md";

// Get all files in the daily notes folder
const dailyNotes = app.vault.getFiles().filter(file => file.path.startsWith(dailyNotesFolder));

// Function to apply the update script to a note
async function applyUpdateScript(notePath) {
    const updateScript = await app.vault.read(app.vault.getAbstractFileByPath(updateScriptPath));
    const noteContent = await app.vault.read(app.vault.getAbstractFileByPath(notePath));
    
    // Split the note content into frontmatter and body
    const frontmatterEnd = noteContent.indexOf('---', 3) + 3;
    const frontmatter = noteContent.substring(0, frontmatterEnd);
    const body = noteContent.substring(frontmatterEnd);

    // Log the contents for debugging
    console.log("Frontmatter:", frontmatter);
    console.log("Body before update:", body);
    console.log("Update script:", updateScript);

    // Define the update script logic here
    const updatedBody = body + "\n" + updateScript; // Example logic: append the update script to the body

    // Log the updated body for debugging
    console.log("Updated body:", updatedBody);

    // Combine the frontmatter and the updated body
    const updatedContent = frontmatter + "\n" + updatedBody;
    
    await app.vault.modify(app.vault.getAbstractFileByPath(notePath), updatedContent);
}

// Apply the update script to each daily note
for (const note of dailyNotes) {
    await applyUpdateScript(note.path);
}
%>
1 Like

God bless your beautiful soul thank you!

At first, it didn’t work, but you gave me a great head start at understanding what line of code does what.

I had to move some things around, I’m not 100% sure that my deductions are correct, but here is what I think was happening with this scropt you shared:

“// Clear content of the file” > If you do this before reading the file with vault.read() you get an empty note at the end, so I moved it to the start of the script.

“// Calculate yesterday and tomorrow dates” > I was getting an error that “fileDate.clone() isn’t an function” and I thought that if the title wasn’t exactly in the format to use as a date variable this code wouldn’t work, so I tweaked around for a few hours and this worked for me:

   // Calculate yesterday and tomorrow dates
    const yesterday = moment(tp.file.creation_date("YYYY-MM-DD"), "YYYY-MM-DD").add(-1,'days').format("YYYY-MM-DD")
    const tomorrow = moment(tp.file.creation_date("YYYY-MM-DD"), "YYYY-MM-DD").add(+1,'days').format("YYYY-MM-DD")

It still creates duplicate content if you apply this template multiple times, but it works!

Here’s the end code that I edited:

<%*
async function updateNoteContent() {
	// Get file path
	const file = tp.file.find_tfile(tp.file.path(true));
	
	// Get the content of the file
	const content = await app.vault.read(file);

	// Clear the content of the file
	app.vault.modify(file, " ");
	
	//Update frontmatter
	setTimeout(() => {    app.fileManager.processFrontMatter(this.app.workspace.getActiveFile(), (frontmatter) => {
		// create a new property or update an existing one by name
			//updates title property
	        frontmatter["title"] = `${tp.file.title}` 
	        //updates creation date property
	        frontmatter["creation date"] = `${tp.file.creation_date()}`
			//updates modification date property
			frontmatter["modification date"] =`${tp.file.last_modified_date("dddd Do MMMM YYYY HH:mm:ss")}`
			//updates file folder property
			frontmatter["file folder"] = `${tp.file.folder(true)}`
			//sets the tags property the following tag
			frontmatter["tags"] = `dailyNote`
	    });
	}, 1);

    // Remove the old frontmatter and lines with Yesterday and Tomorrow links
    const contentWithoutFrontmatterAndLinks = content.replace(/---[\s\S]*?---/, '').replace(/<< Yesterday: \[\[.*?\]\] \| Tomorrow: \[\[.*?\]\] >>/, '').trim();


   // Calculate yesterday and tomorrow dates
    const yesterday = moment(tp.file.creation_date("YYYY-MM-DD"), "YYYY-MM-DD").add(-1,'days').format("YYYY-MM-DD")
    const tomorrow = moment(tp.file.creation_date("YYYY-MM-DD"), "YYYY-MM-DD").add(+1,'days').format("YYYY-MM-DD")

    // Define the new content with the placeholder for reinsertion
    const newContent = `\`File created at: ${tp.file.creation_date("dddd Do MMMM YYYY HH:mm:ss")}\`

---

***↳*** ${contentWithoutFrontmatterAndLinks}

---

<< Yesterday: [[${yesterday}]] | Tomorrow: [[${tomorrow}]] >>
    `;

    // Replace the content of the file with the new content
    await app.vault.modify(file, newContent);
}

// Call the function
updateNoteContent();
%>
1 Like

EDIT: Because I formatted my computer once, and the obsidian files got copied down from a backup, their creation dates aren’t actually the dates the original notes where created, but the dates the copies were made.

So I rewrote the section that set the yersterday and tommorow links. Otherwise, this should work for future notes I create in my vault.

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.