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