Doolollys - Custom extensions to {eac}Doojigger or Doojigger derivatives - Add easy-to-code extensions to {eac}Doojigger or your own derivative plugins using the extension framework.
Document Header
Homepage:https://eacDoojigger.earthasylum.com/
Author:EarthAsylum Consulting
Last Updated:03-Dec-2024
Contributors:EarthAsylum Consulting, Kevin Burkholder
Requires {eac}Doojigger:3.0
WordPress URI:https://wordpress.org/plugins/search/earthasylum/
GitHub URI:https://github.com/EarthAsylum/docs.eacDoojigger/wiki/
Description
Summary
Doololly extensions are, relatively, small PHP classes that extend the main plugin. Typically they are created to address specific requirements for your website or business. An extension focuses on your requirements while having available the full plugin functionality of {eac}Doojigger.
- Naming Conventions
- Define The Extension Class
- Instantiating The Extension
- Registering The Extension
- More...
Naming Conventions
The name of the extension file must end with .extension.php
or .doololly.php
.
Required file name :
{something}.extension.php
or{something}.doololly.php
- e.g. myAwesomeExtension.extension.php or myAwesomeExtension.doololly.php
class.{something}.extension.php
orclass.{something}.doololly.php
- e.g. class.myAwesomeExtension.extension.php or class.myAwesomeExtension.doololly.php
Using {something}.{someother}.extension.php
will use {someother}_extension_enabled
as the 'Enabled' option for the {something} extension (assuming class names match file names).
myAwesomeExtension.extension.php
andmyAwesomeAddons.myAwesomeExtension.extension.php
both usemyAwesomeExtension_extension_enabled
.- Both extensions (
myAwesomeExtension
andmyAwesomeAddons
) are enabled or disabled by the same checkbox on the administration settings screen.
The name of the extension class must be unique and should match the file name.
Recommended class name :
{something}
- e.g. myAwesomeExtension
{something}_extension
- e.g. myAwesomeExtension_extension
{something}_doololly
- e.g. myAwesomeExtension_doololly
Define The Extension Class
The first executable line in your extension class must define the namespace as ...
namespace myAwesomeNamespace\Extensions;
Or namespace myAwesomeNamespace\Doolollys;
Then declare your extension class by extending \EarthAsylumConsulting\abstract_extension
...
namespace myAwesomeNamespace\Extensions;
class myAwesomeExtension extends \EarthAsylumConsulting\abstract_extension
{
public function __construct($plugin)
{
parent::__construct($plugin, self::ALLOW_ALL);
if ($this->is_admin())
{
$this->registerExtension( $this->className );
// Register plugin options when needed
$this->add_action( "options_settings_page", array($this, 'admin_options_settings') );
}
}
public function admin_options_settings()
{
$this->registerExtension( $this->className,
[
...option meta data...
]
);
}
public function initialize()
{
}
public function addActionsAndFilters()
{
}
public function addShortcodes()
{
}
}
return new myAwesomeExtension($this);
Instantiating The Extension
The extension file (myAwesomeExtension.extension.php
) must return the instantiated class passing $this
(the main plugin instance) as the first argument:
return new myAwesomeExtension($this);
The main plugin will automatically load the class/extension file when WordPress triggers the 'plugins_loaded' action.
The extension must call the parent constructor within its __construct()
method:
parent::__construct( $plugin, {option_flags} );
- Sets $this->plugin to the class instance of the main plugin (e.g. eacDoojigger or myAwesomePlugin).
- Sets $this->pluginName to the short name of the main plugin (sans namespace - 'eacDoojigger' or 'myAwesomePlugin').
- Sets $this->className to the short name of this extension class (sans namespace - 'myAwesomeExtension').
- Returns bool (enabled).
The main plugin will then:
- Fire the
eacDoojigger_extensions_loaded
action. - Call the
initialize()
method. - Fire the
eacDoojigger_initialize
action. - Call the
addActionsAndFilters()
method. - Call the
addShortcodes()
method. - Fire the
eacDoojigger_ready
action.
* For Doojigger plugin derivatives, the action names use the derivative plugin name (e.g. myAwesomePlugin_extensions_loaded instead of eacDoojigger_extensions_loaded).
Registering The Extension
The extension must register itself in the constructor with:
$this->registerExtension( [$this->className, {admin_tab_name}], [option meta data] );
- Registers '{classname}_extension_enabled' option for this extension.
- Registers extension options with 'Enabled' checkbox option.
- Adds options to the {admin_tab_name} tab on the settings page.
If the 1st argument is a string (not an array and not another extension name), the options will be added to the 'General' tab:
$this->registerExtension( $this->className, [option meta data] );
Equivalent to:
$this->registerExtension( [$this->className, 'general'], [option meta data] );
The 1st argument may be replaced with another extension's name to append options to that extension & tab:
$this->registerExtension( 'debugging', [...additional debugging options] );
if the extension has no options/settings to register, the array may be omitted:
$this->registerExtension( [$this->className, {admin_tab_name}]);
if the extension has no options/settings to register AND wants no 'Enabled' option (the extension is essentially invisible):
$this->registerExtension( false );
if the extension has options/settings to register BUT wants no 'Enabled' option:
$this->enable_option = false; // <- before registerExtension();
$this->registerExtension( [$this->className, {admin_tab_name}], [option meta data] );
Since version 3.0, both the tab name and the 'Enabled' option may be coded as a constants:
const TAB_NAME = 'General';
const ENABLE_OPTION = false;
It is rare that extension options are needed anywhere but within the plugin's administrator settings page. It is both optimal and good practice to register your settings within a test for the page using $this->plugin->isSettingsPage()
...
if ($this->plugin->isSettingsPage())
{
$this->registerExtension( [$this->className, {admin_tab_name}], [option meta data] );
}
Or, preferably, use the just-in-time options_settings_page
action that is fired right before rendering the settings html page.
public function __construct(array $header)
{
if ($this->is_admin())
{
$this->registerExtension( [$this->className, {admin_tab_name}] );
$this->add_action( "options_settings_page", array($this, 'admin_options_settings') );
}
}
public function admin_options_settings()
{
$this->registerExtensionOptions( [$this->className, {admin_tab_name}], [option meta data] );
}
Extension Option Flags
The {option_flags} passed to the parent constructor may included any of the abstract_extension constants shown here.
const ALLOW_ADMIN = 0b00000001; // enabled on admin pages (default is disabled)
const ONLY_ADMIN = 0b00000010; // enabled only on admin pages, not front-end
const ALLOW_NETWORK = 0b00000100; // enabled for network admin in multisite (uses network options)
const ALLOW_CRON = 0b00001000; // enabled for cron requests
const ALLOW_CLI = 0b00010000; // enabled for wp-cli requests
const ALLOW_ALL = self::ALLOW_ADMIN|self::ALLOW_NETWORK|self::ALLOW_CRON|self::ALLOW_CLI;
const ALLOW_NON_PHP = 0b00100000; // enabled when loaded for a url not ending in .php
const DEFAULT_DISABLED = 0b01000000; // force {classname}_enabled' option to default to not enabled
Multiple options are logically OR'd together:
parent::__construct( $plugin, self::ALLOW_ADMIN | self::ONLY_ADMIN | self::ALLOW_NETWORK );
Extension Option Meta Data
Option Meta Data is an array of arrays defining options/settings that can be updated from the plugin's 'settings' page. Each option name is automatically prefixed with the plugin name (i.e. 'eacDoojigger').
An option is defined as:
'my_option_name' => array(
'type' => 'type: {input type}',
'label' => 'label: {field label}',
'title' => 'title: information text/html to be displayed',
'options' => array({option,...}),
'default' => 'default: {default option or value}',
'info' => 'info: Information/instructions',
'attributes' => html attributes array ['name="value", name="value"'],
'help' => 'contextual help'
),
See Administrator Options (found in the /Extras/OptionMetaData/readme.txt file) for details on registering and using options in you plugin and extensions.
Extension Methods
The extension may use:
$this->isEnabled(false);
to disable further calls to the extension
The extension should use:
$this->is_option(optionName [,value]);
to check for option value; returns true|false or actual value, 'Enabled'=true, 'Disabled'=false.
The extension may use:
$this->is_network_enabled();
to check if the same extension is enabled at the network level.
The extension should use:
$this->is_network_option(optionName [,value]);
to check network enabled and network option value.
The extension may use:
$this->registerExtensionOptions( $this->className, [option meta data] );
to register additional options (after $this->registerExtension(...)).
Extension Version Updates
If a constant 'VERSION' is set, automatic version checking and update methods may be used.
const VERSION = '22.0915.1';
Version format shown, a Calendar Versioning variation:
YY.MMDD.s
(year.monthday.sequence). Semantic versioning:Mj.Mn.p
(major.minor.patch) works just as well.
When the VERSION changes:
- An action is triggered :
{pluginName}_version_updated_{extensionName}
.- e.g.
myAwesomPlugin_version_updated_myAwesomeExtension
- e.g.
- If the method
adminVersionUpdate()
is defined by the extension, it will be called directly.
Both options take 2 parameters, the previous version and the new (current) version.
Extension Method Calling
Extension methods may be called programmatically through the plugin class:
by using:
$this->plugin->callMethod([extensionName, extensionMethodName], [,args...]);
$this->callMethod([extensionName, extensionMethodName], [,args...]);
eacDoojigger()->callMethod([extensionName, extensionMethodName], [,args...]);
or: (as of Version 2.0.1)
$this->extensionName->extensionMethodName(args...);
eacDoojigger()->extensionName->extensionMethodName(args...);
this will attempt to call "extensionMethodName" in the 'extensionName' extensions.
by using:
$this->plugin->callAllExtensions(extensionMethodName [,args...]);
$this->callAllExtensions(extensionMethodName [,args...]);
eacDoojigger()->callAllExtensions(extensionMethodName [,args...]);
this will attempt to call "extensionMethodName" in all enabled extensions.
Filters and Shortcodes
Through the abstract_extension class, extensions provide a filter to overrids the $this->enabled() method (as part of the method)...
This filter is called for each extension and passes the extension class name as the 2nd argument. Other external code may enable or disable an extension through this filter.
/**
* filter {pluginName}_extension_enabled allow disabling extensions
* @param bool current enabled status
* @param string $this->className (extension name)
* @return bool enabled value
*/
$this->enabled = $this->apply_filters( 'extension_enabled', $this->enabled, $this->className );
Filter Examples:
\add_filters( 'eacDoojigger_extension_enabled', function($enabled,$extension) {
if ($extension == 'myDisabledExtension') $enabled = false;
return $enabled;
});
{eac}Doojigger (and your derivatives) provides a front-end filter and shortcode that gives access to (nearly) all public methods in extensions.
The filter and shortcode name is the plugin class name (e.g. 'eacDoojigger' or 'myAwesomePlugin'). Arguments include:
- method='{methodName}', which is made up of the extension name and the extension method (extension.method).
- args='...', to pass a list of arguments/values.
- default='...', to set a default value.
- index='...', to index an item from an array returned by your method.
Filter Examples:
\apply_filters('eacDoojigger', null, [ method='myAwesomeExtension.myCoolMethod' ]);
Shortcode Examples:
['eacDoojigger' method='myAwesomeExtension.myCoolMethod']
Arguments to the filter or shortcode may be passed as a comma-delimited string as 'args='.
\apply_filters('eacDoojigger', null, [ method='myAwesomeExtension.myCoolMethod' args='arg1,arg2,...']);
['eacDoojigger' method='myAwesomeExtension.myCoolMethod' args='arg1,arg2,...']
Extension Contextual Help
Adding contextual help to your extension, through the WordPress help system, is easy using the methods built into {eac}Doojigger...
In your __constructor()
method, add the options_settings_help
action...
$this->add_action( 'options_settings_help', array( $this, 'admin_options_help') );
Then add the method to create your help content...
public function admin_options_help()
{
$this->addPluginHelpTab('help-tab-name','...help content...');
$this->addPluginSidebarText('...sidebar content...');
$this->addPluginSidebarLink('title','url');
}
If you want your extension help to only appear on the extension tab, use the isSettingsPage()
method before adding any help content...
if ($this->plugin->isSettingsPage('extension-tab-name')) {
$this->addPluginHelpTab('help-tab-name','...help content...');
}
See Contextual Help (found in the /Extras/ContextualHelp/readme.txt file) for more details.
Extension Debugging
Extensions may implement a debugging filter to provide debugging/state information:
/*
* filter {pluginname}_debugging get debugging information
* param array current array
* return array extended array with [ extension_name => [key=>value array] ]
*/
add_filter( '{pluginname}_debugging', array($this, 'my_debugging'));
public function my_debugging($debugging_array)
{
$debugging_array[$this->className] = array(
'somekey' => 'somevalue',
'anotherkey'=> 'anothervalue',
)
return $debugging_array;
}
Extension Plugins (Doohickeys)
A simple plugin can be created to add extensions to an existing plugin (eacDoojigger or myAwesomePlugin) that are outside of the plugin folder. This new plugin answers a filter to point to a separate Extensions
directory and exist in its own plugin folder with no risk of being overwritten.
/**
* Plugin Name: My Awesome Extensions
*/
namespace myAwesomeNamespace;
class myAwesomeExtension
{
public function __construct()
{
add_filter( 'eacDoojigger_load_extensions', function($extensionDirectories)
{
$extensionDirectories[ plugin_basename( __FILE__ ) ] = [ plugin_dir_path( __FILE__ ).'/Extensions' ];
return $extensionDirectories;
}
);
}
}
new \myAwesomeNamespace\myAwesomeExtension();
Doololly extensions are then placed in the '.../myAwesomeExtension/Extensions' folder.
This extension can also provide automatic updating.
See Automatic Updates (found in the /Extras/AutoUpdate/readme.txt file).
Skeleton/Framework
There is a complete, functional myAwesomeExtension skeleton with these examples in the Extras/Extensions folder of {eac}Doojigger that you can use to build your extensions by simply changing the namespace name, plugin name, extension name, and adding your own code.
There is also a fully functional myFunctions extension plugin in the Extras/Extensions folder intended to be used to replace (or augment) a custom theme functions.php
, with optional custom stylesheet and javascript.
Screen Shots
- My Awesome Plugin with My Awesome Extension
Other Notes
Additional Information
- Extensions in the plugin 'Extensions' or Doolollys folder are automatically loaded.
- Extensions in the plugin '{namespace}/Extensions' folder are automatically loaded.
- Extensions in a 'admin' or 'backend' folder are only loaded for admin requests.
- Extensions in a 'network' folder are only loaded for network admin requests.
- Extensions in a 'public' or 'frontend' folder are only loaded for front-end requests.
- Other directory names in the Extensions folder may be used to categorize extensions.
- Directory or extension names beginning with '-', '_' or '.' are ignored (disabled).
- New extensions can be added by placing them in one of the plugin 'Extensions' folders. However, when the plugin is updated, those extensions will be lost and must be re-installed. A better alternative is to create an extension plugin (doohickey) to add new extensions.