API Reference Mishka Blog v#0.0.1

Copy Markdown View Source

Modules

The blog's Ash domain: posts, collections, tags, bloggers and teams with their followers, comments, ratings, bookmarks and views, and auto posting, and the JSON:API routes that serve them to a master, to a site's admin and to a visitor.

The blog's OTP application. It supervises the task supervisor that highlights a post's code blocks and every mishka_installer plugin the extension ships (plugins/0): the dashboard widgets, the notification producers, the settings, sidebar, install, SEO, share card, stylesheet and page plugins. A plugin registers on the event it listens on once it is supervised here.

Manages auto-posting configurations in the MishkaBlog plugin with full versioning support.

Manages blog posts in the MishkaBlog plugin with full versioning and translation support.

Manages blogger profiles in the MishkaBlog plugin with full versioning support.

Manages user follows for bloggers.

Manages blog post collections in the MishkaBlog plugin with full versioning support.

Manages blog post comments in the MishkaBlog plugin with full versioning support.

Manages user votes (upvote/downvote) on comments.

Every number on the blog analytics page (/admin/dashboard/blog/analytics), read from the database.

Every number on the blog admin overview page (/admin/dashboard/blog), read from the database.

Every read of the blog dashboard — MishkaBlog.Dashboard.Overview, MishkaBlog.Dashboard.Analytics and the widgets under MishkaBlog.Dashboard.Widgets — as the user viewing it, through the resource's own policies.

Registers every mishka_blog dashboard widget's own settings with the Settings page through the settings:register mishka_installer hook — so "Posts to show" is documented under the Blog tab (category: "blog", group Dashboard widgets) alongside the rest of the blog's settings, instead of hiding inside the dashboard's per-user layout where nothing else could see it.

Dashboard widget (a dashboard:widgets plugin): the top bloggers leaderboard — a podium of the three most-published profiles plus the runners-up, each with their post tally and publish role (Blogger + the post_count aggregate), read as the viewer through MishkaBlog.Dashboard.Scope: a master ranks bloggers across every site, a site's admin only their own site's, and a viewer without admin:dashboard:blog:post none.

Dashboard widget (a dashboard:widgets plugin): comments awaiting moderation — a pending count plus the latest few with an excerpt of their content (Comment), read as the viewer through MishkaBlog.Dashboard.Scope: a master moderates across every site, a site's admin only their own site's, and a viewer without admin:dashboard:blog:comment none. Each author is named as the comments page names them (MishkaBlogWeb.Templates.CommentCard.author/1), from what the viewer may read of the account.

Dashboard widget (a dashboard:widgets plugin): draft vs scheduled post counts plus the latest unpublished posts — drafts with their age, scheduled posts with their publish time (BlogPost), read as the viewer through MishkaBlog.Dashboard.Scope: a master sees every site's pipeline, a site's admin only their own site's, and a viewer without admin:dashboard:blog:post none.

Dashboard widget (a dashboard:widgets plugin): the latest blog posts with their status, read as the viewer through MishkaBlog.Dashboard.Scope: a master sees every site's posts, a site's admin only their own site's, and a viewer without admin:dashboard:blog:post none.

Dashboard widget (a dashboard:widgets plugin): the most-viewed published posts with their view tally (BlogPost + the view_count aggregate), read as the viewer through MishkaBlog.Dashboard.Scope: a master ranks posts across every site, a site's admin only their own site's, and a viewer without admin:dashboard:blog:post none.

Generator for MishkaBlog resources.

Dev and stress seeds for MishkaBlog resources.

Where this extension's UI kit bundle is, and how to install it.

Registers mishka_blog's notification toggles with the Settings page through the settings:register mishka_installer hook. Each toggle is a boolean (default on) under the Blog tab (category: "blog") in a Notifications group (group:), with scope: :both — a global default (shown in the master's Global view) that any site may override. Every mishka_blog setting lives under the Blog tab; group separates concerns within it (Notifications, and e.g. AI later). Delivery honours it: the engine gates every notification on Settings.get(Notify.setting_key(type), true, site_id) (site → global → default) before fanning it out.

The master half of MishkaBlog.Notifiers.PostPublished. A master publishes through :master_publish, which fires blog:blog_post:after_master_publish — not the tenant action's event — so without a plugin here a post a master published would tell nobody. It delivers exactly what a tenant publish delivers, to the same audience. Registered in MishkaBlog.Application.

A plain mishka_installer plugin: when a tenant publishes a blog post (blog:blog_post:after_publish), notify the tenant's blog admins AND master admins — in one Notify.deliver/3 call — except the publisher themselves (the notifier's meta.actor, passed as except:), so no one is told about their own post.

The rows a page of the blog is made of, read once for the request and handed to everything that draws them: the head (MishkaBlog.Plugins.PageSeo), the frame (MishkaBlog.Plugins.PageFrame) and the page's blocks.

A plain mishka_installer plugin: after a blogger is saved (blog:blogger:after_save — created, updated or published, a master's twin alike), its share card is looked at in the background and drawn when what it shows changed (MishkaCmsCore.Runtime.ShareCard.refresh/3), so it is ready before the first visitor. Only while it is not archived (MishkaBlog.ShareCards.target/1). Registered in MishkaBlog.Application.

A plain mishka_installer plugin: after a category is saved (blog:collection:after_save — created, updated or published, a master's twin alike), its share card is looked at in the background and drawn when what it shows changed (MishkaCmsCore.Runtime.ShareCard.refresh/3), so it is ready before the first visitor. Only while it is active (MishkaBlog.ShareCards.target/1). Registered in MishkaBlog.Application.

Tells a site's stylesheet which components its posts draw, which icons they name and which classes they write, through the runtime:compile:content_components hook MishkaCmsCore.Runtime.Compilers.TailwindCompiler.content_components/1 fires while it builds a site's stylesheet: the names the site's published posts list in content_components, the icon classes they list in content_icons and the classes they list in content_classes, which MishkaBlog.Resources.Changes.ContentFacts stores when a post is written. A template that draws a post's body — the kit's blog-post-detail — then reaches those components and no others (MishkaCmsCore.Runtime.Compilers.CssClosure), the stylesheet carries a rule for each icon, and it is built with each class.

Installs the blog onto one site, when asked.

What the blog tells the site's layout about each of its pages, through the runtime:page:frame mishka_installer hook MishkaCmsCore.Runtime.SiteLayout fires in handle_params/3: the bar under the header, and the languages the record a page shows is written in. The layout draws both, so no page of the blog draws a bar or a language switcher of its own.

Names the kinds of record the blog's pages show — a post, a collection, a tag, a blogger, a team — on the runtime:page:records mishka_installer hook, for a page's "This page shows each" choice (see MishkaCmsCore.Runtime.Seo.record_types/1), each with a few of the site's own to preview a page with. Each is labelled as the blog's admin names it, where its Permissions and SEO Tags are set. MishkaBlog.Plugins.PageSeo answers for the same kinds.

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).

Reads the rows a page of the blog shows, once, through the runtime:page:source mishka_installer hook MishkaCmsWeb.RuntimeLive fires in handle_params/3 before the frame and the head (MishkaCmsCore.Runtime.PageSource is the contract: the map it is handed and where what it reads goes).

A plain mishka_installer plugin: after a post is saved (blog:blog_post:after_save — created, updated or published, a master's twin alike), its share card is looked at in the background and drawn when what it shows changed (MishkaCmsCore.Runtime.ShareCard.refresh/3), so it is ready before the first visitor. Only while it is published (MishkaBlog.ShareCards.target/1). Registered in MishkaBlog.Application.

A plain mishka_installer plugin: answers MishkaCmsCore.Runtime.ShareCard.targets_event/0 with the blog's share cards on the site asked, under "mishka_blog" (MishkaBlog.ShareCards.targets/1), so a redraw of every card of a site — and the blog's own Redraw button in its check-and-repair modal — reaches its posts, categories, tags, bloggers and teams. Registered in MishkaBlog.Application.

Adds the blog's posts, categories, bloggers, teams and the tags that ask to be indexed to a site's /sitemap.xml, through the seo:sitemap:urls mishka_installer hook MishkaCmsCore.Runtime.Compilers.SitemapCompiler fires when it builds a site's sitemap. A post, a category, a tag, a blogger or a team written rebuilds its site's sitemap, because those resources list MishkaCmsCore.Runtime.Resources.Notifiers.SitemapRefresh.

A plain mishka_installer plugin: after a tag is saved (blog:tag:after_save — created, updated or published, a master's twin alike), its share card is looked at in the background and drawn when what it shows changed (MishkaCmsCore.Runtime.ShareCard.refresh/3), so it is ready before the first visitor. Only while it is not archived (MishkaBlog.ShareCards.target/1). Registered in MishkaBlog.Application.

A plain mishka_installer plugin: after a team is saved (blog:team:after_save — created, updated or published, a master's twin alike), its share card is looked at in the background and drawn when what it shows changed (MishkaCmsCore.Runtime.ShareCard.refresh/3), so it is ready before the first visitor. Only while it is active (MishkaBlog.ShareCards.target/1). Registered in MishkaBlog.Application.

Names the words the blog's bar looks up (MishkaBlog.Plugins.PageFrame.words/0) on the runtime:translations:used_keys mishka_installer hook MishkaCmsCore.Runtime.Translations fires when it works out which keys a site still uses.

Manages the many-to-many relationship between blog posts and bloggers with full version control.

Manages user bookmarks for blog posts.

Manages the many-to-many relationship between blog posts and collections with full version control.

Manages user ratings for blog posts.

Manages the many-to-many relationship between blog posts and tags with full version control.

Tracks unique page views for blog posts using upsert.

What a site needs before anybody can look at its blog: this extension's live components, nine sample pages built out of them, and the sidebar saved as a snippet an author can drop anywhere.

Previews a record as it was in one of its own versions, without restoring it: the generic action takes the record's id and a :version_id argument and returns the record with the version's values over it.

The permissions a post or a category opens with on its blog page, in its sitemap entry and wherever else a reader is let in, and those a comment is reached with

What a post's content says about it, worked out once, when the content is written — reading a post works out neither

Highlights the code blocks of a post's content with Makeup, once, when the post is written.

Keeps a post's publish times in step with its :status.

Restores a record to one of its own versions, named by the action's :version_id argument.

The version resource a PaperTrail-tracked blog resource keeps its history in: the table, its foreign key to the record, and the actions and policies that read the history.

Keeps a public read to the records its reader may open, by the rule the record's page keeps: a record whose lock names permissions opens only for a reader holding one of them (AccessPermissions.match?/3), and never for a visitor who is not signed in. A list leaves out, in its own query, every record the reader may not open, so its pages and its count are of what the reader sees; asking for one of them by itself finds nothing, as an id nothing is stored at does.

Turns a read of one record into a preview of it as it was in one of its own versions, named by the read's :version_id argument. Nothing is saved.

What a reader may open, as the filter of the read that fetches the records: the answer MishkaCmsCore.Accounts.Checks.AccessPermissions gives for a record's lock, worked out by the database in the statement that reads the rows, so that no lock is read beforehand.

Keeps a public list to the site it is asked on: only the rows whose :through record belongs to the tenant.

Refuses an update that makes a record its own parent: the attribute :field may not hold the record's own id. Any other record, or none, is let through. The refusal is :message on :field.

Refuses a write onto a record its actor may not open — a comment, a rating or a bookmark on a locked post, a vote on a comment of one — with the message the action gives for a record that is not there, so the refusal tells nothing a reader may not know. Who may open it is what its page asks (MishkaBlog.Resources.Preparations.OpenToActor.opens?/2).

Which share card (MishkaCmsCore.Runtime.ShareCard) a blog record shows: the kind of record its page shows (MishkaBlog.Plugins.PageRecords) and the captures that name it — what a page of that kind answers for (MishkaBlog.Plugins.PageSeo).

Manages blog post tags in the MishkaBlog plugin with full versioning support.

Manages team structures in the MishkaBlog plugin with full versioning support.

Manages user follows for teams.

Manages the many-to-many relationship between teams and bloggers with full version control.

Manages the many-to-many relationship between teams and permissions.

The router the blog's JSON:API is served through, with its OpenAPI document at /open_api. The domains it routes are set by the host application's config.

The blog analytics page: five KPI tiles, a daily views chart, the most-read posts, where their readers came from and whether they were signed in — every figure read from the view log by MishkaBlog.Dashboard.Analytics.

The auto posting list: a Gervaz table of the site's auto posting configurations. The page decodes the URL state and, once connected, forwards the PubSub broadcasts of its site (every site for a master) into the table component.

The bloggers grid: a Gervaz table drawn as MishkaBlogWeb.Templates.BloggerCard, its create/edit form, and the version history of one blogger.

The collections grid: a Gervaz table drawn as MishkaBlogWeb.Templates.CollectionCard, its create/edit form, a modal that edits one language edition of a collection, and the version history of one collection, which switches between its language editions.

The comments list: a Gervaz table drawn as MishkaBlogWeb.Templates.CommentCard, with a create / edit / reply form.

The blog admin overview: five KPI cards, eight section cards, an editorial calendar and three summary panels, every number read from the database by MishkaBlog.Dashboard.Overview.

The blog posts list: a Gervaz table drawn as MishkaBlogWeb.Templates.PostCard, its create/edit form, and the version history of one post.

The tags grid: a Gervaz table drawn as MishkaBlogWeb.Templates.TagCard, its create/edit form, and the version history of one tag.

The teams grid: a Gervaz table drawn as MishkaBlogWeb.Templates.TeamCard, its create/edit form, and the version history of one team.

The version history of a dashboard list page: a modal that lists one record's versions a page at a time, previews one of them, and restores one. The page keeps the template, its :versions_modal and the one-line event handlers; everything they do is here.

Extension routes for MishkaBlog.

The blog's admin pages and the one sidebar entry that links to them — a "sidebar:menus" plugin (MishkaCmsCore.Sidebar).

The bloggers grid: one card per blogger, in as many columns as fit the screen.

The collections grid: one card per collection, in as many columns as fit the screen.

The comments list: one full-width row per comment, stacked.

The language chips of a translated blog record: one per edition, the record's own first, each opening that edition.

The blog posts list: one full-width row per post, stacked.

The tags grid: one compact chip per tag, packed several to a row.

The teams grid: one card per editorial team, in as many columns as fit the screen.