Kirby3 HTMLHead - best-practice HTML Head Element extendable with snippets

I am creating posts for my plugins to make it easier to find them using the forum search and not just the docs search.

The basic idea for this plugin is to use kirbys snippets to render the dom elements that go into <head>. The only config value just defines which snippets and in what order they are rendered. The plugin comes with some snippets to get you started but you can add as many as you like.

Snippets

alternates.php link-css.php meta-robots.php
base.php link-feedjson.php recommended-minimum.php
canonical.php link-feedrss.php script-instantpage.php
google-analytics.php link-prefetch.php script-js.php
google-globalsitetag.php link-preload.php script-webfontloader.php
google-tagmanager.php meta-author.php title.php
link-a11ycss.php meta-description.php

Page Method: htmlhead

In any template or your header snippet call the page method right after the tags that should come first.

   <!DOCTYPE html>
-  <html>
+  <html <?= site()->langAttr() ?>>
     <head>
-      <meta charset="utf-8">
-      <meta http-equiv="x-ua-compatible" content="ie=edge">
-      <meta name="viewport" content="width=device-width, initial-scale=1 shrink-to-fit=no">
-      <base href="<?= site()->url() ?>'">'
-      <title><?= $page->title() ?></title>
+      <?= $page->htmlhead() ?>
+      <?= $page->metaTags(['og', 'twitter', 'json-ld']) ?>

Setting

There is only one setting called bnomei.htmlhead.snippets and it takes an array of callbacks. It has sensible defaults but you can add any of the provided snippets or your own snippets. The unittests for this plugin have a more specific example for you to explore.

https://github.com/bnomei/kirby3-htmlhead/blob/master/tests/config/config.php

<?php

return [
    'bnomei.htmlhead.snippets' => [
        /********************************
         * IMPORTANT: order matters!
         */
        'htmlhead/recommended-minimum' => null,
        'htmlhead/title' => function ($kirby, $site, $page) {
            return ['title' => $page->title()];
        },
        'htmlhead/base' => function ($kirby, $site, $page) {
            return ['href' => kirby()->site()->url()];
        },
        'htmlhead/link-preload' => function ($kirby, $site, $page) {
            return ['files' => ['/assets/app.css', '/endpoint/data.json']];
        },
        'htmlhead/link-prefetch' => function ($kirby, $site, $page) {
            return ['files' => ['/assets/next-page.js']];
        },
        'htmlhead/meta-robots' => function ($kirby, $site, $page) {
            return ['content' => 'index, follow, noodp'];
        },
        'htmlhead/meta-author' => function ($kirby, $site, $page) {
            return ['content' => $site->author()];
        },
        'htmlhead/meta-description' => function ($kirby, $site, $page) {
            return ['content' => Str::unhtml($page->seodesc())];
        },
        'htmlhead/link-css' => function ($kirby, $site, $page) {
            return ['files' => ['/assets/app.css']];
        },
        'htmlhead/script-js' => function ($kirby, $site, $page) {
            return ['files' => [
                [
                    'src' => '//unpkg.com/alpinejs', 
                    'defer' => true,
                ],
                '/assets/app.js',
                'https://cdn.jsdelivr.net/npm/webfontloader@1.6.28/webfontloader.min.js|sha256-4O4pS1SH31ZqrSO2A/2QJTVjTPqVe+jnYgOWUVr7EEc=',
            ]];
        },
        'htmlhead/script-webfontloader' => function ($kirby, $site, $page) {
            return [
                'nonce' => null, // $page->nonceAttr('my-webfontloader-nonce') from https://github.com/bnomei/kirby3-security-headers#setter
                'json' => [
                    'google' => [
                        'families' => ['Montserrat']
                    ],
                ],
            ];
        },
        'htmlhead/link-a11ycss' => function ($kirby, $site, $page) {
            return ['url' => 'https://github.com/ffoodd/a11y.css/blob/master/css/a11y-en_errors-only.css'];
        },
        'htmlhead/link-feedrss' => function ($kirby, $site, $page) {
            // defaults
            return [
                'url' => url('/feed'),
                'title' => $page->title(),
            ];
        },
    ],
    // ... other options
];