Wallogit.com
2017 © Pedro Peláez
Platform to allow developers to build bespoke functionality in an MVC and OOP fashion
Install via composer:, (*1)
composer require spindogs/wp-platform
Ensure you add the following PSR-4 autoloading location to your composer.json file:, (*2)
"autoload": {
"psr-4": {
"App\\": "app/"
}
}
Assuming your vendor directory is in your theme root, add the following line to functions.php to hook up the composer autoloading to your theme:, (*3)
require('vendor/autoload.php');
All platform classes can be accessed via the namespace Platform., (*4)
To setup the platform for Wordpress add the following line to your functions.php:, (*5)
Platform\Setup::setupWordpress();
If you are using the platform outside of Wordpress you must call the following method instead to run some core setup routines:, (*6)
Platform\Setup::setup();
To make a Wordpress custom post type create a new class in the namespace App\PostType that extends Platform\PostType.php:, (*7)
<?php
namespace App\PostType;
use Platform\PostType;
class Event extends PostType {
protected static $custom_type = 'event';
/**
* @return void
*/
public static function setup()
{
parent::setup();
self::registerPostType();
}
/**
* @return void
*/
public static function registerPostType()
{
$labels = array(
'name' => 'Events',
'singular_name' => 'Event',
'add_new' => 'Add event',
'add_new_item' => 'Add event',
'edit_item' => 'Edit event',
'new_item' => 'New event',
'view_item' => 'View event',
'search_items' => 'Search events',
'not_found' => 'No events found',
'all_items' => 'List events',
'menu_name' => 'Events',
'name_admin_bar' => 'Event'
);
$args = array(
'labels' => $labels,
'public' => true,
'show_ui' => true,
'capability_type' => 'post',
'menu_icon' => 'dashicons-calendar-alt',
'hierarchical' => false,
'supports' => ['title', 'editor', 'author', 'thumbnail'],
'taxonomies' => [],
'has_archive' => true,
'rewrite' => ['slug' => 'events', 'with_front' => false]
);
register_post_type(self::$custom_type, $args);
}
}
You can then register this new post type in functions.php by calling the setup() method:, (*8)
App\PostType\Event::setup();
There are a number of helpful features going on behind the scenes when you register your custom post types in this manner. In particular, it means that if a CMS page URL is created with a matching URL of the rewrite slug then Wordpress will automatically load the CMS page into the global $post variable when viewing the post type archive., (*9)
For example, if your post_type has the rewrite slug /events/ and a visitor accesses the archive page for this post_type then the platform will attempt to load a CMS page with the matching url /events/., (*10)
This allows an editor to content manage fields on an archive page that is not possible with core Wordpress alone., (*11)
For more bespoke development requirements, you can create your own custom URLs and bypass the core Wordpress template loader. Create a class called App\Routes.php that extends Platform\Route.php. All rules should be placed in the Routes::register() method as demonstrated below:, (*12)
<?php
namespace App;
use Platform\Route;
class Routes extends Route {
/**
* @return void
*/
public static function register()
{
self::match('basket/add/([0-9]+)')->call('BasketController', 'add');
}
}
Create your controllers in the App\Controller namespace extending the class Platform\Controller.php., (*13)
<?php
namespace App\Controller;
use Platform\Controller;
class BasketController extends Controller {
/**
* @param int $product_id
* @return void
*/
public function add($product_id)
{
$this->data('product_id', $product_id); //pass data to view
$this->render('basket'); //render the view
}
}
There are a number of helpful methods within a controller:, (*14)
Render a template - the template path defaults to the theme root
$this->render('template_name'), (*15)
Pass data to the view
$this->data('key', 'value'), (*16)
Get any data that had already been passed to the view
$this->getData('product_id'), (*17)
Call a method from a different controller and merge the data into view
$this->uses('AnotherController', 'methodName'), (*18)
Encode data and render with a JSON content type header
$this->json($data), (*19)
Return a view object pre-populated with data from the controller ready to be rendered
$this->getView($template_name), (*20)
For your models extend the Platform\Model.php class. Set the protected static $table property to match the model's database table and define the public properties available for this model:, (*21)
<?php
namespace App;
use Platform\Model;
class Order extends Model {
protected static $table = 'Orders';
public $id;
public $date_created;
public $subtotal;
public $discount;
public $shipping;
public $tax;
public $total;
public $status;
}
Every model MUST have a query() method that returns a query string:, (*22)
/**
* @return string
*/
public function query()
{
$q = 'SELECT o.*
FROM Orders AS o
WHERE 1
{where_id}
ORDER BY
o.date_created DESC
{limit}';
return $q;
}
You can also use this method to setup the schema of your model passing an array to the fields() method:, (*23)
$this->fields([
'id' => [
'column' => 'o.id',
'type' => self::INTEGER
],
'date_created' => [
'column' => 'o.date_created',
'type' => self::DATETIME
],
]);
This does two things - firstly it defines what fields can be searched on by using the {where_*} tags in the query string by mapping to a column., (*24)
Secondly it allows values from the database to be cast to a particular data type using the type key., (*25)
There are a number of data types built in:, (*26)
Model::INTEGERModel::STRINGModel::FLOATModel::DATETIMEModel::DATETo access data from a model use the Platform\Collection.php and pass the name of the model to the constructor (as a string):, (*27)
$collection = new Collection('App\Order');
Alternatively, you can call the collection() method on a model:, (*28)
$collection = Order::collection();
You are then able to filter the query using your fields previously setup in the model:, (*29)
$collection->where('id', 9999);
By default, the where() method will produce an = clause but you can override this by passing an operator as a third parameter:, (*30)
$collection->where('id', 9999, '>=');
The following operators are recognised:, (*31)
=<, >, <=, >=, <>
LIKECall the method getAll() to retrieve an array of objects:, (*32)
$orders = $collection->getAll();
Alternatively, you can grab a single object using the following method:, (*33)
$order = $collection->getSingle();
There are a number of helpful methods you can use on a collection:, (*34)
Customise the fields to return from a query
$collection->select('field_name'), (*35)
Do a DISTINCT select query
$collection->distinct(), (*36)
Do a COUNT aggregate query on a field
$collection->count('field_name'), (*37)
Get the SQL generated by a collection
$collection->getSql(), (*38)
Get the raw results of a collection (not strongly typed to an object)
$collection->getRaw(), (*39)
Get a single value from a query result (useful for aggregates)
$collection->getVal(), (*40)
The platform comes with built in interfaces to allow the translating of static strings used in your templates. This mechanism assumes a multisite setup whereby each site installation corresponds to a different language (eg. English, Welsh)., (*41)
To use the functionality, first create the translation database tables by calling the following method once only:, (*42)
Platform\Translation::install();
To activate the admin interfaces, simply add the following line to your functions.php to set the default language to your primary multisite installation:, (*43)
Platform\Setup::defaultLang(1); Platform\Translation::setup();
Finally, ensure you wrap all the static strings in your templates with the Translation::_() method. To make your code more readable could always assign a shorter alias for the translation class:, (*44)
<?php
use Platform\Translation as T;
echo '<h1>'.T::_('Hello world').'</h1>';
If you want new translations to automatically be created in the database, add the following line to functions.php:, (*45)
Platform\Setup::debug();
From time to time you may want to add custom interfaces to the wordpress back office. You can do this by setting up routes in App\Routes.php using the Routes::admin() method:, (*46)
Note - all routes you add using the
Routes::admin()method will be auto prefixed bywp-admin/, (*47)
<?php
namespace App;
use Platform\Route;
class Routes extends Route {
/**
* @return void
*/
public static function register()
{
self::admin('orders')->call('AdminController', 'listOrders');
}
}
You can then register a new admin menu item using the following wordpress function:, (*48)
add_menu_page(
'Orders',
'Orders',
'publish_pages',
'orders',
null,
'dashicons-products',
50
);
There are a number of different helper functions available:, (*49)