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