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)
endFilters 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: queryOptions
: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:redactones and those whose name suggests a secret (password,token,secret,hash…), which only:onlybrings back:fields- per field::label,:type,:role,:sortable,:filterableand:defaults(seeElementorexCms.Source.Field):preload-belongs_to/has_oneassociations 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 infilter/4:path- the page of each record, with:fieldplaceholders ("/products/:slug"); offered as Link to the item:order_by- default order, e.g.[asc: :name](default: newest first when there isinserted_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
@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.
@callback scope(Ecto.Queryable.t(), ElementorexCms.Source.context()) :: Ecto.Queryable.t()
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.