markirby / Chester-WordPress-MVC-Theme-Framework

A lightweight wordpress MVC theming framework for people who want to build their own custom themes with an MVC approach
http://markirby.github.com/Chester-WordPress-MVC-Theme-Framework/
40 stars 16 forks source link

Chester WordPress MVC Theme Framework Documentation

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/

MVC Concepts

Models built from standard WordPress calls

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'),
    );
}

Views based on Mustache templates

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}}" />

Controllers to pull everything together

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

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

Creating basic controllers and views

Creating a controller

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.

Calling a controller from a WordPress template page

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();

Creating mustache templates

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}}}

Loading a template from within a controller

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(),
));

Loading templates with automatically included Header and footer feature

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(),
));

ChesterBaseController - base_controller.php

All controllers should extend this to inherit the following:

render($templateName, $templateVars)

Returns 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(),
));

renderPage($templateName, $templateVars)

Returns 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.

renderSiteTitle()

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.

ChesterWPCoreDataHelpers - wp_core_data_helpers.php

getBlogInfoData()

Returns an array containing:

This content is automatically available to your templates/header.mustache file.

getWordpressPostsFromLoop($dateFormat = false, $customFields = array(), $fetchAllPosts = false)

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'];

getPosts($dateFormat = false, $postType = 'post', $numberPostsToFetch = -1, $customFields = array(), $oddOrEven = false)

To get posts outside of the loop to use elsewhere (for example on the home page), use the getPosts function.

ChesterPatternPrimerController - pattern_primer/pattern_primer_controller.php

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:

Loading the controller

$patternPrimerController = new ChesterPatternPrimerController();

showPatternPrimer($patternSets = array(), $patternsHTML = ""

Calling this will automatically include a set of basic content, h1 - h8, blockquote, link, text etc.

Returns HTML to be echoed.

renderCustomPatternGroup($patternsHTML, $patternTitle)

This generates a block of patterns for use in showPatternPrimer().

Returns HTML to be used in $patternsHTML field of showPatternPrimer().

renderPattern($templateName, $templateVars = false)

Generates a single pattern.

Returns HTML to be used in $patternsHTML field of renderCustomPatternGroup()

Example

$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);

ChesterAdminController - admin_controller.php

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.