Table of Contents

Nucleus CMS Plugin API

Notes:

Introduction

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.

Writing your first plugin

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;
		}
	}
 
}
?>
  1. Copy this code in a file called NP_HelloWorld.php, and put it in your plugins directory. Make sure that there are no spaces after the last ?> or before the first <?php.. NP stands for “Nucleus Plugin”, if you were wondering about that.
  2. Open the Nucleus Administration area and go into Nucleus Management/Manage Plugins
  3. You'll find out that there's a HelloWorld plugin you can install. Do this. If everything worked out correctly, you'll see that your plugin is now listed in the list of installed plugins.
  4. Now edit one of your skins and insert the following statement at a place of which you know where it will show up on the actual page. <%plugin(HelloWorld)%> Note that the name (HelloWorld) is case sensitive!
  5. Now visit a page that uses the skin you edited: notice the “Hello World” at the location where you've added the plugin-skinvar.

So, that wasn't so hard after all. Read on to find out more.

The class NucleusPlugin

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)

Skinvars

Description

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

Notes

Template variables

Description

Template plugin variables work in the same way as skin plugin vars. There are two differences:

  1. They are called from within templates instead of from within skins
  2. They don't take a $skinType parameter. Instead, they take extra parameters with info on the item and comment that is currently being parsed:
    • The doTemplateVar-method gets a &$item parameter.
    • The 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')

Notes

Actions

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.

Events

Nucleus Plugins can subscribe to events that occur whenever something important happens. The plugin can then execute some actions, or output some text.

Example

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.

Subscribing to events

Here's the steps you need to take to subscribe to an event:

  1. Add the event name to the array returned by the getEventList-method
  2. Create a method with signature event_EventName($data), in which the handling of the event is done

Multiple 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.

Parameters

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

Saving options

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:

  1. Global options: Editable on the admin area from the plugins section.
  2. Blog options: Editable from the blogsettings pages.
  3. Category options: Editable from the blogsettings pages (on the 'edit category' page).
  4. Member options: Editable on the 'edit member' pages
  5. Item options: Editable on the 'add item' or 'edit item' pages

Option types

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

Option meta

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
datatypeUsing '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')
accessIf 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');

Restrictions

  1. The name of an option can contain a maximum of 20 characters
  2. The description of an option can contain a maximum of 255 characters
  3. The value for an option has no limit (Prior to v2.5 the limit was 128 characters)
  4. The characters '=', '|' and ';' can not be used inside a select list (for a select-option), or in option-metadata

The methods

Creates a new option in the global context

parameter value
$nameOption name
$descTextual description, to be shown on the page where options can be edited
$typeOption type (see above)
$defValueInitial value
$typeExtrasExtra info on option type (see above)

Creates an option in the blog context (see createOption)

Creates an option in the category context (see createOption)

Creates an option in the member context (see createOption)

Creates an option in the item context (see createOption)

changes the value of an option that was already in the database

parameter value
$nameOption name
$valueNew 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
$nameOption 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
$nameOption 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
$nameOption name
$amountThe amount of options you want
$sortSort 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.

Database tables

Access to Nucleus tables

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:

  1. Instead of using a fixed tablename like nucleus_item, use the global function sql_table('item') to generate the prefixed tablename
  2. Make sure your plugin returns 1 (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 {
...
}
 
?>

Your own tables

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

Plugin Admin Area

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.

Basics

To provide an admin area, you'll need take these steps:

  1. Create a subdirectory of the plugins directory, and name it pluginname if your plugin is NP_PluginName. Note that the name should be lowercase!
  2. In that directory, create a file called index.php, which looks like this:
<?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();
 
?>
  1. Subscribe to the 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'
                        )
                );
        }
  1. Implement this method in your plugin:
function hasAdminArea()
{
        return 1;
}

Considerations

The PluginAdmin class

The purpose of the PluginAdmin is to help you. Once created, you can use $oPluginAdmin→plugin to access the instance of your plugin.

Plugin HelpPage

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.

Basics

To provide a helppage, you'll need take these steps:

  1. Create a subdirectory of the plugins directory, and name it pluginname if your plugin is NP_PluginName. Note that the name should be lowercase! This is actually the same directory as for the admin area.
  2. In that directory, create a file called help.html. In this file you can document your plugin. This is a good template to start from:
<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>
  1. Return a value larger than 0 for supportsFeature('HelpPage'):
function supportsFeature($what) {
        switch($what) {
        case 'HelpPage':
                return 1;
          default:
                return 0;
        }
  }

Plugin Dependency Check

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.

How to write a plugin that utilize this function

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.