Pink-Crab / Perique-Framework

The Perqiue Plugin Framework for WordPress
5 stars 0 forks source link

PinkCrab Perique Plugin Framework

logo

Welcome to the core package of the PinkCrab Perique plugin framework, formally known as just the PinkCrab Plugin Framework.

Latest Stable Version Total Downloads License PHP Version Require GitHub contributors GitHub issues

WP5.9 [PHP7.4-8.1] Tests WP6.0 [PHP7.4-8.1] Tests WP6.1 [PHP7.4-8.3] Tests WP6.2 [PHP7.4-8.3] Tests WP6.3 [PHP7.4-8.3] Tests WP6.4 [PHP7.4-8.3] Tests

Mutation testing badge codecov Scrutinizer Code Quality Maintainability

For more details please visit our docs. https://perique.info

Why?

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.

What is Perique?

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.

Setup

$ composer require pinkcrab/perique-framework-core

First you will need to create your composer.json and plugin.php file.

plugin.php

// @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 between with_wp_dice() and default_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)

Custom View Path

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') or APP_Config::url('views') will not match the path you have set.

return array(
   PHP_Engine::class => array(
      'constructParams' => array( 'custom/view/path' ),
   ),
);

Config files

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.

dependencies.php

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

registration.php

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.

settings.php

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.

Modules and the Registration Service

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.

Modules

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.

Hookable

The Loader::class loader has been deprecated and replaced with the new Hook_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.

DI Container

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.

View

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.

Static Helpers

The App object has a few helper methods which can be called statically (either from an instance or from its name).

App::make(string $class, array $args = array()): object

$emailer = App::make(Customer_Emailer::class); 
$emailer->mail(ADMIN_EMAIL, 'Some Report', $email_body); 
$emailer->send(); 

App::config(string $key, ...$child): mixed

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.

App::view(): View

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

Hooks

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_*

Please see the Perique Docs::Hooks for more details.

License

MIT License

http://www.opensource.org/licenses/mit-license.html

Change Log