Welcome to MG Press, a WordPress starter theme that uses the Timber plugin to add support for Twig template files. It allows developers to make use of the MVC pattern (especially the View-Controller) while creating a WordPress theme, separating the business logic from the view logic.
Install this theme as you would any other, and be sure the Timber plugin is activated. But hey, let's break it down into some bullets:
- Make sure you have installed the plugin for the Timber Library (and Advanced Custom Fields - they play quite nicely together).
- Download the zip for this theme (or clone it) and move it to
wp-content/themes
in your WordPress installation. - Activate the theme in Appearance > Themes.
- Do your thing! And read the docs.
*.php
are the normal WordPress PHP template files that correspond to the template hierarchy, such as index.php
and single.php
. These files act as the controllers: the system (WordPress) determines which file to load based on the URL; runs any necessary business logic; adds any data for the view layer to the $context
variable; determines which view to render; renders the view by passing it the $context
variable and sending the output to the browser. At the end of each PHP template, you'll notice a Timber::render()
function whose first parameter is the Twig file(s) and the second parameter is the $context
variable.
views/
contains all of your Twig templates. The PHP template files determine which view to render.
views/base.twig
is the base template that provides a generic HTML document structure. This template should not render content directly.views/layout/
contains templates that apply structural layout to a page, but do not generally render content directly themselves, such asfull-width.twig
andleft-sidebar.twig
views/detail/
contains views for rendering single post types and pages, such aspost.twig
andpage.twig
.views/list/
contains views for rendering lists of post types, such aspost.twig
,category.twig
andsearch.twig
.views/template/
contains views for rendering custom templates, just add "Template Name: Some Custom Name" to the comment in the file header, like normal WordPress custom templates.views/summary/
contains template includes for post type and page teasers, used in list views, such aspost.twig
andpage.twig
.views/block/
contains template includes for rendering block-level elements.views/menu/
contains template includes for rendering menus.views/form/
contains template includes for rendering forms.views/include/
contains template includes for rendering various HTML snippets, such asheader.twig
andpagination.twig
.views/exception/
contains views for exception handling, such as404.twig
.
assets/
contains static assets, such as CSS, JavaScript, images, fonts, static HTML, etc.
lib/
is where we keep the PHP library for MGPress features, like handling comments or asset management. Unless you know what you are doing it's probably best to leave these alone.
custom/
contains custom PHP code for this theme - it serves the same function as WordPress's default functions.php
. PHP files in this directory will be autoloaded by the functions.php
file. You can also override classes from lib/
here.
controllers/
contains custom controllers for additional business logic that the PHP template files may not provide. Available for Post Type list and detail views and Taxonomy List views by adding a file named list-{post-type}.php
, detail-{post-type}.php
or list-taxonomy-{taxonomy-slug}.php
respectively. An example use case would be to modify the Timber\PostQuery
in a list view to change the listing order or limit.
models/
contains autoloaded classes that register Custom Post Types. Each Custom Post Type should have its own class that registers the post type and any related taxonomies and optionally defines custom properties, although it is usually easier to define properties via the Advanced Custom Fields plugin.
lang/
location for the .mo
translation files, specified by load_theme_textdomain()
in lib/site.php
. (optional)
If you were expecting a normal WordPress theme, this may look a little strange - don't worry, it's actually easier to work with WordPress this way. Why? First of all, it separates the business logic from the presentation layer. Also, you get to use Twig. And - you don't have to work with The Loop.
In your WordPress Settings > Reading section you have the Posts Page set to /blog
. When a visitor visits /blog
, WordPress uses its template hierarchy to load the archive.php
file. Inside the archive.php
file is logic that creates a prioritized list of Twig templates from the views/list/
directory to try to load, depending on the type of archive. In this case, it's a basic blog listing page, so views/list/post.twig
has the highest priority.
As it happens, views/list/post.twig
exists, so Timber passes the data ($context
) to the template and renders it. The views/list/post.twig
template defines the content
block, which contains presentation logic that loops over the posts
variable (from $context
) and renders summary template includes from views/summary/post.twig
. The views/list/post.twig
template also extends the views/layout/full-width.twig
template.
The views/layout/full-width.twig
template applies structural markup for the page layout, displays the content
block, defines the layout
block, and extends the views/base.twig
template. The views/base.twig
template applies the base HTML document structure, such as the <html>
and <body>
tags, includes the views/include/header.twig
and views/include/footer.twig
snippets, and displays the layout
block. Since views/base.twig
doesn't extend any templates, the rendering is complete and the output is sent to the browser.
Your website has a Custom Post Type called Products under the path /products
. When a visitor visits a single product page at /products/product-1
WordPress uses the template hierarchy to load the single.php
file. That file creates a prioritized list of Twig templates from the views/detail/
directory to try to load. The first template in the list follows the format "{POST-TYPE}-{SLUG}.twig", so it becomes views/detail/product-product-1.twig
. This template does not exist, so it tries the next one, views/detail/product.twig
. This one exists, so single.php
passes the template the data ($context
) and renders the view.
The views/detail/product.twig
displays the content of Product 1 and extends the views/layout/left-sidebar.twig
template. The views/layout/left-sidebar.twig
template applies structural markup for the page layout - including rendering a dynamic sidebar in the left column - and extends the views/base.twig
template, which in turn provides HTML document structural markup, the header and footer, etc. which is sent to the browser.
When choosing which Twig template to render, the system closely follows the default WordPress template hierarchy, with some modifications:
- Archive Page
- Author Archive
views/list/author-{nicename}.twig
views/list/author-{id}.twig
views/list/author.twig
views/list/archive.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Category Archive
views/list/category-{slug}.twig
views/list/category-{id}.twig
views/list/category.twig
views/list/archive.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Custom Post Type Archive
views/list/{post-type}.twig
views/list/archive.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Taxonomy Archive
views/list/taxonomy-{slug}-{term}.twig
views/list/taxonomy-{slug}.twig
views/list/taxonomy.twig
views/list/archive.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Date Archive
views/list/date.twig
views/list/archive.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Tag Archive
views/list/tag-{slug}.twig
views/list/tag-{id}.twig
views/list/tag.twig
views/list/archive.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Author Archive
- Singular Page
- Attachment Post
views/detail/{mimetype}-{subtype}.twig
views/detail/{subtype}.twig
views/detail/{mimetype}.twig
views/detail/attachment.twig
views/detail/post.twig
views/detail/single.twig
views/index.twig
- Custom Post
views/detail/{posttype}-{slug}.twig
views/detail/{posttype}.twig
views/detail/post.twig
views/detail/single.twig
views/index.twig
- Blog Post
views/detail/post-{slug}.twig
views/detail/post.twig
views/detail/single.twig
views/index.twig
- Static Page
views/template/{templatename}.twig
views/detail/page-{slug}.twig
views/detail/page-{id}.twig
views/detail/page.twig
views/index.twig
- Site Front Page
- Page shown on front
views/detail/front-page.twig
views/template/{templatename}.twig
views/detail/page-{slug}.twig
views/detail/page-{id}.twig
views/detail/page.twig
views/index.twig
- Posts shown on front
views/list/home.twig
views/list/post.twig
views/list/single.twig
views/index.twig
- Page shown on front
- Attachment Post
- Error 404 Page
views/exception/404.twig
views/index.twig
- Search Results Page
views/list/search.twig
views/list/post.twig
views/list/single.twig
views/index.twig
In addition to the standard Twig API, the following custom features are available to use in the templates.
Add Stylesheet to HTML Output.
* @param string $handle (required) A unique string ID to ensure the resource is loaded only once.
* @param string $src (required) The public path to the resource.
* @param array $deps Array of handles of any stylesheets that this stylesheet depends on.
* @param string $ver String specifying the stylesheet version number, if it has one.
* @param string $media String specifying the media for which this stylesheet has been defined. [Ex: 'all', 'screen', 'handheld', 'print']
* @param bool $http2 True: load resource immediately in HTML; False: register resource with WordPress to load in the header or footer. Default is False.
* @param bool $inline True: print the contents of the file directly in HTML; False: load the file as an external resource. Default is False.
* @param array $environments Array of environments to restrict resource loading to, default is to load in all environments. ['dev', 'test', 'prod']
* @param string $group A group ID to aid resource grouping; assets can share groups.
* @param int $priority A priority weight given to the resource used during sorting when registered with WordPress: higher numbers will load sooner. Default is 0, loading by FIFO.
* @return null
Add Style to HTML Output.
* @param string $handle (required) A unique string ID to ensure the resource is loaded only once.
* @param string $src (required) String of CSS styles to output. [Ex: "p { color: #ff0000; }"]
* @param string $media String specifying the media for which this stylesheet has been defined. [Ex: 'all', 'screen', 'handheld', 'print']
* @param bool $http2 True: print styles immediately in HTML; False: register styles with WordPress to load in the header or footer. Default is False.
* @param array $environments Array of environments to restrict style output to, default is to output in all environments. ['dev', 'test', 'prod']
* @param int $priority A priority weight given to the resource used during sorting when registered with WordPress: higher numbers will load sooner. Default is 0, loading by FIFO.
* @return null
Add Script File to HTML Output.
* @param string $handle (required) A unique string ID to ensure the resource is loaded only once.
* @param string $src (required) The public path to the resource.
* @param array $deps An array of registered script handles this script depends on.
* @param string $ver String specifying script version number, if it has one, which is added to the URL as a query string for cache busting purposes.
* @param bool $http2 True: load resource immediately in HTML; False: register resource with WordPress to load in the header or footer. Default is False.
* @param bool $inline True: print the contents of the file directly in HTML; False: load the file as an external resource. Default is False.
* @param array $environments Array of environments to restrict resource loading to, default is to load in all environments. ['dev', 'test', 'prod']
* @param string $group A group ID to aid resource grouping; assets can share groups.
* @param int $priority A priority weight given to the resource used during sorting when registered with WordPress: higher numbers will load sooner. Default is 0, loading by FIFO.
* @return null
Add Script to HTML Output.
* @param string $handle (required) A unique string ID to ensure the script is output only once.
* @param string $src (required) String of JavaScript to output. [Ex: "var foo = 'bar';"]
* @param bool $http2 True: print script immediately in HTML; False: register script with WordPress to load in the header or footer. Default is False.
* @param array $environments Array of environments to restrict script output to, default is to output in all environments. ['dev', 'test', 'prod']
* @param int $priority A priority weight given to the resource used during sorting when registered with WordPress: higher numbers will load sooner. Default is 0, loading by FIFO.
* @return null
Localize Script.
* @param string $handle (required) The registered script handle you are attaching the data for.
* @param string $name (required) The name of the variable which will contain the data.
* @param array $data (required) The data itself.
* @return null
Check if user can comment on a Post or Comment.
* @param \Timber\Post $post (required) The post to check if comments are allowed.
* @param \Timber\Comment $comment If using nested comments, the comment to check if comments are allowed.
* @return bool
Get list of child comments from Post.
* @param Timber\Post $post (required) The post to return comments for.
* @return array Timber\Comment
Create link for next comments.
* @param \Timber\Post $post (required) The parent post of comments to paginate.
* @param string $label A label to use as the link anchor text.
* @return bool|string
Create link for previous comments.
* @param \Timber\Post $post (required) The parent post of comments to paginate.
* @param string $label A label to use as the link anchor text.
* @return bool|string
At this time there are no additional custom filters.
The main Timber Wiki is super great, so reference those often. Also, check out these articles and projects for more info:
- This branch of the starter theme has some more example code with ACF and a slightly different set up.
- Twig for Timber Cheatsheet
- Timber and Twig Reignited My Love for WordPress on CSS-Tricks
- A real live Timber theme.
- Timber Video Tutorials and an incomplete set of screencasts for building a Timber theme from scratch.