Chester is a lightweight WordPress MVC theming framework for people who want to build their own custom themes with an MVC approach.
To learn how to use it, the easiest thing to do is follow the tutorial and download the boilerplate example over at http://markirby.github.com/Boilerplate-Chester-WordPress-Theme/
We believe in using standard WordPress template calls which return data that can then be pulled into an array for passing to Mustache templates. This keeps the HTML clean and free of PHP calls.
We provide a data helper file, Chester/wp_core_data_helpers.php to provide access to standard data easily gathered from WordPress. At present this is as far as the concept of Models is implemented.
Here is an example of how we pull site data into an array for use in a header template.
public static function getBlogInfoData() {
return array(
'title' => self::getBlogTitle(),
'template_directory' => get_bloginfo('template_directory'),
'charset' => get_bloginfo('charset'),
'pingback_url' => get_bloginfo('pingback_url'),
);
}
You create views using Mustache.
Here is an example of a header template that displays the above data.
<!DOCTYPE html>
<head>
<title>{{{title}}}</title>
<link rel="shortcut icon" href="https://github.com/markirby/Chester-WordPress-MVC-Theme-Framework/blob/master/{{template_directory}}/favicon.ico" />
<meta charset="{{charset}}" />
<link rel="stylesheet" href="https://github.com/markirby/Chester-WordPress-MVC-Theme-Framework/blob/master/{{template_directory}}/css/global.css">
<link rel="pingback" href="https://github.com/markirby/Chester-WordPress-MVC-Theme-Framework/blob/master/{{pingback_url}}" />
A controller talks to the data helpers, loads the mustache template and can then be called from your WordPress template files.
Here's a sample function from a controller that loads the header data into the header template.
public function header() {
echo $this->render('header', ChesterWPCoreDataHelpers::getBlogInfoData());
}
Install Chester into lib/Chester
Add the following line to functions.php:
require_once(dirname(__FILE__).'/lib/chester/require.php');
Create a default structure to store your controllers and templates in.
mkdir mvc
mkdir mvc/controllers
mkdir mvc/templates
Controllers should extend ChesterBaseController. This then provides access to the templating functions.
class PageController extends ChesterBaseController {
public function showPage() {
...
}
}
You could group functions in a single controller, or create separate controllers for each template type. We favour the later.
Place controllers inside mvc/controllers.
Create a template for WordPress, for example page.php which is used when pages are loaded.
Require the controller, init it and call the relevant function.
require_once(dirname(__FILE__).'/mvc/controllers/page_controller.php');
$siteController = new PageController();
$siteController->showPage();
Create your mustache template within mvc/templates.
The Mustache manual will be your guide.
Here is an example template showing a post:
<h1><a href="https://github.com/markirby/Chester-WordPress-MVC-Theme-Framework/blob/master/{{permalink}}">{{{title}}}</a></h1>
<p>{{time}}</p>
{{{content}}}
To load the above template, you can use the built in function render from within your controller.
echo $this->render('template_name', array(
'permalink' => get_permalink(),
'title' => get_the_title(),
'time' => get_the_time($dateFormat),
'content' => self::getTheFilteredContentFromLoop(),
));
Create the following templates:
Examples of each can be found in https://github.com/markirby/Boilerplate-Chester-WordPress-Theme
header_close
can include the tag {{{siteTitleHTML}}}
, which will output the content of site_title
on a regular page, and site_title_on_home
on the homepage, if you wish. Otherwise, leave them both blank.
Once these are created, you can call the function renderPage
from within your controller and get the template surrounded by header, footer and site title files, with wp_head()
and wp_footer()
called.
echo $this->renderPage('template_name', array(
'permalink' => get_permalink(),
'title' => get_the_title(),
'time' => get_the_time($dateFormat),
'content' => self::getTheFilteredContentFromLoop(),
));
All controllers should extend this to inherit the following:
$templateName
- string - name of the template inside the root/mvc/templates folder, without the mustache extension$templateVars
- array - array of variables to output in the templateReturns the template.
E.g (called from within a sub-controller):
echo $this->render('template_name', array(
'permalink' => get_permalink(),
'title' => get_the_title(),
'time' => get_the_time($dateFormat),
'content' => self::getTheFilteredContentFromLoop(),
));
$templateName
- string - name of the template inside the root/mvc/templates folder, without the mustache extension$templateVars
- array - array of variables to output in the templateReturns the following:
E.g (called from within a sub-controller):
echo $this->render('template_name', array(
'permalink' => get_permalink(),
'title' => get_the_title(),
'time' => get_the_time($dateFormat),
'content' => self::getTheFilteredContentFromLoop(),
));
You can override this in a subcontroller if you want, for example, to include navigation on every page with a custom array.
Renders the root/mvc/templates/site_title.mustache if not on home page Renders the root/mvc/templates/site_title_home.mustache if on home page
This is good for SEO, allowing you to render the title in an h1 on the homepage and a p elsewhere.
Returns an array containing:
This content is automatically available to your templates/header.mustache file.
Runs the WordPress loop and returns an array of arrays, one array per post.
Each post contains the following:
Then it returns any custom fields, with the same name as you passed in.
Finally it returns featured images (if you set them), as follows:
e.g. (called from within a controller)
$posts = ChesterWPCoreDataHelpers::getWordpressPostsFromLoop();
echo $this->renderPage('post_previews', array(
'posts' => $posts,
'next_posts_link' => get_next_posts_link(),
'previous_posts_link' => get_previous_posts_link()
));
or
$posts = ChesterWPCoreDataHelpers::getWordpressPostsFromLoop();
echo $posts[0]['permalink'];
To get posts outside of the loop to use elsewhere (for example on the home page), use the getPosts function.
The pattern primer controller allows you to create a pattern primer page to show all your different templates in one place. Read more about the concept, and view an example. Ours is based on this example.
The boilerplate will take you through setting up a pattern primer. Here are the API docs:
$patternPrimerController = new ChesterPatternPrimerController();
Calling this will automatically include a set of basic content, h1 - h8, blockquote, link, text etc.
Returns HTML to be echoed.
This generates a block of patterns for use in showPatternPrimer().
Returns HTML to be used in $patternsHTML field of showPatternPrimer().
Generates a single pattern.
Returns HTML to be used in $patternsHTML field of renderCustomPatternGroup()
$patternPrimerController = new ChesterPatternPrimerController();
$post = $patternPrimerController->renderPattern('post', array(
'post' => array(
'permalink' => 'http://brightonculture.co.uk',
'title' => 'Post title',
'time' => '12th Nov 2012',
'content' => '<p>Sample content</p>',
)
));
$postPreview = $patternPrimerController->renderPattern('post_previews', array(
'posts' => array(
'permalink' => 'http://brightonculture.co.uk',
'title' => 'Post preview title',
'time' => '12th Nov 2012',
'content' => '<p>Sample content</p>',
)
));
$patternGroup = $patternPrimerController->renderCustomPatternGroup($post . $postPreview, 'modules/');
$patternPrimerController->showPatternPrimer(array('typography', 'grids'), $patternGroup);
The admin controller allows you to instantly create custom post types, with a selection of custom fields available courtesy of wpalchemy, which is included in Chester, but not maintained by us.
To use, create an instance of ChesterAdminController, passing in settings, as shown below:
$galleryLocationBlock = array(
'name' => 'location',
'blockTitle' => 'Gallery Location',
'fields' => array(
array(
'name' => 'location',
'labelTitle' => 'Location',
'fieldType' => 'textField',
),
array(
'name' => 'map',
'labelTitle' => 'Link to a map',
'fieldType' => 'textField',
)
)
);
$galleryInfoBlock = array(
'name' => 'other',
'blockTitle' => 'Other details',
'fields' => array(
array(
'name' => 'website',
'labelTitle' => 'Website address',
'fieldType' => 'textField'
)
)
);
$galleryCustomPostType = array(
'name' => 'gallery',
'displayName' => 'Gallery',
'pluralDisplayName' => 'Galleries',
'enablePostThumbnailSupport' => true,
'fieldBlocks' => array($galleryLocationBlock, $galleryInfoBlock)
);
$adminSettings = array(
'customPostTypes' => array($galleryCustomPostType)
);
$adminController = new ChesterAdminController($adminSettings);
This example shows you can create a number of blocks, with fields in each, for a custom post type of gallery.
The settings are as follows:
General
Custom Post
Field Block
Field
You then need to create a file for each block named [customPostType]_[blockName].php, inside mvc/admin_templates.
For above, you create the files:
Each of these needs to contain the following line of code:
<?php ChesterWPAlchemyHelpers::showFields($mb); ?>
This is annoying, but a limitation of the WPAlchemy library we use which expects you to stick HTML into a php file. Instead we are bumping the code back into our system which will generate the HTML for you. In future I will address this.