Collections functions
General functions
Node functions
Render functions
Theme permission functions
User functions
Resource functions

Writing your own plugins

Nearly all modications for ResourceSpace should be done within your own plugin. You can access portions of code through hooks and you can add styling, configuration, language strings and all manner of content.

What is a Plugin?

A plugin in ResourceSpace is a collection of PHP code, language files, graphics, CSS files and other related files that are structured to conform to the ResourceSpace plugin architecture. For deployment, the files that constitute a plugin are packaged together into a self-contained file called a ResourceSpace Plugin (.RSP) file.

To put a plugin into production, a site administrator uploads, activates, and, if necessary, configures the plugin using the Admin > System > Plugins page.

Once activated, the base ResourceSpace code automatically calls functions that make up the plugin's PHP code and utilizes the plugin's other files as needed to put the plugin's changes and extensions into effect.

The Structure of a Plugin

All of the files that constitute a plugin reside in a single folder, called the plugin's root folder, or in subfolders under it. The root folder has the same name as the plugin (which means plugin names need to conform to folder naming conventions). In a running system, the installed plugin root folders are subfolders of the ResourceSpace "plugins" folder or the filestore/plugins folder. All installed plugins must have unique names.

A complete plugin can have any of the following in its root but requires only the first item which is what enables it to be activated in ResourceSpace.

  1. plugin_name.yaml - This is the description of the plugin. When creating your plugin you must follow the guidance set out in the section below. The YAML file must also have exactly the same name as your plugin folder with the ".yaml" extension.
  2. config - Contains config.php This file sets the default values for the plugin's configuration variables.
  3. css - Contains the plugin's style sheets. If a file called 'style.css' is present it will automatically be included in all pages.
  4. dbstruct - Contains database definition files that let a plugin define additional columns or entirely new tables.
  5. gfx - Contains any graphics files needed by the plugin but is also accessible to any other customisations so you can link to it like any other folder location.
  6. hooks - Contains the PHP hook function files. These files contain the functions that implement the plugin logic.
  7. languages - Contains plugin-specific language files. These extend or modify the base ResourceSpace language files.
  8. pages - Contains any new PHP pages specific to the plugin, including the plugin's configuration page, setup.php, if needed.
  9. job_handlers - Contains any offline job handlers specific to the plugin.

In addition, the following files may be included in the root folder:

  • license.txt - Your license details.
  • install.txt - Installation instructions.
  • about[plugin_name].pdf - Plugin documentation.

Plugins need not be complex. A simple plugin might consist of just two files and one subfolder: the [plugin_name].yaml file in the root and a hook folder containing one hook file. In fact, a useful plugin need not contain program logic at all. For example, by including a style.css stylesheet in the 'css' folder and graphics in 'gfx' a 'colour theme' plugin can be created that changes the colour theme of the whole system.

The Plugin YAML file

name: [plugin_name]

author: Your Name

version: [version number]

desc: Short project description

info_url: https://url.to.your/info_pages/ (Link to web page with additional information about the plugin)

config_url: /plugins/[plugin_name]/pages/setup.php (Path to the plugin configuration page.)

default_priority: [three-digit number] (Sets plugin hook execution priority. Low numbers are high priority. Default: 999.)

Hooks and Hook Functions

"Hooks" are named points in the base code of ResourceSpace at which "plugin hook functions" are called. In the base code of Resource space hooks have the form:

hook('hook_name'[, additional parameters]...);

Where hook_name is the name of the hook. As indicated, a hook may or may not have additional parameters. The code in which a hook is embedded may or may not require the hook to return a value. When it does, the return value is often a boolean. In that case the typical form is:

if (hook('hook_name'[, additional parameters]...))
    {
    // Case when no hook function alters the base behavior
    }

Note that hook names are always lower case.

If a plugin wishes to execute code at the point of a hook, it implements a plugin hook function that corresponds to that hook. When the hook is executed in the base code, ResourceSpace calls the corresponding hook function in each active plugin that implements it. When multiple active plugins use the same hook, they are called in priority order. The hook function for the lowest priority plugin is executed first, and the highest priority one last so that the highest priority plugin gets the final say about the ultimate outcome. The execution order for plugins with equal priority is indeterminate. The priority of a plugin is set in its yaml file. (See above.)

All ResourceSpace pages contain certain standard hooks, and most have additional hooks specific to that page. For example, the ResourceSpace file 'search.php', which implements the search page contains quite a few hooks. Among them is one named 'resultsbottomtoolbar'. It is positioned at the end of the code that creates the links near the bottom of the search results page. This hook lets a plugin add additional links to the standard ones by implementing a plugin hook function.

A plugin's hook functions, for any of the hooks in a given ResourceSpace page, reside in that plugin's "hooks" subfolder in a file with the same name as the ResourceSpace PHP file that implements the page. For example, the search page is implemented by search.php. This means a plugin's hook functions for the search page are in the file hooks/search.php.

Not all hooks are in files that implement pages. Some are in files that page-implementing files bring in using the PHP include statement. For example the file /include/general_functions.php contains a number of hooks, but doesn't by itself implement a ResourceSpace page. Instead, page-implementing files like /pages/search.php bring it in with the include statement. In such cases, the hook is considered to be a part of the file that does the include and hook functions are placed accordingly. So when a plugin uses a hook defined in general.php in the context of the search page, the hook function is placed in the plugin's hooks/search.php.

It's also possible to create hook functions that trigger on every page that defines a named hook. Typically, the corresponding hooks are physically in files that are included by files that implement pages. To define a hook function that is triggered this way, use the page name 'all'. In other words, place a hook function that is to be triggered on any page that defines the corresponding hook in the file hooks/all.php.

The plugin hook functions themselves are named using the convention HookPluginnamePagenameHookname. So, for example, for the plugin Myplugin, the hook function for the resultsbottomtoolbar hook in the ResourceSpace search page is defined this way:

function HookMypluginSearchResultsbottomtoolbar()
    {
    # Hook function code goes here

    return true;
    }

Note: The capitalisation convention for the hook function name is required. The plugin name, page name and hook name always start with an upper case letter. The other characters in the function name may not be upper case letters.

This is also true for the hook functions in a hooks/all.php file. The page name is 'all'. So, you would add the function HookMypluginAllInitialise to create a function for the initialise hook that is present at the top of every page.

As noted above, whether a hook function is passed parameters - and what those parameters are - is defined by the hook definition in the base code. Similarly, some hooks require a value to be returned while others do not. To understand the required function signature and the return value (if any) you will need to understand the the base code in which the hook is defined.

Most hooks follow one of a number of common patterns and, after inspecting the code in which a few hooks appear, you'll recognize them. The two most common patterns are noted in the discussion about hooks, above. But there are others so be sure to take the time to understand the context for any hook you plan to use.

One final note: Please be sure to read the Coding Standards. Plugins should follow them. If you're new to writing code for Web applications in PHP, pay particular attention to how you handle user provided data or any data that comes in from the "outside." It's all too easy to introduce security vulnerabilities if you're not careful.

Finding or Making the Hooks You Need

To develop a plugin, you'll need a copy of the ResourceSpace base code. By far the best way to get a copy and keep it current (which as a developer you will certainly want to do) is to use Subversion ("svn") to grab a current copy and keep it up to date. You'll also need proper development tools and a working knowledge of the technologies used in ResourceSpace (principally Subversion, PHP, HTML, CSS, MySQL, and, to some extent, Javascript) to do plugin development.

As you analyse the base code with an eye toward implementing the changes or additions you envision for your new plugin, you'll come across many places in the code that contain hooks. These are the places in the code at which you can add or replace functionality in ResourceSpace.

As with any design work that extends an existing system, you'll find designing hook functions much easier if you spend a little time looking at existing designs. The easiest way to do this is to look at some of the plugins that are a part of the base code (the ones that come "preinstalled" in the /plugins folder) when you get it from svn. They contain many examples of hook and hook function design and will give you a good idea of the range of things you can do with plugins.

Common hooks used

  • extra_checks - Allows plugin to register a warning for the system status so it can be investigated by IT teams monitoring the service.

Adding a Configuration Page

If a plugin needs to be configured there are two ways to enable it: You can have people edit the contents of the the plugin's config.php file or you can provide a plugin configuration page and have an administrator do it through a UI. Editing the config.php is straightforward and requires no code, but it does require skill and access to the config.php file on the server. Using a configuration page requires access to the Admin, but no coding skill or access to the config.php file. It does require the plugin developer to write some code, but usually not much.

As a plugin writer you can do whatever is needed with the configuration page, but doing configuration management from scratch each time leads to a lot of unnecessary work and, potentially, to inconsistencies in how plugin configuration works. To help with this, ResourceSpace provides a set of functions for building plugin configuration pages. Take a look at the existing plugins to see how this works.

Extending the Database with 'dbstruct'

If you need them, you can define additional columns in existing tables, or entirely new tables just for use with your plugin. To do so, create a 'dbstruct' subfolder in the root folder for your plugin, and then create file(s) named:

table_[table_name].txt

If [table_name] names an existing table, it must contain only the definitions for the columns you wish to add. If it's a new table, you must define all the columns you need. The table_[table_name].txt files are simply CSV versions of the results provided from the 'describe (table)' MySQL command. See the existing files in the ResourceSpace dbstruct folder in the base code for examples of the required format.

You can also create 'index_' and 'data_' files to define indices and default data for your tables, exactly as ResourceSpace itself does using the existing dbstruct folder.

You can create your tables via PhpMyAdmin or other tools and create the 'table_', 'index_', and 'data_' files using the pages/tools/dbstruct_create.php tool, then move the created files into your plugin's dbstruct folder.

CSS Overrides

Placing a 'style.css' folder within a 'css' folder in the root of a plugin will allow you to add your own CSS. PHP code is not required within the plugin.

Custom Language Changes

Over the long haul, the easiest way to change the text ResourceSpace displays to users (the strings in the $lang[] array) is to create a plugin. By using a plugin, your changes will carry forward from version to version. If, instead, you simply edit the content of the files in the main ResourceSpace languages folder, you'll have to merge your changes with the base each time it changes.

To make a language customisation plugin create the basic structure of a plugin (the plugin root folder and the plugin yaml file). Then create a language file for each language used in your system. Name the files using the ISO 639-1 code for the language with a suffix for the country if needed (e.g. sv.php, pt-BR.php). Place the files within the 'languages' folder in the root of the plugin. Add only your custom changes to the plugin's language files. (There is no need to redefine all the strings. In fact, it's a bad idea to do so since it would effectively override all the language strings.)

Custom job handlers

A plugin can create custom offline jobs using the job_queue_add() function. The job type name you create should match or be prefixed with your plugin name so that it is unique. The accompanying job handler needs to be created to process the jobs you create and must be located in the 'job_handlers' sub folder of your plugin e.g. 'job_handlers/csv_upload.php'. Note that $offline_job_queue must be enabled in configuration and a cron job/scheduled task created to run the script pages/tools/offline_jobs.php

Packaging Your Plugin

While it is still possible to manually install a plugin on your server the preferred method is to package all of the needed files into a ResourceSpace Plugin (.rsp) file and to use the Plugin Manager.

To create a ResourceSpace Plugin file simply tar and gzip your plugin (.tar.gz) then rename it to "[plugin name].rsp".

Once you have done this you can upload, install, and activate it using the Admin > System > Manage plugins page.