Plugin Tutorial: Several tricks from the Copyrights plugin

In this tutorial you will learn more about the basics of plugin development for Piwigo. This tutorial is a follow up on Tutorial: Hello World!. The entire plugin can be installed from the extension gallery under the name 'Copyrights'. Note that this tutorial follows the v1.0 revision of this plugin.

Since the plugin is relatively large to put all the code on this page, we only explicitly put that code here that is important and clarifies the ideas explained. The reader should read the rest of the code from the sources pointed to above.

Introduction

First of all, download the source code of the Skeleton plugin. We will use that as basis for this plugin.

Outline

With this plugin we want to achieve the following:

  1. Somewhere we want to manage our copyrights.
  2. Somehow copyrights must be added to photos.
  3. Somehow the copyright must be displayed when visitors view a photo.

Therefore, we will write code for:

  1. An administration panel, where the admin can create and edit plugins
  2. An extension to the Batch manager (using events) so that copyrights can be added to photos.
  3. Another event-hook that will display the copyright when a photo is viewed.

The admin panel

For the admin panel we need to do two things. First add a link to the plugins menu, second create an admin page.

The link in the menu

To add a link to the menu of plugins we put the following code in main.inc.php. This is our first serious encounter with event handlers. To see what events are available we refer to the Event tracer plugin.

/* +-----------------------------------------------------------------------+
 * | Plugin admin                                                          |
 * +-----------------------------------------------------------------------+ */
 
// Add an entry to the plugins menu
add_event_handler('get_admin_plugin_menu_links', 'copyrights_admin_menu');
function copyrights_admin_menu($menu) {
  array_push(
    $menu,
    array(
      'NAME'  => 'Copyrights',
      'URL'   => get_admin_plugin_menu_link(dirname(__FILE__)).'/admin.php'
    )
  );
  return $menu;
}

This adds an event handler to the event 'get_admin_plugin_menu_links'. The added handler is the function 'copyrights_admin_menu' that we define right below it. It consists of a simple array_push() to add our link to the plugins menu.

Lets move on to the content of admin.php, since that is what we are linking to.

The admin page

We would like to do several things on the admin page. First of all, we want to be able to create plugins. Next we should be able to view them, and lastly, we want to be able to edit existing copyrights.

Firstly, however, we load the language file and perform a security check.

load_language('plugin.lang', COPYRIGHTS_PATH);
 
// Check access and exit when user status is not ok
check_status(ACCESS_ADMINISTRATOR);

The rest of the code of the admin page does not add much to the learning of plugin writing for Piwigo. It is best read from source directly. The code is commented farely well.

It is, however, good to mention the special use of the '$tab' variable. This is a variable that is used by Piwigo to create the tabbed layout they use. The Copyrights plugin makes use of this variable for deleting and updating Copyrights as if those are 'unvisible' tabs.

Extending the Batch manager

The Batch manager comes with two modes, so we will have to write extensions to both.

Batch Mode

Here we will again use event handlers to extend the functionality of Piwigo. We use two of them:

  • One to add the copyrights selector to the possible actions of the Batch Manager
  • The second to catch the 'Submit' button of the Batch Manager, and update the database
// Add copyrights drop down menu to the batch manager
add_event_handler('loc_end_element_set_global', 'copyrights_batch_global');
// Add handler to the submit event of the batch manager
add_event_handler('element_set_global_action', 'copyrights_batch_global_submit', 50, 2);

Now we should specify the contents of the functions 'copyrights_batch_global' and 'copyrights_batch_global_submit'.

copyrights_batch_global

function copyrights_batch_global()
{
  global $template;
 
  load_language('plugin.lang', dirname(__FILE__).'/');
 
  // Assign the template for batch management
  $template->set_filename('CR_batch_global', dirname(__FILE__).'/batch_global.tpl');
 
  // Fetch all the copyrights and assign them to the template
  $query = sprintf(
    'SELECT `cr_id`,`name`
    FROM %s
    WHERE `visible`<>0
    ;',
  COPYRIGHTS_ADMIN);
  $result = pwg_query($query);
  $CRoptions = array();
  while ($row = pwg_db_fetch_assoc($result)) {
    $CRoptions[$row['cr_id']] = $row['name'];
  }
  $template->assign('CRoptions', $CRoptions);
 
 
  // Add info on the "choose action" dropdown in the batch manager
  $template->append('element_set_global_plugins_actions', array(
    'ID' => 'copyrights', // ID of the batch manager action
    'NAME' => l10n('Edit copyright'), // Description of the batch manager action
    'CONTENT' => $template->parse('CR_batch_global', true)
  )
  );
}

As can be seen, we again load the language file. Next we add the contents of 'batch_global.tpl' to the template and finally assign the list of copyrights obtained from the database to this template.

The file 'batch_global.tpl' contains a small bit of Smarty code to create a copyright selector.

<!-- Template for the copyright selector -->
<div id="copyrights">
	{'Copyright'|@translate}
	<select name="copyrightID">
		<option value="0">--</option>
		{html_options options=$CRoptions}
	</select>
</div>

copyrights_batch_global_submit

When the 'Submit' button is clicked, an event is fired. We attached the following function to this event.

// Process the submit action
function copyrights_batch_global_submit($action, $collection)
{
  // If its our plugin that is called
  if ($action == 'copyrights')
  {
    $crID = pwg_db_real_escape_string($_POST['copyrightID']);
 
    // Delete any previously assigned copyrights
    if (count($collection) > 0) {
      $query = sprintf(
        'DELETE
        FROM %s
        WHERE media_id IN (%s)
        ;',
      COPYRIGHTS_MEDIA, implode(',', $collection));
      pwg_query($query);
    }
 
    // Add the copyrights from the submit form to an array
    $edits = array();
    foreach ($collection as $image_id)
    {
      array_push(
        $edits,
        array(
          'media_id' => $image_id,
          'cr_id' => $crID,
        )
      );
    }
 
    // Insert the array into the database
    mass_inserts(
      COPYRIGHTS_MEDIA,       // Table name
      array_keys($edits[0]),  // Columns
      $edits                  // Data
    );
  }
}

So we first check whether it was our action ('Edit copyright') was chosen in the action list of the Batch Manager. If so, we obtain the chosen copyright id from the form $_POST variable.

Next we assign the the copyrights to all photos in the $collection, by first deleting any previously made assignments, and afterwards inserting the whole bunch with Piwigo's mass_inserts function.

Single Mode

To extend the 'Single Mode' or 'Unit Mode' of the Batch Manager, we have to use prefilters. Prefilters are a really nifty feature of Smarty code. See their site for more information on all the functionality.

When speaking for Piwigo, generally a prefilter can be attached to any file X.tpl that exists in the template folder.

To attach a prefilter to such a file, one should find an event near to where the X.tpl is being used. This will be more clear below.

Setting the prefilter

For the Copyrights plugin, we want to modify the Smarty code of the batch_manager_unit.tpl file. We therefore use the following code.

// Add event handlers for the prefilter
add_event_handler('loc_end_element_set_unit', 'CR_set_prefilter_batch_single', 55 );

This attaches the function 'CR_set_prefilter_batch_single' to the event 'loc_end_element_set_unit' which is fired when Piwigo starts loading the Single Mode page of the Batch Manager.

The event handler function then attaches a prefilter to batch_manager_unit.tpl.

// Add a prefilter to the template
function CR_set_prefilter_batch_single()
{
  global $template;
  $template->set_prefilter('batch_manager_unit', 'CR_batch_single');
}

This means that when Smarty starts rendering batch_manager_unit.tpl, it will first execute CR_batch_single.

That particular function will of course add the copyright selector to the page.

// Insert the copyright selector to the template
function CR_batch_single($content, &$smarty)
{
  $search = "#<td><strong>{'Creation date'#";
 
  // We use the <tr> from the Creation date, and give them a new <tr>
  $replacement = '<td><strong>{\'Copyright\'|@translate}</strong></td>
    <td>
      <select id="copyright-{$element.ID}" name="copyright-{$element.ID}">
        <option value="0">--</option>
        {html_options options=$CRoptions selected=$CRcopyrights[$element.ID]}
      </select>
    </td>
  </tr>
 
  <tr>
    <td><strong>{\'Creation date\'';
 
  return preg_replace($search, $replacement, $content);
}
Assigning variables in Smarty

Now that the Smarty code of the Single Mode is extended we obviously want to assign the variables. This can be done with another event handler.

// Change the variables used by the function that changes the template
add_event_handler('loc_end_element_set_unit', 'CR_add_batch_single_vars_to_template');

Now the smart reader might object that we have to event handlers attached to the same event, the one depending on the other. How do we assure that the prefilter is executed before we try to assign the variables? The even smarter reader might have noticed that the first event_handler line ended with ', 55 );'. This number 55 states the priority of the event handler, which defaults to 50. Hence the first event handler will indeed be executed before the second.

The contents of the second event handler are as follows.

// Assign the variables to the Smarty template
function CR_add_batch_single_vars_to_template()
{
  global $template;
 
  load_language('plugin.lang', dirname(__FILE__).'/');
 
  // Fetch all the copyrights and assign them to the template
  $query = sprintf(
    'SELECT `cr_id`,`name`
    FROM %s
    WHERE `visible`<>0
    ;',
    COPYRIGHTS_ADMIN);
  $result = pwg_query($query);
 
  $CRoptions = array();
  while ($row = pwg_db_fetch_assoc($result)) {
    $CRoptions[$row['cr_id']] = $row['name'];
  }
  $template->assign('CRoptions', $CRoptions);
 
  // Get the copyright for each element
  $query = sprintf(
    'SELECT `media_id`, `cr_id`
    FROM %s
    ;',
    COPYRIGHTS_MEDIA);
  $result = pwg_query($query);
 
  $CRcopyrights = array();
  while ($row = pwg_db_fetch_assoc($result)) {
    $CRcopyrights[$row['media_id']] = $row['cr_id'];
  }
 
  // Assign the copyrights to the template
  $template->assign('CRcopyrights', $CRcopyrights);
}

Note that we again load the language file. Furthermore we just select the visible copyrights from the database and assign them to the copyright selector.

Catching the 'Submit'

Finally we want to really do something with the selected copyrights. So we will have to attach something to the submit button. We will again use an event handler.

add_event_handler('loc_begin_element_set_unit', 'CR_batch_single_submit', 50 );

The content of this event handler checks whether the $_POST['submit'] variable is set. If so it executes some lines of code that very closely resemble the submit code for the Global Mode.

// Catch the submit and update the copyrights tables
function CR_batch_single_submit()
{
  if (isset($_POST['submit']))
  {
    // The image id's:
    $collection = explode(',', $_POST['element_ids']);
 
    // Delete all existing id's of which the copyright is going to be set
    if (count($collection) > 0) {
      $query = sprintf(
        'DELETE
        FROM %s
        WHERE media_id IN (%s)
        ;',
        COPYRIGHTS_MEDIA, implode(',', $collection));
      pwg_query($query);
    }
 
    // Add all copyrights to an array
    $edits = array();
    foreach ($collection as $image_id) {
      // The copyright id's
      $crID = pwg_db_real_escape_string($_POST['copyright-'.$image_id]);
 
      array_push(
        $edits,
        array(
          'media_id' => $image_id,
 
    'cr_id' => $crID,
        )
      );
    }
 
    // Insert the array to the database
    mass_inserts(
      COPYRIGHTS_MEDIA,        // Table name
      array_keys($edits[0]),   // Columns
      $edits                   // Data
    );
  }
}

Modifying copyrights via picture_modify.php

This part of the plugin works in the same way as the single mode of the Batch Manager.

  1. It attaches an event handler, to set a prefilter.
  2. The prefilter adds some Smarty code to the template.
  3. Another event handler assigns the variables in the Smarty code.
  4. Yet another event handler catches the 'Submit' button and updates the database.

The reader should try to understand how this is done by looking at the source code of the plugin.

Showing the copyrights to visitors

To show the copyrights to people visiting the gallery, we again make use of a prefilter. Just like the ways mentioned above. It should by now be pretty straight forward to learn this from the source code.

Using maintain.inc.php

In the file maintain.inc.php one can put code that should be executed at install, activation or deletion of a plugin. The reader can see from the source code of the plugin that the Copyrights plugin inserts several default copyrights into the database by using this file.

Conclusion

One might have noticed from this tutorial that event handlers and in particular prefilters are a mighty tool in developing Piwigo extensions. Still it is difficult to cover everything in a single tutorial. Therefore, the reader should browse and study the source code of Piwigo itself and of other plugins, to gain a stronger sense of how to use these nifty features. In particular, one should also read tutorials on Smarty. Note for example that besides prefilters there also exist postfilters!

 
Back to top
dev/extensions/plugin_tutorial2.txt · Last modified: 2013/03/08 14:43 by flop25
 
 
About this website · Donate · Contact Piwigo project © 2002-2014