PHPackages                             sketch/app - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. sketch/app

ActiveLibrary[Framework](/categories/framework)

sketch/app
==========

The Sketch Wordpress App Framework - Sample App

56323[1 issues](https://github.com/sketchwp/app/issues)[1 PRs](https://github.com/sketchwp/app/pulls)PHP

Since Dec 5Pushed 9y ago7 watchersCompare

[ Source](https://github.com/sketchwp/app)[ Packagist](https://packagist.org/packages/sketch/app)[ RSS](/packages/sketch-app/feed)WikiDiscussions master Synced 4d ago

READMEChangelogDependenciesVersions (1)Used By (0)

\##NOTE: This library is not currently maintained. Probably don't use it. Feel free to fork!

\#Sketch

Sketch is a tiny framework for creating well-structured MVC applications in Wordpress. It provides a set of tools and a suggested architecture for building custom Wordpress functionality in a testable, loosely-coupled way.

Sketch is primarily focused on making it easier to create menu pages where site admins can work with data, as well as custom post types, metaboxes, and taxonomies:

```
    $app = require_once 'app/bootstrap.php';

    // Add our sample menus and submenus
    $app->make('Hello\Hello');
    $app->make('Hello\Submenus\HelloSubmenu');

    // Add our sample post type, with a metabox and a taxonomy
    $app->make('HelloPostType')
        ->addMetabox($app->make('HelloMetabox'))
        ->addTaxonomy($app->make('HelloTaxonomy'));
```

\##Table of Contents

1. [What Makes Sketch Unique?](#what-makes-sketch-unique)
    - [When Should I Use Sketch](#when-should-i-use-sketch)
2. [Installation](#installation)
    - [For Fresh Projects](#installing-into-fresh-projects)
    - [For Projects that already use composer](#installing-into-projects-that-already-use-composer)
3. [Unit Testing](#unit-testing)
4. [Controllers](#controllers)
5. [Views](#views)
6. [Models](#models)
7. [Menus](#menus)
    - [Menu Routes](#menu-routes)
8. [Custom Post Types](#custom-post-types)
9. [Metaboxes](#metaboxes)
10. [Taxonomies](#taxonomies)
11. [Validation](#validation)
12. [Service Providers](#service-providers)
13. [Breaking Changes and Backwards Compatibility](#breaking-changes-and-backwards-compatibility)
14. [Mad Props](#mad-props)

\##What Makes Sketch Unique?

Sketch takes an Object-Oriented approach to interacting with Wordpress. While it's not the first attempt at bringing an MVC style to Wordpress development, it is (to my knowledge) the first to take advantage of Composer autoloading and [Laravel's IoC container](http://laravel.com/docs/ioc).

Sketch has a very small footprint. It's intended to be able to work well in environments lacking command-line access (e.g., shared cloud hosting), which only means that Sketch's default production dependencies are minimal enough that you don't need to sweat having them under version control if need be.

\####When Should I Use Sketch?

Sketch is inspired by full stack PHP frameworks like [Laravel](http://laravel.com) and [Silex](http://silex.sensiolabs.org/), but it is in no way meant to serve as a replacement for them. In fact, it's quite rudimentary in comparison! The goal is simply to provide a better way of working with Wordpress, whenever it makes sense to work with Wordpress.

So instead of asking, "when should I use Sketch?", the better question might be, "[when should I use Wordpress](http://wordpress.stackexchange.com/questions/10594/when-should-we-not-recommend-a-client-use-wordpress/10596#10596)?" Wordpress has many benefits, but it's foolish to ignore its limitations. Sketch can expand what you can do well with Wordpress, but it can't expand what Wordpress can do well.

That being said - does your site include more than a couple custom post types, metaboxes, taxonomies and/or settings pages? Does it interact with 3rd party APIs? Give Sketch a try!

\##Installation

The best way to install Sketch will depend on the type of project you are installing it into.

\####Installing into Fresh Projects If you are installing Sketch into a Wordpress project that doesn't already have a `composer.json` file and `/vendor` directory, you can do it easily with [Composer](http://www.getcomposer.org). In your terminal, navigate to the root of your Wordpress project, and run the following command:

- `composer create-project sketch/app -s dev your-app-name-goes-here --prefer-dist`

Then, from inside your theme's `functions.php` file, or your plugin, or wherever you wish to instantiate Sketch, just require `path/to/sketch/index.php` and start building.

\####Installing into Projects That Already Use Composer If you are installing into a project that already has a `composer.json` file and a `/vendor` directory, follow these steps:

1. Either `git clone https://github.com/sketchwp/app.git` or download and unzip this sample app into your project's root directory.
2. Assuming Composer is already being loaded elsewhere, remove the line that says `require_once __DIR__.'/../vendor/autoload.php';` from the top of `app/bootstrap.php` file. If Composer is not being loaded elsewhere, leave this line in place - but you will likely need to alter it to point to wherever your `/vendor` directory is.
3. Add `"sketch/sketch": "dev-master"` to the "require" section of your `composer.json` file.
4. Run `composer update`.
5. Like with the fresh install, require `path/to/sketch/index.php` from inside your `functions.php` file, plugin, or wherever you wish to instantiate Sketch.

\##Unit Testing

One of the main goals of Sketch is to enable Wordpress developers to more easily test Wordpress functionality.

Unit testing in Wordpress has always been a huge pain, because you can't use any Wordpress function without instantiating the entire Wordpress application. With Sketch, if any of your classes needs to use a Wordpress function, pass that class an instance of `\Sketch\WpApiWrapper`. That class contains precisely one function, `__call($method, $arguments)`, which simply calls and returns the method passed to it. So instead of using `get_post_meta($id, 'meta_key', true);` in your class, you'd use `$this->wp->get_post_meta($id, 'meta_key', true);`.

It takes a bit of discipline, but that little layer of abstraction is all you need to be able to mock any of Wordpress's "globally namespaced" functions in your unit tests.

\##Controllers

Sketch's default controllers come populated with an instance of the template system (Plates, by default) and the [Symfony Request](http://symfony.com/doc/current/components/http_foundation/introduction.html) object. For any other dependencies, use type-hinting and constructor injection - the IoC container will pass them in automatically. Of course, if you are type-hinting an Interface as a dependency, be sure to use `$app->bind('FooInterface', 'FooConcrete')` in your index.php file to tell the IoC container which concrete class it should inject.

Say you want to make a controller that grabs `page` from the query string (i.e., the menu slug) and passes it to the view. Here's how you would do that using Sketch's default controllers:

```
    Class HomeController extends \Sketch\WpBaseController {

        public function index()
        {
            $data = array(
                'page' => $this->request->query->get('page')
            );

            $this->render('home', $data);
        }
    }
```

If you do not wish to use Sketch's default controllers, you don't have to! You can register a different controller type using a [service provider](#service-providers). Feel free to ask for help with this! The docs for that have not yet been written.

\##Views

For a view corresponding to the above controller example, create a file called `app/views/home.php`. To output the `page` variable, use `` anywhere in your template.

A few variables automatically get passed to every view: `nonce_name`, `nonce_action`, `message`, and `errors`. In addition, Sketch comes with a few simple Plates extensions, most notably the `wp()` function, which provides access to `\Sketch\WpApiWrapper`. Pass the name of the function as the first argument, and an array of your parameters as the second.

See the [Plates](http://www.platesphp.com) documentation to learn more about what you can do with default views.

Like Sketch's default controller, Plates is registered as a [service provider](#service-providers). It is not too difficult to swap it out for the templating engine of your choice. Feel free to ask for help with this! The docs for that have not yet been written.

\##Models

The base model provides three ways of interacting with Wordpress data: `\Sketch\WpApiWrapper`, `\Sketch\WpQueryFactory`, and `\Sketch\WpDbWrapper`. That way, you can fetch your posts and database objects however you like, whether with normal Wordpress functions (e.g., `$this->wp->get_posts()`), by creating a new WP\_Query object (`$this->wp_query->make($args)`), or by using `$this->wpdb->get_results($prepared_sql)`.

If that's too simplistic for your project, remember you are in no way required to use Sketch's base model. You can easily write your own base model class or even use something like the [Eloquent ORM](http://www.edzynda.com/use-laravels-eloquent-orm-outside-of-laravel/) if keeping a small footprint isn't a high priority.

\##Menus

Normally when you create a Wordpress menu, you use the `add_menu_page()` function and pass a callback that defines everything the menu should display. With Sketch, you create a menu by extending the `\Sketch\Menu\WpMenuAbstract` or `\Sketch\Menu\WpSubmenuAbstract` class. Define the menu title, slug and permissions etc as properties of the class, and Sketch will take care of the rest. Sketch's menu classes have a routing class as a dependency, and `this->router->resolve()` is the callback passed to Wordpress when the menu is created at runtime.

If you need to add any actions associated with the menu (i.e., enqueueing public assets), override the menu's `addActions()` method, and add those actions there using the menu's `\Sketch\WpApiWrapper` instance. For example:

```
    protected function addActions()
    {
        $this->wp->wp_enqueue_script('my_script', 'path/to/my/script.js');
    }
```

Define your menu classes like you see in the `app/menus` folder, and instantiate them in `index.php` by calling `$app->make('MyMenu')`;

\####Menu Routes

Sketch's menu router is primarily intended to create navigation for menu pages in the Wordpress admin backend. For now, it's not interested in creating front-end routes or "hijacking" Wordpress' native routing system. Instead, it's designed to play nicely with what's already there.

Wordpress's admin menu navigation is largely based on the contents of the query string, so Sketch's router is configured by passing in either an associative array of the query string variables that need to be matched, or an actual query string. In addition, you will also pass the name of the controller and method that should handle requests matching the route.

These examples are all the same:

- `$app['router']->get('?page=my_menu_slug&action=index', 'HomeController@index');`
- `$app['router']->get('action=index&page=my_menu_slug', 'HomeController@index');`
- `$app['router']->get(['page' => 'my_menu_slug', 'action' => 'index'], 'HomeController@index');`

The above examples will cause Sketch to look for the class `HomeController`, and run its `index()` method. You may also pass in a callback function instead of a controller reference. The router has methods `post()`, or `any()` to handle GET and POST requests. For methods other than GET and POST, use `register('METHOD', $params, $controller)`. Note that, whether you pass a query string or an array, the order of the variables passed does not matter. Also, when passing a query string, you can include or exclude the '?'.

Right now, the router is very simple. It can only match identical strings, or `{int}` variables. So if you wanted to edit a particular "foo" item, your route might look something like this:

`$app['router']->get(array('page' => 'my_foo_menu_slug', 'action' => 'edit', 'id' => '{int}'), 'FooController@edit');`

Define your menu routes in `app/menus/routes.php`. Since the first matching route will be selected, define your most specific routes first and your least specific routes last.

\##Custom Post Types

Similar to menus, you can create a new custom post type by extending the `\Sketch\CustomPostType\BaseCustomPostType` class. Again, define the post type's arguments as properties on the class. You can define `$args`, `$labels`, and `$rewrite` variables as their own separate arrays. Sketch will add the `$labels` and `$rewrite` parameters to the `$args` array automatically when creating the post type at run-time. This arrangement does distort the normal "Wordpress way" a bit - but it seemed like the most readable solution.

Add metaboxes and taxonomies to your Custom Post Type when you instantiate it in `index.php` (see the first code sample at the top of the page).

\##Metaboxes

Sketch metaboxes are a lot like custom post types and menus. Create a metabox by extending the `\Sketch\Metabox\BaseMetabox` class. Define the metabox arguments as parameters on the class.

But wait - that's not all! In addition to defining standard metabox arguments as class parameters, you must also specify a controller and method to handle the metabox's business logic.

Here is code for the basic metabox that ships with the sample Sketch app:

```
    class HelloMetabox extends BaseMetabox {
        protected
            $id = 'hello_metabox',
            $post_type = 'hello_post_type',
            $callback_controller = 'HelloController@metabox'
        ;
    }
```

Just like with menu routes, the metabox's controller is resolved out of the IoC container and has access to both the Symfony Request object and the Plates template system. In addition, (like all WordPress metaboxes) it will also be passed information about the currently displayed post, and the metabox itself. Here is our sample metabox controller:

```
    public function metabox($post, $metabox)
    {
        $data = [
            'post' => $post,
            'metabox' => $metabox
        ];
        $this->render('hello::metabox', $data);
    }
```

There are two ways to instantiate this metabox in your application. The first is illustrated at the top of this page - by calling `->addMetabox($app->make('HelloMetabox'))` on the post type that the metabox should be added to. Note that, if you use this method, you do not need to set a `$post_type` parameter on the metabox itself. It will be set automatically when you add it to the post type object.

The second method is to call the metabox's `->manuallyAddAction()` function after you've instantiated it in your Sketch app's `index.php` file. For example:

```
     $app->make('HelloMetabox')->manuallyAddAction();
```

If you use this method, then the `$post_type` parameter must be set. Otherwise, it won't display anywhere.

\##Taxonomies

To create a taxonomy, extend the `\Sketch\Taxonomy\BaseTaxonomy` class, and add the taxonomy's parameters in the same way as for a custom post type. In addition to the `$args`, `$labels` and `$rewrite` arrays, taxonomies can also have a `$capabilities` array.

\##Validation

Sketch ships with the [Valitron](http://github.com/vlucas/valitron) validation class by default. You can use Valitron directly in any class, and Sketch also provides a `\Sketch\ValidatorFactory` class so that you can more easily inject validator instances or set up validation as a service.

\##Service Providers

Service providers are a great place to put bootstrap code for third party services and register them on the Sketch Application. To create a service provider, first create a new class that implements `\Sketch\ServiceProviderInterface`.

Sketch service providers only need to implement one method: `register(\Sketch\Application $app)`. That method is a good place to register bindings on the application. For example:

```
    use \Sketch\Application;
    use \Sketch\ServiceProviderInterface;

    class MyProvider implements ServiceProviderInterface {

        public function register(Application $app) {
            $app->bind('FooInterface', function() {
                $config = array('foo' => 'bar');
                return new FooClass($config);
            });
        }
    }
```

You may also pass in an array of configuration values as the second parameter of the register method:

```
    public function register(Application $app, $config) {
        $app->bind('FooInterface', function() use($config) {
            return new FooClass($config);
        });
    }
```

Register your service providers in `Sketch\index.php`, right next to where you instantiate menus, custom post types, etc. This is also where you would pass in those configuration values, if the situation called for it:

```
    $app = require_once 'app/bootstrap.php';

    $config = array('foo' => 'bar');
    $app->register(new MyProvider(), $config);
```

To see more service provider examples, look at the `app/bootstrap.php` file where the Plates template system and Sketch's default controller factory is registered.

\##Breaking Changes and Backwards Compatibility

Sketch is in some sort of alpha or beta stage, and some changes to the core framework will necessitate changes to the application.

If you are using Sketch (which you are not, according to packagist), and running `composer update` causes your application to break (please never update production dependencies without testing locally first), here are a few things you can do:

1. Copy the code from [the most current Sketch bootstrap file](https://github.com/sketchwp/app/blob/master/app/bootstrap.php) into your application's `app/bootstrap.php` file.
2. Update controller references in [metaboxes](#metaboxes) and in `app/menus/routes.php`. The `Sketch\ControllerDispatcher` class was recently changed so that you must now pass the controller's full class name to the router. I.e., change `hello@index` to `HelloController@index`.
3. If #1 and #2 don't work, create a github issue or, if it's urgent, [contact me directly](https://github.com/pnoonan). I'm happy to help!

\##Mad Props

Sketch was created at [ArcStone](http://www.arcstone.com), a web development, design and marketing agency located in Minneapolis, Minnesota.

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity20

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity41

Maturing project, gaining track record

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/65b9570ae19f8677ba9b74a3582a3837680a449c2265caaf3709f8c9ce6f4e98?d=identicon)[sketchwp](/maintainers/sketchwp)

### Embed Badge

![Health badge](/badges/sketch-app/health.svg)

```
[![Health](https://phpackages.com/badges/sketch-app/health.svg)](https://phpackages.com/packages/sketch-app)
```

###  Alternatives

[laravel/telescope

An elegant debug assistant for the Laravel framework.

5.2k67.8M192](/packages/laravel-telescope)[spiral/roadrunner

RoadRunner: High-performance PHP application server and process manager written in Go and powered with plugins

8.4k12.2M84](/packages/spiral-roadrunner)[nolimits4web/swiper

Most modern mobile touch slider and framework with hardware accelerated transitions

41.8k177.2k1](/packages/nolimits4web-swiper)[laravel/dusk

Laravel Dusk provides simple end-to-end testing and browser automation.

1.9k36.7M259](/packages/laravel-dusk)[laravel/prompts

Add beautiful and user-friendly forms to your command-line applications.

708181.8M596](/packages/laravel-prompts)[cakephp/chronos

A simple API extension for DateTime.

1.4k47.7M121](/packages/cakephp-chronos)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
