Skip to content

Partials

Greg Bowler edited this page Apr 12, 2026 · 12 revisions

Partials let us build page templates in plain HTML using INI syntax at the top of the file.

The everyday use case is straightforward: one page contains its own content, and a comment at the top says which base template it extends.

A simple partial extension

Page HTML:

<!--
extends=base-page
-->

<h2>Welcome</h2>
<p>This page body will be injected into the template.</p>

Base template:

_partial/base-page.html

<!doctype html>
<html>
<head>
	<title>My site</title>
</head>
<body>
	<header>
		<h1>My site</h1>
	</header>

	<main data-partial></main>
</body>
</html>

PHP:

use GT\DomTemplate\PartialContent;
use GT\DomTemplate\PartialExpander;

$partialExpander = new PartialExpander(
	$document,
	new PartialContent(__DIR__ . "/_partial"),
);

$partialExpander->expand();

If we do this, the page's body content is moved into the template's data-partial element.

Note

WebEngine applications automatically expand any partial content added to pages so the only thing you need to do in WebEngine is place the HTML files in the correct directory. All PHP is automated for you.

Template variables with [vars]

The opening comment can also contain a [vars] section.

Page HTML:

<!--
extends=base-page

[vars]
title=Orders
heading=Order history
-->

<p>Your recent orders are shown below.</p>

Base template:

<!doctype html>
<html>
<head>
	<title>{{title ?? Home}}</title>
</head>
<body>
	<h1 data-bind:text="heading">Default heading</h1>
	<main data-partial></main>
</body>
</html>

If we pass a DocumentBinder into expand(), those variables are bound automatically:

$partialExpander->expand(binder: $binder);

Recursive partials

Partials can extend other partials.

That means we can have:

  • a page extending a section layout
  • that section layout extending a global site layout

DomTemplate expands that chain from the inside out until the final page is assembled.

Rules for the opening comment

The comment is parsed as INI syntax.

That means:

  • it must be the leading meaningful node in the document
  • extends names the partial file to load
  • [vars] provides simple string variables for binding

If the comment is in the wrong place, DomTemplate throws CommentIniInvalidDocumentLocationException.

Injection point rules

The target partial must contain exactly one element marked with data-partial.

  • If there's no data-partial element -> PartialInjectionPointNotFoundException
  • If there's more than one data-partial element -> PartialInjectionMultiplePointException

That keeps the template structure explicit and avoids guesswork.

Partial file lookup

PartialContent resolves partial files from the directory we gave it:

$partialContent = new PartialContent(__DIR__ . "/_partial");

Then:

  • extends=base-page -> _partial/base-page.html

The same PartialContent helper is also used by components.


The page composition story is now complete. Next, move on to debugging so we can see how to inspect where binds came from.

Clone this wiki locally