Gives each post, category, tag, blogger and team its own head on the blog page that serves it,
through the
runtime:page:seo mishka_installer hook MishkaCmsWeb.RuntimeLive fires in
handle_params/3 (see MishkaCmsCore.Runtime.Seo for the map it is handed and what the head
builds from it).
A page is matched by the kind of record it says it shows (record, its extra's "record"):
"blog:post", "blog:category", "blog:tag", "blog:author" or "blog:team", the kinds
MishkaBlog.Plugins.PageRecords
names. Its path may be anything that captures the slug. Every other page is handed back
untouched before anything is read. A kind has one owner, so the answer for one of these halts the
chain: no later plugin is asked.
Everything returned is a default: what the page sets in its own SEO — a title, a description, a
tag, structured data — wins, and may name the variables below, {{post.title}} | Blog.
What is read
Nothing, on a page a visitor reads: MishkaCmsWeb.RuntimeLive hands it the rows the page read
once for its head, its frame and its blocks, as the visitor (source, MishkaBlog.PageSource),
and the record below is the one there, with what that read loaded. A record the visitor's read
left out is answered with its lock alone, read here as the system, so the address answers them
404 and nothing else of it reaches them. An editor's preview and a share card hand no rows, and
the record is read here, once: a post, a category or a tag as the system, and a blogger or a
team, which carry no lock of their own, as a guest, through the public action.
A post, "blog:post"
The post the slug capture names in the page's language, published — read through
:public_list as blog-post-detail reads it, on the page's site, with its authors, categories,
tags and its other published editions:
title,description,image— the post's title, excerpt and featured image;type—"article";tags—author(the authors' names), atwitter:creatorwith the X account of the first author, in the authors' order, who has one,article:published_time,article:modified_time,article:section(the first category), onearticle:tagper tag, the pairs Slack and Discord show under a link —twitter:label1/twitter:data1, thentwitter:label2/twitter:data2: "Written by" the authors' names, "Reading time" the post's, each only when known and numbered from 1 — and arel="alternate"link per language the post is published in among the site's languages, withx-defaultat the site's primary one, when there are two or more. The post's ownseo_tagscome last and replace any of these they name;schema— the post's ownschemawhen it holds one, else aBlogPostingwhoseauthoris aPersonper author — their name, their address on the site's"blog:author"page andsameAstheir social links — whosearticleSectionis the first category, and whosepublisheris the site's Organization by its@id,<site address>/#organization; then aBreadcrumbList, Home → Blog → the post;vars—post.title,post.excerpt,post.image,post.author,post.published_at,post.modified_at,post.url,post.collection,post.tags, andpost.rating(the readers' average, one decimal) withpost.rating_countonce a reader has rated it.
card — what its share card shows (MishkaCmsCore.Runtime.ShareCard): the first category above
the title, the authors' photos and names, their teams, the date and the reading time, over the
featured image.
A category, "blog:category"
The active category the slug capture names in the page's language: its name and description,
its own seo_tags, its own schema (else a CollectionPage) and a
BreadcrumbList, Home → Blog → the category. vars — collection.name,
collection.description, collection.url. Its share card says "Category" above the name.
A tag, "blog:tag"
The tag the slug capture names in the page's language: its name and description, its own
seo_tags, a CollectionPage and a BreadcrumbList, Home → Blog → the tag. A public tag says
robots noindex, follow, unless its own seo_tags hold a robots; the sitemap lists exactly the
tags that say index (MishkaBlog.Plugins.SitemapUrls). vars — tag.name, tag.description,
tag.url. Its share card says "Tag" above the name.
A blogger, "blog:author"
The blogger the slug capture names: their name, their bio as plain text, their avatar, a
twitter:creator with their X account when they have one, a
ProfilePage in the language of the page whose mainEntity is the Person — with sameAs
their social links and knowsAbout their expertise — and a BreadcrumbList, Home → Blog → the
blogger. vars —
author.name, author.bio, author.image, author.url. Its share card says "Author" above the
name, with their photo and their teams. A blogger is the same row in every language, so the slug
alone names them.
A team, "blog:team"
The active team the slug capture names: its name, description and avatar, a ProfilePage in
the language of the page whose mainEntity is the Organization with its members as Persons, and a BreadcrumbList,
Home → Blog → the team. vars — team.name, team.description, team.url. Its share card
says "Team" above the name, with the members' photos and how many they are.
Where "Blog" points
The breadcrumb's middle item is the blog's home, read off the page's own path: the post page's
parent, the parent of every other kind's parent — /blog/:slug and /blog/tag/:slug both lead
to /blog, /:lang/blog/:slug to /:lang/blog in the page's language.
What every matched page returns
permissions — what the record opens with: named, MishkaCmsWeb.RuntimeLive opens the address
only for whoever holds one of them, and the head keeps it out of an index. A tag opens with its
own; a category with its own, else its nearest parent category's; a post with its own, else its
categories' (MishkaBlog.Resources.Calculations.EffectivePermissions).
var_docs lists the page's variables in the current locale, whether or not this request filled
them. Called with no params — an editor asking which variables a page has — that is all it
changes. A slug that names no row a reader may open changes nothing else.
A module because a mishka_installer hook is one. Registered in MishkaBlog.Application.
Summary
Functions
Returns a specification to start this module under a supervisor.
Callback implementation for MishkaInstaller.Event.Hook.enable/0.
Callback implementation for MishkaInstaller.Event.Hook.get/0.
Optional. See MishkaInstaller.Event.Hook.health_check/0. Override to report health.
Optional. See MishkaInstaller.Event.Hook.on_dependency_error/1. Override to react.
Callback implementation for MishkaInstaller.Event.Hook.register/0.
Callback implementation for MishkaInstaller.Event.Hook.restart/0.
Callback implementation for MishkaInstaller.Event.Hook.start/0.
Callback implementation for MishkaInstaller.Event.Hook.stop/0.
Callback implementation for MishkaInstaller.Event.Hook.unregister/0.
Types
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec config() :: keyword()
@spec enable() :: okey_return() | error_return()
Callback implementation for MishkaInstaller.Event.Hook.enable/0.
@spec get() :: keyword()
Callback implementation for MishkaInstaller.Event.Hook.get/0.
Optional. See MishkaInstaller.Event.Hook.health_check/0. Override to report health.
Optional. See MishkaInstaller.Event.Hook.on_dependency_error/1. Override to react.
@spec register() :: okey_return() | error_return()
Callback implementation for MishkaInstaller.Event.Hook.register/0.
@spec restart() :: okey_return() | error_return()
Callback implementation for MishkaInstaller.Event.Hook.restart/0.
@spec start() :: okey_return() | error_return()
Callback implementation for MishkaInstaller.Event.Hook.start/0.
@spec stop() :: okey_return() | error_return()
Callback implementation for MishkaInstaller.Event.Hook.stop/0.
@spec unregister() :: okey_return() | error_return()
Callback implementation for MishkaInstaller.Event.Hook.unregister/0.