ElementorexCms.Source.Ecto behaviour (ElementorexCms v0.2.0)

Copy Markdown View Source

A source (ElementorexCms.Source) from an Ecto schema. Its fields are read from the schema when they are needed, so a field added to the schema (with its migration) shows up in the editor without touching anything else.

The shortest form is the schema itself in the config:

config :elementorex_cms, sources: [MyApp.Catalog.Product]

A module gives you options and a place to restrict the records (mix elementorex.gen.source Catalog.Product writes it):

defmodule MyAppWeb.Sources.Products do
  use ElementorexCms.Source.Ecto,
    schema: MyApp.Catalog.Product,
    repo: MyApp.Repo,
    label: "Products",
    icon: "shopping-bag",
    path: "/products/:slug",
    except: [:stock],
    fields: [
      price: [defaults: %{"before" => "$", "format" => "number", "decimals" => 0}],
      image_url: [label: "Photo"]
    ]

  # Every list and lookup starts here: only published products.
  @impl true
  def scope(query, _context), do: where(query, [p], p.published)
end

Filters of your own

Some filters are not a field with a value: In stock is stock > 0, On sale compares two prices. Declare them with filters: and write their query in filter/4; the editor offers them next to the fields, in loops and in the visitors' filters:

use ElementorexCms.Source.Ecto,
  schema: MyApp.Catalog.Product,
  filters: [in_stock: [label: "In stock", type: :boolean]]

@impl true
def filter(query, "in_stock", "true", _context), do: where(query, [p], p.stock > 0)
def filter(query, _name, _value, _context), do: query

Options

  • :schema (required) - the Ecto schema
  • :repo - default: config :elementorex_cms, repo: ..., else the first of the schema's app :ecto_repos
  • :key - stored in documents (default: the table name, "products")
  • :label, :icon - shown in the editor (default: the key in words and "circle-stack")
  • :only / :except - the fields to offer. By default every field except :redact ones and those whose name suggests a secret (password, token, secret, hash…), which only :only brings back
  • :fields - per field: :label, :type, :role, :sortable, :filterable and :defaults (see ElementorexCms.Source.Field)
  • :preload - belongs_to / has_one associations whose fields are offered too (category.name)
  • :search - the fields the visitors' search box looks in (default: every text field)
  • :filters - filters with logic of their own, for the visitors' filters and the loops: [in_stock: [label: "In stock", type: :boolean]]. Implement them in filter/4
  • :path - the page of each record, with :field placeholders ("/products/:slug"); offered as Link to the item
  • :order_by - default order, e.g. [asc: :name] (default: newest first when there is inserted_at)

Field types

Types come from the schema (:integer, :decimal, :boolean, dates…) and, for strings, from the name: image, photo, thumbnail, avatar, *_image_url… are images; url, link, website, *_url are links; description, body, summary, content… are text with paragraphs; *_html is rich text; color is a color. Change any with fields:.

{ElementorexCms.Source.Ecto, opts} in the config takes the same options (except scope/2, which needs a module).

Summary

Callbacks

The query of a filter declared with filters: for value (a string, or a list of strings when the visitor picked several). Default: no filter.

The query every list and lookup starts from (default: the whole table). Override it to restrict what documents can show; context has the mode (:public or :editor) and the data the host passed.

Callbacks

filter(t, name, value, context)

@callback filter(
  Ecto.Queryable.t(),
  name :: String.t(),
  value :: term(),
  ElementorexCms.Source.context()
) ::
  Ecto.Queryable.t()

The query of a filter declared with filters: for value (a string, or a list of strings when the visitor picked several). Default: no filter.

scope(t, context)

The query every list and lookup starts from (default: the whole table). Override it to restrict what documents can show; context has the mode (:public or :editor) and the data the host passed.