Skip to content

Commit 246e3f6

Browse files
committed
Merge branch '1.2' into develop
2 parents 8259f77 + 7bf75ca commit 246e3f6

File tree

2 files changed

+217
-0
lines changed

2 files changed

+217
-0
lines changed

cms/themes.md

Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,3 +196,219 @@ Winter CMS comes with another very useful feature, disabled by default, called D
196196
Files modified in the database are cached to indicate that they should be loaded from the database.
197197

198198
> **NOTE:** All CMS template objects (ex. `Layout`, `Page`, `Content`, `Partial`, `Meta`, etc) are stored in the database when this feature is enabled and a change is made to the template in question; however theme asset files will **not** be.
199+
200+
## Child Themes
201+
202+
Child themes allow you to create a new theme that inherits templates and assets from a "parent" theme. This is useful when you want to customize an existing theme without modifying the original files, create variations of a base theme, or manage multiple similar themes for different clients or tenants.
203+
204+
When using a child theme, you can override specific pages, partials, layouts, content files, or assets from the parent theme by creating files with the same path in your child theme. Any files not present in the child theme will automatically fall back to the parent theme.
205+
206+
### Configuring a Child Theme
207+
208+
To create a child theme, specify the parent theme's directory name using the `parent` key in your child theme's `theme.yaml` file:
209+
210+
```yaml
211+
name: "My Custom Theme"
212+
description: "A customized version of the Demo theme"
213+
author: "Your Name"
214+
homepage: "https://example.com"
215+
parent: demo
216+
```
217+
218+
The value of `parent` should be the directory name of the parent theme (e.g., if the parent theme is located at `themes/demo`, use `demo` as the parent value).
219+
220+
> **NOTE:** See the [Theme information file](../themes/development#theme-information-file) documentation for more details on configuring the `parent` option.
221+
222+
### Creating a Child Theme
223+
224+
The minimal requirement for a child theme is a `theme.yaml` file that specifies a parent theme. Here's how to create a basic child theme:
225+
226+
**Step 1:** Create a new theme directory:
227+
228+
```treeview
229+
themes/
230+
|-- demo/ # Parent theme
231+
`-- my-custom-theme/ # Child theme
232+
`-- theme.yaml
233+
```
234+
235+
**Step 2:** Define the parent in `themes/my-custom-theme/theme.yaml`:
236+
237+
```yaml
238+
name: "My Custom Theme"
239+
parent: demo
240+
```
241+
242+
At this point, your child theme will function identically to the parent theme, as it inherits all templates and assets.
243+
244+
**Step 3:** Override specific files as needed. For example, to customize the homepage:
245+
246+
```treeview
247+
themes/
248+
|-- demo/
249+
| |-- pages/
250+
| | `-- home.htm # Parent's homepage
251+
| `-- theme.yaml
252+
`-- my-custom-theme/
253+
|-- pages/
254+
| `-- home.htm # Child's customized homepage
255+
`-- theme.yaml
256+
```
257+
258+
When the child theme is active, Winter will use `my-custom-theme/pages/home.htm` instead of `demo/pages/home.htm`, while all other pages from the parent theme remain available.
259+
260+
### Inheritance Behavior
261+
262+
Child themes use a cascading file resolution system. When Winter needs to load a template or asset, it searches in the following order:
263+
264+
1. Child theme database templates (if [database templates](#database-driven-themes) are enabled)
265+
2. Child theme filesystem
266+
3. Parent theme database templates (if database templates are enabled)
267+
4. Parent theme filesystem
268+
269+
This means:
270+
271+
- **Templates** (pages, partials, layouts, content files) in the child theme override those in the parent theme when they have the same path
272+
- **Assets** (CSS, JavaScript, images, fonts) in the child theme override those in the parent theme when they have the same path
273+
- **Localization strings** from the child theme's `lang` directory override parent theme strings
274+
- Any file not present in the child theme falls back to the parent theme
275+
276+
#### Example Directory Structure
277+
278+
Here's an example showing a child theme that overrides specific files:
279+
280+
```treeview
281+
themes/
282+
|-- demo/ # Parent theme
283+
| |-- assets/
284+
| | |-- css/
285+
| | | `-- theme.css # Parent CSS
286+
| | `-- images/
287+
| | `-- logo.png # Parent logo
288+
| |-- layouts/
289+
| | `-- default.htm # Parent layout
290+
| |-- pages/
291+
| | |-- home.htm # Parent homepage
292+
| | `-- about.htm # Parent about page
293+
| |-- partials/
294+
| | |-- header.htm # Parent header
295+
| | `-- footer.htm # Parent footer
296+
| `-- theme.yaml
297+
|
298+
`-- my-custom-theme/ # Child theme
299+
|-- assets/
300+
| |-- css/
301+
| | `-- theme.css # OVERRIDES parent CSS
302+
| `-- images/
303+
| `-- logo.png # OVERRIDES parent logo
304+
|-- partials/
305+
| `-- header.htm # OVERRIDES parent header
306+
`-- theme.yaml # Specifies parent: demo
307+
```
308+
309+
In this example, when `my-custom-theme` is active:
310+
- `theme.css` and `logo.png` load from the child theme
311+
- `header.htm` loads from the child theme
312+
- `footer.htm` loads from the parent theme (inherited)
313+
- `default.htm` layout loads from the parent theme (inherited)
314+
- Both `home.htm` and `about.htm` pages load from the parent theme (inherited)
315+
316+
### Asset Management
317+
318+
Assets in child themes work with the same fallback mechanism as templates. When referencing assets using the `theme.assetUrl()` helper or the `| theme` filter, Winter will check the child theme first, then fall back to the parent theme if the asset doesn't exist.
319+
320+
#### Example: Asset References
321+
322+
In your templates:
323+
324+
```twig
325+
{# This will use child theme's logo if it exists, otherwise parent's logo #}
326+
<img src="{{ 'assets/images/logo.png' | theme }}" alt="Logo">
327+
328+
{# CSS files cascade the same way #}
329+
<link href="{{ 'assets/css/theme.css' | theme }}" rel="stylesheet">
330+
```
331+
332+
#### Asset Compilation
333+
334+
When using the [asset combiner](../markup/filter/theme#combiner-aliases), child theme assets are resolved first:
335+
336+
```twig
337+
{# If custom.css exists in child theme, it will be used; otherwise parent's version #}
338+
<link href="{{ ['assets/css/theme.css', 'assets/css/custom.css'] | theme }}" rel="stylesheet">
339+
```
340+
341+
### Database-Driven Child Themes
342+
343+
Child themes can be purely virtual, meaning they don't require a physical directory on the filesystem. This is particularly useful for multi-tenant applications where each tenant needs a customized theme.
344+
345+
When [database templates](#database-driven-themes) are enabled, you can:
346+
347+
1. Create a database-only record for the child theme with a `theme.yaml` file specifying the parent
348+
2. Store all template customizations in the database
349+
3. Inherit all other files from the parent theme's filesystem
350+
351+
This approach allows you to:
352+
- Manage hundreds of similar themes without duplicating files
353+
- Update the parent theme and have changes cascade to all child themes automatically
354+
- Store tenant-specific customizations in the database while sharing a common codebase
355+
356+
**Example: Creating a virtual child theme**
357+
358+
1. Enable database templates in `config/cms.php`:
359+
360+
```php
361+
'databaseTemplates' => true,
362+
```
363+
364+
2. Create a theme record in the database with just the `theme.yaml` content:
365+
366+
```yaml
367+
name: "Client A Custom Theme"
368+
parent: base-theme
369+
```
370+
371+
3. Customize only the templates that need to differ from the parent by saving them to the database
372+
373+
The child theme will now function without any physical directory, inheriting everything from `themes/base-theme` except for the database-stored customizations.
374+
375+
### Best Practices
376+
377+
**When to use child themes:**
378+
- Customizing a third-party theme while preserving the ability to update it
379+
- Creating multiple branded variations of a base theme
380+
- Building a multi-tenant application where each tenant needs minor customizations
381+
- Developing a theme framework where a base theme provides core functionality
382+
383+
**When to create a new theme instead:**
384+
- Making extensive changes that affect most templates and assets
385+
- Building something significantly different from the original design
386+
- When you need to modify the theme structure itself
387+
388+
**Organization tips:**
389+
- Keep child themes minimal - only override what's necessary
390+
- Document which files are overridden and why
391+
- Use clear, descriptive names for child themes (e.g., `mytheme-client-a`, `mytheme-blue-variant`)
392+
- Consider using [theme customization](../themes/development#theme-customization) for simple configuration changes before creating a child theme
393+
394+
**Performance considerations:**
395+
- Child themes have minimal performance impact - file resolution is cached
396+
- Avoid deep nesting (grandparent/parent/child) - only one level of inheritance is supported
397+
- Database-driven templates are cached, so virtual child themes perform well
398+
399+
### Updating Parent Themes
400+
401+
When updating a parent theme, child themes automatically inherit the changes for any files they haven't overridden. This means:
402+
403+
- Bug fixes and improvements in the parent theme benefit all child themes
404+
- New templates added to the parent theme become available to child themes
405+
- Breaking changes in parent templates that are overridden in the child theme won't affect the child theme
406+
407+
To update a parent theme safely:
408+
409+
1. Test the parent theme update in a development environment
410+
2. Check if any overridden templates in child themes are affected by parent theme changes
411+
3. Update child theme overrides if necessary to maintain compatibility
412+
4. Deploy the parent theme update
413+
414+
> **NOTE:** Child themes only support one level of inheritance. A child theme cannot specify another child theme as its parent.

themes/development.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ Field | Description
2222
`description` | the theme description, required.
2323
`previewImage` | custom preview image, path relative to the theme directory, eg: `assets/images/preview.png`, optional.
2424
`code` | the theme code, optional. The value is used on the Winter CMS marketplace for initializing the theme code value. If the theme code is not provided, the theme directory name will be used as a code. When a theme is installed from the Marketplace, the code is used as the new theme directory name.
25+
`parent` | the directory name of a parent theme to inherit from, used for [child themes](../cms/themes#child-themes), optional.
2526
`form` | a configuration array or reference to a form field definition file, used for [theme customization](#theme-customization), optional.
2627
`require` | an array of plugin names used for [theme dependencies](#theme-dependencies), optional.
2728
`mix` | an object that defines Mix packages contained in your theme for [asset compilation](../console/asset-compilation).

0 commit comments

Comments
 (0)