OSDN Git Service

Merge branch 'skinnable-master'
[nucleus-jp/nucleus-next.git] / nucleus / documentation / devdocs / plugins.html
1 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
2 <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml">
3 <head>
4         <!-- $Id: plugins.html 1721 2012-03-31 10:18:25Z sakamocchi $ -->
5         <title>Nucleus - Plugin API</title>
6         <link rel="stylesheet" type="text/css" href="styles/manual.css" />
7         <style type="text/css">
8                 /* refence parameters (greenish) */
9                 .ref {
10                         background-color: #afa;
11                         color: #000;
12                 }
13
14                 /* object parameters */
15                 .obj {
16                         color: #00f;
17                 }
18                 .obj:after {
19                         content: " (object)";
20                 }
21
22                 /* read-only parameters (non-ref; reddish) */
23                 .ro {
24                         background-color: #faa;
25                         color: #000;
26                 }
27         </style>
28 </head>
29 <body>
30
31 <div class="heading">
32 Plugin API
33 <i>December 7, 2010</i>
34 </div>
35
36 <div class="note"><strong>Notes:</strong>
37         <ul>
38                 <li>This document should contain enough information to write basic plugins. If you have more questions, see the <a href="http://forum.nucleuscms.org/viewforum.php?f=10">Plugin Development Forum</a></li>
39                 <li>Methods and events introduced after Nucleus v1.5 was released have the Nucleus version in which they were introduced listed. If you use any of those functions, don't forget to adapt <code>getMinNucleusVersion</code> appropriately.
40                 </li>
41   </ul>
42 </div>
43
44 <h1>Introduction</h1>
45
46 <p>
47 <a href="index.html">Back to the developer docs index</a>
48 </p>
49
50 <p>
51 This document contains information on how you can write your own Nucleus plugins
52 </p>
53
54 <h1><a name="toc"></a><a name="top"></a>Table Of Contents</h1>
55
56 <ul>
57         <li><a href="#introduction">Introduction</a></li>
58         <li><a href="#firstplug">Writing your first plugin</a></li>
59         <li><a href="#nucleusplugin">Overview of the <code>NucleusPlugin</code> class</a></li>
60         <li><a href="#skinvars">The <code>&lt;%plugin(...)%&gt;</code> skinvar</a></li>
61         <li><a href="#templatevars">The <code>&lt;%plugin(...)%&gt;</code> templatevar</a></li>
62         <li><a href="#actions">Actions using <code>action.php</code></a></li>
63         <li><a href="#events">Events, and subscribing to them</a></li>
64         <li><a href="#options">Saving options</a></li>
65         <li><a href="#tables">Database tables</a></li>
66         <li><a href="#admin">Providing an admin area</a></li>
67         <li><a href="#help">Providing a helppage</a></li>
68         <li><a href="#dependency">Plugin Dependency Check</a></li>
69         <li><a href="#internationalization">Internationalizing a Plugin</a></li>
70         <li><a href="#skinvar-formatting">Formatting Output of SkinVars</a></li>
71         <li><a href="#additional-reading">Additional Reading</a></li>
72 <!--    <li><a href="#parser">Using the <code>PARSER</code> class</a></li>      
73         <li><a href="#"></a></li>
74         <li><a href="#"></a></li>
75         <li><a href="#"></a></li>-->
76 </ul>
77
78 <h1>Introduction <a name="introduction" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
79
80 <p>
81 Nucleus plugins allow just about anyone to extend the functionality that Nucleus offers, without having to alter the PHP code itself. Plugins are simple php scripts that must implement certain methods, and can easily be exchanged between Nucleus users. Installing goes as easy as adding the plugin file to the plugin directory and letting Nucleus know it's there.
82 </p>
83
84 <p>
85 Some advantages of plugins are listed below:
86 </p>
87
88 <ul>
89         <li>Extra functionality can easily be added to the Nucleus framework, without having to know much details about the implementation.</li>
90         <li>You can install only the plugins you need, saving on the time needed to generate a page</li>
91 </ul>
92
93 <p>
94 All plugin files should be placed in the directory that is listed in <code>config.php</code>. Commonly, this will be <code>/your/path/nucleus/plugins/</code>. Plugin files can be recognized by their form: <code>NP_<i>name</i>.php</code>. Some plugins require a subdirectory with the same <i>name</i> to store extra files or their admin area.
95 </p>
96
97 <div class="note">
98 <b>Note:</b> the names are case-sensitive, so they should start with <code>NP_</code>, not <code>Np_</code> or <code>np_</code>. Also note that when the plugin uses a subdirectory, the name of that directory should be <em>all lowercase</em>.
99 </div>
100
101
102
103
104 <h1>Writing your first plugin <a name="firstplug" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
105
106 <p>
107 Ok, lets start by writing a simple plugin. Basically, each plugin is a PHP class that inherits from the predefined class <code>NucleusPlugin</code>. Below is an example of a <code>HelloWorld</code>-plugin:
108 </p>
109
110 <pre class="example"><code>&lt;?php
111
112 class NP_HelloWorld extends NucleusPlugin
113 {
114         // name of plugin
115         function getName()
116         {
117                 return 'Hello World';
118         }
119
120         // author of plugin
121         function getAuthor()
122         {
123                 return 'Wouter Demuynck';
124         }
125
126         // an URL to the plugin website
127         // can also be of the form mailto:foo@bar.com
128         function getURL()
129         {
130                 return 'http://nucleuscms.org/';
131         }
132
133         // version of the plugin
134         function getVersion()
135         {
136                 return '1.0';
137         }
138
139         // a description to be shown on the installed plugins listing
140         function getDescription()
141         {
142                 return 'Just a sample plugin.';
143         }
144
145         function doSkinVar($skinType)
146         {
147                 echo 'Hello World!';
148         }
149
150         function supportsFeature ($what)
151         {
152                 switch ($what)
153                 {
154                         case 'SqlTablePrefix':
155                                 return 1;
156                         case 'SqlApi':
157                                 return 1;
158                         default:
159                                 return 0;
160                 }
161         }
162
163 }
164 ?&gt;</code></pre>
165
166 <ol>
167         <li>
168                 Copy this code in a file called <code>NP_HelloWorld.php</code>, and put it in your plugins directory. <em>Make sure that there are no spaces after the last <code>?&gt;</code> or before the first <code>&lt;?php</code>.</em>. NP stands for "Nucleus Plugin", if you were wondering about that.
169         </li>
170         <li>Open the Nucleus Administration area and go into <em>Nucleus Management/Manage Plugins</em></li>
171         <li>You'll find out that there's a <em>HelloWorld</em> plugin you can install. Do this. If everything worked out correctly, you'll see that your plugin is now listed in the list of installed plugins.</li>
172         <li>
173                 Now edit one of your skins and insert the following statement at a place of which you know where it will show up on the actual page.
174 <pre class="example"><code>&lt;%HelloWorld%&gt;</code></pre>
175                 Note that the name (<code>HelloWorld</code>) is case sensitive!
176         </li>
177         <li>Now visit a page that uses the skin you edited: notice the "Hello World" at the location where you've added the <code>plugin</code>-skinvar.</li>
178 </ol>
179
180 <p>
181 So, that wasn't so hard after all. Read on to find out more.
182 </p>
183
184
185
186
187
188
189
190 <h1>The class NucleusPlugin <a name="nucleusplugin" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
191
192 <p>All Nucleus plugins must inherit from the PHP class <code>NucleusPlugin</code>. If this sounds complicated, don't worry, it isn't. It even makes your life easier, allowing you to only implement the methods that your plugin needs, and giving access to some auxiliary functions.</p>
193
194 <p>Below is an overview of the methods that the <code>NucleusPlugin</code> offers, and that you can re-implement in your own plugin. If you want to see the source of the class itsself, it's located at <code>nucleus/libs/PLUGIN.php</code></p>
195
196 <table summary="An overview of the redefinable methods in the class NucleusPlugin">
197         <caption>Overview of the class <code>NucleusPlugin</code> (redefinable methods)</caption>
198         <tr>
199                 <th>Method&nbsp;Signature</th><th>Explanation</th>
200         </tr>
201         <tr>
202                 <td><code>getName()</code></td>
203                 <td>Returns the name of the plugin. This will be the name that will show up on the list of installed plugins. You should definately redefine this method, since the default implementation returns <q>Undefined</q></td>
204         </tr>
205         <tr>
206                 <td><code>getAuthor()</code></td>
207                 <td>Returns the name of author of the plugin. This name will show up on the list of installed plugins. You should definately redefine this method, since the default implementation returns <q>Undefined</q></td>
208         </tr>
209         <tr>
210                 <td><code>getURL()</code></td>
211                 <td>Returns the URL of the site where the plugin can be downloaded, or where additional information about the plugin can be found. If no such site exists, a <code>mailto:</code>-link with the authors email address is appropriate. You should definately redefine this method, since the default implementation returns <q>Undefined</q></td>
212         </tr>
213         <tr>
214                 <td><code>getDescription()</code></td>
215                 <td>Returns a longer description of the plugin. This will show up on the list of installed plugins. The default implementation returns <q>Undefined</q></td>
216         </tr>
217         <tr>
218                 <td><code>getVersion()</code></td>
219                 <td>Returns the current version of the plugin. Returns <q>0.0</q> by default</td>
220         </tr>
221         <tr>
222                 <td><code>getMinNucleusVersion()</code></td>
223                 <td>(v2.0b) Returns the minimum required Nucleus version. By default, this returns <code>155</code> (v1.55). If you are using plugin features that were introduced later, please implement this function (e.g. v2.0 => 200). Please note that Nucleus v1.55 does not use this function at all, so it remains possible to install newer plugins there, even if they use newer features.</td>
224         </tr>
225         <tr>
226                 <td><code>getMinNucleusPatchLevel()</code></td>
227                 <td>(v3.1) Returns the minimum required Nucleus patch level that needs to be present when running the minimal required Nucleus version (<code>getMinNucleusVersion</code>). By default, this returns <code>0</code>. This function is generally used when new plugin features are available only as patches to the latest released Nucleus version.</td>
228         </tr>
229         <tr>
230                 <td><code>init()</code></td>
231                 <td>Initializes the plugin. This method gets called immediately after the plugin object is created and the <code>plugid</code>-attribute has been set. By default, this method does nothing.</td>
232         </tr>
233         <tr>
234                 <td><code>doSkinVar($skinType)</code></td>
235                 <td>When plugins are called using the <code>&lt;%plugin(...)%&gt;</code>-skinvar, this method will be called. the <code>$skinType</code> parameter contains the type of skin (<code>item</code>, <code>archive</code>, ...) from where the plugin is called. Don't get confused by the fact that there's only one parameter. Multiple parameters <strong>can</strong> still be passed. <a href="#skinvars">More info on implementing the <code>doSkinVar</code> method.</a> By default, this method does no output at all.</td>
236         </tr>
237         <tr>
238                 <td><code>doTemplateVar(&amp;$item)</code></td>
239                 <td>Basically the same as <code>doSkinVar</code>, but this time for calls of the &lt;%plugin(...)%&gt;-var in <i>templates</i> (item header/body/footer and dateheader/footer). By default, this method forwards the handling to the <code>doSkinVar</code>-method, using <code>template</code> as skintype. <a href="#templatevars">More information on implementing the <code>doTemplateVar</code> method</a></td>
240         </tr>
241         <tr>
242                 <td><code>doTemplateCommentsVar(&amp;$item, &amp;$comment)</code></td>
243                 <td>(v2.0b) Basically the same as <code>doSkinVar</code>, but this time for calls of the &lt;%plugin(...)%&gt;-var in <i>templates</i> (comments-related parts). By default, this method forwards the handling to the <code>doSkinVar</code>-method, using <code>template</code> as skintype. <a href="#templatevars">More information on implementing the <code>doTemplateCommentsVar</code> method</a></td>
244         </tr>
245         <tr>
246                 <td><code>doItemVar(&amp;$item, &amp;$param)</code></td>
247                 <td>(v3.30) Basically the same as <code>doSkinVar</code>, but this time for calls of the &lt;%plugin(...)%&gt;-var in an <i>item</i>. <code>&amp;$item</code> provides the full item object of the item in which the ItemVar appears and <code>&amp;$param</code> the parameters of the ItemVar.</td>
248         </tr>
249         <tr>
250                 <td><code>doIf($key, $value)</code></td>
251                 <td>(v3.30) Evaluates a custom conditional statement for the <code>if/ifnot/elseif/elseifnot</code> skin variables. Must return either <code>true</code> or <code>false</code>. $key and $value are strings passed from the <code>if/ifnot/elseif/elseifnot</code> skin variable. Normally, the plugin should check whether <code>$key</code> has the value of <code>$value</code>, but other uses are possible. Plugins that make use of this method, should document its use for users of the plugin.</td>
252         </tr>
253         <tr>
254                 <td><code>doAction($type)</code></td>
255                 <td>When a plugin wants to allow user interaction, it can allow actions through <code>action.php</code>. This is the script that Nucleus uses itself to handle new comments and karma votes. Called with the correct parameters, the <code>doAction</code>-method from a plugin can be called. The <code>$type</code> contains an optional message type. Extra variables from the request can be accessed from within the <code>doAction</code> method. By default, this method returns a string <q>No Such Action</q> which will trigger an error message. <a href="#actions">More info on <code>doAction</code>.</a></td>
256         </tr>
257         <tr>
258                 <td><code>install()</code></td>
259                 <td>This method gets called on the moment the plugin is installed. It can perform initializing actions, such as the creation of database tables, the creation of plugin options, etc... By default, this method does nothing.</td>
260         </tr>
261         <tr>
262                 <td><code>unInstall()</code></td>
263                 <td>Called when the plugin is uninstalled. It's a good thing to clean up information your plugin created in the database at this point. By default, this method does nothing.</td>
264         </tr>
265         <tr>
266                 <td><code>getEventList()</code></td>
267                 <td>Plugins can subscribe to events. Events get generated whenever Nucleus performs a certain action. An <code>AddItem</code> event for example, will call all plugins that subscribed to this event. The called method will be <code>event_AddItem($params)</code>. The <code>$params</code>-parameter is an associative array containing several fields of information, like the itemid for <code>AddItem</code>. Returns an empty array by default, indicating that the plugin does not subscribe to any event at all. <a href="#events">More information about events.</a></td>
268         </tr>
269         <tr>
270                 <td><code>getTableList()</code></td>
271                 <td>This method should return an array of database tables that the plugin has created. It's used in the backup feature that Nucleus offers, so plugin tables are also included in the backup. By default, returns an empty array.</td>
272         </tr>
273         <tr>
274                 <td><code>hasAdminArea()</code></td>
275                 <td>Should return <code>1</code> if the plugin has an admin area of its own, and <code>0</code> if it doesn't. By default, <code>0</code> is returned.</td>
276         </tr>
277         <tr>
278                 <td><code>getPluginDep()</code></td>
279                 <td>(v3.2) Returns an array of plugin names. Nucleus refuses to install the plugin if any of these plugins is not installed. By default, an empty array is returned. <a href="#dependency">More information on plugin dependencies.</a></td>
280         </tr>
281 </table>
282
283 <p>Next to the methods that can be implemented, the class <code>NucleusPlugin</code> offers some extra methods which you <em>should not</em> implement yourself. They can be called from within your plugin using the <code>$this-&gt;functionName()</code> syntax.</p>
284
285 <table summary="An overview of the auxiliary methods in the class NucleusPlugin. You should NOT redefine these">
286         <caption>Overview of the class <code>NucleusPlugin</code> (non-redefinable methods)</caption>
287         <tr>
288                 <th>Method&nbsp;Signature</th><th>Explanation</th>
289         </tr>
290         <tr>
291                 <td>
292                                   <code>createOption(...)</code>
293                         <br /><code>createBlogOption(...)</code>(v2.2)
294                         <br /><code>createCategoryOption(...)</code>(v2.2)
295                         <br /><code>createMemberOption(...)</code>(v2.2)
296           <br /><code>createItemOption(...)</code>(v3.2)
297                 </td>
298                 <td><a href="#options" title="More info on options">Creates a new option</a></td>
299         </tr>
300         <tr>
301                 <td>
302                                   <code>deleteOption(...)</code>
303                         <br /><code>deleteBlogOption(...)</code>(v2.2)
304                         <br /><code>deleteCategoryOption(...)</code>(v2.2)
305                         <br /><code>deleteMemberOption(...)</code>(v2.2)
306           <br /><code>deleteItemOption(...)</code>(v3.2)
307                 </td>
308                 <td><a href="#options" title="More info on options">Deletes an option</a></td>
309         </tr>
310         <tr>
311                 <td>
312                                   <code>setOption(...)</code>
313                         <br /><code>setBlogOption(...)</code>(v2.2)
314                         <br /><code>setCategoryOption(...)</code>(v2.2)
315                         <br /><code>setMemberOption(...)</code>(v2.2)
316           <br /><code>setItemOption(...)</code>(v3.2)
317                 </td>
318                 <td><a href="#options" title="More info on options">Sets the value of an option</a></td>
319         </tr>
320         <tr>
321                 <td>
322                                   <code>getOption(...)</code>
323                         <br /><code>getBlogOption(...)</code>(v2.2)
324                         <br /><code>getCategoryOption(...)</code>(v2.2)
325                         <br /><code>getMemberOption(...)</code>(v2.2)
326           <br /><code>getItemOption(...)</code>(v3.2)
327                 </td>
328                 <td><a href="#options" title="More info on options">Retrieves the value of an option</a></td>
329         </tr>
330         <tr>
331                 <td>
332                         <code>getAllBlogOptions(...)</code>(v2.2)
333                         <br /><code>getAllCategoryOptions(...)</code>(v2.2)
334                         <br /><code>getAllMemberOptions(...)</code>(v2.2)
335           <br /><code>getAllItemOptions(...)</code>(v3.2)
336                 </td>
337                 <td><a href="#options" title="More info on options">For a given option, returns an associative of all values (one value per context)</a></td>
338         </tr>
339
340   <tr>
341                 <td>
342                         <code>getBlogOptionTop(...)</code>(v3.2)
343                         <br /><code>getMemberOptionTop(...)</code>(v3.2)
344                         <br /><code>getCategoryOptionTop(...)</code>(v3.2)
345           <br /><code>getItemOptionTop(...)</code>(v3.2)
346                 </td>
347                 <td><a href="#options" title="More info on options">For a given option, returns the top of all values</a></td>
348         </tr>
349         <tr>
350                 <td><code>getID()</code></td>
351                 <td>Returns the ID for this plugin (this is the ID internally used inside Nucleus)</td>
352         </tr>
353         <tr>
354                 <td><code>getAdminURL()</code></td>
355                 <td>Returns the URL of where the admin area of the plugin is located (if there is no such admin area, this information is invalid)</td>
356         </tr>
357         <tr>
358                 <td><code>getDirectory()</code></td>
359                 <td>Returns the path in the servers filesystem where the extra files for the plugin are stored (if there are no such files, this information makes no sense). The result is something like "<code>.../nucleus/plugins/<i>plugname</i>/</code>"</td>
360         </tr>
361         <tr>
362                 <td><code>getShortName()</code></td>
363                 <td>Returns the part of the plugin classname without the "<code>NP_</code>"-part, and in all-lowercase. This information is used in the functions <code>getAdminURL</code> and <code>getDirectory</code></td>
364         </tr>
365
366 </table>
367
368 <h1>Skinvars <a name="skinvars" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
369
370 <h2>Description</h2>
371
372 <p>
373 You can create your own skinvars, and call them using <code>&lt;%plugin(<i>PlugName</i>,<i>parameters</i>)%&gt; </code> or <code>&lt;%PlugName(parameters)%&gt;</code> (when this does not conflict with an existing skinvar). Parameters are comma-separated.
374 </p>
375
376 <p>
377 To handle skinvars, you'll need to implement the <code>doSkinVar</code> method. Some samples of signatures are given below:
378 </p>
379
380 <pre class="example"><code>function doSkinVar($skinType)
381 function doSkinVar($skinType, $param1, $param2)
382 function doSkinVar($skinType, $skinVar, $param1, $param2)
383 function doSkinVar($skinType, $skinVar, $param1 = 'default value')</code></pre>
384
385 <ul>
386         <li>The <code>$skinType</code> parameter will be one of 'index', 'item', 'archive', 'archivelist', 'member', 'error', 'search', 'imagepopup' or <a href="#templatevars" title="Information on templatevars">'template'</a></li>
387         <li>The <code>$skinVar</code> is actually the first parameter that's being interpreted as a type of skinvar (e.g. <code>&lt;%plugin(PlugName,VarType)%&gt;</code>)</li>
388         <li>You can use <code>doSkinVar()</code> (no parameters) and retrieve the parameters using the PHP function <code>func_get_args()</code>. Could be handy if you have different types of skinvars with different numbers of arguments</li>
389 </ul>
390
391 <h2>Notes</h2>
392
393 <ul>
394         <li>(v2.0b) You can find the name of the skin that's currently being parsed in the global variable <code>$currentSkinName</code></li>
395 </ul>
396
397
398
399
400 <h1>Template variables <a name="templatevars" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
401
402 <h2>Description</h2>
403
404 <p>
405 Template plugin variables work in the same way as skin plugin vars. There are two differences:</p>
406
407 <ol>
408         <li>They are called from within templates instead of from within skins</li>
409         <li>They don't take a <code>$skinType</code> parameter. Instead, they take extra parameters with info on the item and comment that is currently being parsed:
410                 <ul>
411                         <li>The <code>doTemplateVar</code>-method gets a <code>&amp;$item</code> parameter.</li>
412                         <li>The <code>doTemplateCommentsVar</code>-method gets an <code>&amp;$item</code> parameter as well as a <code>&amp;$comment</code> parameter.</li>
413                 </ul>
414                 <strong>Note the ampersands!</strong>
415         </li>
416 </ol>
417
418 <p>Template variables are called in exactly the same way as skinvars (using <code>&lt;%plugin(<i>PlugName</i>,<i>parameters</i>)%&gt; </code> or <code>&lt;%PlugName(parameters)%&gt;</code>)
419 </p>
420
421 <p>
422 By default, all template variables are passed on to the <code>doSkinVar</code>-method, using '<code>template</code>' as <code>skinType</code>-parameter.
423 </p>
424
425 <p>
426 If you want to provide your own implementation, you'll need to redefine the method <code>doTemplateVar</code> and/or <code>doTemplateCommentsVar</code>. It works in the same way as <code>doSkinVar</code>, except that now the <code>skinType</code>-parameter is missing.
427 </p>
428
429 <pre class="example"><code>function doTemplateVar(&amp;$item)
430 function doTemplateVar(&amp;$item, $param1, $param2)
431 function doTemplateVar(&amp;$item, $type, $param1, $param2)
432 function doTemplateVar(&amp;$item, $type, $param1 = 'default value')
433 function doTemplateCommentsVar(&amp;$item, &amp;$comment)
434 function doTemplateCommentsVar(&amp;$item, &amp;$comment, $param1, $param2)
435 function doTemplateCommentsVar(&amp;$item, &amp;$comment, $type, $param1, $param2)
436 function doTemplateCommentsVar(&amp;$item, &amp;$comment, $type, $param1 = 'default value')</code></pre>
437
438 <h2>Notes</h2>
439
440 <ul>
441         <li>(v2.0b) You can find the name of the template that's currently being used inside the global variable <code>$currentTemplateName</code></li>
442 </ul>
443
444
445
446
447 <h1>Actions <a name="actions" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
448
449 <p>Plugins can perform actions through <code>action.php</code>, the same script that's being used to receive comments and karma votes. You can call it using both GET and POST methods. Required parameters are <code>action</code> (should be 'plugin'), <code>name</code> (name of the plugin) and <code>type</code> (type of requested action)</p>
450
451 <p>To enable these actions, you should implement the <code>doAction($actionType)</code> method in your plugin. Extra parameters from the request can be received using <code>requestVar('<i>name</i>')</code> (<code>requestVar</code> takes care of magic_quotes_gpc that PHP might have added)</p>
452
453 <p>
454 When your <code>doAction</code> method returns a string, it will be interpreted as an error, and an error message will be shown.
455 </p>
456
457
458
459
460
461
462 <h1>Events <a name="events" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
463
464 <p>
465 Nucleus Plugins can subscribe to events that occur whenever something important happens. The plugin can then execute some actions, or output some text.
466 </p>
467
468 <h2>Example</h2>
469
470 <p>
471 Below is an example of how a plugin subscribes to the <code>PreAddComment</code>-event, an event that is generated immediately before a comment is added to a blog.
472 </p>
473
474 <pre class="example"><code>class NP_Acronyms extends NucleusPlugin {
475   ...
476   function getEventList() { return array('PreAddComment'); }
477   ...
478   function event_PreAddComment(&amp;$data) {
479         // replace acronym HTML
480         $data['comment']['body'] =
481                 strreplace('HTML',
482                                    '&lt;acronym title="HyperText Markup Language"&gt;HTML&lt;/acronym&gt;',
483                                    $data['comment']['body']);
484   }
485 }
486 </code></pre>
487
488 <p>This plugin replaces the text <code>HTML</code> in each comment by the text <code>&lt;acronym title="HyperText Markup Language"&gt;HTML&lt;/acronym&gt;</code>. The <code>acronym</code>-tag is a <acronym title="HyperText Markup Language">HTML</acronym>-tag that allows authors to provide extra information on acronyms.</p>
489
490 <h2>Subscribing to events</h2>
491
492 <p>Here's the steps you need to take to subscribe to an event:</p>
493
494 <ol>
495         <li>Add the event name to the array returned by the <code>getEventList</code>-method</li>
496         <li>Create a method with signature <code>event_<em>EventName</em>($data)</code>, in which the handling of the event is done</li>
497 </ol>
498
499 <p>Multiple plugins can subscribe to the same event. The order in which these plugins are notified is the same order as the ordening in the plugin list of the admin area. Plugins higher in the list get notified earlier on.</p>
500
501 <h2>Parameters</h2>
502
503 <p>The <code>event_<em>EventName</em></code>-method gets only one parameter, <code>$data</code>, of which the contents differs depending on the event. It is an associative array with data. Objects and arrays that are passed in this array, are passed by <strong>reference</strong>, so the changes you make there will be remembered.</p>
504
505 <p>The event list below uses some colors to indicate if changes in the parameters will be seen by nucleus or not:</p>
506
507 <ul>
508         <li><var class="ref">pass-by-reference</var>: when changes are made to this kind of parameters, they will be seen by Nucleus.</li>
509         <li><var class="ro">pass-by-value</var>: a copy of the value is made before it is sent to the plugin event handler. Changes in the contents of these variables will be discarded automatically.</li>
510 </ul>
511
512 <p>Objects that are passed as parameters are indicates as follows: <var class="obj">object</var>. Most objects are also passed by reference, making them look like <var class="obj ref">object by ref</var></p>
513
514 <h2>Event List</h2>
515
516 <table summary="An overview of events to which a Nucleus Plugin can subscribe, and what parameters are passed along to the method that handles the event">
517         <caption>Events on which a plugin can subscribe</caption>
518         <tr>
519                 <th>Name</th><th>When</th><th>Parameters</th>
520         </tr>
521         <tr>
522                 <td>InitSkinParse</td>
523                 <td>Just before the skin is initialized</td>
524                 <td><dl>
525                         <dt class="obj ref">skin</dt>
526                         <dd>The <code>SKIN</code>-object that is handling the parse</dd>
527                         <dt class="ro">type</dt>
528                         <dd>Type of skinpart (one of 'index', 'item', 'archive', 'archivelist', 'member', 'error', 'search', 'imagepopup', 'fileparser')</dd>
529                 </dl></td>
530         </tr>
531         <tr>
532                 <td>PreSkinParse</td>
533                 <td>Immediately before the parsing of a skin begins</td>
534                 <td><dl>
535                         <dt class="obj ref">skin</dt>
536                         <dd>The <code>SKIN</code>-object that is handling the parse</dd>
537                         <dt class="ro">type</dt>
538                         <dd>Type of skinpart (one of 'index', 'item', 'archive', 'archivelist', 'member', 'error', 'search', 'imagepopup', 'fileparser')</dd>
539                         <dt class="ref">contents</dt>
540                         <dd>The content of the skin</dd>
541                 </dl></td>
542         </tr>
543         <tr>
544                 <td>PostSkinParse</td>
545                 <td>Immediately after parsing a skin</td>
546                 <td><dl>
547                         <dt class="obj ref">skin</dt>
548                         <dd>The <code>SKIN</code>-object that is handling the parse</dd>
549                         <dt class="ro">type</dt>
550                         <dd>Type of skinpart (one of 'index', 'item', 'archive', 'archivelist', 'member', 'error', 'search', 'imagepopup', 'fileparser')</dd>
551                 </dl></td>
552         </tr>
553         <tr>
554                 <td>PreItem</td>
555                 <td>Before an item is parsed, but after the item header has been placed</td>
556                 <td><dl>
557                         <dt class="ref obj">blog</dt>
558                         <dd><code>BLOG</code> object</dd>
559                         <dt class="ref obj">item</dt>
560                         <dd>object containing item data</dd>
561                 </dl></td>
562         </tr>
563         <tr>
564                 <td>PostItem</td>
565                 <td>After an item has been parsed, but before the item footer has been parsed</td>
566                 <td><dl>
567                         <dt class="ref obj">blog</dt>
568                         <dd><code>BLOG</code> object</dd>
569                         <dt class="ref obj">item</dt>
570                         <dd>object containing item data</dd>
571                 </dl></td>
572         </tr>
573         <tr>
574                 <td>PreComment</td>
575                 <td>Before a comment is shown</td>
576                 <td><dl>
577                         <dt class="ref">comment</dt>
578                         <dd>associative array containing comment data</dd>
579                 </dl></td>
580         </tr>
581         <tr>
582                 <td>PostComment</td>
583                 <td>After a comment has been shown</td>
584                 <td><dl>
585                         <dt class="ref">comment</dt>
586                         <dd>associative array containing comment data</dd>
587                 </dl></td>
588         </tr>
589         <tr>
590                 <td>PreDateHead</td>
591                 <td>Before a date header is shown</td>
592                 <td><dl>
593                         <dt class="obj ref">blog</dt>
594                         <dd><code>BLOG</code> object</dd>
595                         <dt class="ro">timestamp</dt>
596                         <dd>Timestamp for date header</dd>
597                 </dl></td>
598         </tr>
599         <tr>
600                 <td>PostDateHead</td>
601                 <td>After a date header has been parsed</td>
602                 <td><dl>
603                         <dt class="obj ref">blog</dt>
604                         <dd><code>BLOG</code> object</dd>
605                         <dt class="ro">timestamp</dt>
606                         <dd>Timestamp for date header</dd>
607                 </dl></td>
608         </tr>
609         <tr>
610                 <td>PreDateFoot</td>
611                 <td>Before a date footer is parsed</td>
612                 <td><dl>
613                         <dt class="ref obj">blog</dt>
614                         <dd><code>BLOG</code> object</dd>
615                         <dt class="ro">timestamp</dt>
616                         <dd>Timestamp for day that is closed</dd>
617                 </dl></td>
618         </tr>
619         <tr>
620                 <td>PostDateFoot</td>
621                 <td>After a date footer has been parsed</td>
622                 <td><dl>
623                         <dt class="ref obj">blog</dt>
624                         <dd><code>BLOG</code> object</dd>
625                         <dt class="ro">timestamp</dt>
626                         <dd>Timestamp for day that is closed</dd>
627                 </dl></td>
628         </tr>
629         <tr>
630                 <td>LoginSuccess</td>
631                 <td>After a successful login</td>
632                 <td><dl>
633                         <dt class="obj ref">member</dt>
634                         <dd><code>MEMBER</code> object</dd>
635                         <dt class="ro">username</dt>
636                         <dd>login name that was used in the login attempt</dd>
637                 </dl></td>
638         </tr>
639         <tr>
640                 <td>LoginFailed</td>
641                 <td>After a failed login</td>
642                 <td><dl>
643                         <dt class="ro">username</dt>
644                         <dd>login name that was used in the login attempt</dd>
645                 </dl></td>
646         </tr>
647         <tr>
648                 <td>Logout</td>
649                 <td>After logout</td>
650                 <td><dl>
651                         <dt class="ro">username</dt>
652                         <dd>name of the user that logged out</dd>
653                 </dl></td>
654         </tr>
655         <tr>
656                 <td>PreBlogContent</td>
657                 <td>Before blog content has been inserted through a skinvar</td>
658                 <td><dl>
659                         <dt class="obj ref">blog</dt>
660                         <dd><code>BLOG</code> object</dd>
661                         <dt class="ro">type</dt>
662                         <dd>Type of skinvar that's being called ('blog', 'otherblog', 'archive', 'archivelist', 'item', 'searchresults', 'othersearchresults', 'categorylist', 'otherarchive', 'otherarchivelist')</dd>
663                 </dl></td>
664         </tr>
665         <tr>
666                 <td>PostBlogContent</td>
667                 <td>After blog content has been inserted through a skinvar</td>
668                 <td><dl>
669                         <dt class="obj ref">blog</dt>
670                         <dd><code>BLOG</code> object</dd>
671                         <dt class="ro">type</dt>
672                         <dd>Type of skinvar that's being called ('blog', 'otherblog', 'archive', 'archivelist', 'item', 'searchresults', 'othersearchresults', 'categorylist', 'otherarchive', 'otherarchivelist')</dd>
673                 </dl></td>
674         </tr>
675         <tr>
676                 <td>PreAddComment</td>
677                 <td>Before adding a comment to the database</td>
678                 <td><dl>
679                         <dt class="ref">comment</dt>
680                         <dd>comment data (associative array)</dd>
681                         <dt class="ref">spamcheck</dt>
682                         <dd>the resulting datastructure of the previously called <code>SpamCheck</code> event (associative array)</dd>
683                 </dl></td>
684         </tr>
685         <tr>
686                 <td>PostAddComment</td>
687                 <td>After adding a comment to the database</td>
688                 <td><dl>
689                         <dt class="ref">comment</dt>
690                         <dd>comment data (associative array)</dd>
691                         <dt class="ref">commentid</dt>
692                         <dd>comment ID</dd>
693                         <dt class="ref">spamcheck</dt>
694                         <dd>the resulting datastructure of the previously called <code>SpamCheck</code> event (associative array)</dd>
695                 </dl></td>
696         </tr>
697         <tr>
698                 <td>PostRegister</td>
699                 <td>After a new user has registered</td>
700                 <td><dl>
701                         <dt class="obj ref">member</dt>
702                         <dd>New <code>MEMBER</code> object</dd>
703                 </dl></td>
704         </tr>
705         <tr>
706                 <td>PostAddItem</td>
707                 <td>After an item has been added to the database</td>
708                 <td><dl>
709                         <dt class="ro">itemid</dt>
710                         <dd>new itemid in database</dd>
711                 </dl></td>
712         </tr>
713         <tr>
714                 <td>PostUpdateItem</td>
715                 <td>Immediately after an item gets updates in the database</td>
716                 <td><dl>
717                         <dt class="ro">itemid</dt>
718                         <dd>item ID</dd>
719                 </dl></td>
720         </tr>
721         <tr>
722                 <td>PreAddItem</td>
723                 <td>Immediately before an item is added to the database</td>
724                 <td><dl>
725                         <dt class="ref">title</dt>
726                         <dd>title</dd>
727                         <dt class="ref">body</dt>
728                         <dd>body text</dd>
729                         <dt class="ref">more</dt>
730                         <dd>extended text</dd>
731                         <dt class="ref obj">blog</dt>
732                         <dd><code>BLOG</code> object</dd>
733                         <dt class="ref">authorid</dt>
734                         <dd>ID of author</dd>
735                         <dt class="ref">timestamp</dt>
736                         <dd>UNIX timestamp</dd>
737                         <dt class="ref">closed</dt>
738                         <dd>1 (no comments allowed) or 0 (comments allowed)</dd>
739                         <dt class="ref">draft</dt>
740                         <dd>1 (draft) or 0 (not draft)</dd>
741                         <dt class="ref">catid</dt>
742                         <dd>ID fo category</dd>
743                 </dl></td>
744         </tr>
745         <tr>
746                 <td>PreUpdateItem</td>
747                 <td>Immediately before an item gets updates in the database</td>
748                 <td><dl>
749                         <dt class="ro">itemid</dt>
750                         <dd>item ID</dd>
751                         <dt class="ref">title</dt>
752                         <dd>title</dd>
753                         <dt class="ref">body</dt>
754                         <dd>body text</dd>
755                         <dt class="ref">more</dt>
756                         <dd>extended text</dd>
757                         <dt class="ref obj">blog</dt>
758                         <dd><code>BLOG</code> object</dd>
759                         <dt class="ref">closed</dt>
760                         <dd>1 (no comments allowed) or 0 (comments allowed)</dd>
761                         <dt class="ref">catid</dt>
762                         <dd>ID fo category</dd>
763                 </dl></td>
764         </tr>
765         <tr>
766                 <td>PrepareItemForEdit</td>
767                 <td>Called after getting an item from the database, and before presenting it to the user to be edited.</td>
768                 <td><dl>
769                         <dt class="ref">item</dt>
770                         <dd>associative array containing item data</dd>
771                 </dl></td>
772         </tr>
773         <tr>
774                 <td>PreUpdateComment</td>
775                 <td>Immediately before a comment is updated and saved into the database</td>
776                 <td><dl>
777                         <dt class="ref">body</dt>
778                         <dd>Comment body</dd>
779                 </dl></td>
780         </tr>
781         <tr>
782                 <td>PrepareCommentForEdit</td>
783                 <td>After a comment is retrieved from the database, and before it is presented to the user to be edited.</td>
784                 <td><dl>
785                         <dt class="ref">comment</dt>
786                         <dd>comment data (associative array)</dd>
787                 </dl></td>
788         </tr>
789         <tr>
790                 <td>PrePluginOptionsEdit</td>
791                 <td>
792                         (v2.0b) before the 'edit plugin options' form is created.
793                         <br />(v2.2) extra parameters
794           <br />(v3.2) extra parameter for every option
795                 </td>
796                 <td><dl>
797                         <dt class="ro">context</dt>
798                         <dd>(v2.2) <code>global</code>, <code>blog</code>, <code>member</code>, <code>item</code> or <code>category</code></dd>
799                         <dt class="ref">options</dt>
800                         <dd>Array with for each option an associative array, having the following indices: <code>name</code>, <code>value</code>, <code>oid</code>, <code>description</code>, <code>type</code>, <code>typeinfo</code>, <code>contextid</code>, <code>extra</code>. Extra options can be added here (if you want to do something with them, you'll need to subscribe to PostPluginOptionsUpdate as well)<br />
801           Using the <code>extra</code>-field you can add extra html (by example formcontrols) to the option. If you do so, you should compare <code>pid</code> with <code>getID()</code> and also check <code>name</code> before adding things to <code>extra</code></dd>
802                         <dt class="ro">plugid</dt>
803                         <dd>plugin ID (compare with <code>GetID()</code> to find out if this concerns you) (only present when context is global)</dd>
804                         <dt class="ro">contextid</dt>
805                         <dd>context ID (blogid, memberid, catid, itemid depending on context)</dd>
806
807                 </dl></td>
808         </tr>
809   <tr>
810                 <td>PrePluginOptionsUpdate</td>
811                 <td>
812                         (v3.2) Before the options for a plugin have been updated. (using this event you can validate/change the new value for an option)
813                 </td>
814                 <td><dl>
815           <dt class="ro">context</dt>
816                         <dd>(v2.2) <code>global</code>, <code>member</code>, <code>blog</code>, <code>item</code> or <code>category</code></dd>
817                         <dt class="ro">plugid</dt>
818                         <dd>plugin ID (compare with <code>GetID()</code> to find out if this concerns you)</dd>
819           <dt class="ro">optionname</dt>
820                         <dd>Name of the option</dd>
821                         <dt class="ro">contextid</dt>
822                         <dd>context ID (blogid, memberid, catid, itemid depending on context)</dd>
823                         <dt class="ref">value</dt>
824                         <dd>New value for the option</dd>
825                 </dl></td>
826
827         </tr>
828
829         <tr>
830                 <td>PostPluginOptionsUpdate</td>
831                 <td>
832                         (v2.0b) After the options for a plugin have been updated.
833                         <br />(v2.2) Different parameters depending on context
834                 </td>
835                 <td><dl>
836                         <dt class="ro">context</dt>
837                         <dd>(v2.2) <code>global</code>, <code>member</code>, <code>blog</code>, <code>item</code> or <code>category</code></dd>
838                         <dt class="ro">plugid</dt>
839                         <dd>plugin ID (compare with <code>GetID()</code> to find out if this concerns you) (global context)</dd>
840                         <dt class="ro">blogid</dt>
841                         <dd>(v2.2) blog ID (blog context)</dd>
842                         <dt class="ref obj">blog</dt>
843                         <dd>(v2.2) BLOG object (blog context)</dd>
844                         <dt class="ro">memberid</dt>
845                         <dd>(v2.2) member ID (member context)</dd>
846                         <dt class="ref obj">member</dt>
847                         <dd>(v2.2) MEMBER object (member context)</dd>
848                         <dt class="ro">catid</dt>
849                         <dd>(v2.2) category ID (category context)</dd>
850           <dt class="ro">itemid</dt>
851                         <dd>(v2.2) item ID (item context)</dd>
852           <dt class="ref obj">member</dt>
853                         <dd>(v2.2) ITEM object (item context)</dd>
854                 </dl></td>
855
856         </tr>
857         <tr>
858                 <td>PostAuthentication</td>
859                 <td>(v2.0b) After the login procedure has been completed. This occurs on each page request.</td>
860                 <td><dl>
861                         <dt class="ro">loggedIn</dt>
862                         <dd>result of <code>$member->isLoggedIn()</code></dd>
863                 </dl></td>
864         </tr>
865         <tr>
866                 <td>PreAddItemForm</td>
867                 <td>(v2.0b) Immediately before an add item form (bookmarklet or admin area) is created.</td>
868                 <td><dl>
869                         <dt class="ref">contents</dt>
870                         <dd>reference to an associative array, in which the values 'title', 'body' and 'more' can be filled with initial values for the formfields. To avoid multiple plugins to alter these values, set the 'hasBeenSet' value to 1 when you're done (and check for it before starting)</dd>
871                         <dt class="ref obj">blog</dt>
872                         <dd>reference to a <code>BLOG</code> object</dd>
873                 </dl></td>
874         </tr>
875         <tr>
876                 <td>AddItemFormExtras</td>
877                 <td>(v2.0b) Somewhere inside the add item page or bookmarklet. Here, plugins can add their custom fields without having to alter one of the <code>.template</code> files.</td>
878                 <td><dl>
879                         <dt class="ref obj">blog</dt>
880                         <dd>reference to a <code>BLOG</code> object</dd>
881                 </dl></td>
882         </tr>
883         <tr>
884                 <td>EditItemFormExtras</td>
885                 <td>
886                         (v2.0b) Somewhere inside the edit item page or bookmarklet. Here, plugins can add their custom fields without having to alter one of the <code>.template</code> files.
887                         <br /><br />
888                         Don't add too much data, and please generate <strong>valid XHTML</strong>, looking like this:
889 <pre class="example"><code>&lt;h3&gt;plugin name&lt;/h3&gt;
890 &lt;p&gt;your stuff&lt;/p&gt;</code></pre>
891                         This way, multiple plugins can add options here while things keep a good structure. Also try to use prefixes for your fieldnames, in order to avoid nameclashes (e.g. <code>plug_tb_url</code>)
892                 </td>
893                 <td><dl>
894                         <dt class="ref obj">blog</dt>
895                         <dd>reference to a <code>BLOG</code> object</dd>
896                         <dt class="ro">variables</dt>
897                         <dd>
898                                 (read-only) An associative array containing all sorts of information on the item that's being edited: 'itemid', 'draft', 'closed', 'title', 'body', 'more', 'author', 'authorid', 'timestamp', 'karmapos', 'karmaneg', 'catid'
899                         </dd>
900                         <dt class="ro">itemid</dt>
901                         <dd>shortcut to the item ID</dd>
902                 </dl></td>
903         </tr>
904         <tr>
905                 <td>BlogSettingsFormExtras</td>
906                 <td>(v2.0) On the blog settings page. You can add your own forms here.
907                         <br /><br />
908                         Don't add too much data, and please generate <strong>valid XHTML</strong>, looking like this:
909 <pre class="example"><code>&lt;h4&gt;plugin name&lt;/h4&gt;
910 &lt;form method="post" action="..."&gt;&lt;p&gt;
911 your stuff
912 &lt;/p&gt;&lt;/form&gt;</code></pre>
913                         This way, multiple plugins can add options here while things keep a good structure. Also try to use prefixes for your fieldnames, in order to avoid nameclashes (e.g. <code>plug_tb_url</code>)
914
915                 </td>
916                 <td><dl>
917                         <dt class="obj ref">blog</dt>
918                         <dd>reference to a <code>BLOG</code> object</dd>
919                 </dl></td>
920         </tr>
921         <tr>
922                 <td>PreDeleteItem</td>
923                 <td>(v2.0) Immediately before an item gets deleted in the database</td>
924                 <td><dl>
925                         <dt class="ro">itemid</dt>
926                         <dd>id of the item that will be deleted</dd>
927                 </dl></td>
928         </tr>
929         <tr>
930                 <td>PostDeleteItem</td>
931                 <td>(v2.0) Immediately after an item has been deleted in the database</td>
932                 <td><dl>
933                         <dt class="ro">itemid</dt>
934                         <dd>id of the deleted item</dd>
935                 </dl></td>
936         </tr>
937         <tr>
938                 <td>PreDeleteCategory</td>
939                 <td>(v2.0) Immediately before a category gets deleted from the database</td>
940                 <td><dl>
941                         <dt class="ro">catid</dt>
942                         <dd>category ID</dd>
943                 </dl></td>
944         </tr>
945         <tr>
946                 <td>PostDeleteCategory</td>
947                 <td>(v2.0) Immediately after a category has been deleted from the database</td>
948                 <td><dl>
949                         <dt class="ro">catid</dt>
950                         <dd>category ID</dd>
951                 </dl></td>
952         </tr>
953         <tr>
954                 <td>PreDeleteBlog</td>
955                 <td>(v2.0) Immediately before a blog gets deleted from the database</td>
956                 <td><dl>
957                         <dt class="ro">blogid</dt>
958                         <dd>ID of the blog that will be deleted</dd>
959                 </dl></td>
960         </tr>
961         <tr>
962                 <td>PostDeleteBlog</td>
963                 <td>(v2.0) Immediately after a blog has been deleted from the database</td>
964                 <td><dl>
965                         <dt class="ro">blogid</dt>
966                         <dd>ID of the blog that was deleted from the database</dd>
967                 </dl></td>
968         </tr>
969         <tr>
970                 <td>PreDeleteMember</td>
971                 <td>(v2.0) Immediately before a member gets deleted from the database</td>
972                 <td><dl>
973                         <dt class="ref obj">member</dt>
974                         <dd>reference to the <code>MEMBER</code> object associated with the member that needs to be deleted</dd>
975                 </dl></td>
976         </tr>
977         <tr>
978                 <td>PostDeleteMember</td>
979                 <td>(v2.0) Immediately after a member has been deleted from the database</td>
980                 <td><dl>
981                         <dt class="ref obj">member</dt>
982                         <dd>reference to the <code>MEMBER</code> object associated with the member that has been deleted</dd>
983                 </dl></td>
984         </tr>
985         <tr>
986                 <td>PreDeleteTeamMember</td>
987                 <td>(v2.0) Immediately before a member gets deleted from a weblog team</td>
988                 <td><dl>
989                         <dt class="ref obj">member</dt>
990                         <dd>reference to the <code>MEMBER</code> object</dd>
991                         <dt class="ro">blogid</dt>
992                         <dd>ID of the blog</dd>
993                 </dl></td>
994         </tr>
995         <tr>
996                 <td>PostDeleteTeamMember</td>
997                 <td>(v2.0) Immediately after a member has been deleted from a weblog team</td>
998                 <td><dl>
999                         <dt class="ref obj">member</dt>
1000                         <dd>reference to the <code>MEMBER</code> object</dd>
1001                         <dt class="ro">blogid</dt>
1002                         <dd>ID of the blog</dd>
1003                 </dl></td>
1004         </tr>
1005         <tr>
1006                 <td>PreDeleteComment</td>
1007                 <td>(v2.0) Immediately before a comment gets deleted from the database</td>
1008                 <td><dl>
1009                         <dt class="ro">commentid</dt>
1010                         <dd>ID of the comment that will be deleted</dd>
1011                 </dl></td>
1012         </tr>
1013         <tr>
1014                 <td>PostDeleteComment</td>
1015                 <td>(v2.0) Immediately after a comment has been deleted from the database</td>
1016                 <td><dl>
1017                         <dt class="ro">commentid</dt>
1018                         <dd>ID of the deleted comment</dd>
1019                 </dl></td>
1020         </tr>
1021         <tr>
1022                 <td>ActionLogCleared</td>
1023                 <td>(v2.0) After the action log has been cleared</td>
1024                 <td>None</td>
1025         </tr>
1026         <tr>
1027                 <td>PreDeleteTemplate</td>
1028                 <td>(v2.0) Immediately before a template gets deleted from the database</td>
1029                 <td><dl>
1030                         <dt class="ro">templateid</dt>
1031                         <dd>ID of the template that will be deleted</dd>
1032                 </dl></td>
1033         </tr>
1034         <tr>
1035                 <td>PostDeleteTemplate</td>
1036                 <td>(v2.0) Immediately after a template has been deleted from the database</td>
1037                 <td><dl>
1038                         <dt class="ro">templateid</dt>
1039                         <dd>ID of the deleted template</dd>
1040                 </dl></td>
1041         </tr>
1042         <tr>
1043                 <td>PreDeleteSkin</td>
1044                 <td>(v2.0) Immediately before a skin gets deleted from the database</td>
1045                 <td><dl>
1046                         <dt class="ro">skinid</dt>
1047                         <dd>ID of the skin that will be deleted</dd>
1048                 </dl></td>
1049         </tr>
1050         <tr>
1051                 <td>PostDeleteSkin</td>
1052                 <td>(v2.0) Immediately after a skin has been deleted from the database</td>
1053                 <td><dl>
1054                         <dt class="ro">skinid</dt>
1055                         <dd>ID of the deleted skin</dd>
1056                 </dl></td>
1057         </tr>
1058         <tr>
1059                 <td>PreDeletePlugin</td>
1060                 <td>(v2.0) Immediately before a plugin gets deleted from the database</td>
1061                 <td><dl>
1062                         <dt class="ro">plugid</dt>
1063                         <dd>ID of the plugin that will be deleted</dd>
1064                 </dl></td>
1065         </tr>
1066         <tr>
1067                 <td>PostDeletePlugin</td>
1068                 <td>(v2.0) Immediately after a plugin has been deleted from the database</td>
1069                 <td><dl>
1070                         <dt class="ro">plugid</dt>
1071                         <dd>ID of the deleted plugin</dd>
1072                 </dl></td>
1073         </tr>
1074         <tr>
1075                 <td>PreDeleteBan</td>
1076                 <td>(v2.0) Immediately before an IP ban gets deleted from the database</td>
1077                 <td><dl>
1078                         <dt class="ro">blogid</dt>
1079                         <dd>ID of the blog for which the ban will be deleted</dd>
1080                         <dt class="ro">iprange</dt>
1081                         <dd>banned IP range</dd>
1082                 </dl></td>
1083         </tr>
1084         <tr>
1085                 <td>PostDeleteBan</td>
1086                 <td>(v2.0) Immediately after an IP ban has been deleted from the database</td>
1087                 <td><dl>
1088                         <dt class="ro">blogid</dt>
1089                         <dd>ID of the blog for which the ban has been deleted</dd>
1090                         <dt class="ro">iprange</dt>
1091                         <dd>banned IP range</dd>
1092                 </dl></td>
1093         </tr>
1094         <tr>
1095                 <td>PreAddCategory</td>
1096                 <td>(v2.0) Immediately before a new category is created in the database</td>
1097                 <td><dl>
1098                         <dt class="ref obj">blog</dt>
1099                         <dd>reference to <code>BLOG</code> object</dd>
1100                         <dt class="ref">name</dt>
1101                         <dd>name of new category</dd>
1102                         <dt class="ref">description</dt>
1103                         <dd>description of new category</dd>
1104                 </dl></td>
1105         </tr>
1106         <tr>
1107                 <td>PostAddCategory</td>
1108                 <td>(v2.0) Immediately after a new category has been created in the database</td>
1109                 <td><dl>
1110                         <dt class="ref obj">blog</dt>
1111                         <dd>reference to <code>BLOG</code> object</dd>
1112                         <dt class="ro">name</dt>
1113                         <dd>name of new category</dd>
1114                         <dt class="ro">description</dt>
1115                         <dd>description of new category</dd>
1116                         <dt class="ro">catid</dt>
1117                         <dd>New category ID</dd>
1118                 </dl></td>
1119         </tr>
1120         <tr>
1121                 <td>PreAddBlog</td>
1122                 <td>(v2.0) Immediately before a new blog is created</td>
1123                 <td><dl>
1124                         <dt class="ref">name</dt>
1125                         <dd>name of new blog</dd>
1126                         <dt class="ref">shortname</dt>
1127                         <dd>shortname of new blog</dd>
1128                         <dt class="ref">timeoffset</dt>
1129                         <dd>time offset of new blog</dd>
1130                         <dt class="ref">description</dt>
1131                         <dd>description of new blog</dd>
1132                         <dt class="ref">defaultskin</dt>
1133                         <dd>ID of default skin for new blog</dd>
1134                 </dl></td>
1135         </tr>
1136         <tr>
1137                 <td>PostAddBlog</td>
1138                 <td>(v2.0) Immediately after a new blog has been created</td>
1139                 <td><dl>
1140                         <dt class="ref obj">blog</dt>
1141                         <dd>new <code>BLOG</code> object</dd>
1142                 </dl></td>
1143         </tr>
1144         <tr>
1145                 <td>PreAddPlugin</td>
1146                 <td>(v2.0) Immediately before a plugin is added</td>
1147                 <td><dl>
1148                         <dt class="ref">file</dt>
1149                         <dd>filename of the new plugin</dd>
1150                 </dl></td>
1151         </tr>
1152         <tr>
1153                 <td>PostAddPlugin</td>
1154                 <td>(v2.0) Immediately after a plugin has been added</td>
1155                 <td><dl>
1156                         <dt class="ref obj">plugin</dt>
1157                         <dd>An object of the newly added plugin</dd>
1158                 </dl></td>
1159         </tr>
1160         <tr>
1161                 <td>PreAddTeamMember</td>
1162                 <td>(v2.0) Immediately before a member gets added to a blog team</td>
1163                 <td><dl>
1164                         <dt class="ref obj">blog</dt>
1165                         <dd><code>BLOG</code> object</dd>
1166                         <dt class="ref obj">member</dt>
1167                         <dd><code>MEMBER</code> object</dd>
1168                         <dt class="ref">admin</dt>
1169                         <dd>boolean indicating if the newly added member will have blog admin rights or not</dd>
1170                 </dl></td>
1171         </tr>
1172         <tr>
1173                 <td>PostAddTeamMember</td>
1174                 <td>(v2.0) Immediately after a member has been added to a blog team</td>
1175                 <td><dl>
1176                         <dt class="ref obj">blog</dt>
1177                         <dd><code>BLOG</code> object</dd>
1178                         <dt class="ref obj">member</dt>
1179                         <dd><code>MEMBER</code> object</dd>
1180                         <dt class="ro">admin</dt>
1181                         <dd>boolean indicating if the newly added member has admin rights or not</dd>
1182                 </dl></td>
1183         </tr>
1184         <tr>
1185                 <td>PreAddTemplate</td>
1186                 <td>(v2.0) Immediately before a new template is created (note: this one also gets called when a template is cloned))</td>
1187                 <td><dl>
1188                         <dt class="ref">name</dt>
1189                         <dd>name of the new template</dd>
1190                         <dt class="ref">description</dt>
1191                         <dd>description of the new template</dd>
1192                 </dl></td>
1193         </tr>
1194         <tr>
1195                 <td>PostAddTemplate</td>
1196                 <td>(v2.0) Immediately after a new template has been created</td>
1197                 <td><dl>
1198                         <dt class="ro">name</dt>
1199                         <dd>name of the new template</dd>
1200                         <dt class="ro">description</dt>
1201                         <dd>description of the new template</dd>
1202                         <dt class="ro">templateid</dt>
1203                         <dd>ID of the new template</dd>
1204                 </dl></td>
1205         </tr>
1206         <tr>
1207                 <td>PreAddSkin</td>
1208                 <td>(v2.0) Immediately before a new skin is created (note: this one also gets called when a skin is cloned))</td>
1209                 <td><dl>
1210                         <dt class="ref">name</dt>
1211                         <dd>name of the new skin</dd>
1212                         <dt class="ref">description</dt>
1213                         <dd>description of the new skin</dd>
1214                         <dt class="ref">type</dt>
1215                         <dd>content type of the skin</dd>
1216                         <dt class="ref">includeMode</dt>
1217                         <dd>includeMode of the new skin</dd>
1218                         <dt class="ref">includePrefix</dt>
1219                         <dd>includePrefix of the new skin</dd>
1220                 </dl></td>
1221         </tr>
1222         <tr>
1223                 <td>PostAddSkin</td>
1224                 <td>(v2.0) Immediately after a new skin has been created</td>
1225                 <td><dl>
1226                         <dt class="ro">name</dt>
1227                         <dd>name of the new skin</dd>
1228                         <dt class="ro">description</dt>
1229                         <dd>description of the new skin</dd>
1230                         <dt class="ro">type</dt>
1231                         <dd>content type of the skin</dd>
1232                         <dt class="ro">includeMode</dt>
1233                         <dd>includeMode of the new skin</dd>
1234                         <dt class="ro">includePrefix</dt>
1235                         <dd>includePrefix of the new skin</dd>
1236                         <dt class="ro">skinid</dt>
1237                         <dd>ID of the new skin</dd>
1238                 </dl></td>
1239         </tr>
1240         <tr>
1241                 <td>PreAddBan</td>
1242                 <td>(v2.0) Immediately before a new ban is added to a weblog</td>
1243                 <td><dl>
1244                         <dt class="ref">blogid</dt>
1245                         <dd>ID of the blog</dd>
1246                         <dt class="ref">iprange</dt>
1247                         <dd>IP range to be banned</dd>
1248                         <dt class="ref">reason</dt>
1249                         <dd>textual message describing the reason for the ban</dd>
1250                 </dl></td>
1251         </tr>
1252         <tr>
1253                 <td>PostAddBan</td>
1254                 <td>(v2.0) Immediately after a new ban has been added</td>
1255                 <td><dl>
1256                         <dt class="ro">blogid</dt>
1257                         <dd>ID of the blog</dd>
1258                         <dt class="ro">iprange</dt>
1259                         <dd>IP range to be banned</dd>
1260                         <dt class="ro">reason</dt>
1261                         <dd>textual message describing the reason for the ban</dd>
1262                 </dl></td>
1263         </tr>
1264
1265         <tr>
1266                 <td>PreMoveItem</td>
1267                 <td>(v2.0) Immediately before an item is moved to another blog/category</td>
1268                 <td><dl>
1269                         <dt class="ref">itemid</dt>
1270                         <dd>ID of the item</dd>
1271                         <dt class="ref">destblogid</dt>
1272                         <dd>ID of the destination blog</dd>
1273                         <dt class="ref">destcatid</dt>
1274                         <dd>ID of the destination category</dd>
1275                 </dl></td>
1276         </tr>
1277         <tr>
1278                 <td>PostMoveItem</td>
1279                 <td>(v2.0) Immediately after an item has been moved to another blog/category</td>
1280                 <td><dl>
1281                         <dt class="ro">itemid</dt>
1282                         <dd>ID of the item</dd>
1283                         <dt class="ro">destblogid</dt>
1284                         <dd>ID of the new blog</dd>
1285                         <dt class="ro">destcatid</dt>
1286                         <dd>ID of the new category</dd>
1287                 </dl></td>
1288         </tr>
1289         <tr>
1290                 <td>PreMoveCategory</td>
1291                 <td>(v2.0) Immediately before a catgeory is moved to another blog</td>
1292                 <td><dl>
1293                         <dt class="ref">catid</dt>
1294                         <dd>ID of the catgeory</dd>
1295                         <dt class="ref obj">sourceblog</dt>
1296                         <dd>source <code>BLOG</code> object</dd>
1297                         <dt class="ref obj">destblog</dt>
1298                         <dd>destination <code>BLOG</code> object</dd>
1299                 </dl></td>
1300         </tr>
1301         <tr>
1302                 <td>PostMoveCategory</td>
1303                 <td>(v2.0) Immediately after a catgeory has been moved to another blog</td>
1304                 <td><dl>
1305                         <dt class="ro">catid</dt>
1306                         <dd>ID of the catgeory</dd>
1307                         <dt class="ref obj">sourceblog</dt>
1308                         <dd>source <code>BLOG</code> object</dd>
1309                         <dt class="ref obj">destblog</dt>
1310                         <dd>destination <code>BLOG</code> object</dd>
1311                 </dl></td>
1312         </tr>
1313         <tr>
1314                 <td>MemberSettingsFormExtras</td>
1315                 <td>(v2.0) On the member settings page. You can add your own forms here.
1316                         <br /><br />
1317                         Don't add too much data, and please generate <strong>valid XHTML</strong>, looking like this:
1318 <pre class="example"><code>&lt;h4&gt;plugin name&lt;/h4&gt;
1319 &lt;form method="post" action="..."&gt;&lt;p&gt;
1320 your stuff
1321 &lt;/p&gt;&lt;/form&gt;</code></pre>
1322                         This way, multiple plugins can add options here while things keep a good structure. Also try to use prefixes for your fieldnames, in order to avoid nameclashes (e.g. <code>plug_tb_url</code>)
1323
1324                 </td>
1325                 <td><dl>
1326                         <dt class="ref obj">member</dt>
1327                         <dd>reference to a <code>MEMBER</code> object</dd>
1328                 </dl></td>
1329         </tr>
1330         <tr>
1331                 <td>GeneralSettingsFormExtras</td>
1332                 <td>(v2.0) On the general settings page. You can add your own forms here.
1333                         <br /><br />
1334                         Don't add too much data, and please generate <strong>valid XHTML</strong>, looking like this:
1335 <pre class="example"><code>&lt;h4&gt;plugin name&lt;/h4&gt;
1336 &lt;form method="post" action="..."&gt;&lt;p&gt;
1337 your stuff
1338 &lt;/p&gt;&lt;/form&gt;</code></pre>
1339                         This way, multiple plugins can add options here while things keep a good structure. Also try to use prefixes for your fieldnames, in order to avoid nameclashes (e.g. <code>plug_tb_url</code>)
1340
1341                 </td>
1342                 <td>None</td>
1343         </tr>
1344         <tr>
1345                 <td>AdminPrePageHead</td>
1346                 <td>(v2.5) On admin area pages, immediately before the page head is printed. This event could be used to add extra script/css includes in the head section</td>
1347                 <td><dl>
1348                         <dt class="ref">extrahead</dt>
1349                         <dd>Extra information to be included in the head section of the HTML page. Append your extras here.</dd>
1350                         <dt class="ro">action</dt>
1351                         <dd>Currently executed action or pagetype</dd>
1352                 </dl></td>
1353         </tr>
1354         <tr>
1355                 <td>AdminPrePageFoot</td>
1356                 <td>(v2.5) On admin area pages, immediately before the page footer is printed.</td>
1357                 <td><dl>
1358                         <dt class="ro">action</dt>
1359                         <dd></dd>
1360                 </dl>Currently executed action or pagetype</td>
1361         </tr>
1362         <tr>
1363                 <td>PreSendContentType</td>
1364                 <td>(v2.5) Immediately before a content type is being set in the HTTP header</td>
1365                 <td><dl>
1366                         <dt class="ref">contentType</dt>
1367                         <dd>content type (e.g. <code>application/xhtml+xml</code>)</dd>
1368                         <dt class="ref">charset</dt>
1369                         <dd>Character set</dd>
1370                         <dt class="ro">pageType</dt>
1371                         <dd>String indicating which type of page we're displaying: <code>skin</code> (skinparts), <code>media</code> (media library), <code>admin-<em>action</em></code> (admin area), <code>bookmarklet-<em>action</em></code> (bookmarklet)</dd>
1372                 </dl></td>
1373         </tr>
1374         <tr>
1375                 <td>QuickMenu</td>
1376                 <td>(v2.5) At the end of the Admin Area quick menu. This can be used to add extra plugin entries. To add entries, push associative arrays on the <code>options</code> array. An example can be found in the section about <a href="#admin">creating a plugin admin area</a>.</td>
1377                 <td><dl>
1378                         <dt class="ref">options</dt>
1379                         <dd>Array</dd>
1380                 </dl></td>
1381         </tr>
1382         <tr>
1383                 <td>BookmarkletExtraHead</td>
1384                 <td>(v2.5) Somewhere inside the <code>head</code> section of the bookmarklet XHTML code.</td>
1385                 <td><dl>
1386                         <dt class="ref">extrahead</dt>
1387                         <dd>Information to be included in the <code>head</code> section of the XHTML code. Add your extras here.</dd>
1388                 </dl></td>
1389         </tr>
1390         <tr>
1391                 <td>FormExtra</td>
1392                 <td>(v3.2) Inside one of the comment, membermail or account activation forms. This event allows plugins to insert extra fields in the form. This event corresponds with the <code>ValidateForm</code> event that is fires when the form is handled.</td>
1393                 <td><dl>
1394                         <dt class="ro">type</dt>
1395                         <dd>Type of the form from which the event fired.
1396                                 <ul>
1397                                         <li><code>activation</code></li>
1398                                         <li><code>additemform</code> (note: this is not the add item form from the admin area!)</li>
1399                                         <li><code>commentform-loggedin</code></li>
1400                                         <li><code>commentform-notloggedin</code></li>
1401                                         <li><code>membermailform-loggedin</code></li>
1402                                         <li><code>membermailform-notloggedin</code></li>
1403                                 </ul>
1404                         </dd>
1405                         <dt class="ro obj">member</dt>
1406                         <dd>When <code>type</code> is <code>activation</code>, this field contains the details of the member that's being activated</dd>
1407                 </dl></td>
1408         </tr>
1409         <tr>
1410                 <td>ValidateForm</td>
1411                 <td>(v3.2) Called when one of the comment, membermail or account activation forms is being handled. This event allows plugins to perform their own validation on the data, and prevent further handling if something is wrong. When used together with the <code>FormExtra</code> field, it can be used to add extra fields to forms.</td>
1412                 <td><dl>
1413                         <dt class="ro">type</dt>
1414                         <dd>Type of the form being handled
1415                                 <ul>
1416                                         <li><code>membermail</code></li>
1417                                         <li><code>comment</code></li>
1418                                         <li><code>activation</code></li>
1419                                 </ul>
1420                         </dd>
1421                         <dt class="ref">error</dt>
1422                         <dd>When the plugin wants to stop the handling of the form, it needs to fill out a non-empty error string message in this <code>error</code> field. This error message will then be presented to the user.</dd>
1423                         <dt class="ref">comment</dt>
1424                         <dd>On <code>comment</code>-type forms, contains an associative array with the comment data.</dd>
1425                         <dt class="ref">spamcheck</dt>
1426                         <dd>On <code>comment</code>-type forms, the resulting datastructure of the previously called <code>SpamCheck</code> event (associative array)</dd>
1427                         <dt class="ro obj">member</dt>
1428                         <dd>On <code>activation</code>-type forms, contains information about the member being activated.</dd>
1429                 </dl></td>
1430         </tr>
1431         <tr>
1432                 <td>ParseURL</td>
1433                 <td>(v3.22) Called before an URL is resolved from the Nucleus Core. This event allows Plugins to interpret URLs.</td>
1434                 <td><dl>
1435                         <dt class="ro">type</dt>
1436                         <dd>Type of the page, e.g. item, blog, ...</dd>
1437                         <dt class="ro">info</dt>
1438                         <dd>The full URL which should be resolved (the name is derived from the old fashion variable <code>pathinfo</code>).</dd>
1439                         <dt class="ref">complete</dt>
1440                         <dd>Should be set to <b>true</b> if the plugin has resolved the URL and to <b>false</b> if the plugin hasn't resolved the URL.</dd>
1441                 </dl></td>
1442         </tr>
1443         <tr>
1444                 <td>GenerateURL</td>
1445                 <td>(v3.22) Called before an URL is output on the page. Allows plugins to rewrite the output URLs and offer an own URL logic.</td>
1446                 <td><dl>
1447                         <dt class="ro">type</dt>
1448                         <dd>Type of the page, e.g. item, blog, ...</dd>
1449                         <dt class="ro">params</dt>
1450                         <dd>Parameters which should be added to the URL.</dd>
1451                         <dt class="ref">completed</dt>
1452                         <dd>Should be set to <b>true</b> if the plugin returns an URL and to <b>false</b> if the plugin don't returns an URL.</dd>
1453                         <dt class="ref">url</dt>
1454                         <dd>The URL itself which should be output from Nucleus.</dd>
1455                 </dl></td>
1456         </tr>
1457         <tr>
1458                 <td>SpamCheck</td>
1459                 <td>(v3.3) Called when a new comment is added. This event allows anti-spam plugins to mark this comment as spam. A complete descriptions of the <code>SpamCheck</code> event can be found in a seperate document: <a href='http://wakka.xiffy.nl/spamcheck_api'>SpamCheck API 2.0</a>.</td>
1460                 <td><dl>
1461                         <dt class="ref">spamcheck</dt>
1462                         <dd>The spamcheck datastructure</dd>
1463                 </dl></td>
1464         </tr>
1465         <tr>
1466                 <td>PreMediaUpload</td>
1467                 <td>(v3.3) Before an uploaded media file is written to the media directory.</td>
1468                 <td><dl>
1469                         <dt class="ref">collection</dt>
1470                         <dd>The collection where the uploaded file should be saved.</dd>
1471                         <dt class="ro">uploadfile</dt>
1472                         <dd>The temporary name of the uploaded file.</dd>
1473                         <dt class="ref">filename</dt>
1474                         <dd>The filename under which the file should be saved.</dd>
1475                 </dl></td>
1476         </tr>
1477         <tr>
1478                 <td>PostMediaUpload</td>
1479                 <td>(v3.3) After an uploaded is written to the media directory.</td>
1480                 <td><dl>
1481                         <dt class="ro">collection</dt>
1482                         <dd>The collection to which the uploaded file has been added.</dd>
1483                         <dt class="ro">mediadir</dt>
1484                         <dd>The media directory to which the uploaded file has been written.</dd>
1485                         <dt class="ro">filename</dt>
1486                         <dd>The filename under which the file has been saved.</dd>
1487                 </dl></td>
1488         </tr>
1489         <tr>
1490                 <td>SendPing</td>
1491                 <td>(v3.3) Called when a new item is added and the blog is configured to send ping (need NP_Ping installed). This event is used by NP_Ping to ping various weblog listing service (i.e. pingomatic.com)</td>
1492                 <td><dl>
1493                         <dt class="ref">blogid</dt>
1494                         <dd>ID of the blog</dd>
1495                 </dl></td>
1496         </tr>
1497         <tr>
1498                 <td>JustPosted</td>
1499                 <td>(v3.3) Called when a future post appears on the blog the first time. The event is trigger after a skin parse is completed</td>
1500                 <td><dl>
1501                         <dt class="ref">blogid</dt>
1502                         <dd>ID of the blog</dd>
1503                 </dl></td>
1504         </tr>
1505         <tr>
1506                 <td>RegistrationFormExtraFields</td>
1507                 <td>(v3.40) Called from createaccount.php after basic account fields, but before FormExtra event. This event can be used by plugins to add custom fields to the registration form. Plugins that subscribe to this event should also subscribe to PostRegister event to process the added fields. The parameters should be used to fit custom fields into existing format of registration form. Plugins should output the html code needed for their extra fields. For an example of using this event, see the NP_Profile plugin.</td>
1508                 <td><dl>
1509                         <dt class="ro">type</dt>
1510                         <dd>String. Type of registration form. Normally, <code>createaccount.php</code>.</dd>
1511                         <dt class="ro">prelabel</dt>
1512                         <dd>HTML code or string that should be inserted <strong>before</strong> the field label.</dd>
1513                         <dt class="ro">postlabel</dt>
1514                         <dd>HTML code or string that should be inserted <strong>after</strong> the field label.</dd>
1515                         <dt class="ro">prefield</dt>
1516                         <dd>HTML code or string that should be inserted <strong>before</strong> the input field.</dd>
1517                         <dt class="ro">postfield</dt>
1518                         <dd>HTML code or string that should be inserted <strong>after</strong> the input field.</dd>
1519                 </dl></td>
1520         </tr>
1521         <tr>
1522                 <td>TemplateExtraFields</td>
1523                 <td>(v3.40) Called when templates are edited and updated from the admin area. Allows plugin developers to add fields to existing templates to encourage the use of the core template storage system to provide formatting for their output. It is the responsibility of the plugin authors to use the template fields they add and to provide the variables used in those fields. Plugins should also document their variables and provide for a default, either in the code or through a plugin option. <a href="http://forum.nucleuscms.org/viewtopic.php?p=87672#87672" title="Sample">Sample plugin using this event.</a></td>
1524                 <td><dl>
1525                         <dt class="ref">fields</dt>
1526                         <dd>Associative Array. Key should be name of the plugin, i.e. <code>NP_TemplateTest</code>, and value should be an associative array with keys designating the template field name, and values designating the label used for the field. Template field names should be lowercase and incorporate the plugin name to avoid duplication of template field names.</dd>
1527                 </dl></td>
1528         </tr>
1529         <tr>
1530                 <td>PreArchiveListItem</td>
1531                 <td>(v3.40) Called right before the archive list is displayed. Allows plugin developers to add/modify template variables in the Archive List Item field of the template used for displaying archive lists. Plugins should document the variables added. </td>
1532                 <td><dl>
1533                         <dt class="ref">listitem</dt>
1534                         <dd>Associative Array. The key represents the template variable, i.e. <code>month</code>, and the value of the array element is a string representing the value of the template variable. To add a variable, simply add an element to this array with a key-value pair representing the new variable.</dd>
1535                 </dl></td>
1536         </tr>
1537         <tr>
1538                 <td>PreCategoryListItem</td>
1539                 <td>(v3.40) Called right before the category list is displayed. Allows plugin developers to add/modify template variables in the Category List Item field of the template used for displaying category lists. Plugins should document the variables added. </td>
1540                 <td><dl>
1541                         <dt class="ref">listitem</dt>
1542                         <dd>Associative Array. The key represents the template variable, i.e. <code>catname</code>, and the value of the array element is a string representing the value of the template variable. To add a variable, simply add an element to this array with a key-value pair representing the new variable.</dd>
1543                 </dl></td>
1544         </tr>
1545         <tr>
1546                 <td>PreBlogListItem</td>
1547                 <td>(v3.40) Called right before the blog list is displayed. Allows plugin developers to add/modify template variables in the Blog List Item field of the template used for displaying blog lists. Plugins should document the variables added. </td>
1548                 <td><dl>
1549                         <dt class="ref">listitem</dt>
1550                         <dd>Associative Array. The key represents the template variable, i.e. <code>blogname</code>, and the value of the array element is a string representing the value of the template variable. To add a variable, simply add an element to this array with a key-value pair representing the new variable.</dd>
1551                 </dl></td>
1552         </tr>
1553         <tr>
1554                 <td>PreTemplateRead</td>
1555                 <td>(v3.40) Called right before a template is read and its parts returned. Allows plugin developers to change the name of the template being used. NP_MultiLanguage makes use of this event. </td>
1556                 <td><dl>
1557                         <dt class="ref">name</dt>
1558                         <dd>String containing the name of the template being called.</dd>
1559                 </dl></td>
1560         </tr>
1561         <tr>
1562                 <td>CustomLogin</td>
1563                 <td>(v3.40) Called right before local (Nucleus) login. Allows plugin developers to customize the login process. This simplifies external authentication and permits using something beside the displayname, i.e. email address, to be used for the login name. </td>
1564                 <td><dl>
1565                         <dt class="ref">login</dt>
1566                         <dd>String containing the name entered by user in login field. If this is other than the Nucleus mname (display name), it should be mapped by the plugin, after a successful authentication, to a valid mname corresponding to the authenticated member. Otherwise the authentication will last only one page and no cookies will be set.</dd>
1567                         <dt class="ref">password</dt>
1568                         <dd>String containing the password entered by user in password field.</dd>
1569                         <dt class="ref">success</dt>
1570                         <dd>Integer indicating whether the login is successful. 1 means success, 0 means unsuccessful. 0 is the default. The plugin should set this.</dd>
1571                         <dt class="ref">allowlocal</dt>
1572                         <dd>Integer indicating whether local authentication should be tried after an unsuccessful authentication by your plugin. 1 means yes, 0 means no. 1 is the default.</dd>
1573                 </dl></td>
1574         </tr>
1575
1576         <tr>
1577                 <td>PrePasswordSet</td>
1578                 <td>(v3.50) Called when user tries to set password in admin area or during activation. Allows for plugins to enforce password complexity rules.</td>
1579                 <td><dl>
1580                         <dt class="ro">password</dt>
1581                         <dd>String containing the user-entered password.</dd>
1582                         <dt class="ref">errormessage</dt>
1583                         <dd>String containing the error message the user should see upon failure. Should be left blank if no validation error occurs.</dd>
1584                         <dt class="ref">valid</dt>
1585                         <dd>Boolean indicating whether the proposed password is valid. Default is true. Plugin code should check this value to verify it is not already false before processing a password</dd>
1586                 </dl></td>
1587         </tr>
1588         
1589         <tr>
1590                 <td>PostParseURL</td>
1591                 <td>(v3.60) Triggers right after the url is fully parsed (by ParseURL in globalfunctions). Useful to tweak global variables before selector() runs or to set something based on path-related globals.</td>
1592                 <td><dl>
1593                         <dt class="ro">type</dt>
1594                         <dd>Type of the page, e.g. item, blog, ...</dd>
1595                         <dt class="ro">info</dt>
1596                         <dd>The full URL which should be resolved (the name is derived from the old fashion variable <code>pathinfo</code>).</dd>
1597                 </dl></td>
1598         </tr>
1599         
1600         <tr>
1601                 <td>MediaUploadFormExtras</td>
1602                 <td>(v3.60) Add fields to File Upload page of Nucleus Media Manager. All output should be valid XHTML 1.0. You must also subscribe to the PreMediaUpload event and get values from your added fields using requestVar(). </td>
1603                 <td>No Data is passed.</td>
1604         </tr>
1605         <tr>
1606                 <td>PreUpdateSkinPart</td>
1607                 <td>(v4.00) Triggers right before a skin part is updated.</td>
1608                 <td><dl>
1609                         <dt class="ro">skinid</dt>
1610                         <dd>The id of the skin whose part is being updated</dd>
1611                         <dt class="ro">type</dt>
1612                         <dd>The type of skin part being updated, e.g. index, item, member, error, archive, archivelist, etc... For special skin parts, the type is the name of the special skin part.</dd>
1613                         <dt class="ref">content</dt>
1614                         <dd>The new contents of the skin part that is being updated.</dd>
1615                 </dl></td>
1616         </tr>
1617         <tr>
1618                 <td>PreAddSkinPart</td>
1619                 <td>(v4.00) Triggers right before a new skin part is added.</td>
1620                 <td><dl>
1621                         <dt class="ro">skinid</dt>
1622                         <dd>The id of the skin whose part is being added</dd>
1623                         <dt class="ro">type</dt>
1624                         <dd>The type of skin part being added, e.g. index, item, member, error, archive, archivelist, etc... For special skin parts, the type is the name of the special skin part.</dd>
1625                         <dt class="ref">content</dt>
1626                         <dd>The contents of the skin part that is being added.</dd>
1627                 </dl></td>
1628         </tr>
1629         <tr>
1630                 <td>PreDeleteSkinPart</td>
1631                 <td>(v4.00) Triggers right before a skin part is deleted.</td>
1632                 <td><dl>
1633                         <dt class="ro">skinid</dt>
1634                         <dd>The id of the skin whose part is being deleted</dd>
1635                         <dt class="ro">type</dt>
1636                         <dd>The type of skin part being deleted, e.g. index, item, member, error, archive, archivelist, etc... For special skin parts, the type is the name of the special skin part.</dd>
1637                 </dl></td>
1638         </tr>
1639                 <tr>
1640                 <td>PostUpdateSkinPart</td>
1641                 <td>(v4.00) Triggers right after a skin part is updated in the database.</td>
1642                 <td><dl>
1643                         <dt class="ro">skinid</dt>
1644                         <dd>The id of the skin whose part was updated</dd>
1645                         <dt class="ro">type</dt>
1646                         <dd>The type of skin part that was updated, e.g. index, item, member, error, archive, archivelist, etc... For special skin parts, the type is the name of the special skin part.</dd>
1647                         <dt class="ref">content</dt>
1648                         <dd>The new contents of the skin part that was updated.</dd>
1649                 </dl></td>
1650         </tr>
1651         <tr>
1652                 <td>PreAddSkinPart</td>
1653                 <td>(v4.00) Triggers right after a new skin part was added to the database.</td>
1654                 <td><dl>
1655                         <dt class="ro">skinid</dt>
1656                         <dd>The id of the skin whose part was added</dd>
1657                         <dt class="ro">type</dt>
1658                         <dd>The type of skin part that was added, e.g. index, item, member, error, archive, archivelist, etc... For special skin parts, the type is the name of the special skin part.</dd>
1659                         <dt class="ref">content</dt>
1660                         <dd>The contents of the skin part that was added.</dd>
1661                 </dl></td>
1662         </tr>
1663         <tr>
1664                 <td>PreDeleteSkinPart</td>
1665                 <td>(v4.00) Triggers right after a skin part was deleted from the database.</td>
1666                 <td><dl>
1667                         <dt class="ro">skinid</dt>
1668                         <dd>The id of the skin whose part was deleted</dd>
1669                         <dt class="ro">type</dt>
1670                         <dd>The type of skin part that was deleted, e.g. index, item, member, error, archive, archivelist, etc... For special skin parts, the type is the name of the special skin part.</dd>
1671                 </dl></td>
1672         </tr>
1673 <!--    <tr>
1674                 <td></td>
1675                 <td></td>
1676                 <td><dl>
1677                         <dt></dt>
1678                         <dd></dd>
1679                 </dl></td>
1680         </tr>
1681         <tr>
1682                 <td></td>
1683                 <td></td>
1684                 <td><dl>
1685                         <dt></dt>
1686                         <dd></dd>
1687                 </dl></td>
1688         </tr>
1689         <tr>
1690                 <td></td>
1691                 <td></td>
1692                 <td><dl>
1693                         <dt></dt>
1694                         <dd></dd>
1695                 </dl></td>
1696         </tr>
1697         <tr>
1698                 <td></td>
1699                 <td></td>
1700                 <td><dl>
1701                         <dt></dt>
1702                         <dd></dd>
1703                 </dl></td>
1704         </tr>
1705         <tr>
1706                 <td></td>
1707                 <td></td>
1708                 <td><dl>
1709                         <dt></dt>
1710                         <dd></dd>
1711                 </dl></td>
1712         </tr>
1713         <tr>
1714                 <td></td>
1715                 <td></td>
1716                 <td><dl>
1717                         <dt></dt>
1718                         <dd></dd>
1719                 </dl></td>
1720         </tr>
1721         <tr>
1722                 <td></td>
1723                 <td></td>
1724                 <td><dl>
1725                         <dt></dt>
1726                         <dd></dd>
1727                 </dl></td>
1728         </tr> -->
1729 </table>
1730
1731
1732
1733 <h1>Saving options <a name="options" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
1734
1735 <p>A series of methods are offered to make it easy for plugins to set and retrieve options. These options can be directly edited from inside the Nucleus admin area, taking the need away for the plugin to provide an admin area of its own, and avoiding that options need to be set inside the PHP file itself.</p>
1736
1737 <p>Options are available in different contexts:</p>
1738
1739 <ol>
1740         <li><strong>Global options</strong>: Editable on the admin area from the plugins section.</li>
1741         <li><strong>Blog options</strong>: Editable from the blogsettings pages.</li>
1742         <li><strong>Category options</strong>: Editable from the blogsettings pages (on the 'edit category' page).</li>
1743         <li><strong>Member options</strong>: Editable on the 'edit member' pages</li>
1744   <li><strong>Item options</strong>: Editable on the 'add item' or 'edit item' pages</li>
1745 </ol>
1746
1747 <h2>Option types</h2>
1748
1749 <p>Several types of options are provided</p>
1750
1751 <dl>
1752         <dt>text</dt>
1753         <dd>Simple text</dd>
1754         <dt>yesno</dt>
1755         <dd>Either the value '<code>yes</code>' or the value '<code>no</code>' (on edit, shown as radio button)</dd>
1756         <dt>password</dt>
1757         <dd>Text field (starred on edit)</dd>
1758         <dt>textarea (v2.2)</dt>
1759         <dd>Text field with multiple rows and columns</dd>
1760         <dt>select (v2.2)</dt>
1761         <dd>Drop down menu. Needs extra info in the following form: <code>Option 1|value1|Option 2|value2|Option 3|value3</code>
1762         </dd>
1763 </dl>
1764
1765 <h2>Option meta</h2>
1766
1767 <p>As of Nucleus v3.2, some option types can be limited to only accept certain values using option-metadata. This metadata is stored in the <code>$typeExtras</code>-field, and is a semicolon-seperated list of values. Note: In a select-option, the select list must be the first value in <code>$typeExtras</code>.</p>
1768
1769 <table><tr>
1770         <th>key</th>
1771         <th>explanation</th>
1772 </tr><tr>
1773         <td><code>datatype</code></td>
1774         <td>Using '<code>datatype</code>' you can give some extra hints to Nucleus about the datatype you want to use. Currently only '<code>numerical</code>' is available. '<code>numerical</code>' will cause Nucleus to only accept numerical values for this option (using both client-side and server-side check) (available for optiontypes: '<code>select</code>' and '<code>text</code>')</td>
1775 </tr><tr>
1776         <td><code>access</code></td>
1777         <td>If set to '<code>readonly</code>', the option will not be editable (available for optiontypes: '<code>text</code>' and '<code>textarea</code>')<br />
1778         If set to '<code>hidden</code>', the option will be completely hidden for the end-user (available for optiontypes: '<code>text</code>')</td>
1779 </tr></table>
1780
1781 <p>some examples:</p>
1782 <pre class="example"><code>// following code creates a text-option that only accepts numerical values
1783 $this->createBlogOption('FooBar', 'foobar', 'text', '0', 'datatype=numerical');
1784 // following code creates a select-option that only accepts numerical values
1785 $this->createItemOption('FooBar', 'foobar', 'select', '0', '0|0|1|1|2|2;datatype=numerical');
1786 // following code creates a textarea-option that is readonly
1787 $this->createOption('FooBar', 'foobar', 'textarea', 'This textarea is readonly', 'access=readonly');
1788 </code></pre>
1789
1790 <h2>Restrictions</h2>
1791
1792 <ol>
1793         <li>The name of an option can contain a maximum of 20 characters</li>
1794         <li>The description of an option can contain a maximum of 255 characters</li>
1795         <li>The value for an option has no limit (Prior to v2.5 the limit was 128 characters)</li>
1796   <li>The characters '=', '|' and ';' can not be used inside a select list (for a select-option), or in option-metadata</li>
1797 </ol>
1798
1799 <h2>The methods</h2>
1800
1801 <h3>createOption($name, $desc, $type, $defValue = '', $typeExtras = '')</h3>
1802
1803 <p>Creates a new option in the <strong>global</strong> context</p>
1804
1805 <table><tr>
1806         <th>parameter</th>
1807         <th>value</th>
1808 </tr><tr>
1809         <td>$name</td>
1810         <td>Option name</td>
1811 </tr><tr>
1812         <td>$desc</td>
1813         <td>Textual description, to be shown on the page where options can be edited</td>
1814 </tr><tr>
1815         <td>$type</td>
1816         <td>Option type (see above)</td>
1817 </tr><tr>
1818         <td>$defValue</td>
1819         <td>Initial value</td>
1820 </tr><tr>
1821         <td>$typeExtras</td>
1822         <td>Extra info on option type (see above)</td>
1823 </tr></table>
1824
1825 <h3>[v2.2] createBlogOption($name, $desc, $type, $defValue = '', $typeExtras = '')</h3>
1826
1827 <p>Creates an option in the <strong>blog</strong> context (see <code>createOption</code>)</p>
1828
1829 <h3>[v2.2] createCategoryOption($name, $desc, $type, $defValue = '', $typeExtras = '')</h3>
1830
1831 <p>Creates an option in the <code>category</code> context (see <code>createOption</code>)</p>
1832
1833 <h3>[v2.2] createMemberOption($name, $desc, $type, $defValue = '', $typeExtras = '')</h3>
1834
1835 <p>Creates an option in the <code>member</code> context (see <code>createOption</code>)</p>
1836
1837 <h3>[v3.2] createItemOption($name, $desc, $type, $defValue = '', $typeExtras = '')</h3>
1838
1839 <p>Creates an option in the <code>item</code> context (see <code>createOption</code>)</p>
1840
1841 <h3>setOption($name, $value)</h3>
1842
1843 <p>changes the value of an option that was already in the database</p>
1844
1845 <table><tr>
1846         <th>parameter</th>
1847         <th>value</th>
1848 </tr><tr>
1849         <td>$name</td>
1850         <td>Option name</td>
1851 </tr><tr>
1852         <td>$value</td>
1853         <td>New value for option</td>
1854 </tr></table>
1855
1856 <h3>[v2.2] setBlogOption($blogid, $name, $value)</h3>
1857
1858 <p>Changes the value for a blog option. The <code>blogid</code> attribute indicates for which blog the option is valid. (other options: see <code>setOption</code>)</p>
1859
1860 <h3>[v2.2] setCategoryOption($catid, $name, $value)</h3>
1861
1862 <p>Changes the value for a category option. The <code>catid</code> attribute indicates for which category the option is valid. (other options: see <code>setOption</code>)</p>
1863
1864 <h3>[v2.2] setMemberOption($memberid, $name, $value)</h3>
1865
1866 <p>Changes the value for a member option. The <code>memberid</code> attribute indicates for which member the option is valid. (other options: see <code>setOption</code>)</p>
1867
1868 <h3>[v3.2] setItemOption($itemid, $name, $value)</h3>
1869
1870 <p>Changes the value for an item option. The <code>itemid</code> attribute indicates for which item the option is valid. (other options: see <code>setOption</code>)</p>
1871
1872 <h3>getOption($name)</h3>
1873
1874 <p>Returns the value for an option in the database</p>
1875
1876 <table><tr>
1877         <th>parameter</th>
1878         <th>value</th>
1879 </tr><tr>
1880         <td>$name</td>
1881         <td>Option name</td>
1882 </tr></table>
1883
1884 <h3>[v2.2] getBlogOption($blogid, $name)</h3>
1885
1886 <p>Returns the value for a blog option. <code>blogid</code> indicates for which blog a value is requested (other parameters: see <code>getOption</code>)</p>
1887
1888 <h3>[v2.2] getCategoryOption($catid, $name)</h3>
1889
1890 <p>Returns the value for a category option. <code>catid</code> indicates for which category a value is requested (other parameters: see <code>getOption</code>)</p>
1891
1892 <h3>[v2.2] getMemberOption($memberid, $name)</h3>
1893
1894 <p>Returns the value for a member option. <code>memberid</code> indicates for which member a value is requested (other parameters: see <code>getOption</code>)</p>
1895
1896 <h3>[v3.2] getItemOption($itemid, $name)</h3>
1897
1898 <p>Returns the value for an item option. <code>itemid</code> indicates for which item a value is requested (other parameters: see <code>getOption</code>)</p>
1899
1900 <h3>deleteOption($name)</h3>
1901
1902 <p>Deletes an option from the database</p>
1903
1904 <table><tr>
1905         <th>parameter</th>
1906         <th>value</th>
1907 </tr><tr>
1908         <td>$name</td>
1909         <td>Option name</td>
1910 </tr></table>
1911
1912 <h3>[v2.2] deleteBlogOption($name)</h3>
1913
1914 <p>Deletes a blog option (see <code>deleteOption</code>)</p>
1915
1916 <h3>[v2.2] deleteCategoryOption($name)</h3>
1917
1918 <p>Deletes a category option (see <code>deleteOption</code>)</p>
1919
1920 <h3>[v2.2] deleteMemberOption($name)</h3>
1921
1922 <p>Deletes a member option (see <code>deleteOption</code>)</p>
1923
1924 <h3>[v3.2] deleteItemOption($name)</h3>
1925
1926 <p>Deletes an item option (see <code>deleteOption</code>)</p>
1927
1928 <h3>[v2.2] getAllBlogOptions($name)</h3>
1929
1930 <p>Returns all values for a given blog option. The result is an associative array with a value for each existing blogid</p>
1931
1932 <h3>[v2.2] getAllCategoryOptions($name)</h3>
1933
1934 <p>Returns all values for a given category option. The result is an associative array with a value for each existing catid</p>
1935
1936 <h3>[v2.2] getAllMemberOptions($name)</h3>
1937
1938 <p>Returns all values for a given member option. The result is an associative array with a value for each existing memberid</p>
1939
1940 <h3>[v3.2] getAllItemOptions($name)</h3>
1941
1942 <p>Returns all values for a given item option. The result is an associative array with a value for each existing itemid</p>
1943
1944 <h3>[v3.2] getBlogOptionTop($name, $amount = 10, $sort = 'desc')</h3>
1945
1946 <p>Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each blogid ('id')</p>
1947
1948 <table><tr>
1949         <th>parameter</th>
1950         <th>value</th>
1951 </tr><tr>
1952         <td>$name</td>
1953         <td>Option name</td>
1954 </tr><tr>
1955         <td>$amount</td>
1956         <td>The amount of options you want</td>
1957 </tr><tr>
1958         <td>$sort</td>
1959         <td>Sort ascending ('asc') or descending ('desc')</td>
1960 </tr></table>
1961
1962 <h3>[v3.2] getMemberOptionTop($name, $amount = 10, $sort = 'desc')</h3>
1963
1964 <p>Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each memberid ('id') (parameters: see <code>getBlogOptionTop</code>)</p>
1965
1966 <h3>[v3.2] getCategoryOptionTop($name, $amount = 10, $sort = 'desc')</h3>
1967
1968 <p>Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each categoryid ('id') (parameters: see <code>getBlogOptionTop</code>)</p>
1969
1970 <h3>[v3.2] getItemOptionTop($name, $amount = 10, $sort = 'desc')</h3>
1971
1972 <p>Returns the top of the values for a given option. The result is an array where every element is an array with a value ('value') for each itemid ('id') (parameters: see <code>getBlogOptionTop</code>)</p>
1973
1974 <div class="note">
1975 <b>Note:</b> You can't call these functions from inside constructors of plugin classes. If you want to execute them when the plugin is loaded, place them in the <code>init()</code> method instead.
1976 </div>
1977
1978 <h1>Database tables <a name="tables" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
1979
1980 <h2>Access to Nucleus tables</h2>
1981
1982 <p>Up to v2.0, accessing the nucleus tables was just a matter of performing an SQL query on one of the <code>nucleus_</code> tables. Since it is possible to use a custom table name in Nucleus versions >2.0, some precautions are needed in plugin development:</p>
1983
1984 <p>As of v3.5, Nucleus is moving toward support for database handlers different from MySQL, such as PDO. Though, this support is beta in version 3.5, plugin developers need to start making their plugins compatible with the new sql_* api used to implement the generic database calls. 
1985 Essentially, you need onnly replace any mysql_* functions with sql_*, e.g. <code>mysql_fetch_assoc($result)</code> becomes <code>sql_fetch_assoc($result)</code>. 
1986 you must do this for every interaction with the database. Be sure to indicate that you support the SqlApi feature as indicated below, and that you set the minNucleusVersion to 350, like this: <br /><code>function getMinNucleusVersion( return '350';)</code></p>
1987
1988 <ol>
1989         <li>Instead of using a fixed tablename like <code>nucleus_item</code>, use the global function <code>sql_table('item')</code> to generate the prefixed tablename</li>
1990         <li>Make sure your plugin returns <code>1</code> (<code>true</code>) when <code>supportsFeature('SqlTablePrefix')</code> is called on it. If it doesn't, you won't be able to load the plugin on Nucleus versions > 2.0 when a custom prefix has been set (as a precaution)</li>
1991         <li>v3.5+. Make sure your plugin returns <code>1</code> (<code>true</code>) when <code>supportsFeature('SqlApi')</code> is called on it. If it doesn't, you won't be able to load the plugin on Nucleus versions > 3.5 when a user is using a non-mysql database backend (as a precaution)</li>
1992 </ol>
1993
1994 <p class="note">Note that the <code>sql_table</code> global function in not available in Nucleus versions up to v2.0. If you use this method and want your plugin to work on Nucleus versions &lt;= 2.0, add the following snippet of code on top of your plugin class:</p>
1995
1996 <pre class="example"><code>&lt;?php
1997
1998 // plugin needs to work on Nucleus versions &amp;=2.0 as well
1999 if (!function_exists('sql_table'))
2000 {
2001         function sql_table($name) {
2002                 return 'nucleus_' . $name;
2003         }
2004 }
2005
2006 class NP_HelloWorld extends NucleusPlugin {
2007 ...
2008 }
2009
2010 ?&gt;</code></pre>
2011
2012 <h2>Your own tables</h2>
2013
2014 <p>If your plugin needs database tables of it's own, you should create them in the <code>install</code> method and remove them in the <code>unInstall</code> method.</p>
2015
2016 <p>Some pointers</p>
2017 <ul>
2018         <li>Consider using a table name like <code>nucleus_plug_<i>plugname</i></code> to avoid conflicts with other plugins. Generate them through <code>sql_table('plug_plugname')</code> to make it work with custom prefixes</li>
2019         <li>You don't need to make a database connection yourself. You can execute queries using the Nucleus function <code>sql_query()</code> which is a wrapper for the PHP command <code>mysql_query()</code></li>
2020         <li>If you do make a database connection yourself, make sure to restore the connection with the Nucleus database afterwards. You can do this by calling <code>sql_connect()</code> at the end of your function. It might also be good to do this from the constructor, to avoid reconnecting constantly. You could then save your link identifier in <code>$this->db</code> and pass that along with every query.</li>
2021         <li>Also redefine the <code>getTableList()</code> method to make sure your table gets backed up when using the backup function.</li>
2022         <li>It's a good idea to make the removal of your database tables optional. This will allow your users to temporarily remove your plugin without losing the data. For instance, you may need to make changes to options or database tables requiring that the install() method be run to execute code neccessary to modify existing tables or options. This will require that your users uninstall the old version and then install the new version and losing their data in the process. To make the deletion of your tables optional, you can add an option like this in install():
2023         <pre class="example"><code>$this->createOption('del_uninstall', 'Delete NP_MyPlugin data tables on uninstall?', 'yesno','no');</code></pre>
2024         and this snippet in uninstall():
2025         <pre class="example"><code>if ($this->getOption('del_uninstall') == 'yes')      {
2026         foreach ($this->getTableList() as $table) {
2027                 sql_query("DROP TABLE $table");
2028         }
2029 }</code></pre></li>
2030 </ul>
2031
2032
2033
2034 <h1>Plugin Admin Area <a name="admin" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
2035
2036 <p>As of Nucleus v2.5, plugins can create admin area pages that integrate with the Nucleus admin area. These pages can be accessed either from the plugin admin page, or the quickmenu on the left.</p>
2037
2038 <h2>Basics</h2>
2039
2040 <p>To provide an admin area, you'll need to take these steps:</p>
2041
2042 <ol>
2043   <li>Create a subdirectory of the plugins directory, and name it <strong>pluginname</strong> if your plugin is <code>NP_PluginName</code>. Note that the name should be <strong>lowercase</strong>!</li>
2044   <li>
2045         In that directory, create a file called <strong>index.php</strong>, which looks like this:
2046         <pre><code>&lt;?php
2047
2048         // if your 'plugin' directory is not in the default location,
2049         // edit this variable to point to your site directory
2050         // (where config.php is)
2051         $strRel = '../../../';
2052
2053         include($strRel . 'config.php');
2054         if (!$member->isLoggedIn())
2055                 doError('You\'re not logged in.');
2056
2057         include($DIR_LIBS . 'PLUGINADMIN.php');
2058
2059         // create the admin area page
2060         $oPluginAdmin = new PluginAdmin('<strong>PluginName</strong>');
2061         $oPluginAdmin->start();
2062
2063         echo '&lt;h2&gt;Plugin Name&lt;/h2&gt;';
2064
2065         echo '&lt;p&gt;<strong>Page contents here</strong>&lt;p&gt;';
2066
2067         $oPluginAdmin->end();
2068
2069 ?&gt;</code></pre>
2070   </li>
2071   <li>
2072         Subscribe to the <code>QuickMenu</code> event and add this code in your plugin:
2073         <pre><code>function event_QuickMenu(&amp;$data) {
2074                 array_push(
2075                         $data['options'],
2076                         array(
2077                                 'title' => '<strong>Plugin Name</strong>',
2078                                 'url' => $this->getAdminURL(),
2079                                 'tooltip' => '<strong>Tooltip text</strong>'
2080                         )
2081                 );
2082         }</code></pre>
2083   </li>
2084   <li>
2085         Implement this method in your plugin:
2086         <pre><code>function hasAdminArea()
2087 {
2088         return 1;
2089 }</code></pre>
2090   </li>
2091   <li> Optional. Make the <code>QuickMenu</code> entry optional, and restrict who sees it. The following assumes that an option, of type <code>yesno</code> and called <code>quickmenu</code>, exists in install(). It also will restrict viewing of the <code>QuickMenu</code> entry to super-admins and to blog-admins.
2092         <pre class="example"><code>function event_QuickMenu(&$data) {
2093     // only show when option enabled
2094     if ($this->getOption('quickmenu') != 'yes') return;
2095     global $member;
2096     if (!$member->isAdmin() && !count($member->getAdminBlogs())) return;
2097     array_push($data['options'],
2098         array('title' => 'PluginName',
2099         'url' => $this->getAdminURL(),
2100         'tooltip' => 'Administer NP_PluginName'));
2101 }</code></pre>
2102   </li>
2103 </ol>
2104
2105 <h2>Considerations</h2>
2106
2107 <ul>
2108  <li>Don't just add an entry to the quick menu because it is possible. Imagine having 100 plugins installed, which all add an entry in the menu. This would result in a real mess. So, even if you add an entry in the menu, please consider adding an option (global or member-level) to enable/disable the quick menu entry.</li>
2109  <li>The <code>$strRel</code> variable in the <code>index.php</code> needs to be adapted manually if the plugins directory is not located in <code>nucleus/plugins/</code></li>
2110  <li>Make sure your admin area outputs <strong>valid XHTML</strong>. If not, the page will be broken in Gecko-based (Mozilla etc) browsers.</li>
2111 </ul>
2112
2113 <h2>The PluginAdmin class</h2>
2114
2115 <p>The purpose of the <code>PluginAdmin</code> is to help you. Once created, you can use <code>$oPluginAdmin->plugin</code> to access the instance of your plugin.</p>
2116
2117 <h1>Plugin HelpPage <a name="help" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
2118
2119 <p>As of Nucleus v3.2 plugins can provide a helppage with an overview of the plugins' functionality, the available skinvars and templatevars, where to get more info,...</p>
2120
2121 <p>The helppage will be accessible from the plugin overview in the admin area.</p>
2122
2123 <h2>Basics</h2>
2124 <p>To provide a helppage, you'll need take these steps:</p>
2125 <ol>
2126 <li>Create a subdirectory of the plugins directory, and name it pluginname if your plugin is NP_PluginName. Note that the name should be lowercase! This is actually the same directory as for the <a href="#admin">admin area</a>.</li>
2127 <li>In that directory, create a file called help.html. In this file you can document your plugin. This is a good template to start from:
2128 <pre><code>&lt;h3&gt;Plugin overview&lt;/h3&gt;
2129
2130 &lt;p&gt;The only purpose of this plugin is to show how the plugin helppages work&lt;/p&gt;
2131
2132 &lt;h3&gt;Installation&lt;/h3&gt;
2133
2134 &lt;p&gt;If you can read this you correctly installed the plugin :-)&lt;/p&gt;
2135
2136 &lt;h3&gt;SkinVars&lt;/h3&gt;
2137
2138 &lt;p&gt;Because this plugin is only a testcase it doesn't has any skinvars/templatevars but suppose it would have:
2139
2140 &lt;ul&gt;&lt;li&gt;&lt;b&gt;&lt;%HelpPageTestCase1%&gt;&lt;/b&gt;: does something&lt;/li&gt;
2141 &lt;li&gt;&lt;b&gt;&lt;%HelpPageTestCase1(foobar)%&gt;&lt;/b&gt;: does something else&lt;/li&gt;&lt;/ul&gt;&lt;/p&gt;
2142
2143 &lt;h3&gt;Support and Bug reports&lt;/h3&gt;
2144
2145 &lt;p&gt;For additional support and/or bug reports please use this forum thread:
2146 &lt;a href="http://forum.nucleuscms.org/viewtopic.php?t=&lt;TOPIC_ID_GOES_HERE&gt;"&gt;
2147 http://forum.nucleuscms.org/viewtopic.php?t=&lt;TOPIC_ID_GOES_HERE&gt;&lt;/a&gt;&lt;/p&gt;
2148
2149 &lt;h3&gt;Version History&lt;/h3&gt;
2150
2151 &lt;ul&gt;&lt;li&gt;Version 0.1: initial testcaseversion&lt;/li&gt;
2152 &lt;li&gt;Version 0.0: pre-initial version ;-)&lt;/li&gt;&lt;/ul&gt;</code></pre>
2153 </li>
2154 <li>Return a value larger than 0 for supportsFeature('HelpPage'):
2155 <pre><code>function supportsFeature($what) {
2156         switch($what) {
2157         case 'HelpPage':
2158                 return 1;
2159           default:
2160                 return 0;
2161         }
2162   }</code></pre>
2163 </li>
2164 </ol>
2165
2166 <h1>Plugin Dependency Check <a name="dependency" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
2167
2168 <p>Starting from 3.2, a new plugin interface is added to allow one to declare any dependency on other plugin(s). This is useful for any
2169 plugin that requires another plugin to function. It is particularly useful for a plugin to detect broken dependencies that prevent if from functioning properly.</p>
2170
2171 <h2>How to write a plugin that utilizes this function</h2>
2172
2173 <p>Let's start from a real world example:</p>
2174
2175 <p>NP_PageLinkList depends on NP_BlogWithOffset to function, so we want to make sure a user cannot install NP_PageLinkList whithout first installing
2176 NP_BlogWithOffset. With this API, Nucleus offers a way for a plugin to detect any missing dependency before it is installed.</p>
2177
2178 <p>In this case, we want to code into NP_PageLinkList to mark that it requires NP_BlogWithOffset. When the plugin is installed, the core calls a
2179 function in the plugin called <code>getPluginDep()</code>. This function returns a list of plugin it requires, and the core will check against all installed plugins and
2180 refuse to install the plugin if a dependency is missing.</p>
2181
2182 <p>All we have to do is add this function to NP_PageLinkList:</p>
2183
2184 <pre><code>function getPluginDep() {
2185          return array('NP_BlogWithOffset');
2186 }</code></pre>
2187
2188 <p>The plugin dependency check also prevent a plugin from being uninstalled if other plugins have a dependancy on it.</p>
2189
2190 <h1>Internationalizing Your Plugin <a name="internationalization" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
2191
2192 <p>Internationalization of a plugin allows your plugin to be easily used by people all over the world, people who do not 
2193 use the same language as you do. It requires a little additional work for you, but makes translating the output of your plugin 
2194 as easy as translating a few phrases in a text file. Below is a description of the standard method suggested for use by Nucleus plugins. 
2195 Thanks to Andy Matsubara for the instructions.</p>
2196
2197 <ol>
2198         <li><strong>Develop your plugin</strong>
2199
2200 At first, it is easier to develop it in your language. Use of translation files is recommended after the plugin becomes stable.</li>
2201         <li><strong>Create plugin directory</strong>
2202
2203 If your plugin name is NP_AbcDef, the plugin directory name is abcdef (always lower case).</li>
2204         <li><strong>Create translation files</strong>
2205
2206 Create the translation files in the directory of your plugin. The name of the language file must be the same as that of the Nucleus translation file name. For example, english.php is for English and default use. japanese-utf8.php for Japanese(UTF-Cool,japanese-euc.php for Japanese(EUC-JP).</li>
2207         <li><strong>Define strings</strong>
2208
2209 Define strings like below in the translation file:
2210
2211 <pre class="example"><code>&lt;?php
2212 define('_ABCDEF_MESSAGENAME',                  'actual strings in the language');
2213   . . .
2214 ?&gt;</code></pre>
2215
2216 You have to define them for all static strings in your plugin. As defined name is used globally in the environment, it is recommended to have a prefix derived from the plugin name(in this case _ABCDEF).</li>
2217         <li><strong>Replace static strings</strong>
2218
2219 Replace static strings in your plugin with the defined names so they will change according to the translation file.</li>
2220         <li><strong>Create init method</strong>
2221
2222 Make the init method in the plugin like below
2223
2224 <pre class="example"><code>   function init() {
2225       // include translation file for this plugin
2226       $language = preg_replace( '#[\\|/]#', '', getLanguageName());
2227       if (file_exists($this->getDirectory().$language.'.php'))
2228          include_once($this->getDirectory().$language.'.php');
2229       else
2230          include_once($this->getDirectory().'english.php');
2231    }</code></pre>
2232 </li>
2233 This logic is same as Nucleus' translation file setting.
2234         <li><strong>Add translation files</strong>
2235
2236 As English is the default language, it is recommended to have at least the English version.     </li>
2237 </ol>
2238
2239
2240
2241 <h1>Formatting your SkinVar output <a name="skinvar-formatting" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
2242
2243 <p>Some great plugin ideas never receive general use simply because the output generated by the <code>doSkinVar()</code> method is not flexible enough to meet the needs of 
2244 different skins or URL schemes. Nucleus provides some tools to help you generalize your output in ways that allow each user to fit it to his or her needs.</p>
2245
2246 <p>To create links to Nucleus pages, such as blogs, categories, items, member details, action.php, admin area, or the plugin admin page, use the built in Nucleus functions 
2247 and global variables described below:</p>
2248
2249 <table summary="An overview of functions and variables useful in creating links to Nucleus pages">
2250         <caption>Functions and variables useful in creating links to Nucleus pages</caption>
2251         <tr>
2252                 <th>Name</th><th>What</th><th>Parameters</th><th>Description</th>
2253         </tr>
2254         <tr>
2255                 <td><code>$CONF['AdminURL']</code></td>
2256                 <td>Global variable</td>
2257                 <td>None</td>
2258                 <td>Full URL to the Nucleus Admin Area</td>
2259         </tr>
2260         <tr>
2261                 <td><code>$CONF['PluginURL']</code></td>
2262                 <td>Global variable</td>
2263                 <td>None</td>
2264                 <td>Full URL to the Nucleus plugins directory. Use it to link to a plugin's admin page, like this <code>$CONF['PluginURL'].'pluginname/'</code></td>
2265         </tr>
2266         <tr>
2267                 <td><code>$CONF['ActionURL']</code></td>
2268                 <td>Global variable</td>
2269                 <td>None</td>
2270                 <td>Full URL to the Nucleus action.php file</td>
2271         </tr>
2272         <tr>
2273                 <td><code>$CONF['MediaURL']</code></td>
2274                 <td>Global variable</td>
2275                 <td>None</td>
2276                 <td>Full URL to the Nucleus media folder</td>
2277         </tr>
2278         <tr>
2279                 <td><code>$CONF['SkinsURL']</code></td>
2280                 <td>Global variable</td>
2281                 <td>None</td>
2282                 <td>Full URL to the Nucleus skins folder</td>
2283         </tr>
2284         <tr>
2285                 <td><code>$CONF['IndexURL']</code></td>
2286                 <td>Global variable</td>
2287                 <td>None</td>
2288                 <td>Full URL to the main Nucleus directory.</td>
2289         </tr>
2290         <tr>
2291                 <td><code>$DIR_NUCLEUS</code></td>
2292                 <td>Global variable</td>
2293                 <td>None</td>
2294                 <td>Full system path to the Nucleus Admin folder</td>
2295         </tr>
2296         <tr>
2297                 <td><code>$DIR_SKINS</code></td>
2298                 <td>Global variable</td>
2299                 <td>None</td>
2300                 <td>Full system path to the Nucleus skins folder</td>
2301         </tr>
2302         <tr>
2303                 <td><code>$DIR_MEDIA</code></td>
2304                 <td>Global variable</td>
2305                 <td>None</td>
2306                 <td>Full system path to the Nucleus media folder</td>
2307         </tr>
2308         <tr>
2309                 <td><code>$DIR_PLUGINS</code></td>
2310                 <td>Global variable</td>
2311                 <td>None</td>
2312                 <td>Full system path to the Nucleus plugins folder</td>
2313         </tr>
2314         <tr>
2315                 <td><code>$DIR_LANG</code></td>
2316                 <td>Global variable</td>
2317                 <td>None</td>
2318                 <td>Full system path to the Nucleus language folder</td>
2319         </tr>
2320         <tr>
2321                 <td><code>$DIR_LIBS</code></td>
2322                 <td>Global variable</td>
2323                 <td>None</td>
2324                 <td>Full system path to the Nucleus libs folder</td>
2325         </tr>
2326         <tr>
2327                 <td><code>getAdminURL()</code></td>
2328                 <td>method, PLUGIN class</td>
2329                 <td>None</td>
2330                 <td>Returns the URL of where the admin area of the plugin is located (if there is no such admin area, this information is invalid)</td>
2331         </tr>
2332         <tr>
2333                 <td><code>getDirectory()</code></td>
2334                 <td>method, PLUGIN class</td>
2335                 <td>None</td>
2336                 <td>Returns the full system path where the extra files for the plugin are stored (if there are no such files, this information makes no sense). The result is something like ".../nucleus/plugins/plugname/"</td>
2337         </tr>
2338         <tr>
2339                 <td><code>Link::create_item_link($itemid, $extra = '')</code></td>
2340                 <td>Public function</td>
2341                 <td><code>$itemid</code> Integer. ID of item being linked.<br />
2342                         <code>$extra</code> Associative Array. Containing key-value pairs corresponding to additional parameters-values that should appear in the link.
2343                 </td>
2344                 <td>Returns the full URL, in scheme chosen by user, of item indicated by <code>$itemid</code></td>
2345         </tr>
2346         <tr>
2347                 <td><code>Link::create_member_link($memberid, $extra = '')</code></td>
2348                 <td>Public function</td>
2349                 <td><code>$memberid</code> Integer. ID of member being linked.<br />
2350                         <code>$extra</code> Associative Array. Containing key-value pairs corresponding to additional parameters-values that should appear in the link.
2351                 </td>
2352                 <td>Returns the full URL, in scheme chosen by user, of member page indicated by <code>$memberid</code></td>
2353         </tr>
2354         <tr>
2355                 <td><code>Link::create_category_link($catid, $extra = '')</code></td>
2356                 <td>Public function</td>
2357                 <td><code>$catid</code> Integer. ID of category being linked.<br />
2358                         <code>$extra</code> Associative Array. Containing key-value pairs corresponding to additional parameters-values that should appear in the link.
2359                 </td>
2360                 <td>Returns the full URL, in scheme chosen by user, of category index page indicated by <code>$catid</code></td>
2361         </tr>
2362         <tr>
2363                 <td><code>Link::create_archivelist_link($blogid = '', $extra = '')</code></td>
2364                 <td>Public function</td>
2365                 <td><code>$blogid</code> Integer. ID of blog whose archivelist is being linked.<br />
2366                         <code>$extra</code> Associative Array. Containing key-value pairs corresponding to additional parameters-values that should appear in the link.
2367                 </td>
2368                 <td>Returns the full URL, in scheme chosen by user, of archivelist page indicated by <code>$blogid</code></td>
2369         </tr>
2370         <tr>
2371                 <td><code>Link::create_archive_link($blogid, $archive, $extra = '')</code></td>
2372                 <td>Public function</td>
2373                 <td><code>$blogid</code> Integer. ID of blog whose archive is being linked.<br />
2374                         <code>$archive</code> String. Valid archive parameter for date (year-month) being linked.<br />
2375                         <code>$extra</code> Associative Array. Containing key-value pairs corresponding to additional parameters-values that should appear in the link.
2376                 </td>
2377                 <td>Returns the full URL, in scheme chosen by user, of archive page indicated by <code>$blogid</code> and <code>$archive</code></td>
2378         </tr>
2379         <tr>
2380                 <td><code>Link::create_blogid_link($blogid, $extra = '')</code></td>
2381                 <td>Public function</td>
2382                 <td><code>$blogid</code> Integer. ID of blog being linked.<br />
2383                         <code>$extra</code> Associative Array. Containing key-value pairs corresponding to additional parameters-values that should appear in the link.
2384                 </td>
2385                 <td>Returns the full URL, in scheme chosen by user, of main index page indicated by <code>$blogid</code></td>
2386         </tr>
2387 </table>
2388
2389 <p>Using a template to format your output is always a good idea. You may want to output an unordered list, but another user may want the same data 
2390 separated by a simple character, or other unique format. Nucleus provides two ways to create and store the template data. In both 
2391 examples below, we will be creating a template with 2 variables, <code>&lt;%foo%&gt;</code> and <code>&lt;%bar%&gt;</code>.</p>
2392
2393 <ol>
2394         <li><strong>Using Plugin Options</strong>. This method may be the simplest and will work on all versions 3.2 and higher. It's 
2395         big disadvantage is that plugin options are deleted during an uninstall, so your users may lose customizations during an upgrade of 
2396         your plugin. Simply create an option in the <code>install()</code> method like the following:
2397         <pre class="example"><code>$this->createOption('my_template', 
2398                 'Template used to format output of plugin.', 
2399                 'textarea', 
2400                 '&lt;li&gt;&lt;%foo%&gt; loves &lt;%bar%&gt;&lt;/li&gt;');</code></pre>
2401         Then in the <code>doSkinVar()</code> method, determine the values of <code>foo</code> and <code>bar</code> and fill the template like this:
2402         <pre class="example"><code>$mytemplate = $this->getOption('my_template');
2403 $couples = array(
2404                         array(
2405                                 'foo'=>'Ricky',
2406                                 'bar'=>'Lucy'),
2407                         array(
2408                                 'foo'=>'Sid',
2409                                 'bar'=>'Nancy'),
2410                         array(
2411                                 'foo'=>'Mickey',
2412                                 'bar'=>'Minnie')
2413                         );
2414 foreach ($couples as $values) {
2415         echo Template::fill($mytemplate,$values);
2416 }</code></pre>
2417         Now the skinvar for our plugin <code>&lt;%TemplateTest%&gt;</code> will output three lines like this:
2418         <pre class="example"><code>&lt;li&gt;Ricky loves Lucy&lt;/li&gt;
2419 &lt;li&gt;Sid loves Nancy&lt;/li&gt;
2420 &lt;li&gt;Mickey loves Minnie&lt;/li&gt;</code></pre>
2421         </li>
2422         
2423         <li><strong>Using Nucleus Core Template System</strong>. This method will only work with versions 3.4 and higher. It has the advantage of 
2424         being using the database-stored template system and can be exported like other template fields. For a full sample plugin using this method, 
2425         see this <a href="http://forum.nucleuscms.org/viewtopic.php?p=87672#87672" title="Sample">thread from the support forum</a>. A summary is given here. 
2426         First, create the option in <code>install()</code> as in method 1, but now we will use it as a default.
2427         <pre class="example"><code>$this->createOption('my_template', 
2428                 'Template used to format output of plugin.', 
2429                 'textarea', 
2430                 '&lt;li&gt;&lt;%foo%&gt; loves &lt;%bar%&gt;&lt;/li&gt;');</code></pre>
2431         Then, subscribe to the <code>TemplateExtraFields</code> event like this:
2432         <pre class="example"><code>function getEventList() { return array('TemplateExtraFields'); }</code></pre>
2433         Then, create a <code>event_TemplateExtraFields</code> method in your plugin, like this:
2434         <pre class="example"><code>function event_TemplateExtraFields(&$data) {
2435     /* Add an element in the $data['fields'] array using your plugin name as the key 
2436         and an associative array containing the field name and field label*/
2437     /* note that your field names should be lowercase and include the name 
2438         of your template as shown below. This will ensure that all template field names are unique. */
2439     $data['fields']['NP_TemplateTest'] = array(
2440         'templatetest_body'=>'TemplateTest Body'
2441     );
2442 }</code></pre>
2443         Then, in the <code>doSkinVar()</code> method, you need to retrieve the template and fill it. Note the skinvar now needs to take 
2444         the template name as a parameter.
2445         <pre class="example"><code>function doSkinVar($skinType,$template = '') {
2446         global $blog, $CONF, $manager,$member;
2447
2448         $template =& $manager->getTemplate($template);
2449         if (trim($template['templatetest_body']) == '')
2450                 $template['templatetest_body'] = $this->getOption('my_template');
2451                 
2452         $couples = array(
2453                         array(
2454                                 'foo'=>'Ricky',
2455                                 'bar'=>'Lucy'),
2456                         array(
2457                                 'foo'=>'Sid',
2458                                 'bar'=>'Nancy'),
2459                         array(
2460                                 'foo'=>'Mickey',
2461                                 'bar'=>'Minnie')
2462                         );
2463         foreach ($couples as $values) {
2464                 echo Template::fill($template['templatetest_body'],$values);
2465         }       
2466 }</code></pre>
2467         Here, the user needs to go to the template he wants to use and enter the formatting he desires into the TemplateTest Body field. 
2468         For our purposes, we are using the default/index template. He may enter something like this:
2469         <pre class="example"><code>&lt;li&gt;&lt;%foo%&gt; loves &lt;%bar%&gt;!!!&lt;/li&gt;</code></pre>
2470         And using a SkinVar like <code>&lt;%TemplateTest(default/index)%&gt;</code> will output this:
2471         <pre class="example"><code>&lt;li&gt;Ricky loves Lucy!!!&lt;/li&gt;
2472 &lt;li&gt;Sid loves Nancy!!!&lt;/li&gt;
2473 &lt;li&gt;Mickey loves Minnie!!!&lt;/li&gt;</code></pre>
2474         </li>
2475         
2476         <li><strong>Formatting Items Using Regular Template</strong>. This applies only to versions 3.40 and higher and for 
2477         plugins which output items. It has the advantage of using the existing Item fields in the core template system, 
2478         just like the <code>&lt;%blog%&gt;</code> SkinVar does. This requires the use of a method in the BLOG class called 
2479         <code>readLogFromList()</code> and requires that you input an array of itemids and a template name. If you need to 
2480         add variables to the template, you can do so using the <code>doTemplateVar()</code> method. Here is an example of 
2481         a <code>doSkinVar()</code> method that uses this technique. It takes 4 itemids as parameters, then outputs those four 
2482         items using the default/index template
2483         <pre class="example"><code>function doSkinVar($skinType,$item1 = 0,$item2 = 0,$item3 = 0,$item4 = 0) {
2484         global $blog;
2485         $highlight = '';
2486         $template = 'default/index';
2487         $item_array = array($item1,$item2,$item3,$item4);
2488         $blog->readLogFromList($item_array, $template);
2489 }</code></pre>
2490         
2491         </li>
2492 </ol>
2493
2494
2495 <h1>Additional Reading <a name="additional-reading" href="#top" class="toplink"><img src="../icon-up.gif" width="15" height="15" alt="back to top" /></a></h1>
2496
2497 <p>As this document is intended to get you started, there are other resources available that offer additional insight.</p>
2498 <ul>
2499 <li><a href="http://wiki.nucleuscms.org/plugindev:index" title="Development Wiki">Development Wiki</a></li>
2500 <li><a href="sqltables.html" title="Database Tables">Nucleus Database Table Structure</a></li>
2501 <!-- <li><a href="" title=""></a></li> -->
2502 </ul>
2503
2504 <!--
2505 <pre class="example"><code></code></pre>
2506 <pre class="example"><code></code></pre>
2507 <pre class="example"><code></code></pre>
2508 <pre class="example"><code></code></pre>
2509 -->
2510
2511 </body>
2512 </html>