11ty / eleventy

A simpler site generator. Transforms a directory of templates (of varying types) into HTML.
https://www.11ty.dev/
MIT License
17.33k stars 495 forks source link

Provide access to the contents of the current inner page (inside an Eleventy layout) #3458

Open nex3 opened 2 months ago

nex3 commented 2 months ago

Is your feature request related to a problem? Please describe.

I'm looking to add OpenGraph metadata to my page, specifically a description that's automatically generated from a snippet of the text on the current page.

Describe the solution you'd like

I'd like a way to get the rendered contents of the current template (without any layout around it) from the page object. Specifically, I'm looking to process this HTML using some JavaScript and produce a simplified, truncated description for use in a <meta> tag.

Describe alternatives you've considered

I can work around this by passing collections to a filter, since this actually does have full metadata for the current page, and just iterating through it until I hit the current page. This is the code I'm using right now:

let content = "";
const matchingEntries = collections.all.filter(
  (collectionEntry) => collectionEntry.page === this.page,
);
if (matchingEntries.length === 1) {
  const entry = matchingEntries[0];
  content = entry.content;
}

However, this is inelegant and inefficient, since it involves iterating across every page of my website to render each one. It does demonstrate that the data I'm looking for exists somewhere, though.

Additional context

https://github.com/11ty/eleventy/issues/1206 seems to suggest that at some point, page.content did exist and contained the rendered contents of a template. However, it doesn't seem to anymore, at least using this.page in a JS filter in Eleventy 3.0.0-beta.1.

nex3 commented 2 months ago

Note that this workaround does not work if I'm trying to use this in the front matter of a layout, failing with a "Tried to use templateContent too early" error. It makes sense that the collection information isn't available at this point, but the actual page contents are available right there in my template with the content variable.

zachleat commented 1 month ago

You’re not looking for page.rawInput are you? https://www.11ty.dev/docs/data-eleventy-supplied/#page-variable

I’m not sure we can allow access to rendered output from inside of the same template (e.g. page.content) as that would create a circular reference!

nex3 commented 1 month ago

You’re not looking for page.rawInput are you? https://www.11ty.dev/docs/data-eleventy-supplied/#page-variable

No, I'm specifically looking for the processed content of the inner page.

I’m not sure we can allow access to rendered output from inside of the same template (e.g. page.content) as that would create a circular reference!

It's not circular because I'm trying to access the content of a page during layout rendering. This information definitely exists—it's available within the layout body as the content variable, and it's available in includes by traversing collections as described above. I'm advocating for a clearer, faster way to access it that also works in frontmatter.

zachleat commented 1 month ago

Ah, thank you for the clarification!

nex3 commented 1 month ago

Thinking about this more, the ideal would be to have page.content available in directory data files as well (if they're implemented in JS), which I believe should be possible without circular references since templates seem to be rendered before their directory-level frontmatter is evaluated. That would let me set frontmatter directly based on the templates' contents, which would be a much more elegant and performant solution than anything I've got going right now.