Creating plugins for Question2Answer

Question2Answer plugins (introduced in Q2A 1.3) allow the platform to be modified or extended without changing the Q2A core. Plugins can integrate with Q2A in one of three ways:

  • Modules extend Q2A in a defined and specific way. The following types of module are supported from Q2A 1.3+:
    • page modules add a new type of page to a Question2Answer site.
    • login modules allow users to log in to Q2A via an external identity provider such as Facebook.
    • editor modules provide a web interface for writing and editing posts.
    • viewer modules render content as HTML or text, and often work together with an editor module.

    From Q2A 1.4+:

    • event modules are notified when something important happens, such as content being posted or voted on.
    • widget modules allow extra content to be shown on Q2A pages, as chosen by the site administrator.

    From Q2A 1.5+:

    • filter modules can validate and/or modify many types of user input, including the content of posts.
    • search modules can implement a custom indexer and/or search engine for a Q2A site.
    • captcha modules provide a web interface for human verification, such as reCAPTCHA.
    • process modules have the opportunity to run at specific stages of Q2A's response processing.

    Modules are the preferred method for extending Q2A - more about modules.

  • Layers modify the HTML output for some elements of a Q2A page. Layers work similarly to advanced themes, by overriding some functions in the base theme class in qa-theme-base.php. Unlike advanced themes, multiple layers can be installed simultaneously via their respective plugins. Layers require Q2A 1.4+.
  • Overrides allow over 150 core Q2A functions to be modified. Core functions can be replaced by the plugin's code, or they can be wrapped, with the plugin modifying the function's inputs and/or outputs. With wrapping, multiple overrides for the same function in different plugins can be active simultaneously. Overrides require Q2A 1.5+.

The sections below explain the general principles behind plugins. You will also need to read about implementing modules, layers and/or overrides, as well as some functions in Q2A that may be useful in developing your plugin.

An alternative is to work through the plugin tutorial, which introduces all of this material in a more gentle and gradual way.

To see some examples of plugins, modules and layers, take a look at the qa-plugin directory in your Q2A installation as well as the modules registered in the function qa_register_core_modules() in qa-base.php of Q2A 1.5+.

Directory structure

Plugins for Question2Answer have the following directory structure:

  • A plugin is contained inside a directory whose name should use only numbers, lowercase letters and hyphens.
  • The directory name should be descriptive and similar to the plugin's name, such as facebook-login or wysiwyg-editor.
  • The plugin directory must contain a PHP file named qa-plugin.php whose purpose is described below.
  • The plugin directory may also contain any other files and subdirectories, including PHP, HTML, Javascript, CSS, etc...
  • A plugin is activated by installing its directory inside Q2A's qa-plugin directory.

The qa-plugin.php file has two main purposes. First, it registers any modules, layers or overrides provided by the plugin. Second, it contains optional metadata about the plugin and its author. As of Q2A 1.5, it is not recommended for qa-plugin.php to perform any other actions - if this seems necessary, please consider using a process module instead. If you wish to use non English characters in qa-plugin.php, ensure your text editor is using UTF-8 encoding without a BOM (byte order mark).

Registering modules

Each module is implemented as a PHP class with specific member functions, as detailed here. For the sake of speed, the class definition for each module should be in a separate PHP file, since Q2A will only include this file when necessary.

To register a module, call qa_register_plugin_module() in qa-plugin.php, with the following parameters in order:

  1. The type of module, e.g. 'page' or 'login'. You can also use 'module' to register a generic module which can display a form in the admin interface, but is not otherwise used.
  2. The name of the PHP file in the plugin directory containing the module's class declaration, e.g. qa-xml-sitemap.php. Use null if the module's class is defined within qa-plugin.php itself (not recommended for non-trivial modules).
  3. The name of the PHP class in this file that implements the module, e.g. qa_xml_sitemap.
  4. A human-readable module name, which should be descriptive and unique, e.g. 'XML Sitemap'. This may be displayed in the Admin panel and/or used to refer to the module within Q2A's internals.

Registering layers

Each layer is implemented as a PHP file containing a fixed class declaration, as described here. To register a layer, call qa_register_plugin_layer() in qa-plugin.php, with the following parameters in order:

  1. The name of the PHP file in the plugin directory containing the layer's class declaration, e.g. qa-mouseover-layer.php.
  2. A human-readable layer name, which should be descriptive and unique, e.g. 'Mouseover Layer'. This may also be used to refer to the layer within Q2A's internals.

Registering overrides

Overrides are implemented as PHP files which contain the replacement function definitions, as described here. Your functions can call the original Q2A functions using the _base suffix, e.g. qa_lang_base(). To register a file containing overrides, call qa_register_plugin_overrides() in qa-plugin.php with the name of the overrides PHP file in the plugin directory.

Plugin localization

Throughout Q2A, the functions qa_lang() and qa_lang_html() are used to obtain localized language phrases. An identifier string is passed to these functions, which consists of a file prefix, a slash (/) and a phrase key. For example, the identifier 'main/cancel_button' obtains the element with key 'cancel_button' from the appropriate qa-lang-main.php language file. Each language file is a PHP script which returns an array mapping keys to phrases, e.g. see qa-lang-main.php. If you wish to use non English characters in your language files, ensure your text editor is using UTF-8 encoding without a BOM (byte order mark).

From Q2A 1.5+, plugins can add their own language prefixes and phrases by calling qa_register_plugin_phrases() from within qa-plugin.php, with the following parameters in order:

  1. A pattern for the language files within the plugin's directory. The pattern must contain an asterisk (*), which is substituted for the appropriate language code or 'default', which is used if the desired language cannot be found. For example, the pattern 'qa-phrases-*.php' maps to qa-phrases-fr.php for French, qa-phrases-de.php for German and qa-phrases-default.php for defaults. The asterisk can also be in a directory name, e.g. the pattern 'lang-*/phrases.php' would map to lang-fr/phrases.php, lang-de/phrases.php and lang-default/phrases.php respectively.
  2. A prefix used to access the phrases, which must be unique to your plugin. For example, the prefix 'whizbang' means that your phrase with key 'whizzy_title' would be obtained by calling qa_lang('whizbang/whizzy_title').

Plugin metadata

Apart from registering modules, layers and overrides, the qa-plugin.php file can include metadata - all fields are optional:

/*
	Plugin Name: Human-readable name of your plugin
	Plugin URI: Web address for your plugin
	Plugin Description: Human-readable description of your plugin
	Plugin Version: Your plugin version number
	Plugin Date: Build date of your plugin in YYYY-MM-DD
	Plugin Author: Human-readable name of plugin author
	Plugin Author URI: Web address for plugin author
	Plugin License: Short name of plugin license, e.g. GPLv2
	Plugin Minimum Question2Answer Version: Numerical part only, e.g. 1.3
	Plugin Minimum PHP Version: Numerical part only, e.g. 5
	Plugin Update Check URI: Web address for Q2A to check for updates
*/

Most of this metadata is only used for display purposes in the Q2A admin interface. However Q2A will automatically disable any plugins whose Plugin Minimum Question2Answer Version is higher than the currently installed version of Q2A, or whose Plugin Minimum PHP Version is higher than the version of PHP running.

In addition, Plugin Update Check URI allows you to inform users about new versions of the plugin. Q2A will retrieve the content from Plugin Update Check URI, and look for metadata in the same format as above. If the Plugin Version values don't match, a message will show up, along with a link to the Plugin URI from the online metadata. This requires Q2A 1.5+.