picocms / Pico

Pico is a stupidly simple, blazing fast, flat file CMS.
http://picocms.org/
MIT License
3.81k stars 616 forks source link

Creating a new twig variable #616

Closed notakoder closed 2 years ago

notakoder commented 2 years ago

I wish to add some additional meta data for the .md pages inside the YAML header and access them in the twig template. How do I create twig variables in Pico and access them in templates?

mayamcdougall commented 2 years ago

lol, the simplest answer is that you can just do it. Anything in the metadata can be accessed from that page's meta property (eg, page.meta.your_variable). However, the problem you might notice is that this becomes case sensitive. Writing it as Your_Variable in your YAML would require you to access it via page.meta.Your_Variable, not page.meta.your_variable.

To get around this, you can define your extra properties in a pico-theme.yml file in your theme folder.

Take a look at the Default Theme's pico-theme.yml.

meta:                         # Register meta headers used by this theme
  Logo: logo                  # The URL to your website's logo (value is passed to Pico's "url" Twig filter)
  Tagline: tagline            # Your website's tag line, shown right below your site title (supports Markdown)
  Social: social              # A list of social icons that will be shown in your website's footer;

You can think of the items you see under meta as aliases for your variables. So, in the Default Theme, the Logo: property in your metadata is exposed in lowercase as logo (page.meta.logo) to the Twig template. (And they technically don't have to match, you can call each variable whatever you want internally).

Or even simpler I guess, left side YAML, right side Twig. ๐Ÿ˜‚

Unfortunately, this aliasing only goes one layer deep (I'm in the habit of using a lot of nested variables in my themes, lol ๐Ÿ˜…), but it's good enough for most use cases.

You can actually just start with a copy of the Default Theme's pico-theme.yml Change the meta parts, and omit the widescreen line, since that's just a config option the default theme uses.

For that matter, any theme configuration variables you create here can also be accessed via config.theme_config. So in this example, the Default Theme uses config.theme_config.widescreen to determine if it should use a wider layout.

notakoder commented 2 years ago

Since my meta values are page specific, I can only use the in-page YAML header for it. So I am directly declaring the variables on the page as Changed: 2022-02-09 and accessing it using meta.Changed (not page.meta.Changed) in the template.

The problem is, my variable must be of date type (just like the date variable) and unless I do something about the variable type, only a random string of characters are displayed. Else, I'll have to change the date to a desired string like Changed: Feb, 08 2022 in the YAML header itself.

mayamcdougall commented 2 years ago

So... what you really want to know is how to convert a variable to a date? ๐Ÿคจ

I mean absolutely no offense by this, but you seem good at asking one question when you really want to know something completely different. ๐Ÿ˜‚

Twig has a date filter that should do what you're looking for. Just run your variable through it when you do comparisons, eg, page.meta.changed | date.

Hopefully you just want to do a comparison with it... I tried to do some digging into date formatting for you as well, and the Twig docs are a bit bleak. Twig 1.x (which current Pico uses, but we'll soon be switching to 3.x) docs 404 on the format_date filter page, while 3.x docs simply say those filters aren't included by default and you'd have to install an extension for them. So that's... frustrating. ๐Ÿ˜ฃ

Anyway, as I said above, you can also try adding a pico-theme.yml with the metadata aliases that way you can use page.meta.changed instead of page.meta.Changed. If you want, that is. ๐Ÿคท๐Ÿปโ€โ™€๏ธ

meta:
  Changed: changed
notakoder commented 2 years ago

I mean absolutely no offense by this, but you seem good at asking one question when you really want to know something completely different.

No offence taken because the date question is actually a continuation of the how to question. :smile: I got to know how to create custom variables from your answer. So thanks. :smile:

Anyway, as I said above, you can also try adding a pico-theme.yml with the metadata aliases that way you can use page.meta.changed instead of page.meta.Changed.

Sure I shall try them.

Twig has a date filter that should do what you're looking for. Just run your variable through it when you do comparisons, eg, page.meta.changed | date.

Great. It works, except that the date format is wrong. I have a date format set in config.yml which is how other dates are displayed. I use meta.date_formatted instead of meta.date and I get the date displayed as per the desired format in config file. But with the custom variable, the format is not honoured even if I tweak the variable name with the word formatted. Any suggestions?

mayamcdougall commented 2 years ago

No offence taken because the date question is actually a continuation of the how to question. ๐Ÿ˜„

Alright, as long as that did help answer your original question. ๐Ÿ˜‰

Any suggestions?

Not really.

Edit: Leaving the rest of this because it's informational, but jump to the end for an answer.


Yeah, your regular date_formatted variable is being processed by Pico's core (in PHP) and returned as a string.

Your new variable is a string to start, because YAML doesn't have a date datatype (your original Date variable was too, but Pico converted it for you already).

Twig is entirely unaware of this, it's happening before it ever sees the variable.

Likewise, Twig really has no idea that you even expect dates to be formatted. Twig doesn't really know that Pico exists (๐Ÿ˜‚), it just gets handed a dataset and told "Here, make a page from this."

I've seen you bump against this concept a few times, so maybe that explanation helps.

Pico does its work, then hands things off to Twig. They don't really "talk" much to each other. They kind of just hand things back and forth at the start and end. Pico's Core goes "Alright, I've put together this big stack of pages for you, now make them into HTML for me."

Then, Twig hands the HTML back when it's done.

So, all the "fancy" stuff like what order your pages should be in, or how your dates should be formatted all happens before Twig gets involved.


Alright, so... I was being dumb and looking at the date function instead of the date filter documentation.

The date filter does indeed let you format a date. I could have sworn it did, but then I got stuck reading the wrong page. ๐Ÿคฆ๐Ÿปโ€โ™€๏ธ

You should be able to pass your format string as a parameter like this: page.meta.changed | date(config.date_format)

Aaaaand that didn't work. The format is different apparently. ๐Ÿ‘Ž๐Ÿป

You can indeed specify a format string, but it's not compatible with the same syntax as Pico uses.

I found this article discussing Twig's date formatting, that you should hopefully be able to use to construct the same date format you're using in Pico, it'll just be written differently for Twig.

If you wanted, you could even store it as a second variable in your Pico config* that way it's not hardcoded in the Twig template.

* Or Theme config, or "Wherever your variables are stored.โ„ข" ๐Ÿ˜‚

Let me know if that helps at all.

notakoder commented 2 years ago

Alright, as long as that did help answer your original question. wink

Yes, it did. The whole progress is based on your answers. :+1:

Alright, so... I was being dumb and looking at the date function instead of the date filter documentation.

No problem, I saw the updated answer anyhow. May I suggest that you strike through those unnecessary parts (if there are) that are written with the misconception? That would prevent any misunderstandings.

I found this article discussing Twig's date formatting, that you should hopefully be able to use to construct the same date format you're using in Pico, it'll just be written differently for Twig.

This worked... Thanks. I was hoping there was a way to use the date_formatted variable to the new variable, but nonetheless, the alternative worked.

If you wanted, you could even store it as a second variable in your Pico config* that way it's not hardcoded in the Twig template.

  • Or Theme config, or "Wherever your variables are stored.โ„ข" joy

Since I only have one variable, I find it easier to manage it directly on the twig template. I am also not using aliases under meta in theme config for the same reason that I have only one custom variable. I am sure these functionalities are easier methods when the number of variables are more. So will wait until then. :smile: But thank you for introducing them. :+1:

Once again, thanks for your help.

mayamcdougall commented 2 years ago

May I suggest that you strike through those unnecessary parts

There wasn't anything left that was incorrect, I just wrote the middle part (about Pico and Twig talking) before I had a good answer. Once I found a solution, I didn't want the whole comment to sound like a let down, with the answer hidden at the end.

But I also didn't want to delete the rest of the it because I thought it might still be informative. ๐Ÿ˜…

I was hoping there was a way to use the date_formatted variable

Me too. I like clean solutions like that, but it doesn't look like it's happening in Twig. If you did it in a plugin, you could use the same formatting string via PHP (just like Pico's core does), but that's a bit outside what I can do at the moment. ๐Ÿ˜“

Once again, thanks for your help.

No problem! ๐Ÿ˜

Glad I could help. ๐Ÿ‘๐Ÿป

notakoder commented 2 years ago

If you did it in a plugin, you could use the same formatting string via PHP (just like Pico's core does), but that's a bit outside what I can do at the moment. sweat

That's alright... The solution you gave is good enough. Cheers!