Blog plugin events
v0.0.1
The blog fires mishka_installer events at the points below, so a plugin can react to a change, adjust a query, rewrite content or veto an action without editing the blog. This page lists those events, what a plugin receives and what it returns, and the events of the CMS that the blog's own plugins listen on. A plugin is a module that uses MishkaInstaller.Event.Hook and is started in a supervision tree, as the blog does for its own.
Event names
A blog event is named blog:<resource>:<phase>_<action>. The resource is the last part of the module name, in snake case: MishkaBlog.BlogPost is blog_post, MishkaBlog.PostRating is post_rating. The action is the Ash action that ran, such as publish. The action of a master, such as master_publish, fires its own event.
After events
Fired after the action's transaction commits. The plugin receives the saved record and a read-only meta of %{actor:, site_id:}. The reply does not change the action.
| Event | Fired when |
|---|---|
blog:<resource>:after_<action> | Any action of the resource runs, such as blog:blog_post:after_publish, blog:comment:after_create or blog:post_rating:after_remove. |
blog:<resource>:after_save | Any create or update action of the resource runs, including a master's. It fires after the event of the action itself. |
These resources fire them: blog_post, collection, tag, blogger, team, comment, auto_posting, post_rating, post_bookmark, comment_vote, blogger_follower, team_follower, post_view, post_blogger, post_collection, post_tag, team_member and team_permission.
Before events
Fired before the action runs. The plugin receives the changeset. It returns the changeset, changed or not, or the changeset with Ash.Changeset.add_error/2 to reject the action.
| Event | Runs on |
|---|---|
blog:blog_post:before_create | A site admin creating a post. A master's create does not fire it. |
blog:comment:before_create_public | A reader writing a comment. |
Query events
Fired before a read runs. The plugin receives the Ash.Query and returns it, usually with an added filter or sort.
| Event | Read |
|---|---|
blog:blog_post:query_published | The published posts of a site admin. |
blog:blogger:query_public_list, blog:blogger:query_public_by_slug | The public bloggers. |
blog:team:query_public_list, blog:team:query_public_by_slug | The public teams. |
blog:comment:query_public_list | The public comments. |
Render events
Fired when the rendered_content calculation of a post or comment is loaded, which blog-post-detail and blog-post-comments do. The plugin receives %{html: raw, record: record} and returns %{html: changed}.
| Event | Content |
|---|---|
blog:blog_post:render_content | A post's body. |
blog:comment:render_content | A comment's text. |
Example: reject a comment
This plugin refuses a reader's comment that contains a phrase. Start it in your application's supervision tree.
defmodule MyApp.Plugins.RejectComment do
use MishkaInstaller.Event.Hook, event: "blog:comment:before_create_public"
@impl true
def call(changeset, _meta) do
content = Ash.Changeset.get_attribute(changeset, :content) || ""
if String.contains?(content, "buy now") do
{:reply, Ash.Changeset.add_error(changeset, field: :content, message: "Rejected")}
else
{:reply, changeset}
end
end
endAn after event listens by name too. MishkaCmsCore.Runtime.Resources.Notifiers.PluginHook.event_name/2 builds the name, so the plugin cannot misspell it.
alias MishkaCmsCore.Runtime.Resources.Notifiers.PluginHook
use MishkaInstaller.Event.Hook,
event: PluginHook.event_name(MishkaBlog.BlogPost, :publish)Events the blog listens on
The blog starts 24 plugins of its own. These are the events they listen on.
| Event | What the blog does |
|---|---|
sidebar:menus | Adds the Blog entry and the blog's screens to the admin sidebar. |
dashboard:widgets | Adds the five dashboard widgets. |
settings:register | Registers the widget sizes, the notification toggle, and the set-up version and active switch. |
installer:extension:install | Sets the blog up on a site when an install is asked for, and hands any other request on untouched. |
seo:sitemap:urls | Adds posts, collections, bloggers and teams to the sitemap, and the tags that ask to be indexed. |
runtime:page:records | Names the five kinds of record a page can show. |
runtime:page:source | Reads the rows a blog page shows once, as the visitor, for the page's head, its frame and its blocks. |
runtime:page:frame | Hands the site layout the blog's bar and the languages of the record the page shows. |
runtime:page:seo | Builds the head of a page that shows one of those records, from the rows the page read once. |
runtime:translations:used_keys | Names the words the blog's bar looks up, so Remove unused keeps them. |
runtime:compile:content_components | Tells the site's stylesheet which icons and classes the published posts use, and which components. A component name reaches the stylesheet only when a template of the site draws a post's body, as blog-post-detail does. |
runtime:share_card:targets | Names every share card of a site, for a redraw of all of them. |
blog:<resource>:after_save for posts, collections, tags, bloggers and teams | Draws the record's share image again when what it shows has changed. |
blog:blog_post:after_publish, blog:blog_post:after_master_publish | Notifies the holders of admin:dashboard:blog:post, except the publisher. |
Plugins that read and frame a page
Three plugins read a blog page once and frame it. A request runs PageSource first, then PageFrame, then the blog's PageSeo, which builds the head from the same rows. PageSource and PageFrame answer only for their own pages and hand every other page back untouched before they read anything. TranslationKeys runs when the CMS works out which translation keys a site still uses. All three run at priority 50.
| Plugin | Event | Answers for | Returns |
|---|---|---|---|
MishkaBlog.Plugins.PageSource | runtime:page:source | A page whose record is blog:post, blog:category, blog:tag, blog:author or blog:team, whatever its section. Also the blog's front page, which is the page of the Posts place. | {:reply, :halt, given} with source set to a MishkaBlog.PageSource struct. Any other page: {:reply, given}. |
MishkaBlog.Plugins.PageFrame | runtime:page:frame | A page of the section blog: translations and section_bar. A page of another section that shows one of the five records: translations only, with no bar. | {:reply, :halt, frame}. Any other page: {:reply, frame}. |
MishkaBlog.Plugins.TranslationKeys | runtime:translations:used_keys | Every call. | {:reply, data} with the bar's five words added to keys. |
What the source holds
The source is read in handle_params/3, as the signed-in visitor or as a guest, through the same public actions the blocks read with. A record that visitor may not open is nil in the struct.
- A post is read with its text as the site draws it, its readers' rating, its count of approved comments, its categories and tags, its authors with their teams, and its other editions.
- A category and a tag are read with the number of posts their own page lists and their other editions. The page of their post list that the address names is read with them.
- A blogger is read with their teams. A team is read with its members and how many posts each has.
- The front page holds the featured posts of its strip, how many posts the visitor may open in the page's language, and the page of the list that the address names.
A list the reader narrows with a search, or on the front page with a tag, reads for itself. A live patch that stays on the same record, such as another page of a list, takes from the read of the address before it what the new address left unchanged. A block takes rows from the source only when it declares the page_source attribute and the source was read for the same site, visitor, language and page. See Page source: read a page's rows once.
What the frame holds
- The bar shows the blog's name, which leads to the front page, and four places (Posts, Categories, Tags and People). The place the reader is in is marked. A post, a category and a tag are in Posts, and a blogger and a team are in People.
- The bar's words are the site's translations in the response's language. A word nobody translated shows as its key.
- For a post, a category and a tag, the languages are every published edition the visitor may open, each at its own slug. A blogger and a team are one record in every language, so each language the site publishes in is offered at the same slug. A list page keeps the layout's own list: the same path in each language.
See Page frame: languages and the section bar for the shape of both entries.
What the translation keys name
The five words are Blog, Posts, Categories, Tags and People. No template holds them, because a plugin draws the bar. Without TranslationKeys, Remove unused on the Translations screen would delete them and what a translator wrote for them. Setting the blog up registers the same words for each language of the site. See Translate an extension's words.