Coppermine Photo Gallery v1.6.x: Documentation and Manual

Table of Contents

Plugin Writing for Coppermine

Quick Start Guide

Coppermine comes with a plugin architecture that allows skilled users to come up with plugins that can be installed by the end user with just some clicks in the plugin manager section. Main benefit of plugins is that end users don't have to hack core code files. As a result, plugins don't need to be applied when upgrading between minor versions of coppermine (when replacing all core files due to maintenance releases).

Many things that could be done using core hacks can be accomplished using plugins as well. The only disadvantage of plugins is the fact that the plugin author needs to become a bit more familiar with coppermine's plugin API.

This short guide is supposed to help possible plugin authors to get familiar with the plugin system. You have to understand though that this section will not teach you how to edit PHP - this would be beyond the scope of this documentation. We asume that you're familar both with HTML as well as PHP to some extent. This section of the docs will definitely not teach you how to code in the first place, nor is it a beginner's tutorial for programming. If you have never written one line of PHP code you should get familiar with PHP first and apply some hacks before actually considering to come up with a plugin of your own.

Plugins from Coppermine 1.4.x may not work in 1.5. If the plugin uses superglobals like $_POST and $_GET, you need to rewrite those superglobal calls using the new code sanitization in 1.5. See the section "Use of Superglobals". Also, the plugin may include Coppermine files that Coppermine 1.5 now includes for you. You can change "require" to "require_once" or remove the call if Coppermine will always include the file you want. Finally, check the notices under the Debug box to see if any constants you define may already be defined by Coppermine and include checks in the plugin before defining such constants.

Intended Audience

Here's a list of who should and who should not (or doesn't need to) read this documentation. The categories overlap in many places, so make sure to read the entire list. Find yourself in the list and then decide whether you should read on.

People who should read this documentation:

People who do not need to read this documentation:

People interested in using plugins but who do not need to modify them or write their own should read the main documentation instead - the plugins section describes everything you need to know.

Why write plugins?

The biggest advantage of a plugin over a mod is the fact that plugins will remain when updating Coppermine, while mods (aka "modifications" or "hacks") need to be re-applied after updating.

It's pretty easy to come up with a plugin of your own. This page and it's sub-pages is meant to explain how to come up with your first home-made plugin.

Preparations

Before starting to hack away, you should make some preparations and maybe sketch the layout of your plugin.

Core files

Every plugin contains at least two mandatory files: codebase.php and configuration.php:

Naming conventions

Even if you plan to write a plugin just for your purposes you should pay attention to the naming conventions for plugins to make sure that your plugin will not stop working as expected at a later stage (e.g. after an update).

The naming conventions exist for two purposes: they enable Coppermine's developers to come with restrictive rules for Coppermine's core code to prevent hacking. Unsanitized user input can have a huge impact in hacking scenarios, that's why there are rules for plugins as well. Additionally, naming conventions are supposed to make maintenance and support easier, and finally, end users will find their way around easier as well.

Use of Superglobals

If you are going to use superglobals in your plugin, you will have to take notice of the Coppermine code sanitization.
You will also have to include the following line to make sure you can use these superglobals:
$superCage = Inspekt::makeSuperCage();

Double check this if you're getting a 500 error.

Database access

A plugin can access the database in the same manner that core code is accessing the database. However, there are some things to keep in mind for plugin authors:

Direct queries

Don't use the native PHP commands (like mysql_query) to perform queries against the coppermine database tables. Instead, use the function cpg_db_query built into coppermine. You don't need to explicitely open the connection - it is already established for you when using the plugin API.
Bad example $result = mysql_query("SELECT * WHERE 1=1");
Good example $result = cpg_db_query("SELECT * WHERE 1=1");

Accessing database tables

Don't hard-code table names into your custom queries, as your queries are bound to break if users have chosen another table prefix than the default one.
Instead, coppermine defines a variable $CONFIG['TABLE_PREFIX'] that contains the table prefix that you can (and should) use if you need to access a table within coppermine's database and using the prefix: use the prefix for custom tables for your plugin.
Bad example $result = cpg_db_query("SELECT * FROM cpg16x_plugin_example WHERE 1=1");
Good example $result = cpg_db_query("SELECT * FROM {$CONFIG['TABLE_PREFIX']}plugin_example WHERE 1=1");
If you want to access an existing table (like the coppermine table that contains all categories), use the variables outlined in Database reference within coppermine code.
Bad example $result = cpg_db_query("SELECT * FROM {$CONFIG['TABLE_PREFIX']}categories WHERE 1=1");
Good example $result = cpg_db_query("SELECT * FROM $CONFIG['TABLE_CATEGORIES'] WHERE 1=1");

Creating database tables

If you need to expand the database schema of coppermine to add a table for your plugin, you should follow the following rules: This could be an example for a database table creation query inside your plugin's install function:
$query = <<< EOT
    CREATE TABLE IF NOT EXISTS `{$CONFIG['TABLE_PREFIX']}plugin_coffee_maker` (
      `cid` mediumint(10) NOT NULL default '0',
      `some_field` smallint(6) NOT NULL default '0'
    ) COMMENT='Your clever description of the table here';
EOT;
$result = cpg_db_query($query);	

Deleting database tables

It's important that your plugin removes all tables it created during install when the end user uninstalls it. In some rare cases it might make sense to keep the database tables if the user decides to install it later again (if the re-population of the database table records would be time-consuming or complicated). If that's the case for your plugin, you should add a form to the uninstall process of your plugin that asks the end user if the database table should be kept or not. Out of the box, the database tables that were created during install need to be deleted when the plugin is uninstalled.
It's safer to use DROP TABLE IF EXISTS instead of just using DROP TABLE. To get rid of the table created in the example above, run a query like
cpg_db_query("DROP TABLE IF EXISTS {$CONFIG['TABLE_PREFIX']}plugin_coffee_maker");
in the uninstall function of your plugin.

Storing your plugin's config values

If you need just a few database records to store your plugin's config settings, you don't have to create a separate table just for those few plugin config records - instead, you're encouraged to use the existing config table where coppermine stores it's core settings in as well. There are some great benefits in using the existing config table: the main benefit is that you don't have to run a query to get your setting's values - coppermine's core code will populate the $CONFIG-array insteadd accordingly.
It's important though that it get's obvious what your config records are being used for and from which plugin they come from. That's why there is a strict naming schema for new records in coppermine's config that a plugin should adhere to: prefix the record with the word "plugin" followed by an underscore followed by your plugin's short name followed by an underscore followed by the actual config setting name.
To make sure that your script doesn't break if such a setting already exists (e.g. if the user re-installs your plugin that hasn't been uninstalled properly before) it's advisable to use INSERT IGNORE instead of using an ordinary INSERT.
If your plugin's short name is "coffee_maker" and you need to store a setting for the height of the coffee mug with the default value of 20, the corresponding setting record could be named plugin_coffee_maker_mug_height
The query in the install section of your plugin could be something like
cpg_db_query("INSERT IGNORE INTO {$CONFIG['TABLE_CONFIG']} ( `name` , `value` ) VALUES ('plugin_coffee_maker_mug_height', '20')");
and the corresponding line inside the uninstall section would be
cpg_db_query("DELETE FROM {$CONFIG['TABLE_CONFIG']} WHERE name = 'plugin_coffee_maker_mug_height'");
The resulting element inside the $CONFIG array would be $CONFIG['plugin_coffee_maker_mug_height']

Plugin Types

Plugins (or rather individual pages of a plugin) can roughly fall into two categories: they can reside on a page of their own (a good example would be the plugin config screen some plugins come with or a plugin that adds a contact form) or they can reside within each or some coppermine-driven pages, modifying the output or functionality of the pages they reside on (a good example would be plugins that add menu items).
It is comparatively easy to come up with plugins that fall into the first category (creating additional pages). The second option is the more advanced and powerfull option that plugins authors can use. For this purpose, there are "anchors" all over coppermine's core code that allow plugin interaction with the code, the so-called "plugin hooks".

Using includes

Files the plugin is meant to include on the index page of the gallery can only contain one single dot that separates the actual filename from the php-extension, as suggested in "Linking to Custom Plugin Scripts"

Sub-sections

These plugin documents are a work-in-progress, and a to-do list. The following sub-sections exist so far that are recommended to read:

Recommended reading

Although primarily written for dev team members it's recommended for plugin authors to review the coding guidelines for coppermine.