Skip to content
Ryan Mark edited this page Oct 13, 2011 · 29 revisions

MTV is a plugin for WordPress that provides a new API for developing plugins and themes. Born out of frustration with the undocumented, inconsistent WordPress API, MTV provides a simple, familiar, consistent way to develop heavily customized WordPress sites.

MTV borrows a lot from existing MVC-style frameworks, namely Django and Backbone.js. If you're familiar with those frameworks, you should feel at home using MTV. If you're not familiar, go try some tutorials. It'll make you a better programmer.

This plugin hijacks and takes over how WordPress handles URLs and templates, and gives you new ORM-style tools for handling posts, users and blogs. This plugin does nothing by itself, and (hopefully) will not break stuff that you already have. It's just a set of tools for developers to use.

Why?

The way that WordPress handles requests and serves responses is not clear to anyone who is not well aquatinted with the internals. This is fine for theme development and for simple plugin development. Great actually. Create template files in the correct spot with the right names; use the magical template tags in the right places in the right files, and you can quickly build a WordPress theme with the structure and style you want.

The problem with this, and the genesis of this project, is that once you try to step outside the lines of the standard theme and plugin development, the simplicity of WordPress unravels frighteningly quickly.

WordPress is magic. When you want to setup a quick blog, make it your own and start writing, WordPress is magic. But when you want to heavily customize it, adding post types, new URLs and rivers for those post types, new widgets, the list goes on and on, WordPress's magic goes awry and all of a sudden you have these mops dancing around breaking your website.

Getting started

  • Bare MTV
  • My first theme

The model layer

The model layer is a collection of classes which handle the retrieval and manipulation data. Models are objects which represent a single item or row from a database.

In MTV, two types of classes comprise the model layer: Model and ModelCollection. A Model represents a single item from the database; a post, user, category, etc., and contains all the logic for accessing data, saving to the database, validating changes, and retrieving related models or data. A ModelCollection represents an array of a single type of Model and contains all the logic needed to retrieve and filter one or more models from the database, as well as logic to work on multiple models at once.

\mtv\Model

Constructor new Model( [$attributes] )

The constructor creates a real live model for you to use. It takes one optional parameter, an associative array of attributes to attach to the model.

$data = array(
	"title" => "My blog post",
	"published_on" => now(),
	"author" => "Bobby Tables",
	"content" => "I can blog!!"
);
$model = new Model($data);

print "<h1>" . $model->title . "</h1>";
print "by " . $model->author;
print "<p>" . $model->content . "<p>";

save $model->save()

Save this model to the database.

$model = new Model();
$model->title = "My blog post";
$model->save();

The base Model class does not implement save. It's up to you to extend the Model class and write this function.

validate $model->validate()

Validate the attributes in this model. Call this before saving the model to verify that all of the attributes are correct.

$model = new Model();
$model->email_address = "bobby";
$model->validate();
// ERROR! "bobby" is not a valid email address

The base Model class does not implement validate. It's up to you to extend the Model class and write this function.

initialize $model->initialize( $attributes )

Process the attributes when creating a new model. If you need to do something when a model object is created, you can implement this method instead of overriding the constructor. The base Model class does not implement this.

clear $model->clear()

Delete all of the attributes on the model.

set $model->set( $attributes )

Takes an associative array of attributes and sets them on the model.

$data = array(
	"title" => "My blog post",
	"published_on" => now(),
	"author" => "Bobby Tables",
	"content" => "I can blog!!"
);
$model = new Model($data);

$model->set(array(
	"title"=>"Better title",
	"status"=>"draft"
))

print $model->status; // draft
print $model->author; // Bobby Tables
print $model->title; // Better title

fetch $model->fetch()

Populates the model's attributes from the database.

The base Model class does not implement fetch. It's up to you to extend the Model class and write this function.

parse $model->parse( $data )

Parses the raw data from the database and returns an associative array of attributes for the model.

reload $model->reload( $data )

Takes a variable containing raw data from the database and loads it into the model's attributes. reload calls parse then set.

to_json $model->to_json()

Returns an associative array containing a subset of the model's attributes that are appropriate to send over the wire as json. Does not return an actual JSON string.

to_json uses an variable called json_fields to determine which attributes it should return.

$data = array(
	"name" => "Bobby Tables",
	"birthday" => "02/01/00",
	"secret_desire" => "space man"
);
$model = new Model($data);

$model->json_fields = array('name', 'birthday');

print $model->to_json() // only shows name and birthday

from_json Model::from_json( $data )

set_from_json $model->set_from_json( $data )

The reverse of to_json, takes an associative array of attributes, filters and sets them on the model. Does not accept an actual JSON string.

set_from_json uses an variable called editable_json_fields to determine which attributes it should set.

$json = '{
	"name": "Bobby Tables",
	"birthday": "02/01/00",
	"secret_desire": "space man"
}'
$model = new Model();

$model->editable_json_fields = array("name", "birthday");

$model->set_from_json(json_decode($json));

print $model->name; // Bobby Tables
print $model->secret_desire; // Null

from_json is a static function that you can use to create a new model object from an array

$json = '{
	"name": "Bobby Tables",
	"birthday": "02/01/00",
}'

$model = Model::from_json(json_decode($json));

print $model->name; // Bobby Tables

Extending Model

You can extend a Model like you would any PHP class. When extending a model there are a few variables you might be interested in.

class MyModel extends Model {
    // Default model data used when a new model is created
    public $defaults             = array();
    // Attributes that are OK to send over the wire
    public $json_fields          = array();
    // Attributes that can be updated over the wire
    public $editable_json_fields = array();
}

\mtv\ModelCollection

A ModelCollection represents a bunch of models. It has only a few functions but it acts as the gateway to retrieving models. You can treat a ModelCollection object as an array.

Constructor $collection = new ModelCollection( [$attributes] )

add $collection->add( $model )

clear $collection->clear()

to_json $collection->to_json()

get $model = ModelCollection::get( $attributes )

get_by $model = ModelCollection::get_by( $attributes )

filter $collection = ModelCollection::filter( $attributes )

Extending ModelCollection

You can extend a ModelCollection like you would any PHP class. There is only one thing you absolutely must put in your new class.

class MyModelCollection extends Collection {
    public static $model = 'myapp\models\MyModel';
}

The static variable $model must be the globally accessible name of the model class that this collection will be handling.

\mtv\wp\Post

The Post model represents a WordPress post in the database. It inherits and implements all of the features of the Model class.

Here are the typical WordPress post fields you'll find on a Post object:

id             // ID of the post
post_author    // ID of the post author
post_date      // timestamp in local time
post_date_gmt  // timestamp in gmt time
post_content   // Full body of the post
post_title     // title of the post
post_excerpt   // excerpt field of the post, caption if attachment
post_status    // post status: publish, new, pending, draft, auto-draft, future, private, inherit, trash
comment_status // comment status: open, closed
ping_status    // ping/trackback status
post_password  // password of the post
post_name      // post slug, string to use in the URL
to_ping        // to ping ??
pinged         // pinged ??
post_modified  // timestamp in local time
post_modified_gmt // timestatmp in gmt tim
post_content_filtered // filtered content ??
post_parent    // id of the parent post. If attachment, id of the post that uses this image
guid           // global unique id of the post
menu_order     // menu order
post_type      // type of post: post, page, attachment, or custom string
post_mime_type // mime type for attachment posts
comment_count  // number of comments
filter         // filter ??

The Post model also adds these fields, not typical to WordPress:

post_meta      // an array containing all of the meta for this post
post_format    // the post_format of this post
blogid         // id number of the blog this post lives on
url            // attachments only, url of the original uploaded image or whatever
thumb_url      // attachments only, url of the thumbnail image, if thumbnails are enabled

With the exception of the last three fields above (blogid, url, thumb_url), you can read, update and save any field using the Post model:

$post = new Post(array('id'=>1));
$post->fetch();

$post->post_status = 'publish';
$post->post_title  = 'Better headline';
$post->post_meta['my_special_meta'] = 'this post is special';
$post->post_meta['my_related_items'] = array(2,5,7);

$post->save();

The Post model also has these extra special functions:

password_required $post->password_required()

is_sticky $post->is_sticky()

post_class $post->post_class( [$extra_classes] )

permalink $post->permalink()

categories $post->categories()

tags $post->tags()

the_time $post->the_time( [$format] )

the_date $post->the_date( [$format] )

make_excerpt $post->make_excerpt( [$more_text] )

\mtv\wp\PostCollection

Your gateway to the wonderful world of WordPress posts. PostCollection only implements the basic features set out in the ModelCollection above. With a couple twists. PostCollection really is just a thin wrapper around WordPress's WP_Query object.

$query = array(
	'post_type' => 'post',
	'posts_per_page' => 10,
	'order' => 'DESC'
);
$posts = PostCollection::filter( $query );

foreach ( $posts as $post )
	print $post->post_title;

The PostCollection object ($posts in this example), holds on to the WP_Query object for later reference. So if you need to see how many pages of posts you have:

$max_pages = $posts->wp_query->max_num_pages;

Not to shabby.

\mtv\wp\User

\mtv\wp\UserCollection

\mtv\wp\Site

\mtv\wp\SiteCollection

The view layer

The view layer is the switching yard for all the requests your crazy WordPress/MTV website will receive. This is where MTV breaks WordPress and takes control.

  • urls.php
  • Including urls from other places
  • Writing a view

The template layer

  • Available wp template functions
  • How to add a template functions, tags, filters
  • Deep links to twig

AJAX

  • Setting up ajax urls
  • Writing an ajax view
    • Calling ajax
Clone this wiki locally