Notes:
getMinNucleusVersion appropriately.Nucleus plugins allow just about anyone to extend the functionality that Nucleus offers, without having to alter the PHP code itself. Plugins are simple php scripts that must implement certain methods, and can easily be exchanged between Nucleus users. Installing goes as easy as adding the plugin file to the plugin directory and letting Nucleus know it's there.
Some advantages of plugins are listed below:
All plugin files should be placed in the directory that is listed in config.php. Commonly, this will be /your/path/nucleus/plugins/. Plugin files can be recognized by their form: NP_name.php. Some plugins require a subdirectory with the same name to store extra files or their admin area.
Note: the names are case-sensitive, so they should start with NP_, not Np_ or np_. Also note that when the plugin uses a subdirectory, the name of that directory should be all lowercase.
Ok, lets start by writing a simple plugin. Basically, each plugin is a PHP class that inherits from the predefined class NucleusPlugin. Below is an example of a HelloWorld-plugin:
<?php class NP_HelloWorld extends NucleusPlugin { // name of plugin function getName() { return 'Hello World'; } // author of plugin function getAuthor() { return 'Wouter Demuynck'; } // an URL to the plugin website // can also be of the form mailto:foo@bar.com function getURL() { return 'http://nucleuscms.org/'; } // version of the plugin function getVersion() { return '1.0'; } // a description to be shown on the installed plugins listing function getDescription() { return 'Just a sample plugin.'; } function doSkinVar($skinType) { echo 'Hello World!'; } function supportsFeature ($what) { switch ($what) { case 'SqlTablePrefix': return 1; default: return 0; } } } ?>
So, that wasn't so hard after all. Read on to find out more.
All Nucleus plugins must inherit from the PHP class NucleusPlugin. If this sounds complicated, don't worry, it isn't. It even makes your life easier, allowing you to only implement the methods that your plugin needs, and giving access to some auxiliary functions.
Below is an overview of the methods that the NucleusPlugin offers, and that you can re-implement in your own plugin. If you want to see the source of the class itsself, it's located at nucleus/libs/PLUGIN.php
Overview of the class NucleusPlugin (redefinable methods)
Next to the methods that can be implemented, the class NucleusPlugin offers some extra methods which you should not implement yourself. They can be called from within your plugin using the $this→functionName() syntax.
Overview of the class NucleusPlugin (non-redefinable methods)
You can create your own skinvars, and call them using <%plugin(PlugName,parameters)%> or <%PlugName(parameters)%> (when this does not conflict with an existing skinvar). Parameters are comma-separated.
To handle skinvars, you'll need to implement the doSkinVar method. Some samples of signatures are given below:
function doSkinVar($skinType) function doSkinVar($skinType, $param1, $param2) function doSkinVar($skinType, $skinVar, $param1, $param2) function doSkinVar($skinType, $skinVar, $param1 = 'default value')
$skinType parameter will be one of 'index', 'item', 'archive', 'archivelist', 'member', 'error', 'search', 'imagepopup' or template'$skinVar is actually the first parameter that's being interpreted as a type of skinvar (e.g. <%plugin(PlugName,VarType)%>)doSkinVar() (no parameters) and retrieve the parameters using the PHP function func_get_args(). Could be handy if you have different types of skinvars with different numbers of arguments$currentSkinNameTemplate plugin variables work in the same way as skin plugin vars. There are two differences:
$skinType parameter. Instead, they take extra parameters with info on the item and comment that is currently being parsed:doTemplateVar-method gets a &$item parameter.doTemplateCommentsVar-method gets an &$item parameter as well as a &$comment parameter.Note the ampersands!
Template variables are called in exactly the same way as skinvars (using <%plugin(PlugName,parameters)%> or <%PlugName(parameters)%>)
By default, all template variables are passed on to the doSkinVar-method, using 'template' as skinType-parameter.
If you want to provide your own implementation, you'll need to redefine the method doTemplateVar and/or doTemplateCommentsVar. It works in the same way as doSkinVar, except that now the skinType-parameter is missing.
function doTemplateVar(&$item) function doTemplateVar(&$item, $param1, $param2) function doTemplateVar(&$item, $type, $param1, $param2) function doTemplateVar(&$item, $type, $param1 = 'default value') function doTemplateCommentsVar(&$item, &$comment) function doTemplateCommentsVar(&$item, &$comment, $param1, $param2) function doTemplateCommentsVar(&$item, &$comment, $type, $param1, $param2) function doTemplateCommentsVar(&$item, &$comment, $type, $param1 = 'default value')
$currentTemplateName
Plugins can perform actions through action.php, the same script that's being used to receive comments and karma votes. You can call it using both GET and POST methods. Required parameters are action (should be 'plugin'), name (name of the plugin) and type (type of requested action)
To enable these actions, you should implement the doAction($actionType) method in your plugin. Extra parameters from the request can be received using requestVar('name') (requestVar takes care of magic_quotes_gpc that PHP might have added)
When your doAction method returns a string, it will be interpreted as an error, and an error message will be shown.
Nucleus Plugins can subscribe to events that occur whenever something important happens. The plugin can then execute some actions, or output some text.
Below is an example of how a plugin subscribes to the PreAddComment-event, an event that is generated immediately before a comment is added to a blog.
class NP_Acronyms extends NucleusPlugin { ... function getEventList() { return array('PreAddComment'); } ... function event_PreAddComment(&$data) { // replace acronym HTML $data['comment']['body'] = strreplace('HTML', '<acronym title="HyperText Markup Language">HTML</acronym>', $data['comment']['body']); } }
This plugin replaces the text HTML in each comment by the text <acronym title=“HyperText Markup Language”>HTML</acronym>. The acronym-tag is a HTML-tag that allows authors to provide extra information on acronyms.
Here's the steps you need to take to subscribe to an event:
getEventList-methodevent_EventName($data), in which the handling of the event is doneMultiple plugins can subscribe to the same event. The order in which these plugins are notified is the same order as the ordening in the plugin list of the admin area. Plugins higher in the list get notified earlier on.
The event_EventName-method gets only one parameter, $data, of which the contents differs depending on the event. It is an associative array with data. Objects and arrays that are passed in this array, are passed by reference, so the changes you make there will be remembered.
The event list uses some colors to indicate if changes in the parameters will be seen by nucleus or not:
Objects that are passed as parameters are indicates as follows: object. Most objects are also passed by reference, making them look like object by ref
A series of methods are offered to make it easy for plugins to set and retrieve options. These options can be directly edited from inside the Nucleus admin area, taking the need away for the plugin to provide an admin area of its own, and avoiding that options need to be set inside the PHP file itself.
Options are available in different contexts:
Several types of options are provided
text
Simple text
yesno
Either the value 'yes' or the value 'no' (on edit, shown as radio button)
password
Text field (starred on edit)
textarea (v2.2)
Text field with multiple rows and columns
select (v2.2)
Drop down menu. Needs extra info in the following form: Option 1|value1|Option 2|value2|Option 3|value3
As of Nucleus v3.2, some option types can be limited to only accept certain values using option-metadata. This metadata is stored in the $typeExtras-field, and is a semicolon-seperated list of values. Note: In a select-option, the select list must be the first value in $typeExtras.
| key | explanation |
|---|---|
datatype | Using 'datatype' you can give some extra hints to Nucleus about the datatype you want to use. Currently only 'numerical' is available. 'numerical' will cause Nucleus to only accept numerical values for this option (using both client-side and server-side check) (available for optiontypes: 'select' and 'text') |
access | If set to 'readonly', the option will not be editable (available for optiontypes: 'text' and 'textarea')If set to 'hidden', the option will be completely hidden for the end-user (available for optiontypes: 'text') |
some examples:
// following code creates a text-option that only accepts numerical values $this->createBlogOption('FooBar', 'foobar', 'text', '0', 'datatype=numerical'); // following code creates a select-option that only accepts numerical values $this->createItemOption('FooBar', 'foobar', 'select', '0', '0|0|1|1|2|2;datatype=numerical'); // following code creates a textarea-option that is readonly $this->createOption('FooBar', 'foobar', 'textarea', 'This textarea is readonly', 'access=readonly');
, $typeExtras = )Creates a new option in the global context
| parameter | value |
|---|---|
| $name | Option name |
| $desc | Textual description, to be shown on the page where options can be edited |
| $type | Option type (see above) |
| $defValue | Initial value |
| $typeExtras | Extra info on option type (see above) |
, $typeExtras = )
Creates an option in the blog context (see createOption)
, $typeExtras = )
Creates an option in the category context (see createOption)
, $typeExtras = )
Creates an option in the member context (see createOption)
, $typeExtras = )
Creates an option in the item context (see createOption)
changes the value of an option that was already in the database
| parameter | value |
|---|---|
| $name | Option name |
| $value | New value for option |
Changes the value for a blog option. The blogid attribute indicates for which blog the option is valid. (other options: see setOption)
Changes the value for a category option. The catid attribute indicates for which category the option is valid. (other options: see setOption)
Changes the value for a member option. The memberid attribute indicates for which member the option is valid. (other options: see setOption)
Changes the value for an item option. The itemid attribute indicates for which item the option is valid. (other options: see setOption)
Returns the value for an option in the database
| parameter | value |
|---|---|
| $name | Option name |
Returns the value for a blog option. blogid indicates for which blog a value is requested (other parameters: see getOption)
Returns the value for a category option. catid indicates for which category a value is requested (other parameters: see getOption)
Returns the value for a member option. memberid indicates for which member a value is requested (other parameters: see getOption)
Returns the value for an item option. itemid indicates for which item a value is requested (other parameters: see getOption)
Deletes an option from the database
| parameter | value |
|---|---|
| $name | Option name |
Deletes a blog option (see deleteOption)
Deletes a category option (see deleteOption)
Deletes a member option (see deleteOption)
Deletes an item option (see deleteOption)
Returns all values for a given blog option. The result is an associative array with a value for each existing blogid
Returns all values for a given category option. The result is an associative array with a value for each existing catid
Returns all values for a given member option. The result is an associative array with a value for each existing memberid
Returns all values for a given item option. The result is an associative array with a value for each existing itemid
Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each blogid ('id')
| parameter | value |
|---|---|
| $name | Option name |
| $amount | The amount of options you want |
| $sort | Sort ascending ('asc') or descending ('desc') |
Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each memberid ('id') (parameters: see getBlogOptionTop)
Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each categoryid ('id') (parameters: see getBlogOptionTop)
Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each itemid ('id') (parameters: see getBlogOptionTop)
Note: You can't call these functions from inside constructors of plugin classes. If you want to execute them when the plugin is loaded, place them in the init() method instead.
Up to v2.0, accessing the nucleus tables was just a matter of performing an SQL query on one of the nucleus_ tables. Since it is possible to use a custom table name in Nucleus versions >2.0, some precautions are needed in plugin development:
nucleus_item, use the global function sql_table('item') to generate the prefixed tablename1 (true) when supportsFeature('SqlTablePrefix') is called on it. If it doesn't, you won't be able to load the plugin on Nucleus versions > 2.0 when a custom prefix has been set (as a precaution)
Note that the sql_table global function in not available in Nucleus versions up to v2.0. If you use this method and want your plugin to work on Nucleus versions ⇐ 2.0, add the following snippet of code on top of your plugin class:
<?php // plugin needs to work on Nucleus versions &=2.0 as well if (!function_exists('sql_table')) { function sql_table($name) { return 'nucleus_' . $name; } } class NP_HelloWorld extends NucleusPlugin { ... } ?>
If your plugin needs database tables of it's own, you should create then in the install method and remove them in the unInstall method.
Some pointers
nucleus_plug_plugname to avoid conflicts with other plugins. Generate them through sql_table('plug_plugname') to make it work with custom prefixesmysql_query()sql_connect() at the end of your function. It might also be good to do this from the constructor, to avoid reconnecting constantly. You could then save your link identifier in $this→db and pass that along with every query.getTableList() method to make sure your table gets backupped when using the backup function.As of Nucleus v2.5, plugins can create admin area pages that integrate with the Nucleus admin area. These pages can be accessed either from the plugin admin page, or the quickmenu on the left.
To provide an admin area, you'll need take these steps:
NP_PluginName. Note that the name should be lowercase!<?php // if your 'plugin' directory is not in the default location, // edit this variable to point to your site directory // (where config.php is) $strRel = '../../../'; include($strRel . 'config.php'); if (!$member->isLoggedIn()) doError('You\'re not logged in.'); include($DIR_LIBS . 'PLUGINADMIN.php'); // create the admin area page $oPluginAdmin = new PluginAdmin('PluginName'); $oPluginAdmin->start(); echo '<h2>Plugin Name</h2>'; echo '<p>Page contents here<p>'; $oPluginAdmin->end(); ?>
QuickMenu event and add this code in your plugin:function event_QuickMenu(&$data) { array_push( $data['options'], array( 'title' => 'Plugin Name', 'url' => $this->getAdminURL(), 'tooltip' => 'Tooltip text' ) ); }
function hasAdminArea() { return 1; }
$strRel variable in the index.php needs to be adapted manually if the plugins directory is not located in nucleus/plugins/
The purpose of the PluginAdmin is to help you. Once created, you can use $oPluginAdmin→plugin to access the instance of your plugin.
As of Nucleus v3.2 plugins can provide a helppage with an overview of the plugins' functionality, the available skinvars and templatevars, where to get more info,…
The helppage will be accessible from the plugin overview in the admin area.
To provide a helppage, you'll need take these steps:
<h3>Plugin overview</h3> <p>The only purpose of this plugin is to show how the plugin helppages work</p> <h3>Installation</h3> <p>If you can read this you correctly installed the plugin :-)</p> <h3>SkinVars</h3> <p>Because this plugin is only a testcase it doesn't has any skinvars/templatevars but suppose it would have: <ul><li><b><%HelpPageTestCase1%></b>: does something</li> <li><b><%HelpPageTestCase1(foobar)%></b>: does something else</li></ul></p> <h3>Support and Bug reports</h3> <p>For additional support and/or bug reports please use this forum thread: <a href="http://forum.nucleuscms.org/viewtopic.php?t=<TOPIC_ID_GOES_HERE>"> http://forum.nucleuscms.org/viewtopic.php?t=<TOPIC_ID_GOES_HERE></a></p> <h3>Version History</h3> <ul><li>Version 0.1: initial testcaseversion</li> <li>Version 0.0: pre-initial version ;-)</li></ul>
function supportsFeature($what) { switch($what) { case 'HelpPage': return 1; default: return 0; } }
Starting from 3.2, a new plugin interface is added to allow one to declare any dependency on other plugin(s). This is useful for any plugin that requires another plugin to function. It is particularly useful for a plugin to detect broken dependencies that prevent if from functioning properly.
Let start from a real world example:
NP_PageLinkList depends on NP_BlogWithOffset to function, so we want to make sure if a user install NP_PageLinkList whithout first install NP_BlogWithOffset. With this API, Nucleus offers a way for a plugin to detect any missing dependency before it is installed.
In this case, we want to code into NP_PageLinkList to mark that it requires NP_BlogWithOffset. When the plugin is installed, the core calls a function in the plugin called getPluginDep(). This function returns a list of plugin it requires, and the core will check against all installed plugins and refuse to install the plugin if a dependency is missing.
All we have to do is added this function to NP_PageLinkList:
function getPluginDep() { return array('NP_BlogWithOffset'); }
The plugin dependency check also prevents plugins from being uninstalled if other plugins have a dependancy on it.