﻿<feed xmlns="http://www.w3.org/2005/Atom">
  <title type="text" xml:lang="en">OpenGraph</title>
  <link type="application/atom+xml" href="https://d.moonfire.us/tags/opengraph/atom.xml" rel="self" />
  <link type="text/html" href="https://d.moonfire.us/tags/opengraph/" rel="alternate" />
  <updated>2026-03-09T17:42:47Z</updated>
  <id>https://d.moonfire.us/tags/opengraph/</id>
  <author>
    <name>D. Moonfire</name>
  </author>
  <rights>Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International</rights>
  <entry>
    <title>Using Nitride - Front Matter</title>
    <link rel="alternate" href="https://d.moonfire.us/blog/2025/06/12/using-nitride-front-matter/" />
    <updated>2025-06-12T05:00:00Z</updated>
    <id>https://d.moonfire.us/blog/2025/06/12/using-nitride-front-matter/</id>
    <category term="development" scheme="https://d.moonfire.us/categories/" label="Development" />
    <category term="mfgames-nitride" scheme="https://d.moonfire.us/tags/" label="MfGames.Nitride" />
    <category term="mfgames-gallium" scheme="https://d.moonfire.us/tags/" label="MfGames.Gallium" />
    <category term="yaml" scheme="https://d.moonfire.us/tags/" label="YAML" />
    <category term="opengraph" scheme="https://d.moonfire.us/tags/" label="OpenGraph" />
    <category term="handlebars" scheme="https://d.moonfire.us/tags/" label="Handlebars" />
    <summary type="html">How to use Nitride to take the front matter from pages and add them as a component into the Entity class.
</summary>
    <content type="html">&lt;p&gt;Being able to associated metadata for a page is a very useful thing. It can be used to group pages into categories, control how it is styled, or to simply provide internal notes. To do that, we use something called a YAML front matter to describe the details.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-markdown"&gt;---
title: Name of the Page
summary: Summary of page
image: /path/to/image.png
---

This is the front page.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a major functionality of the Markdown + YAML pages that I use in my technical, fantasy, and even blog posts. I use the categories and tags heavily on this page, not to mention giving a summary details for links. It can also be used to provide &lt;a href="/tags/opengraph/"&gt;OpenGraph&lt;/a&gt; schemas.&lt;/p&gt;
&lt;h2&gt;Series&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/07/using-nitride-introduction/"&gt;2025-06-07 Using Nitride - Introduction&lt;/a&gt; - I'm going to start a long, erratic journey to update my publisher website. Along the way, I'm going to document how to create a MfGames.Nitride website from the ground up, along with a lot of little asides about reasoning or purpose.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/08/using-nitride-pipelines/"&gt;2025-06-08 Using Nitride - Pipelines&lt;/a&gt; - The first major concept of Nitride is the idea of a &amp;quot;pipeline&amp;quot; which are the largest units of working in the system. This shows a relatively complex setup of pipelines that will be used to generate the website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/09/using-nitride-entities/"&gt;2025-06-09 Using Nitride - Entities&lt;/a&gt; - The continued adventures of creating the Typewriter website using MfGames.Nitride, a C# static site generator. The topic of today is the Entity class and how Nitride uses an ECS (Entity-Component-System) to generate pages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/10/using-nitride-markdown/"&gt;2025-06-10 Using Nitride - Markdown&lt;/a&gt; - Examples and explanations of converting Markdown to HTML using MfGames.Nitride and MarkDig.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/12/using-nitride-front-matter/"&gt;2025-06-12 Using Nitride - Front Matter&lt;/a&gt; - How to use Nitride to take the front matter from pages and add them as a component into the Entity class.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Defining a Model&lt;/h2&gt;
&lt;p&gt;Because C# is a static language, we want to take advantage of a schema so we can have type-safe. Historically, I've called this &lt;code&gt;PageModel&lt;/code&gt; because I wrap that in a &lt;code&gt;TemplateModel&lt;/code&gt; when I get to the styling.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;// In //src/dotnet/Models/PageModel.cs
namespace Generator.Models;

public class PageModel
{
    /// &amp;lt;summary&amp;gt;
    ///     Gets or sets the optional list of categories associated with the page.
    /// &amp;lt;/summary&amp;gt;
    public List&amp;lt;string&amp;gt;? Categories { get; set; }

    /// &amp;lt;summary&amp;gt;
    ///     Gets or sets the URL of the image associated with the page.
    /// &amp;lt;/summary&amp;gt;
    public string? Image { get; set; }

    /// &amp;lt;summary&amp;gt;
    ///     Gets or sets the summary for the page.
    /// &amp;lt;/summary&amp;gt;
    public string? Summary { get; set; }

    /// &amp;lt;summary&amp;gt;
    ///     Gets or sets the title of the page.
    /// &amp;lt;/summary&amp;gt;
    public string? Title { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Naturally, this can and will get a lot more complicated. Because we are using YAML, we can have nested objects, tags, and references that are appropriate for our page. In the above example, we are defining an optional title, summary, an image, and a list of categories.&lt;/p&gt;
&lt;p&gt;It may come to a surprise to you, but this will eventually become a component in the page &lt;code&gt;Entity&lt;/code&gt; class that is passed through the pipelines.&lt;/p&gt;
&lt;h2&gt;Including the YAML module.&lt;/h2&gt;
&lt;p&gt;Like the others &lt;a href="/tags/mfgames-nitride/"&gt;MfGames.Nitride&lt;/a&gt; modules, we have to add it as a NuGet reference and tell the system to use it.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;cd src/dotnet
dotnet add package MfGames.Nitride.Yaml
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Adding it to the system is just a matter of modifying &lt;code&gt;Program.cs&lt;/code&gt; to include it.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;// In //src/dotnet/Program.cs
var builder = new NitrideBuilder(args)
    .UseIO(rootDirectory)
    .UseMarkdown()
    .UseHtml()
    .UseYaml()
    .UseModule&amp;lt;WebsiteModule&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Parsing Front Matter&lt;/h2&gt;
&lt;p&gt;Parsing the front matter uses an operation, &lt;code&gt;MfGames.Nitride.Yaml.ParseYamlHeader&lt;/code&gt; to parse the text content, pull off the front matter, wrap it in the model call, and then replace &lt;code&gt;ITextContent&lt;/code&gt; with the page without the YAML header.&lt;/p&gt;
&lt;p&gt;In effect, this:&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-markdown"&gt;---
title: Name of the Page
summary: Summary of page
image: /path/to/image.png
---

This is the front page.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;... becomes &amp;ldquo;This is the front page.&amp;rdquo; in the text content with a &lt;code&gt;PageModel&lt;/code&gt; component.&lt;/p&gt;
&lt;p&gt;Adding the operation is relatively simple but this operation uses a generic parameter to identify the model to parse the YAML as.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;// In //src/dotnet/Pipelines/Inputs/PagesModel.cs
public PagesPipeline(
    ILogger&amp;lt;PagesPipeline&amp;gt; logger,
    ReadFiles readFiles,
    IdentifyMarkdownFromPath identifyMarkdownFromPath,
    MoveToIndexPath moveToIndexPath,
    ParseYamlHeader&amp;lt;PageModel&amp;gt; parseYamlHeader)
{
    _logger = logger;
    _identifyMarkdownFromPath = identifyMarkdownFromPath;
    _moveToIndexPath = moveToIndexPath;
    _parseYamlHeader = parseYamlHeader;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And, like the others, it's just a matter of adding the operation into the pipeline.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;// In //src/dotnet/Pipelines/Inputs/PagesModel.cs
var list = _readFiles
    .Run(cancellationToken)
    .Run(_identifyMarkdownFromPath)
    .Run(_parseYamlHeader)
    .Run(_moveToIndexPath)
    .ToList();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Once we run it, we get the following output:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[01:44:05 INF] &amp;lt;PagesPipeline&amp;gt; Entity: Path /contact/index.md, Components [&amp;quot;Zio.UPath&amp;quot;,&amp;quot;Generator.Models.PageModel&amp;quot;,&amp;quot;MfGames.Nitride.Contents.ITextContent&amp;quot;,&amp;quot;MfGames.Nitride.Markdown.IsMarkdown&amp;quot;]
[01:44:05 INF] &amp;lt;PagesPipeline&amp;gt; Entity: Path /index.md, Components [&amp;quot;Zio.UPath&amp;quot;,&amp;quot;Generator.Models.PageModel&amp;quot;,&amp;quot;MfGames.Nitride.Contents.ITextContent&amp;quot;,&amp;quot;MfGames.Nitride.Markdown.IsMarkdown&amp;quot;]
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When we look at the HTML output, you'll notice it has a simplified version.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-sh"&gt;$ cat build/typewriter/html/index.html 
&amp;lt;h1&amp;gt;Typewriter Press&amp;lt;/h1&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Retrieving the component is code just requires the &lt;code&gt;Get&amp;lt;PageModel&amp;gt;()&lt;/code&gt; method or to use the various LINQ-based calls from &lt;a href="/tags/mfgames-gallium/"&gt;MfGames.Gallium&lt;/a&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;var page = entity.Get&amp;lt;PageModel&amp;gt;();

var list = entities
    .SelectEntity&amp;lt;PageModel&amp;gt;(OnlyRunOnEntitiesWithPageModel)
    .ToList();

public Entity OnlyRunOnEntitiesWithPageModel(Entity entity, PageModel page)
{
    return entity.Set(somePageSpecificVariable);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Gallium Methods&lt;/h2&gt;
&lt;p&gt;In the above case, the &lt;code&gt;SelectEntity&lt;/code&gt; call will skip calling the lambda for entities that don't have a &lt;code&gt;PageModel&lt;/code&gt;, but will still return it into the list. This is the &amp;ldquo;systems&amp;rdquo; part of the ECS system. The following will strip out the entities that don't have the appropriate models.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;.SelectEntity&amp;lt;PageModel&amp;gt;((entity, page) =&amp;gt; entity, includeEntitiesWithoutComponents: false)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;So far, Gallium is set up to allow up to four components. I haven't had a need to do more, but those are easy to add. This makes it useful when doing some model processing on files that have a future date.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;.WhereEntity&amp;lt;PageModel, UPage, Instant&amp;gt;(FilterOutFuturePages)
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The &lt;code&gt;SelectEntity&lt;/code&gt; is rather powerful because it takes an &lt;code&gt;Entity&lt;/code&gt; and returns one. It can be the same entity, or it can be one that has zero or more components added or changed inside it. I found this really useful when I'm parsing out categories or I'm trying to build up a list of some specialized functionality that the styling will need.&lt;/p&gt;
&lt;pre&gt;&lt;code class="language-csharp"&gt;public Entity OnSelectEntity(
    Entity entity,
    PageModel page,
    UPath path,
    ITextContent textContent)
{
    return entity
        .Set(nextPreviousModel)
        .SetAll(parentPage, parentUrl)
        .Set(modifiedPageModel);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;What's Next&lt;/h2&gt;
&lt;p&gt;We have the minimum number of components and systems needed to setup styling. Next time, I'll use &lt;a href="/tags/handlebars/"&gt;Handlebars&lt;/a&gt; to style the page and put a little chrome around the output.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/07/using-nitride-introduction/"&gt;2025-06-07 Using Nitride - Introduction&lt;/a&gt; - I'm going to start a long, erratic journey to update my publisher website. Along the way, I'm going to document how to create a MfGames.Nitride website from the ground up, along with a lot of little asides about reasoning or purpose.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/08/using-nitride-pipelines/"&gt;2025-06-08 Using Nitride - Pipelines&lt;/a&gt; - The first major concept of Nitride is the idea of a &amp;quot;pipeline&amp;quot; which are the largest units of working in the system. This shows a relatively complex setup of pipelines that will be used to generate the website.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/09/using-nitride-entities/"&gt;2025-06-09 Using Nitride - Entities&lt;/a&gt; - The continued adventures of creating the Typewriter website using MfGames.Nitride, a C# static site generator. The topic of today is the Entity class and how Nitride uses an ECS (Entity-Component-System) to generate pages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/10/using-nitride-markdown/"&gt;2025-06-10 Using Nitride - Markdown&lt;/a&gt; - Examples and explanations of converting Markdown to HTML using MfGames.Nitride and MarkDig.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="/blog/2025/06/12/using-nitride-front-matter/"&gt;2025-06-12 Using Nitride - Front Matter&lt;/a&gt; - How to use Nitride to take the front matter from pages and add them as a component into the Entity class.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
</content>
  </entry>
</feed>
