Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible to get page content in frontmatter? #329

Closed
zellwk opened this issue Dec 5, 2018 · 17 comments
Closed

Possible to get page content in frontmatter? #329

zellwk opened this issue Dec 5, 2018 · 17 comments

Comments

@zellwk
Copy link

zellwk commented Dec 5, 2018

I set the page's meta description to {{description}}. This description can be found through my frontmatter most of the time. No problems here.

description: 'some-text'

But I have hundreds of blog posts without this description property in the frontmatter. It'll take too long to go through these posts one by one. Is it possible to access page data in the frontmatter (so I can use JavaScript or shortcodes to create the description?).

Here's what I did with my previous static site generator:

  1. Loop through articles
  2. If articles don't have a description tag, look at the contents of the file.
  3. Get everything before <!-- more --> and format them as a description.

Wondering if something like this is possible.

@zellwk
Copy link
Author

zellwk commented Dec 5, 2018

Just saw #135, so I don't think what I mentioned above is possible :(

Curious if you have any solutions though!

@kleinfreund
Copy link
Contributor

kleinfreund commented Dec 5, 2018

Have a look at #179 (very similar tasks, i.e. excerpt creation). It sounds like you’re looking for shortcodes: https://www.11ty.io/docs/shortcodes/.

You loop through your articles like you used to and then you can do something along the lines of:

{% if post.description %}
  {% excerpt post %}
{% endif %}

@zellwk
Copy link
Author

zellwk commented Dec 5, 2018

@kleinfreund Unfortunately what I need is different from what you suggest. I need this for the <meta name="description"> tag. To write the shortcode, the article itself needs access to templateContent. But templateContent is only present when we loop through a collection.

@kleinfreund
Copy link
Contributor

Then you can try to implement the logic in the template that defines the meta tag. There, you could check if the current page has a description. If it has, you’re good to go; if it doesn’t, you call the shortcode with the page variable and try to extract the relevant content.

@zellwk
Copy link
Author

zellwk commented Dec 5, 2018

Does this mean I should get {{page.inputPath}} into the shortcode, parse the inputPath to retrieve said file, parse its content (which contains the frontmatter), and extract the relevant content?

I don't mind doing this. It feels a little hacky to parse through the frontmatter to get the content manually.

@kleinfreund
Copy link
Contributor

kleinfreund commented Dec 5, 2018

Oh, right, I understand. I believed/had hoped that the page object contained some more data. Reading in the file from the inputPath would certainly work, but it’s quite hacky and complicated.

Hm, in my opinion, Eleventy should have a more precise and consistent document model. When processing a file, I should have access to its front matter if present. I get that for documents inside a collection, but not for plain pages. That’s inconsistent. A post is really just a page which happens to be part of a collection. Maybe that can be streamlined in the future.

@edwardhorsford
Copy link
Contributor

What I've done in similar situations is to use collections.all, loop through all content until I find one with page.url == collection.url, and then do something with it. It sounds like templateContent contains the information you need to derive a description - this sounds possible to do.

@zachleat
Copy link
Member

zachleat commented Dec 5, 2018

@zellwk you might have luck with using layouts and the content variable here?

Layout file:

`<meta name="description" content="{% if description %}{{description}}{% else %}{{ /* DO SOMETHING WITH THE content VARIABLE */ }}{% endif %}">`

More about layouts: https://www.11ty.io/docs/layouts/

@zellwk
Copy link
Author

zellwk commented Dec 6, 2018

@zachleat Unfortunately this doesn't work because I have nested layouts. The content variable contains too much unnecessary information. Feels cleaner to work directly with the page itself through inputPath.

@zellwk
Copy link
Author

zellwk commented Dec 6, 2018

I did the above (to read the file manually). It's a pretty decent solution afterall.

eleventyConfig.addShortcode('getDesc', (page) => {
    const { inputPath } = page

   // Only read posts
    const isPost = inputPath.includes('/posts/')
    if (!isPost) return ''

   // Get the post. Includes all frontmatter. 
   // Uses front-matter package to parse files. Separates into frontmatter and body. 
    const file = fs.readFileSync(inputPath)
    const contents = file.toString()
    const fm = frontMatter(contents)

   // Do what you need. 

Would it be useful to include the solution above in 11ty docs?

I'm okay with closing this issue, unless @zachleat you wanna hold this open.

@zachleat
Copy link
Member

zachleat commented Dec 7, 2018

@kleinfreund what do you mean by this?

When processing a file, I should have access to its front matter if present.

@kleinfreund
Copy link
Contributor

@kleinfreund what do you mean by this?

When processing a file, I should have access to its front matter if present.

@zachleat If I have this shortcode:

eleventyConfig.addShortcode('log_input', doc => { console.log(doc) });

and I use it inside a collection of posts for each post, I get heaps of data. All sorts of things. (Also, this object needs to lose some weight. It’s massive!). If I log it for a plain page, I get a tiny object with meta data.

I believe, there shouldn’t be a difference in what I get depending on where I access it. One document model for all documents.

@edwardhorsford
Copy link
Contributor

@kleinfreund put another way, everything that's available about a page via a collection, should be available from the page itself, yes? Currently the page variable has very little.

@jevets
Copy link

jevets commented Dec 7, 2018

I believe, there shouldn’t be a difference in what I get depending on where I access it. One document model for all documents.

I'm down with this

@zellwk
Copy link
Author

zellwk commented Dec 9, 2018

It'd be good to have both frontmatter and content in the page itself.

@zachleat
Copy link
Member

zachleat commented Dec 9, 2018

Going to continue this discussion over at new issue #338 please!

@zachleat zachleat closed this as completed Dec 9, 2018
@henrik
Copy link

henrik commented Mar 15, 2020

Adding a comment here for future googlers if you don't mind – I wanted to add an "og:description" meta tag based on the content of the current blog post, but I didn't want it to include the entire content of the page.

I did what @edwardhorsford suggested and looped like so in my layout:

{%- for post in collections.posts -%}
  {%- if post.url == page.url -%}
    <meta property="og:description" content="{{ post.templateContent | striptags | truncate(200) }}">
  {%- endif -%}
{%- endfor -%}

Do let me know if there's a better way. I've tried various things but didn't find anything else that worked.

Should mention that I have two levels of layout – an outer base layout and an inner blog post layout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants