Yearly template

Things I have tried

I’ve already searched the forum and help docs but couldn’t find what I was looking for.

What I’m trying to do

Currently using templater + periodic notes + calendar, which works great for daily notes.

Every year I reflect on the previous year, and think about the coming year. This all gets added as a note in Obsidian.

I’ve created a template for this special yearly note, but I can’t figure out how to create a new note from it, on the last day of the year. So when I click on Dec 31 on the calendar, it just creates a new note from the daily note template. Ideally I’d like it to create a new note from the yearly note template, but only on 12/31, every year.

I’ve also organized my daily notes in /Journal/YYYY/MMM/MM-dd-YY, it would be nice to place this special yearly note in /Journal/YYYY/YY-Review for example.

Fairly certain the templater plugin would do this, just can’t seem to figure it out.

Cheers

Hi @strex,

Happy NY! I’m not that experienced, but see if I can help. What does your current daily note template look like?

Cheers

If you’ve set a template location (Settings>Community plugins>Periodic Notes>Yearly), Periodic notes has a command Open yearly note. You’ll want to use that rather than clicking on a day in the calendar, but it’s manual.

Thanks for the pointer, manual method is fine since it’s only performed yearly.

I’ve created a yearly template, with templater, and I’m trying to use the tp.date.now module to create files with specific names, but I don’t think it’s working right.

Here’s the yearly template.

---
creation date: <% tp.file.creation_date() %>
modification date: <% tp.file.last_modified_date("dddd Do MMMM YYYY HH:mm:ss") %>
---

<< [[<% tp.date.now("YYYY", "P-1Y") %>-Review]] | [[<% tp.date.now("YYYY", "P1Y") %>-Review]] >>

---

# Goodbye <% tp.date.now("YYYY") %>
- 


# Hello <% tp.date.now("YYYY", "P1Y") %>
- 

This [[<% tp.date.now("YYYY", "P1Y") %>-Review]] created a file for 2023 named 2023-R6vi653. No idea how it got that.

If you are using Periodic notes to make it, it won’t work. Periodic notes doesn’t use the Templater syntax (<% tp.file.creation_date() %>, etc).

If you want to use that template, you need to have Templater to create it. With no changes to your Template, create a note, 2023-Review, and then use Templater’s Open Insert Template modal and choose that template.

edit: I see you said you used Templater. Not sure, your above template looks fine for me.

Maybe try

[[<% tp.date.now("YYYY", "-P1Y") %>--Review]] | [[<% tp.date.now("YYYY", "+P1Y") %>--Review]]

Although your code works fine over here, too.

Thanks guys, I think the templater syntax that @duifkruid recommended is what I needed to fix the name, and it make sense because P1Y would imply current year, where +P1Y would imply next year, which is what I want.

Also, I wasn’t aware of the Open Insert Template modal, which will come in handy, so thank you @ariehen.

Now that the template is figured out, wish there was a better way of creating a yearly review file in the directory structure I’d like. If I click on the 2024-Review link from the 2023-Review file, it just puts the file at the root of the vault tree, which would just require moving it manually, not the end of the world. Of course a programmatic way of doing this would be 10% more fun. ¯_(ツ)_/¯

1 Like

You mean like in Settings > Files & Links > Default location for new files, and setting that to “Same folder as current file”?

Yes actually, but would t that apply globally to all new files?

Every new file will now be located in the same folder as the current file, unless something else should dictate the folder choice.

Hey @Strex,

If you’d like to automate where specific notes are stored, you can let Templater manage the folder where notes derived from a template go:
templater

When using Periodic Notes, the folder may be specified in those options:
periodic_notes

Then you specify moving instructions inside your template, like so, e.g. my own yearly template:

<%*  
let titleName = tp.file.title

if (tp.file.title.startsWith("Untitled"))
titleName = await tp.system.prompt("Please use YYYY[-Review] when naming this Yearly Review")
await tp.file.rename(titleName)

let yr = tp.date.now("YYYY", 0, tp.file.title, "YYYY[-Review]");

const dir = "/Journal/" + yr + "/"
	if (!tp.file.exists(dir)) {
		await this.app.vault.createFolder(dir)
	}
await tp.file.move(dir + titleName);
-%>
---
title: <% titleName %>
creation_time: <% tp.date.now("YYYY-MM-DD, HH:mm") %>
tags: <% tp.file.cursor() %>
type: yearly review
---
# <% titleName %>
<<[[<% tp.date.now("YYYY", "P-1Y", tp.file.title, "YYYY[-Review]") %>]] | [[<% tp.date.now("YYYY", "P+1Y", tp.file.title, "YYYY[-Review]") %>]]>>

With those, it’s possible to give templater a series of instructions of naming and moving while creating the note. My own periodic notes are stored in Journal, and then moving down in file strcuture by period of time. I admit this isn’t necessary if you’re using a very clear tag & link structure; for me, a clear folder structure works best. This depends on how your PKM works best for you. I like the dynamic changes in the folder tree, it gives me a sense of overview.

Hope this helps! Cheers,

G’damn! That’s awesome!

Just reading through it, I see what your doing and how it’s working, and yea that’s exactly what I want. Thank you so much for sharing and writing this up!

I’m wondering if you wouldn’t mind updating the screenshots, I’m trying to read what they say and can’t (and don’t open to full images), I think the forum auto-scaled them.

Thanks again!

1 Like

Hey Strex, Good to hear, happy to help! Lol I scale pix as a lazy anonymiser, but there really is no personal or sensitive data in these, here are the originals (only that I use a lot of plugins :smirk:). I screenshot the Periodic Notes of the Daily Note setup, you can see the whole folder structure of my Journal in that one (again, smart ppl use a tagging system: “pile, don’t file”, but then I’d need to reorganise my tags a little bit and I like my current PKM, it’s working for me. Thank heaven for Obsidian!)


Cheers!

Some things in your template gave me pause, so I implemented a slightly different version. The end result should be mostly the same.

<%*
//Only take action if you're working with a new note
if (tp.file.title.startsWith('Untitled'))
{
   //Use a function to standardize the title format. If you opt for a different format, you 
   //only have to change it in one place.
   function title(year) { return `${year}-Review`; }

   //Prompt for which year to review. Defaults to the current year
   //If you want default to the prior year, use: tp.date.now('YYYY','P-1Y')
   const year = parseInt(await tp.system.prompt('Year to Review',tp.date.now('YYYY')));
   const dir = `/Journal/${year}/`;

   //Set the name of the note
   await tp.file.rename(title(year));

   //Make sure the year's folder exists
   if (!tp.file.exists(dir))
   {
      await this.app.vault.createFolder(dir);
   }

   //Move the note to the year's folder if a review is not already present
   if (!tp.file.exists(dir + title(year)))
   {
      await tp.file.move(dir + title(year));
   }

   //Output the content of the note
   tR = `---
title: ${title(year)}
creation_time: ${tp.date.now('YYY-MM-DD HH:mm')}
tags:
type: yearly review
---
# ${title(year)}
<<[[${title(year-1)}]] | [[${title(year+1)}]]>>

`;
}
-*>

Spotted a typo. The last line in the template should be -%>

@duifkruid So I’m able to follow what your doing, with templater & periodic notes, and it makes sense. I also use a combination of folders & tags; and yes I’ve heard it all before, but some of us are old enough to remember a system before tags, which is (for me) why folders it still my standard. I have a few questions I hope you can answer to help this work for me, let me explain.

Here’s essentially the structure of my Journal folder
/Journal/YYYY/MMM/MM-DD-YY

So in there, you’d expect to see files like /Journal/2023/Jan/01-10-23.md for a daily note.

For the yearly review note I’d like it to be in this format
/Journal/YYYY/YYYY-Review

the delema
Currently I have templater setup with a folder template as such:
Journal - templates/daily.md

I believe this has to be like this because the periodic note format is: YYYY/MMM/MM-DD-YY.

So, if I try to add a new folder template in templater, with Journal as the root, it errors out, because one already exists… Essentially one folder can’t have 2 templates, one for daily and one for yearly. Is there a better way of doing this that I’m not understanding?

Also, @ninjineer You kinda blew my mind with the if loop in a template, after years of coding my brain had an ah-ha moment, so thank you!

@strex, here’s something you can try. Paste all of the following code to the beginning of your daily Templater template:

<%*
if (tp.date.now('MM-DD') == '12-31')
{
   const year = parseInt(tp.date.now('YYYY'));
   const review = `/Journal/${year}/${year}-Review`;
   if (!tp.file.exists(review))
   {
      const content = `---
creation-date: ${tp.date.now("dddd Do MMMM YYYY HH:mm:ss")}
modification-date: ${tp.date.now("dddd Do MMMM YYYY HH:mm:ss")}
---

<< [[${year - 1}-Review]] | [[${year + 1}-Review]] >>

---

# Goodbye ${year}
- 


# Hello ${year + 1}
- 
`;
      await app.vault.create(review,content);
   }  
}
-%>

By including this in your daily template, every time it fires, it will check if the date is the last day of the year (you can pick a different date if you want). If it is so, it will check if you have previously created a review note for that year. If not, it will build the template content of that review note as a string and then write it to a file. Whether or not it’s the magic day, the rest of the daily template will still be processed to create your daily note.

You could apply similar logic if you needed quarterly, monthly, or weekly notes as well.

Damn, that’s a brilliant way of handling it, never would’ve thought of that, thank you!

Thanks for this!

I added the code block to the daily template, an validated that the daily template (for today) still creates the normal daily file, as I’d expect since the if statement is checking for a specific date.

I then deleted today’s note, changed the…
if (tp.date.now('MM-DD') == '12-31')
To
if (tp.date.now('MM-DD') == '01-11') For today, to test it

To my surprise, it still just created a normal daily note, and not a yearly review note…

For reference here’s the daily template, with the code added.

<%*
if (tp.date.now('MM-DD') == '01-11')
{
   const year = parseInt(tp.date.now('YYYY'));
   const review = `/Journal/${year}/${year}-Review`;
   if (!tp.file.exists(review))
   {
      const content = `---
creation-date: ${tp.date.now("dddd Do MMMM YYYY HH:mm:ss")}
modification-date: ${tp.date.now("dddd Do MMMM YYYY HH:mm:ss")}
---

<< [[${year - 1}-Review]] | [[${year + 1}-Review]] >>

---

# Goodbye ${year}
- 


# Hello ${year + 1}
- 
`;
      await app.vault.create(review,content);
   }  
}
-%>
---
creation date: <% tp.file.creation_date() %>
modification date: <% tp.file.last_modified_date("dddd Do MMMM YYYY HH:mm:ss") %>
---

<< [[<% tp.date.now("YYYY-MM-DD", -1) %>]] | [[<% tp.date.now("YYYY-MM-DD", 1) %>]] >>

### Grateful for
- 
- 
- 

### What can _I_ do to make today great?
- 

todoist
{
	"name": "Tasks: {task_count}",
	"filter": "(today | overdue)",
	"sorting": ["date"],
	"group": true
}


### Thoughts & Ideas
- 

### To remember
- 

<% tp.web.daily_quote() %>

#daily 

For formatting sake I removed the ‘```’ that should be around todoist.
Any guess as to why this didn’t work as expected?

Edit: also tried 1-11 for giggles, but that doesn’t match MM-DD, nor did it work.

There are actually two checks happening. The first one is for the date and the second is for the lack of existence of the review note. It’s possible it’s the second test that’s failing. Check to make sure there isn’t a 2023-Review note already there and that the /Journal/2023/ path exists.

I did some testing on my system. One thing you’ll want to change is the line:
const review = `/Journal/${year}/${year}-Review`;
to:
const review = `/Journal/${year}/${year}-Review.md`;
because the create function does not apply the missing file extension.

Note, the above error could be why you’re not seeing the review note. By default Obsidian only displays known file types (.md) in File Explorer. The bug above will create a file without an extension, which won’t be seen in the normal interface. In Options → Files & Links turn on the “Detect all file extensions” options to see if the note was there all along. If it is, you’ll probably want to delete it and rerun your test with the above fix.

1 Like