Who this is for. Developers and content modellers setting up a new definition. After this page you can fill in a definition so that nothing has to be undone once authors start entering records.
Identifier, name and icon
The identifier is the name code uses for the type: in a template query ($_query->findCustomEntityRecordsBy('store')), in the variables the listing and detail templates receive, and in the API paths. It starts with a letter, followed by letters, digits, hyphens or underscores, two characters at least. These words are reserved, because they would shadow a fixed API path: definitions, definition, dynamic, activate-revision, record-revision, duplicate-record and check-record-slug.
Choose it with care: the identifier cannot be changed once the definition has any records.
The name and the icon are what authors see in the admin, and you can change them at any time. The plural forms are derived for you: a definition with the identifier store lists its records as stores, both in the listing template and in the API path.
Paths and URL addressing
Two paths give records their URLs. The path is the prefix of the listing, such as /stores; the record path is the prefix of each record's detail page, such as /store/richmond. Either can be left empty, and that route then does not exist. Both also need the definition to be URL addressable (on by default), which gives each record a slug.
The routes are rebuilt from the definitions on every request, so a changed path works on the next request. Nothing redirects the old URLs: when records were already linked or indexed under the old path, add redirects by hand (Rewrites, redirects and which address wins).
Turning URL addressing on for a definition that already has records does not give them slugs. Instead, the next save of each record that has no slug is refused until a slug is entered.
The layout and the listing template
A definition names two templates, in two different ways:
- The template is a plain path on the definition, such as
stores/index.html. The listing route renders it. Leave it empty and the listing answers 404. - The layout is an ordinary layout record, and the detail route renders the layout's template. A definition cannot be saved without one: if you do not choose a layout, one is created for it, named
Custom entity: <identifier>.
A record's layout areas work as a page's
A record takes its layout areas exactly as a page does. Input types, layout areas, groups, attributes, components and collections, the shorthand and live preview: everything in The chain from input type to template and the rest of Guide 4 applies unchanged. A team that can build a page layout can build this one; there is no separate approach for custom entities.
Content lives in revisions here too. {$store->openingHours} reads the openingHours area of the record's active revision, as {$page->intro} does on a page, and the explicit getters, such as getAreaText('openingHours'), read the same revision. How revisions are made, published and approved is in Revisions and the active revision.
The one difference: the layout belongs to the definition, not to the revision. A page's author picks a layout per page; every record of a definition renders through the same layout and the same detail template. What varies between records is their content, never their layout.
While you build, a record can tell you which definition it belongs to and which template renders it: