MishkaCmsCore.Runtime.PageBuilder.SeoSettings (Mishka CMS Core v0.0.1)

Copy Markdown View Source

The SEO a page or a layout stores, as the builder's settings modal edits it: a Gervaz form.

A resource with no table behind it

An SEO setting is not a row anywhere. It is a Page's description, seo_tags and schema, or a Layout's seo_tags. Gervaz builds a form from an Ash RESOURCE, so this is one with no data layer — Ash.DataLayer.Simple, as MishkaCmsCore.Runtime.PageBuilder.DesignToken — whose :read reads the document as the actor and whose :update writes it back through the document's own action, so every policy and validation stays the document's.

Its id names the document: "page:<id>" or "layout:<id>" (id/2), and "page:draft:<id>" or "layout:draft:<id>" for a draft of one, which the builder edits while it writes that draft.

The record is the draft

What the document stores, the add-a-tag row, whether the JSON box is open, and the head the page would render (preview/1). change/3 is what one edit writes and typed/2 what Save reads from the fields as drawn; MishkaCmsCoreWeb.Templates.SeoForm draws the draft and keeps the edited one on the form's component until Save sends params/1.

What a page sets

  • title — a stored title tag; empty, the record's title on a page that serves records, else the page's own title;
  • description — the page's own description;
  • share image, canonical address, "hide from search engines" — stored og:image, canonical and robots tags;
  • structured data — one object of a type MishkaCmsCore.Runtime.Seo.schema_types/0 offers, written in place among the page's others, or the whole of it as JSON.

Every one of them may name a variable, {{post.title}}; a plugin on MishkaCmsCore.Runtime.Seo.event/0 fills what the page leaves empty. A layout stores tags only.

What the page shows

A page that serves one record per address names the kind in its extra, "record" => "blog:post" — one of MishkaCmsCore.Runtime.Seo.record_types/1, which the installed extensions answer — and the plugin that owns the kind fills its SEO, whatever its path. The page's General tab picks it (MishkaCmsCore.Runtime.Resources.Changes.SetRecordKind); this reads it, for the variables and for a preview drawn with one of the kind's samples instead of placeholders, and Save leaves it as it is.

Summary

Functions

seo with one more, empty, question.

seo with the add-a-tag row written as a stored tag, when the row is complete.

seo after one edit, its head drawn again. params are the form's fields as drawn and target the one that changed (["seo", "add"]), which decides what else the edit writes — picking a tag to add starts its row, picking a structured-data type writes its object, typing JSON replaces the schema.

seo without a share image of its own: each record's, or none, again.

The id of a document's SEO: "page:<id>", or "page:draft:<id>" for a draft.

Validates that the keys in the provided input are valid for at least one action on the resource.

Same as input/1, except restricts the keys to values accepted by the action provided.

Which form a section's SEO is: :page where its resource stores schema and seo_tags, :tags where it stores seo_tags alone (a layout), nil where it stores neither.

What Save sends the :update action for seo.

seo with the head its page would render, asked of MishkaCmsCore.Runtime.Seo.resolve/2 with the draft in place of the stored fields; a dynamic page's plugin answers with its own variables there too. A layout has no head of its own and is returned as it is.

seo previewed in view: "google", "x" or "facebook".

The :read action: the document the id names, read as the actor, as its draft — none for an unknown section, a document the actor may not read, or a query that names no id.

The kind of record seo shows, as its record_types describe it; nil for none.

seo without the question at index.

seo without the stored tag at index.

The :update action: the draft's description, seo_tags and schema written through the document's own update action, as the actor — MishkaCmsCore.Runtime.PageBuilder.Helpers.save_section/5, the write every save in the editor takes. The saved document comes back as the record's document.

seo with the Advanced section opened, or closed.

seo with the share image's address field shown, or hidden.

seo with the fields every edit sends as they are drawn: the description, and the title, share image and canonical address, each of which is one stored tag — a value writes it, a blank removes it, an absent field leaves it.

Types

t()

@type t() :: struct()

Functions

add_question(seo)

@spec add_question(t()) :: t()

seo with one more, empty, question.

add_tag(seo)

@spec add_tag(t()) :: t()

seo with the add-a-tag row written as a stored tag, when the row is complete.

change(seo, params, target)

@spec change(t(), map(), [String.t()]) :: t()

seo after one edit, its head drawn again. params are the form's fields as drawn and target the one that changed (["seo", "add"]), which decides what else the edit writes — picking a tag to add starts its row, picking a structured-data type writes its object, typing JSON replaces the schema.

clear_image(seo)

@spec clear_image(t()) :: t()

seo without a share image of its own: each record's, or none, again.

default_short_name()

id(section, struct)

@spec id(String.t(), map()) :: String.t()

The id of a document's SEO: "page:<id>", or "page:draft:<id>" for a draft.

input(opts)

@spec input(values :: map() | Keyword.t()) :: map() | no_return()

Validates that the keys in the provided input are valid for at least one action on the resource.

Raises a KeyError error at compile time if not. This exists because generally a struct should only ever be created by Ash as a result of a successful action. You should not be creating records manually in code, e.g %MyResource{value: 1, value: 2}. Generally that is fine, but often with embedded resources it is nice to be able to validate the keys that are being provided, e.g

Resource
|> Ash.Changeset.for_create(:create, %{embedded: EmbeddedResource.input(foo: 1, bar: 2)})
|> Ash.create()

input(opts, action)

@spec input(values :: map() | Keyword.t(), action :: atom()) :: map() | no_return()

Same as input/1, except restricts the keys to values accepted by the action provided.

mode(section)

@spec mode(String.t()) :: :page | :tags | nil

Which form a section's SEO is: :page where its resource stores schema and seo_tags, :tags where it stores seo_tags alone (a layout), nil where it stores neither.

params(seo)

@spec params(t()) :: map()

What Save sends the :update action for seo.

preview(seo)

@spec preview(t()) :: t()

seo with the head its page would render, asked of MishkaCmsCore.Runtime.Seo.resolve/2 with the draft in place of the stored fields; a dynamic page's plugin answers with its own variables there too. A layout has no head of its own and is returned as it is.

primary_key_matches?(left, right)

put_view(seo, view)

@spec put_view(t(), String.t()) :: t()

seo previewed in view: "google", "x" or "facebook".

read(query, context)

@spec read(Ash.Query.t(), map()) :: {:ok, [t()]}

The :read action: the document the id names, read as the actor, as its draft — none for an unknown section, a document the actor may not read, or a query that names no id.

record_type(arg1)

@spec record_type(t()) :: map() | nil

The kind of record seo shows, as its record_types describe it; nil for none.

remove_question(seo, index)

@spec remove_question(t(), String.t()) :: t()

seo without the question at index.

remove_tag(seo, index)

@spec remove_tag(t(), String.t()) :: t()

seo without the stored tag at index.

save(changeset, context)

@spec save(Ash.Changeset.t(), map()) :: {:ok, t()} | {:error, term()}

The :update action: the draft's description, seo_tags and schema written through the document's own update action, as the actor — MishkaCmsCore.Runtime.PageBuilder.Helpers.save_section/5, the write every save in the editor takes. The saved document comes back as the record's document.

toggle_advanced(seo)

@spec toggle_advanced(t()) :: t()

seo with the Advanced section opened, or closed.

toggle_image_manual(seo)

@spec toggle_image_manual(t()) :: t()

seo with the share image's address field shown, or hidden.

typed(seo, params)

@spec typed(t(), map()) :: t()

seo with the fields every edit sends as they are drawn: the description, and the title, share image and canonical address, each of which is one stored tag — a value writes it, a blank removes it, an absent field leaves it.