Welcome to the core package of the PinkCrab Perique plugin framework, formally known as just the PinkCrab Plugin Framework.
For more details please visit our docs. https://perique.info
WordPress is a powerful tool for building a wide range of websites, but due to its age and commitment to backwards compatibility it's often frustration to work with using more modern tools.
Perique allows the creation of plugins, MU libraries for use on more complex websites.
The Core only provides access to the Hook_Loader
, Registration
, DI (DICE IOC Container), App_Config
and basic (native) PHP_Engine
rendering views.
Perique is rare form of pipe tobacco produced in the St James Parish of Louisiana. This historic tobacco has been produced in the region for centuries and sees tobaccos taken, packed into a barrels under pressure and left to ferment for over 12 months. The resulting tobacco has a strong and pungent quality, which is used to heavily enhance a tobaccos flavour, nicotine content and aroma with only a small quantity used. This is something we strived to produce in this framework; a small amount of existing code that can be used to enhance any codebase to be big, bold and striking.
$ composer require pinkcrab/perique-framework-core
First you will need to create your composer.json and plugin.php file.
// @file plugin.php
<?php
/**
* @wordpress-plugin
* Plugin Name: My Custom Plugin
* Plugin URI: https://my-custom-plugin.com
* Description: This is an example plugin for the PinkCrab Perique Framework
* Version: 1.2.0
* Author: Me<me@me.com>
* Author URI: https://my-custom-plugin.com
* License: GPL-2.0+
* License URI: http://www.gnu.org/licenses/gpl-2.0.txt
* Text Domain: custom-plugin
*/
require_once __DIR__ . '/vendor/autoload.php';
// Creates an instance of the App_Factory with the current directory as the base path.
$factory = new PinkCrab\Perique\Application\App_Factory(__DIR__);
// Define the default rules.
$factory->default_setup();
// Set rules and configure DI Container
$factory->di_rules(include __DIR__ . '/config/dependencies.php');
// Pass settings for App_Config
$factory->app_config( include __DIR__ . '/config/settings.php' )
// Pass all class names which should be used during registration
$factory->registration_classes(include __DIR__ . '/config/registration.php' );
// Add optional modules.
$factory->module(Some_Module::class);
// Then just boot the application.
$factory->boot();
Previously (pre 1.4.0)
with_wp_dice()
was used to create the App, this is now deprecated, but will remain for a while to account for any legacy code. The main different betweenwith_wp_dice()
anddefault_setup()
is originally a bug existed where view paths by default where the same as the base path, now this is fixed and the default view path is set to the base path +/views
. (Applies to all versions 1.4 and above)
If you wish to use a custom view path, you can can call $app_factory->set_base_view_path('path/to/views')
before calling default_setup()
.
You can also define a DI rule which will allow you to set the base path directly to the PHP_Engine
class.
Please note by doing this, it will the use
APP_Config::path('views')
orAPP_Config::url('views')
will not match the path you have set.
return array(
PHP_Engine::class => array(
'constructParams' => array( 'custom/view/path' ),
),
);
While you can pass arrays to the container_config(), app_config() and registration_classes(), these can get quite large. It can help return them from files.
These files can be placed anywhere, but in the above example and our boilerplate's, these 3 files are placed in the /config directory.
Used to define all of your custom rules for Dice, for more details on how to work with Interfaces and other classes which cant be autowired, see the Perique Docs::Setup
Using the full class name is essential, so ensure you include all needed use statements.
// @file config/dependencies.php
use Some\Namespace\{Some_Interface, Some_Implementation};
return array(
// Your custom rules
Some_Interface::class => array(
'instanceOf' => Some_Implementation::class
)
);
When the app is booted, all classes which have either hook calls or needed to be called, are passed in this array.
By default the Hookable middleware is passed, so all classes which implement the Hookable interface will be called. Adding custom Registration Middleware will allow you to pass them in this array for initialisation at boot.
Using the full class name is essential, so ensure you include all needed use statements.
// @file config/registration.php
use Some\Namespace\Some_Controller;
return array(
Some_Controller::class
);
See the Perique Docs::Registration for more details.
The App holds an internal config class, this can be used as an injectable collection of helper methods in place of defining lots of constants.
Alongside the usual path and url values that are needed frequently. You can also set namespaces (rest, cache), post types (meta and slug), taxonomies (slug & term meta), database table names and custom values. `
// @file config/settings.php
// Assumes the base directory of the plugin, is 1 level up.
$base_path = \dirname( __DIR__, 1 );
$plugin_dir = \basename( $base_path );
return array(
'plugin' => array(
'version' => '1.2.5',
),
'path' => array(
'assets' => $base_path . '/custom/assets',
),
'url' => array(
'assets' => plugins_url( $plugin_dir ) . '/custom/assets',
),
'db_table' => array(
'subscriptions' => 'some_plugin_subscribers'
),
'additional' => array(
// Custom values go here
'key' => 'value' // Config::additional('key'); = value
'other' => 'value' // $app_config->other = value
),
);
The full set of options can be found in the Perique Docs::App_Config.
At the heart of the application is the registration process. Classes can be stacked up and executed at initialisation. This allows for registering into core WP APIs, triggering remote API calls and anything else which needs to be set up when all of WP core is loaded.
It is possible to extend Perique with the use of Modules
. Modules are a way to add additional functionality to Perique and often come bundled with their own Registration Middleware.
Modules are easily added to the App_Factory by calling $factory->module(Some_Module::class)
and often come with there own config and abstract classes to help with the registration process.
Please see the Perique Docs::Modules for more details about how to create your own modules and also a curated list of existing modules.
The
Loader::class
loader has been deprecated and replaced with the newHook_Loader::class
Included with Perique is a single piece of Registration_Middleware. The Hookable
interface and Hookable_Middleware
pair make it easy to register any hooks, shortcodes, post types, taxonomies, admin pages, and rest endpoints. Any class which needs to be processed, implements the Hookable
interface and creates the ```function register(Hook_Hook_Loader $loader): void {...}
class Some_Controller implements Hookable {
public function register(Hook_Loader $loader): void{
$loader->admin_action('some_action', [$this, 'some_callback']);
}
public function some_callback($some_arg): void {...}
}
Now when the init hook is called (priority 1), the some_action hook will be added. So long as the request comes from wp-admin.
Please see the Perique Docs::Hookable for more details.
At its heart, most of Perique makes use a custom version of the Dice DI container. This allows for the easy creation of classes and the injection of dependencies.
class With_Dependencies{
private Some_Repository $repo;
private Some_Service $service;
private View $view;
public function __construct(Some_Repository $repo, Some_Service $service, View $view){
$this->repo = $repo;
$this->service = $service;
$this->view = $view;
}
}
Some_Repository
and Some_Service
can be either concrete classes, interfaces or abstract classes. The container will resolve the correct implementation and inject it into the class. For interfaces and abstract classes, you will need to define a rule in the dependencies.php
config file.
Please see the Perique Docs::Dependency Injection for more details.
Out of the box Perique comes with a basic PHP view engine. This allows for the rendering of templates, partials, Components and other view related tasks.
The View
class can be injected into classes as a dependency, or accessed statically from the App
object.
// As a dependency
class Something{
protected View $view;
public function __construct(View $view){
$this->view = $view;
}
public function render(): void{
$this->view->render('some/template', ['some' => 'data']);
}
}
// As a static call
class Something{
public function render(): void{
App::view()->render('some/template', ['some' => 'data']);
}
}
All template paths are relative to the view_path
defined when creating the app. Also the .php
extension is not required and optionally you can use the .
or /
to separate the path.
Template Path | View Path | Full Path |
---|---|---|
some/template |
/path/to/views |
/path/to/views/some/template.php |
some/template.php |
/path/to/views/ |
/path/to/views/some/template.php |
some.template |
/path/to/views |
/path/to/views/some/template.php |
some.template.php |
/path/to/views/ |
/path/to/views/some/template.php |
Please visit the Perique Docs::View for more details.
The App object has a few helper methods which can be called statically (either from an instance or from its name).
@throws App_Initialization_Exception Code 4 If app isn't initialised.
make()
can be used to access the DI Container to fully resolve the dependencies of an object.
$emailer = App::make(Customer_Emailer::class);
$emailer->mail(ADMIN_EMAIL, 'Some Report', $email_body);
$emailer->send();
Once the app has been booted you can access the App_Config values by either passing App_Config as a dependency or by using the Apps helper.
// Get post type slug
$args = ['post_type' => App::config('post_types', 'my_cpt')];
// Get current plugin version.
$version = App::config('version');
For more details on App_Config and its various use cases, please checkout the full docs.
If you need to render or return a template, you can use the view()
helper. Returns an instance of the View class, populated with the current defined engine (use PHP by default).
App::view()->render('signup/form', ['user' => wp_get_current_user(), 'nonce' => $nonce]);
It is possible to use dot notation in all view file paths. This allows for a simple way of defining paths for use on either Win or Unix file systems.
$view->render('path.to.file',['var' => 'foo']);
Would equate to
$view->render('path/to/file',['var' => 'foo']);
We have a number of hooks you can use to extend or modify how the app works. All of our internal hooks have pinkcrab/pf/app/ prefix, but we have a class of constants you can use PinkCrab\Perique\Application\Hooks:: APP_INIT_*
Hooks::APP_INIT_PRE_BOOT
Hooks::APP_INIT_PRE_REGISTRATION
Hooks::APP_INIT_POST_REGISTRATION
Hooks::APP_INIT_CONFIG_VALUES
Hooks::APP_INIT_REGISTRATION_CLASS_LIST
Hooks::APP_INIT_SET_DI_RULES
Hooks::COMPONENT_ALIASES
Hooks::MODULE_MANAGER
Please see the Perique Docs::Hooks for more details.
http://www.opensource.org/licenses/mit-license.html
Registration_Middleware
to the App at setup.call
rules with multiple Interfaceswbdb_prefix
to App_Config set_base_view_path()
and get_base_view_path()
to App_Factoryget_base_path()
to App_Factory, this gets the base path for the plugin.base_view_path()
to Renderable and PHP_Engine instances.PHP_Engine
template root paths. $app->boot()
method). Before it was only loaded if created using the App_Factory and not available before init
is called.public function set_hook_loader(Hook_Loader $loader):void{}
and public function set_di_container(DI_Container $container):void{}
methods are defined in the Middleware class.