CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

Implementing CWIS Plugins

Plugins are a way of modifying existing functionality or adding new functionality to your CWIS installation, without having to modify the CWIS code itself. They are written in PHP and, once placed in the correct location, are loaded and run automatically by CWIS at the appropriate time.

If you want to just change the look and feel of your CWIS site, then you're probably better off creating a new interface, rather than a plugin. If you want to add a specific feature or modify a specific bit of CWIS functionality, then a plugin may be the right choice.

# Names, Files, and Locations

The first step in creating a plugin is to think about what the plugin is supposed to do, and then use that to choose an (ideally unique) base name for your plugin. A base name should begin with a letter and contain only letters and (if appropriate) numbers. The first letter is usually upper-case. If the name contains multiple words, the first letter of each word is usually made upper-case, and all other letters lower-case. For example, if you were writing a plugin to add new CWIS users to a mailing list, you might give it the base name "ListSubscriber".

The base name is used for the name of the PHP file that will contain your plugin. So for our ListSubscriber plugin the plugin file name would be `ListSubscriber.php`.

Once you've created your plugin file, it should be placed in the `/local/plugin` directory in your CWIS installation.

# Classes and Attributes

Plugins in CWIS are implemented as PHP objects, with the plugin's base name as the class name. All plugins are descendents of the Plugin base class. The minimum a CWIS plugin must implement is its own version of the Plugin::Register() method, to set the basic plugin attributes:

class ListSubscriber extends Plugin {
function Register()
{
$this->Name = "State University Library Mailing List Subscription Plugin";
$this->Version = "1.0";
$this->Description = "This plugin will add new users to the StateLib "
." mailing list when they verify their CWIS account, and remove"
." them if their account is deleted.";
$this->Author = "John Doe";
$this->Url = "http://library.state.edu/cwisdev/listsubscriberplugin.html";
$this->Email = "jdoe@state.edu";
$this->Requires = array(
"CWISCore" => "1.9",
);
}
};

The only attributes that must be set are Plugin::$Name and Plugin::$Version, but assigning values to the others is strongly encouraged, particularly if you may be sharing your plugin with others. The Plugin::$Name attribute should contain a human-readable name for your plugin.

The Plugin::$Requires attribute is used to specify the minimum versions of other plugins that your plugin must have to run. The `CWISCore` plugin can be required to ensure that your plugin is running under at least the specified version of CWIS. Specific descriptions of the other attributes can be found in the documentation for the Plugin class.

# Events and Hooks

CWIS has built into it an event subsystem that provides a way of running some PHP code when certain occurrences happen. Plugins take advantage of this mechanism to accomplish their tasks by "hooking" parts of their code into appropriate events.

To hook into specific events, you'll add an implementation of the Plugin::HookEvents() method to your plugin class:

function HookEvents()
{
return array(
"EVENT_USER_VERIFIED" => "AddUserToMailingList",
"EVENT_USER_DELETED" => "RemoveUserFromMailingList",
);
}

This method is called when your plugin is loaded, and allows you specify methods of your plugin class to be run at specific times, depending on the event type. With CHAIN events, for example, you might modify data before it's saved or before it's displayed, or with a FIRST event like `EVENT_USER_AUTHENTICATION` you might connect CWIS to your own mechanism for authenticating user logins.

A list of the events currently available to hook onto can be found on the CWIS Event Callbacks page. This list will expand with each new version of CWIS, based on feedback from plugin authors about what other events they may want to hook onto. Plugins may also define their own events, for others to hook onto, by implementing a Plugin::DeclareEvents() method.

# Methods and Parameters

So you've come up with a base name for your plugin, you've created a PHP class with that base name and put it into a correspondingly-named file, and you've added a Plugin::HookEvents() method so that your code is called when the appropriate events occur. Now you need to implement that code to accomplish the actual work.

There are often values associated with an event that may be needed by plugins that want to hook into that event. For example, with the `EVENT_USER_AUTHENTICATION` event it's very useful to have the login name and password that the user entered. These values are passed to the hooked methods as parameters, according to the parameter list defined for that event.

So for our ListSubscriber plugin, the method in our `ListSubscriber` class to add a user might look something like this:

function AddUserToMailingList($UserId)
{
$UserToAdd = new CWUser($UserId);
$MLMngr = new MyMailingListManager();
if ($MLMngr->IsSubscribedToList($UserToAdd->Get("Email")) == FALSE)
{
$MLMngr->AddSubscriber($UserToAdd->Get("Name"),
$UserToAdd->Get("Email"));
}
}

The parameters sent by each event are listed and described on the CWIS Event Callbacks page. It's important to make sure the method you hook accepts the right list of parameters and returns the right values, so that the code that signalled the event and any other plugins hooked onto the event execute correctly.

# Configuration

Your plugin may have some configurable settings. If the settings are reasonably simple, you can allow people to change their values via the built-in plugin configuration interface (rather than having to write your own) by defining the configuration settings in Plugin::Register():

$this->CfgSetup["SubConfirm"] = array(
"Type" => "Flag",
"Label" => "Subscription Confirmation",
"Help" => "This determines whether new subscribers will be required to confirm their mailing list subscription.",
"Default" => TRUE,
"OnLabel" => "Yes",
"OffLabel" => "No",
);

(In the above example, `"SubConfirm"` is the name of the configuration setting.)

Configuration settings may be retrieved by calling Plugin::ConfigSetting(), and initial values should be set by including a `"Default"` value. For backwards-compatibility, initial values may also be set by calling Plugin::ConfigSetting() in Plugin::Install():

function Install()
{
$this->ConfigSetting("SubConfirm", TRUE);
}

Plugin::ConfigSetting() can also be used to store and retrieve your own configuration values (i.e. ones not set via the built-in plugin configuration interface).

### Supported Configuration Setting Types

Type | Required | Optional | Notes
--- | --- | --- | ---
(all) | `Type`, `Label` | `Help`, `Default`, `SettingFilter` | The `Help` value is highly recommended, and a string supplied in that value will be displayed along with the parameter on the plugin configuration page. `Default` is used to set the default configuration value when the plugin is installed. `SettingFilter` may contain the name of a plugin method, which will be called each time the configuration value is set. The method should expect two parameters, the setting name and new value, and should return the desired (potentially modified) new value for the setting.
`Flag` | `OnLabel`, `OffLabel` | (none) | `Flag` setting values are `TRUE` for on and `FALSE` for off.
`Heading` | `Label` | (none) | This is a psuedo-type, used for adding section headings to the configuration page. `Label` should contain the heading text.
`MetadataField` | (none) | `FieldTypes`, `AllowMultiple`, `SchemaId` | `FieldTypes` should be constants from the MetadataSchema class logically ORed together (e.g., `MetadataSchema::MDFTYPE_TEXT | MetadataSchema::MDFTYPE_PARAGRAPH`). If `FieldTypes` is not specified, all field types will be used. `AllowMultiple` is a boolean that allows multiple fields to be selected simultaneously. `SchemaId` is an integer metadata schema ID, if not using the default metadata schema, to use when fetching the fields to display as options. The stored value is the field ID or an array of field IDs if `AllowMultiple` is `TRUE`.
`Number` | (none) | `MaxLength`, `MaxVal`, `Size`, `Units` | Form field size is based on `MaxVal`, but may be overridden by specifying `Size` and/or `MaxLength`.
`Option` | `Options` | `AllowMultiple` | `Options` is an associative array, with configuration setting values for the array indexes and setting labels for the array values. `AllowMultiple` is a boolean that allows multiple options to be selected simultaneously.
`Paragraph` | (none) | `Rows`, `Columns` | `Rows` defaults to 4 and `Columns` to 40.
`Privileges` | (none) | `AllowMultiple` | `Privileges` settings are an array of (numerical) privilege values.
`Text` | (none) | `Size`, `MaxLength` | `Size` defaults to 40 and `MaxLength` to 80.

Text can be added to the top of the configuration page by placing it in the `Instructions` class variable in Plugin::Register():

$this->Instructions = <<<EOT
The <i>SU Library Mailing List Subscription</i> plugin adds
users to the StateLib mailing list.
<br/><br/>
Use of the <i>Subscription Confirmation</i> configuration option
is strongly recommended, to ensure users are receiving the mailings
at the expected email address.
EOT;

Instruction text may contain HTML tags (as above). Use of PHP's heredoc string syntax is of course not required, but can provide a convenient way to include a length quantity of instruction text.

# Further Reading

That covers the basics of how to implement a simple CWIS plugin. More advanced information can be found on the Advanced CWIS Plugin Implementation section and in the documentation for the base Plugin class.

If you have questions that aren't answered here, please visit the support page for CWIS. It offers various options for getting help with or discussing CWIS development. Other users may be able to provide help or insight, or may even already have a plugin available that already does what you need!