Skip to content

Templates ​

Introduction ​

For every page kitloom/site lists template names from the most specific to index, by the WordPress template hierarchy, and the active theme shows the page with the first one it has — as locate_template() does. A theme that has only index shows every page with it.

The template gets the page and its parts: the content, the list of posts, the menus, the head meta. Each part is worked out only when a template asks for it.

The template hierarchy ​

PageTemplate names, the first the theme has wins
Front pagefront-page, then the names of the page or of the latest posts it shows
Latest postshome, index
Pagethe template chosen in the editor, page-{slug}, page-{id}, page, singular, index
Post, record of a typethe template chosen in the editor, single-{type}-{slug}, single-{type}, single, singular, index
Categorycategory-{slug}, category-{id}, category, archive, index
Tagtag-{slug}, tag-{id}, tag, archive, index
Other taxonomytaxonomy-{taxonomy}-{slug}, taxonomy-{taxonomy}, taxonomy, archive, index
Authorauthor-{nicename}, author-{id}, author, archive, index
Datedate, archive, index
Post type archivearchive-{type}, archive, index
Searchsearch, index
Not found404, index — the page answers 404

Examples: a book dune → single-book-dune, single-book, single, singular, index; the about page with ID 12 → page-about, page-12, page, singular, index; the genre term sci-fi → taxonomy-genre-sci-fi, taxonomy-genre, taxonomy, archive, index.

A non-Latin slug is stored percent-encoded, as WordPress stores it. The readable name comes first and the encoded one after it, so a theme names its file by the readable slug.

Which kind of page an address is — and the addresses themselves — is the main query's business; see Architecture.

The template chosen in the editor ​

WordPress keeps a page's or post's own template in the _wp_page_template meta field, and it goes first in the list. The value is a path in the theme without .php: templates/full-width.php is asked for as templates/full-width. default, an empty value or a path with .. adds nothing.

The admin panels have no field for it: the value comes with content moved from WordPress, or is set in code:

php
$page->setMeta('_wp_page_template', 'templates/full-width.php');

File names ​

A template's name is its path under the theme's templates directory, without the extension:

TemplateBladeVue
single-bookresources/views/templates/single-book.blade.phpresources/js/Templates/single-book.vue
404resources/views/templates/404.blade.phpresources/js/Templates/404.vue
templates/full-widthresources/views/templates/templates/full-width.blade.phpresources/js/Templates/templates/full-width.vue

A Blade theme's templates are found on disk. A Vue theme's are read from its build: kitloom-templates.json lists the templates the build has, so a template added after the last build is not used until the next one. While the Vite dev server runs, the files themselves are looked at. See Building Assets.

The Vue template's name is also the Inertia component's name: the theme's app.js resolves single-book to ./js/Templates/single-book.vue.

Adding candidates ​

A module or a theme changes the list by listening to Kitloom\Site\Events\TemplateCandidates. The event carries the main query's $result and the $candidates:

php
use Illuminate\Support\Facades\Event;
use Kitloom\Site\Events\TemplateCandidates;

Event::listen(TemplateCandidates::class, function (TemplateCandidates $event): void {
    if ($event->result->isSingle() && $event->result->object?->getMeta('layout') === 'landing') {
        $event->candidates->prepend('landing');
    }
});
MethodDoes
prepend(...$names)Puts the names first.
append(...$names)Puts the names last.
before($existing, ...$names)Puts the names right before another one; at the end when it is not in the list.
remove(...$names)Takes names out.
has($name), all()Reads the list.

index is always in the list before the event is sent. A theme registers its listener in bootTheme(), so it is there only while the theme is active.

Page parts ​

A part is one piece of what a page shows. Each has a key — its name in JSON and in a Vue template's props — and a toArray() whose keys are a contract with theme authors.

Core parts ​

kitloom/site provides these on every site:

PartKeyGives
Kitloom\Site\Page\Parts\ContentcontentWhat the page is about: a record with its text (after the content filters), excerpt, dates, author, thumbnail and terms; a term; an author; or the list itself with its title.
Kitloom\Site\Page\Parts\PostspostsThe posts of a list page (items) and its pagination: page, pages, total, next and previous, page links.
Kitloom\Site\Page\Parts\BreadcrumbsbreadcrumbsFrom the home page to this one: a list of title and url.
Kitloom\Site\Page\Parts\WidgetswidgetsThe widgets of every zone, by zone ID — the zones added on Appearance → Widgets included — and the widget slots of the page's type. in('sidebar-1') gives one zone.
Kitloom\Site\Page\Parts\SiteInfositeThe site's name, description (tagline), url and language.
Kitloom\Site\Page\Parts\AccountaccountThe visitor's account: on the account page, the view to draw (sign in, sign up, details, a module's section) and where its forms post; elsewhere, who is signed in and where the account page is.
Kitloom\Site\Page\Parts\BreadcrumbsSeparatorbreadcrumbsSeparatorThe breadcrumb separator, set by whoever provides the breadcrumbs. Not on a JSON page unless asked for.

Parts of modules ​

PartKeyModule
Kitloom\Navigation\Parts\Menusmenuskitloom/navigation — the menus in the site's locations by their slug, their items as a tree; a menu in no location is not on the page. get('main') gives one, in a location or not. A menu is built only when the page asks for it, as wp_nav_menu() builds the one of its location: a template that draws no menu reads none, and the first get() of a location's menu builds the menus of all the locations together.
Kitloom\Navigation\Parts\LocationsmenuLocationskitloom/navigation — which menu is in which location, the locations added on Menu Locations included: primary → main-menu. menu('primary') gives the slug.
Kitloom\Seo\Site\Headheadkitloom/seo — what goes into <head>: the title, description, robots, canonical address, Open Graph and Twitter tags.
Kitloom\Seo\Site\Schemaschemakitloom/seo — the schema.org @graph, printed as JSON-LD.
Kitloom\Shortcodes\Site\ShortcodeDatashortcodeskitloom/shortcodes — the data of each shortcode on the page, by its anchor's key.
Kitloom\Shop\Site\MiniCartcartkitloom/shop — the item count, total and cart and checkout addresses.
Kitloom\Shop\Site\ShopNoticesnoticeskitloom/shop — what the previous shop action reported.
Kitloom\Shop\Site\Catalogcatalogkitloom/shop — a catalog page's products, filters and sorting.
Kitloom\Shop\Site\ProductDetailsproductkitloom/shop — the product of a product page.
Kitloom\Comments\Site\Commentscommentskitloom/comments — a singular page's comments and the form under them.
Kitloom\Maintenance\Site\ComingSooncomingSoonkitloom/maintenance — what the holding page shows: the mode, headline, text, image and sign-in link.
Kitloom\SocialAccounts\Site\SocialLoginPartsocialLoginkitloom/social-accounts — the social sign-in buttons for the theme's own sign-in form.
Kitloom\Languages\Site\Parts\LanguageSwitcherlanguageskitloom/languages — the site's languages with this page's address in each.
Kitloom\Bookings\Site\BookingDatabookingkitloom/bookings — services, staff and rules for the theme's booking form.
Kitloom\Listings\Site\ListingDetailslistingDetailskitloom/listings — a property's or listing's page: gallery, facts, floor plans, map.
Kitloom\Listings\Site\ListingSearchPartlistingSearchkitloom/listings — a listing page's results, filters and map.
Kitloom\Listings\Site\AgentProfileagentProfilekitloom/listings — an agent's or agency's page.
Kitloom\Listings\Site\ReviewStarsreviewStarskitloom/listings — the stars of each review on a listing's page.
Kitloom\Courses\Site\CourseCatalogPartcourseCatalogkitloom/courses — the course list and the featured courses.
Kitloom\Courses\Site\CourseDetailscourseDetailskitloom/courses — a course's page: its card, curriculum and instructor.
Kitloom\Courses\Site\LessonPartlessonkitloom/courses — a lesson's page inside its course.
Kitloom\Courses\Site\QuizPartquizkitloom/courses — a quiz's page inside its course.

kitloom/seo also replaces the core breadcrumbs with Rank Math's, under the same breadcrumbs key, and prints verification codes, Open Graph, Twitter cards and the schema graph into @siteHead itself. The title, description, robots and canonical tags stay the theme's: it prints them from the head part, with fallbacks of its own.

A part of a module the site does not have is not there. A Blade template asks first — $page->has(Menus::class) — or $page->part() throws MissingPart; a Vue theme may list such parts, and they are left out of the props.

blade
@php($menus = $page->has(\Kitloom\Navigation\Parts\Menus::class) ? $page->part(\Kitloom\Navigation\Parts\Menus::class) : null)
@include('partials.menu', ['menu' => $menus?->get('main')])

A part of your own ​

A part implements Kitloom\Site\Page\Part: a static key(), toArray(), and a static schema() — what toArray() gives, as a JSON Schema written with Kitloom\Site\Page\Schema\Shape, which typed themes, JSON pages and agents rely on (php artisan kitloom:schema writes it out). It is provided — by a module in its provider, by a theme in bootTheme() — with a PartProvider class or a closure:

php
use Kitloom\Site\Page\Page;
use Kitloom\Site\Page\PageParts;

$this->callAfterResolving(PageParts::class, fn (PageParts $parts) => $parts->provide(
    Reviews::class,
    ReviewsProvider::class,                                      // implements PartProvider: for(Page $page): Part
    json: fn (Page $page): bool => $page->result->isSingle(),   // which JSON pages have it by default
));

A provider that needs another part asks the page for it — $page->part(Content::class). A part is worked out once a request, and not at all if nobody asks for it.

JSON pages ​

Any page answers with JSON when asked with Accept: application/json, and every page does when the site has no theme:

GET /books/dune/               Accept: application/json
GET /books/dune/?include=content,menus
json
{
    "kind": "single",
    "template": "single-book",
    "url": "https://example.com/books/dune/",
    "content": { "title": "Dune", "…": "…" }
}

template is the template the active theme would show the page with, so a front end can pick its own component the same way; it is null when there is no theme. The parts are the default set for the page — each part decides whether it is there by default — or exactly those include names. A page not found answers 404, its document still there with kind: not-found. See Headless & APIs.

kitloom — modules and themes for Laravel.
Pricing · Services · License · Refunds · Privacy · Community · [email protected]