Content Modeling in Eleventy
Learn how to handle different content type and nestable blocks, render rich text, and use story references to manage content globally.
Setup
If you don’t want to make any editorial changes in your space, just copy this space in which we provide exactly the intended structure for you to follow this guide. Make sure to update the access token to the one from this space.
Alternatively, in your existing space, create a new content type block article
and an “Articles” folder with content. The article content type block should have the following fields:
title
: Textcontent
: Rich text
Learn more about fields in the concept.
Also, create an article-overview
content type block and create it as the root story of the “Articles” folder. This block requires no fields.
Finally, create a featured-articles
nestable block with the following field:
articles
: References
Add a new featured-articles
block to the body
field of the home story and select some articles to be featured.
Fetch and list articles
Create a new articles.js
data file to get all stories from this new content type.
import storyblok from '../_utils/storyblok.js';
import { richTextResolver } from '@storyblok/richtext';
const { render } = richTextResolver();
export default async function pages() {
const response = await storyblok.getAll('cdn/stories', {
version: 'draft', // or "published"
starts_with: 'articles',
content_type: 'article',
});
return response.map(story => {
const permalink = `/${story.full_slug}/`;
const title = story.content.title;
const content = render(story.content.content);
return {
permalink,
title,
content,
};
})
}
To render rich text fields, install the @storyblok/richtext
package and pass the content
field from the story to its render
method.
Learn more about handling rich text in Storyblok in the fields concept and the @storyblok/richtext
reference.
Using the starts_with
parameter, only stories from the “Articles” folder are fetched. Using the content_type
parameter, the results are restricted to stories of the content type article
.
Learn more about parameters and filter queries in the Content Delivery API documentation.
Create an article_overview.md
page with the following content:
---
layout: 'layouts/base.liquid'
title: 'Article Overview'
permalink: 'article-overview/'
---
<main>
<h1>Article Overview</h1>
<ul>
{%- for article in articles %}
<li>
<a href="{{ article.permalink }}">{{ article.title }}</a>
</li>
{% endfor -%}
</ul>
</main>
Now, the /article-overview
route show a list of links to all articles.
Create the articles block
Add a new article.liquid
layout file and an articles.md
content file to render the new article content type.
---
layout: 'layouts/base.liquid'
---
<main>
<h1>{{ title }}</h1>
{{ content }}
</main>
---
layout: 'layouts/article.liquid'
pagination:
data: articles
size: 1
alias: article
eleventyComputed:
title: '{{ article.title }}'
permalink: '{{ article.permalink }}'
---
{{ article.content }}
When clicking on links present in the article overview page, an article page renders correctly.
Handle referenced stories
In the pages.js
data file, set the resolve_relations
parameter to get the full object response of referenced stories.
import storyblok from '../_utils/storyblok.js';
import Feature from '../_components/feature.js'
import Teaser from '../_components/teaser.js'
import Grid from '../_components/grid.js'
import FeaturedArticles from '../_components/featured_articles.js'
export default async function pages() {
const response = await storyblok.getAll('cdn/stories', {
version: 'draft', // or "published"
content_type: 'page',
resolve_relations: "featured-articles.articles"
});
return response.map(story => {
const permalink = story.slug === 'home' ? '/' : `/${story.full_slug}/`;
const name = story.name;
const body = story.content.body
.map(blok => {
switch (blok.component) {
case 'feature':
return Feature(blok);
case 'teaser':
return Teaser(blok);
case 'grid':
return Grid(blok);
case 'featured-articles':
return FeaturedArticles(blok);
default:
throw new Error(`Could not resolve ${blok.component} block.`);
}
})
.join('');
return {
permalink,
name,
body,
};
})
}
Learn more in the references concept documentation.
Next, create a new src/_components/featured_articles.js
component.
import { storyblokEditable } from '@storyblok/js';
function FeaturedArticles(blok) {
const attrs = storyblokEditable(blok);
return (
`<section class="storyblok__outline" data-blok-uid="${attrs['data-blok-uid']}" data-blok-c="${attrs['data-blok-c']}">
<h2>Featured Articles</h2>
<ul>
${blok.featured_articles.map((article) => {
return (
`<li>
<a href="${article.full_slug}">${article.content.title}</a>
</li>`
);
})}
</ul>
</section>`
);
}
export default FeaturedArticles;
Now, this component will render links to the featured articles in the home page of your project.
Related links
- Eleventy Pagination API
- Eleventy Layouts
- Eleventy Data Files
- Iterations in Liquid
- Storyblok Rich Text fields reference
- Storyblok Rich Text package
- Referenced stories in Storyblok
Previous Part
Dynamic Routing