copy from DokuWiki

Pierrick Le Gall
2023-04-29 17:47:36 +02:00
parent 32ce320b2b
commit 195456fa76
@@ -0,0 +1,468 @@
# 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!](https://github.com/Piwigo/Piwigo/wiki/Plugin-Tutorial:-Hello-world!). The entire plugin can be installed from the
extension gallery under the name
['Copyrights'](http://piwigo.org/ext/extension_view.php?eid=537). 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](http://piwigo.org/ext/extension_view.php?eid=543). 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](http://piwigo.org/ext/extension_view.php?eid=288).
``` php
/* +-----------------------------------------------------------------------+
* | 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.
``` php
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
``` php
// 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
``` php
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.
``` smarty
<!-- 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.
``` php
// 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](http://www.smarty.net/docsv2/en/advanced.features.prefilters.tpl)
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.
``` php
// 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.
``` php
// 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.
``` php
// 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.
``` php
// 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.
``` php
// 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.
``` php
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.
``` php
// 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!