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