diff --git a/OliverBooth/Extensions/HtmlUtility.cs b/OliverBooth/Extensions/HtmlUtility.cs
new file mode 100644
index 0000000..7139ac5
--- /dev/null
+++ b/OliverBooth/Extensions/HtmlUtility.cs
@@ -0,0 +1,118 @@
+using System.Web;
+using Cysharp.Text;
+using OliverBooth.Data.Blog;
+using OliverBooth.Services;
+
+namespace OliverBooth.Extensions;
+
+///
+/// Provides helper methods for generating HTML tags
+///
+public static class HtmlUtility
+{
+ ///
+ /// Creates <meta> embed tags by pulling data from the specified blog post.
+ ///
+ /// The blog post whose metadata should be retrieved.
+ /// The injected by the page.
+ /// A string containing a collection of <meta> embed tags.
+ ///
+ /// is .
+ /// -or-
+ /// is .
+ ///
+ public static string CreateMetaTagsFromPost(IBlogPost post, IBlogPostService blogPostService)
+ {
+ if (post is null)
+ {
+ throw new ArgumentNullException(nameof(post));
+ }
+
+ if (blogPostService is null)
+ {
+ throw new ArgumentNullException(nameof(blogPostService));
+ }
+
+
+ string excerpt = blogPostService.RenderExcerpt(post, out _);
+ var tags = new Dictionary
+ {
+ ["title"] = post.Title,
+ ["description"] = excerpt,
+ ["author"] = post.Author.DisplayName
+ };
+ return CreateMetaTags(tags);
+ }
+
+ ///
+ /// Creates <meta> embed tags by pulling data from the specified dictionary.
+ ///
+ ///
+ /// A dictionary containing the tag values. This dictionary should be in the form:
+ ///
+ ///
+ ///
+ /// Key
+ /// Description
+ ///
+ ///
+ /// -
+ /// description
+ ///
+ /// The value to apply to the description, og:description, and twitter:description, tags.
+ ///
+ ///
+ ///
+ /// -
+ /// author
+ /// The value to apply to the og:site_name, and twitter:creator, tags.
+ ///
+ ///
+ /// -
+ /// title
+ ///
+ /// The value to apply to the title, og:title, and twitter:title, tags.
+ ///
+ ///
+ ///
+ ///
+ /// Any other values contained with the dictionary are ignored.
+ ///
+ /// A string containing a collection of <meta> embed tags.
+ /// is .
+ public static string CreateMetaTags(IReadOnlyDictionary tags)
+ {
+ if (tags is null)
+ {
+ throw new ArgumentNullException(nameof(tags));
+ }
+
+ using Utf8ValueStringBuilder builder = ZString.CreateUtf8StringBuilder();
+ builder.AppendLine("""""");
+
+ if (tags.TryGetValue("description", out string? description))
+ {
+ description = HttpUtility.HtmlEncode(description);
+ builder.AppendLine($"""""");
+ builder.AppendLine($"""""");
+ builder.AppendLine($"""""");
+ }
+
+ if (tags.TryGetValue("author", out string? author))
+ {
+ author = HttpUtility.HtmlEncode(author);
+ builder.AppendLine($"""""");
+ builder.AppendLine($"""""");
+ }
+
+ if (tags.TryGetValue("title", out string? title))
+ {
+ title = HttpUtility.HtmlEncode(title);
+ builder.AppendLine($"""""");
+ builder.AppendLine($"""""");
+ builder.AppendLine($"""""");
+ }
+
+ return builder.ToString();
+ }
+}
diff --git a/OliverBooth/Pages/Shared/_Layout.cshtml b/OliverBooth/Pages/Shared/_Layout.cshtml
index 2ee6fe0..4ed9767 100644
--- a/OliverBooth/Pages/Shared/_Layout.cshtml
+++ b/OliverBooth/Pages/Shared/_Layout.cshtml
@@ -1,4 +1,5 @@
@using OliverBooth.Data.Blog
+@using OliverBooth.Extensions
@using OliverBooth.Services
@inject IBlogPostService BlogPostService
@{
@@ -28,15 +29,7 @@
}
@if (ViewData["Post"] is IBlogPost post)
{
- string excerpt = BlogPostService.RenderExcerpt(post, out bool trimmed);
-
-
-
-
-
-
-
-
+ @Html.Raw(HtmlUtility.CreateMetaTagsFromPost(post, BlogPostService))
}
else
{