]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - doc/Plugin-System.md
Bump version to v0.9.0
[github/shaarli/Shaarli.git] / doc / Plugin-System.md
CommitLineData
992af0b9 1#Plugin System
5409ade2 2[**I am a developer.** Developer API.](#developer-api)[](.html)
992af0b9
V
3
4[**I am a template designer.** Guide for template designer.](#guide-for-template-designer)[](.html)
5
5409ade2 6## Developer API
992af0b9
V
7
8### What can I do with plugins?
9
10The plugin system let you:
11
12 * insert content into specific places across templates.
13 * alter data before templates rendering.
14 * alter data before saving new links.
15
16### How can I create a plugin for Shaarli?
17
18First, chose a plugin name, such as `demo_plugin`.
19
20Under `plugin` folder, create a folder named with your plugin name. Then create a <plugin_name>.php file in that folder.
21
22You should have the following tree view:
23
24```
25| index.php
26| plugins/
27|---| demo_plugin/
28| |---| demo_plugin.php
29```
30
b230bf20
A
31### Plugin initialization
32
33At the beginning of Shaarli execution, all enabled plugins are loaded. At this point, the plugin system looks for an `init()` function to execute and run it if it exists. This function must be named this way, and takes the `ConfigManager` as parameter.
34
35 <plugin_name>_init($conf)
36
37This function can be used to create initial data, load default settings, etc. But also to set *plugin errors*. If the initialization function returns an array of strings, they will be understand as errors, and displayed in the header to logged in users.
38
992af0b9
V
39### Understanding hooks
40
41A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
42
43These functions need to be named with this pattern:
44
45```
b230bf20 46hook_<plugin_name>_<hook_name>($data, $conf)
992af0b9
V
47```
48
b230bf20
A
49Parameters:
50
51 - data: see [$data section](https://github.com/shaarli/Shaarli/wiki/Plugin-System#plugins-data)[](.html)
52 - conf: the `ConfigManager` instance.
53
992af0b9
V
54For exemple, if my plugin want to add data to the header, this function is needed:
55
b230bf20 56 hook_demo_plugin_render_header
992af0b9
V
57
58If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header.
59
60### Plugin's data
61
62#### Parameters
63
64Every hook function has a `$data` parameter. Its content differs for each hooks.
65
66**This parameter needs to be returned every time**, otherwise data is lost.
67
68 return $data;
69
70#### Filling templates placeholder
71
72Template placeholders are displayed in template in specific places.
73
74RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
75
76For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page:
77
78```php
79$data['top_placeholder'[] = 'My content';](]-=-'My-content';.html)
80# OR
81array_push($data['top_placeholder'], 'My', 'content');[](.html)
82
83return $data;
84```
85
86#### Data manipulation
87
88When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
89
90The data contained by this array can be altered before template rendering.
91
92For exemple, in linklist, it is possible to alter every title:
93
94```php
95// mind the reference if you want $data to be altered
96foreach ($data['links'] as &$value) {[](.html)
97 // String reverse every title.
98 $value['title'] = strrev($value['title']);[](.html)
99}
100
101return $data;
102```
103
5409ade2
A
104### Metadata
105
106Every plugin needs a `<plugin_name>.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration.
107
108Each file contain two keys:
109
110 * `description`: plugin description
111 * `parameters`: user parameter names, separated by a `;`.
b230bf20 112 * `parameter.<PARAMETER_NAME>`: add a text description the specified parameter.
5409ade2
A
113
114> Note: In PHP, `parse_ini_file()` seems to want strings to be between by quotes `"` in the ini file.
115
992af0b9
V
116### It's not working!
117
118Use `demo_plugin` as a functional example. It covers most of the plugin system features.
119
120If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).[](.html)
121
122### Hooks
123
124| Hooks | Description |
125| ------------- |:-------------:|
126| [render_header](#render_header) | Allow plugin to add content in page headers. |[](.html)
127| [render_includes](#render_includes) | Allow plugin to include their own CSS files. |[](.html)
128| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. | [](.html)
129| [render_linklist](#render_linklist) | It allows to add content at the begining and end of the page, after every link displayed and to alter link data. |[](.html)
130| [render_editlink](#render_editlink) | Allow to add fields in the form, or display elements. |[](.html)
131| [render_tools](#render_tools) | Allow to add content at the end of the page. |[](.html)
132| [render_picwall](#render_picwall) | Allow to add content at the top and bottom of the page. |[](.html)
b230bf20
A
133| [render_tagcloud](#render_tagcloud) | Allow to add content at the top and bottom of the page, and after all tags. |[](.html)
134| [render_taglist](#render_taglist) | Allow to add content at the top and bottom of the page, and after all tags. |[](.html)
992af0b9 135| [render_daily](#render_daily) | Allow to add content at the top and bottom of the page, the bottom of each link and to alter data. |[](.html)
b230bf20
A
136| [render_feed](#render_feed) | Allow to do add tags in RSS and ATOM feeds. |[](.html)
137| [save_link](#save_link) | Allow to alter the link being saved in the datastore. |[](.html)
138| [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. |[](.html)
139
992af0b9
V
140
141
142#### render_header
143
144Triggered on every page.
145
146Allow plugin to add content in page headers.
147
148##### Data
149
150`$data` is an array containing:
151
152 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
153 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
154
155##### Template placeholders
156
157Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
158
159List of placeholders:
160
161 * `buttons_toolbar`: after the list of buttons in the header.
162
163![buttons_toolbar_example](http://i.imgur.com/ssJUOrt.png)[](.html)
164
165 * `fields_toolbar`: after search fields in the header.
166
167> Note: This will only be called in linklist.
168
169![fields_toolbar_example](http://i.imgur.com/3GMifI2.png)[](.html)
170
171#### render_includes
172
173Triggered on every page.
174
175Allow plugin to include their own CSS files.
176
177##### Data
178
179`$data` is an array containing:
180
181 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
182 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
183
184##### Template placeholders
185
186Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
187
188List of placeholders:
189
190 * `css_files`: called after loading default CSS.
191
192> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
193
194#### render_footer
195
196Triggered on every page.
197
198Allow plugin to add content in page footer and include their own JS files.
199
200##### Data
201
202`$data` is an array containing:
203
204 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
205 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
206
207##### Template placeholders
208
209Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
210
211List of placeholders:
212
213 * `text`: called after the end of the footer text.
08dcd8ea 214 * `endofpage`: called at the end of the page.
992af0b9
V
215
216![text_example](http://i.imgur.com/L5S2YEH.png)[](.html)
217
218 * `js_files`: called at the end of the page, to include custom JS scripts.
219
220> Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`.
221
222#### render_linklist
223
224Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
225
226It allows to add content at the begining and end of the page, after every link displayed and to alter link data.
227
228##### Data
229
230`$data` is an array containing:
231
232 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
233 * All templates data, including links.
234
235##### Template placeholders
236
237Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
238
239List of placeholders:
240
241 * `action_plugin`: next to the button "private only" at the top and bottom of the page.
242
243![action_plugin_example](http://i.imgur.com/Q12PWg0.png)[](.html)
244
245 * `link_plugin`: for every link, between permalink and link URL.
246
247![link_plugin_example](http://i.imgur.com/3oDPhWx.png)[](.html)
248
249 * `plugin_start_zone`: before displaying the template content.
250
251![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)[](.html)
252
253 * `plugin_end_zone`: after displaying the template content.
254
255![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)[](.html)
256
257#### render_editlink
258
259Triggered when the link edition form is displayed.
260
261Allow to add fields in the form, or display elements.
262
263##### Data
264
265`$data` is an array containing:
266
267 * All templates data.
268
269##### Template placeholders
270
271Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
272
273List of placeholders:
274
275 * `edit_link_plugin`: after tags field.
276
277![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)[](.html)
278
279#### render_tools
280
281Triggered when the "tools" page is displayed.
282
283Allow to add content at the end of the page.
284
285##### Data
286
287`$data` is an array containing:
288
289 * All templates data.
290
291##### Template placeholders
292
293Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
294
295List of placeholders:
296
297 * `tools_plugin`: at the end of the page.
298
299![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)[](.html)
300
301#### render_picwall
302
303Triggered when picwall is displayed.
304
305Allow to add content at the top and bottom of the page.
306
307##### Data
308
309`$data` is an array containing:
310
311 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
312 * All templates data.
313
314##### Template placeholders
315
316Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
317
318List of placeholders:
319
320 * `plugin_start_zone`: before displaying the template content.
321
322 * `plugin_end_zone`: after displaying the template content.
323
324![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)[](.html)
325
326#### render_tagcloud
327
328Triggered when tagcloud is displayed.
329
330Allow to add content at the top and bottom of the page.
331
332##### Data
333
334`$data` is an array containing:
335
336 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
337 * All templates data.
338
339##### Template placeholders
340
341Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
342
343List of placeholders:
344
345 * `plugin_start_zone`: before displaying the template content.
346
347 * `plugin_end_zone`: after displaying the template content.
348
b230bf20
A
349For each tag, the following placeholder can be used:
350
351 * `tag_plugin`: after each tag
352
992af0b9
V
353![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)[](.html)
354
b230bf20
A
355
356#### render_taglist
357
358Triggered when taglist is displayed.
359
360Allow to add content at the top and bottom of the page.
361
362##### Data
363
364`$data` is an array containing:
365
366 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
367 * All templates data.
368
369##### Template placeholders
370
371Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
372
373List of placeholders:
374
375 * `plugin_start_zone`: before displaying the template content.
376
377 * `plugin_end_zone`: after displaying the template content.
378
379For each tag, the following placeholder can be used:
380
381 * `tag_plugin`: after each tag
382
992af0b9
V
383#### render_daily
384
385Triggered when tagcloud is displayed.
386
387Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.
388
389##### Data
390
391`$data` is an array containing:
392
393 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
394 * All templates data, including links.
395
396##### Template placeholders
397
398Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
399
400List of placeholders:
401
402 * `link_plugin`: used at bottom of each link.
403
404![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)[](.html)
405
406 * `plugin_start_zone`: before displaying the template content.
407
408 * `plugin_end_zone`: after displaying the template content.
409
b230bf20
A
410#### render_feed
411
412Triggered when the ATOM or RSS feed is displayed.
413
414Allow to add tags in the feed, either in the header or for each items. Items (links) can also be altered before being rendered.
415
416##### Data
417
418`$data` is an array containing:
419
420 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
421 * `_PAGE_`: containing either `rss` or `atom`.
422 * All templates data, including links.
423
424##### Template placeholders
425
426Tags can be added in feeds by adding an entry in `$data['<placeholder>']` array.[](.html)
427
428List of placeholders:
429
430 * `feed_plugins_header`: used as a header tag in the feed.
431
432For each links:
433
434 * `feed_plugins`: additional tag for every link entry.
435
436#### save_link
992af0b9
V
437
438Triggered when a link is save (new link or edit).
439
440Allow to alter the link being saved in the datastore.
441
442##### Data
443
444`$data` is an array containing the link being saved:
445
b230bf20
A
446 * id
447 * title
448 * url
449 * shorturl
450 * description
451 * private
452 * tags
453 * created
454 * updated
455
456
457#### delete_link
458
459Triggered when a link is deleted.
460
461Allow to execute any action before the link is actually removed from the datastore
462
463##### Data
464
465`$data` is an array containing the link being saved:
466
467 * id
992af0b9
V
468 * title
469 * url
b230bf20 470 * shorturl
992af0b9 471 * description
992af0b9
V
472 * private
473 * tags
b230bf20
A
474 * created
475 * updated
992af0b9
V
476
477## Guide for template designer
478
5409ade2
A
479### Plugin administration
480
481Your theme must include a plugin administration page: `pluginsadmin.html`.
482
483> Note: repo's template link needs to be added when the PR is merged.
484
485Use the default one as an example.
486
487Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if:
488
489 * you're using a table.
490 * you call orderUp() and orderUp() onclick on arrows.
491 * you add data-line and data-order to your rows.
492
493Otherwise, you can use your own JS as long as this field is send by the form:
494
495<input type="hidden" name="order_{$key}" value="{$counter}">
496
992af0b9
V
497### Placeholder system
498
499In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
500
501It's a RainTPL loop like this:
502
503 {loop="$plugin_variable"}
504 {$value}
505 {/loop}
506
507You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
508
509### List of placeholders
510
511**page.header.html**
512
513At the end of the menu:
514
515 {loop="$plugins_header.buttons_toolbar"}
516 {$value}
517 {/loop}
518
5409ade2
A
519At the end of file, before clearing floating blocks:
520
521 {if="!empty($plugin_errors) && isLoggedIn()"}
522 <ul class="errors">
523 {loop="plugin_errors"}
524 <li>{$value}</li>
525 {/loop}
526 </ul>
527 {/if}
528
992af0b9
V
529**includes.html**
530
531At the end of the file:
532
533```html
534{loop="$plugins_includes.css_files"}
535<link type="text/css" rel="stylesheet" href="{$value}#"/>
536{/loop}
537```
538
539**page.footer.html**
540
541At the end of your footer notes:
542
543```html
544{loop="$plugins_footer.text"}
545 {$value}
546{/loop}
547```
548
549At the end of file:
550
551```html
552{loop="$plugins_footer.js_files"}
553 <script src="{$value}#"></script>
554{/loop}
555```
556
557**linklist.html**
558
559After search fields:
560
561```html
562{loop="$plugins_header.fields_toolbar"}
563 {$value}
564{/loop}
565```
566
567Before displaying the link list (after paging):
568
569```html
570{loop="$plugin_start_zone"}
571 {$value}
572{/loop}
573```
574
575For every links (icons):
576
577```html
578{loop="$value.link_plugin"}
579 <span>{$value}</span>
580{/loop}
581```
582
583Before end paging:
584
585```html
586{loop="$plugin_end_zone"}
587 {$value}
588{/loop}
589```
590
591**linklist.paging.html**
592
593After the "private only" icon:
594
595```html
596{loop="$action_plugin"}
597 {$value}
598{/loop}
599```
600
601**editlink.html**
602
603After tags field:
604
605```html
606{loop="$edit_link_plugin"}
607 {$value}
608{/loop}
609```
610
611**tools.html**
612
613After the last tool:
614
615```html
616{loop="$tools_plugin"}
617 {$value}
618{/loop}
619```
620
621**picwall.html**
622
623Top:
624
625```html
626<div id="plugin_zone_start_picwall" class="plugin_zone">
627 {loop="$plugin_start_zone"}
628 {$value}
629 {/loop}
630</div>
631```
632
633Bottom:
634
635```html
636<div id="plugin_zone_end_picwall" class="plugin_zone">
637 {loop="$plugin_end_zone"}
638 {$value}
639 {/loop}
640</div>
641```
642
643**tagcloud.html**
644
645Top:
646
647```html
648 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
649 {loop="$plugin_start_zone"}
650 {$value}
651 {/loop}
652 </div>
653```
654
655Bottom:
656
657```html
658 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
659 {loop="$plugin_end_zone"}
660 {$value}
661 {/loop}
662 </div>
663```
664
665**daily.html**
666
667Top:
668
669```html
670<div id="plugin_zone_start_picwall" class="plugin_zone">
671 {loop="$plugin_start_zone"}
672 {$value}
673 {/loop}
674</div>
675```
676
677After every link:
678
679```html
680<div class="dailyEntryFooter">
681 {loop="$link.link_plugin"}
682 {$value}
683 {/loop}
684</div>
685```
686
687Bottom:
688
689```html
690<div id="plugin_zone_end_picwall" class="plugin_zone">
691 {loop="$plugin_end_zone"}
692 {$value}
693 {/loop}
694</div>
695```
b230bf20
A
696
697**feed.atom.xml** and **feed.rss.xml**:
698
699In headers tags section:
700```xml
701{loop="$feed_plugins_header"}
702 {$value}
703{/loop}
704```
705
706After each entry:
707```xml
708{loop="$value.feed_plugins"}
709 {$value}
710{/loop}
711```