]> git.immae.eu Git - github/shaarli/Shaarli.git/blame_incremental - Plugin-system.md
Merge pull request #1698 from ArthurHoaro/feature/plugins-search-filter
[github/shaarli/Shaarli.git] / Plugin-system.md
... / ...
CommitLineData
1# Plugin system
2
3## Developer API
4
5### What can I do with plugins?
6
7The plugin system lets you:
8
9- insert content into specific places across templates.
10- alter data before templates rendering.
11- alter data before saving new links.
12
13
14### How can I create a plugin for Shaarli?
15
16First, chose a plugin name, such as `demo_plugin`.
17
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.
19
20You should have the following tree view:
21
22```
23| index.php
24| plugins/
25|---| demo_plugin/
26| |---| demo_plugin.meta
27| |---| demo_plugin.php
28```
29
30
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 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.
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
39The plugin system also looks for a `description` variable in the <plugin_name>.meta file, to be displayed in the plugin administration page.
40
41 description="The plugin does this and that."
42
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```
50hook_<plugin_name>_<hook_name>($data, $conf)
51```
52
53Parameters:
54
55- data: see [$data section](https://shaarli.readthedocs.io/en/master/Plugin-System/#plugins-data)
56- conf: the `ConfigManager` instance.
57
58For example, if my plugin want to add data to the header, this function is needed:
59
60 hook_demo_plugin_render_header
61
62If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header.
63
64
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
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
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
104$data['top_placeholder'][] = 'My content';
105# OR
106array_push($data['top_placeholder'], 'My', 'content');
107
108return $data;
109```
110
111
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
118For example, in linklist, it is possible to alter every title:
119
120```php
121// mind the reference if you want $data to be altered
122foreach ($data['links'] as &$value) {
123 // String reverse every title.
124 $value['title'] = strrev($value['title']);
125}
126
127return $data;
128```
129
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
136- `description`: plugin description
137- `parameters`: user parameter names, separated by a `;`.
138- `parameter.<PARAMETER_NAME>`: add a text description the specified parameter.
139
140> Note: In PHP, `parse_ini_file()` seems to want strings to be between by quotes `"` in the ini file.
141
142
143### It's not working!
144
145Use `demo_plugin` as a functional example. It covers most of the plugin system features.
146
147If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).
148
149
150### Hooks
151
152| Hooks | Description |
153| ------------- |:-------------:|
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. |
156| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. |
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. |
167| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
168
169
170#### render_header
171
172Triggered on every page - allows plugins to add content in page headers.
173
174
175##### Data
176
177`$data` is an array containing:
178
179 - [Special data](#special-data)
180
181##### Template placeholders
182
183Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
184
185List of placeholders:
186
187- `buttons_toolbar`: after the list of buttons in the header.
188
189![buttons_toolbar_example](http://i.imgur.com/ssJUOrt.png)
190
191- `fields_toolbar`: after search fields in the header.
192
193> Note: This will only be called in linklist.
194
195![fields_toolbar_example](http://i.imgur.com/3GMifI2.png)
196
197
198#### render_includes
199
200Triggered on every page - allows plugins to include their own CSS files.
201
202##### data
203
204`$data` is an array containing:
205
206 - [Special data](#special-data)
207
208##### Template placeholders
209
210Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
211
212List of placeholders:
213
214- `css_files`: called after loading default CSS.
215
216> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
217
218
219#### render_footer
220
221Triggered on every page.
222
223Allow plugin to add content in page footer and include their own JS files.
224
225##### data
226
227`$data` is an array containing:
228
229 - [Special data](#special-data)
230
231##### Template placeholders
232
233Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
234
235List of placeholders:
236
237- `text`: called after the end of the footer text.
238- `endofpage`: called at the end of the page.
239
240![text_example](http://i.imgur.com/L5S2YEH.png)
241
242- `js_files`: called at the end of the page, to include custom JS scripts.
243
244> Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`.
245
246
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
253##### data
254
255`$data` is an array containing:
256
257 - All templates data, including links.
258 - [Special data](#special-data)
259
260##### template placeholders
261
262Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
263
264List of placeholders:
265
266- `action_plugin`: next to the button "private only" at the top and bottom of the page.
267
268![action_plugin_example](http://i.imgur.com/Q12PWg0.png)
269
270- `link_plugin`: for every link, between permalink and link URL.
271
272![link_plugin_example](http://i.imgur.com/3oDPhWx.png)
273
274- `plugin_start_zone`: before displaying the template content.
275
276![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)
277
278- `plugin_end_zone`: after displaying the template content.
279
280![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)
281
282
283#### render_editlink
284
285Triggered when the link edition form is displayed.
286
287Allow to add fields in the form, or display elements.
288
289##### data
290
291`$data` is an array containing:
292
293 - All templates data.
294 - [Special data](#special-data)
295
296##### template placeholders
297
298Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
299
300List of placeholders:
301
302- `edit_link_plugin`: after tags field.
303
304![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)
305
306
307#### render_tools
308
309Triggered when the "tools" page is displayed.
310
311Allow to add content at the end of the page.
312
313##### data
314
315`$data` is an array containing:
316
317 - All templates data.
318 - [Special data](#special-data)
319
320##### template placeholders
321
322Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
323
324List of placeholders:
325
326- `tools_plugin`: at the end of the page.
327
328![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)
329
330
331#### render_picwall
332
333Triggered when picwall is displayed.
334
335Allow to add content at the top and bottom of the page.
336
337##### data
338
339`$data` is an array containing:
340
341 - All templates data.
342 - [Special data](#special-data)
343
344##### template placeholders
345
346Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
347
348List of placeholders:
349
350- `plugin_start_zone`: before displaying the template content.
351- `plugin_end_zone`: after displaying the template content.
352
353![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)
354
355
356#### render_tagcloud
357
358Triggered when tagcloud 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 - All templates data.
367 - [Special data](#special-data)
368
369##### Template placeholders
370
371Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
372
373List of placeholders:
374
375- `plugin_start_zone`: before displaying the template content.
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
382![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)
383
384
385#### render_taglist
386
387Triggered when taglist is displayed - allows to add content at the top and bottom of the page.
388
389##### data
390
391`$data` is an array containing:
392
393 - All templates data.
394 - [Special data](#special-data)
395
396##### Template placeholders
397
398Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
399
400List of placeholders:
401
402- `plugin_start_zone`: before displaying the template content.
403- `plugin_end_zone`: after displaying the template content.
404
405For each tag, the following placeholder can be used:
406
407- `tag_plugin`: after each tag
408
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
415
416##### data
417
418`$data` is an array containing:
419
420 - All templates data, including links.
421 - [Special data](#special-data)
422
423##### Template placeholders
424
425Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
426
427List of placeholders:
428
429- `link_plugin`: used at bottom of each link.
430
431![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)
432
433- `plugin_start_zone`: before displaying the template content.
434- `plugin_end_zone`: after displaying the template content.
435
436
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
443##### data
444
445`$data` is an array containing:
446
447 - All templates data, including links.
448 - [Special data](#special-data)
449
450##### Template placeholders
451
452Tags can be added in feeds by adding an entry in `$data['<placeholder>']` array.
453
454List of placeholders:
455
456- `feed_plugins_header`: used as a header tag in the feed.
457
458For each links:
459
460- `feed_plugins`: additional tag for every link entry.
461
462
463#### save_link
464
465Triggered when a link is save (new link or edit).
466
467Allow to alter the link being saved in the datastore.
468
469##### data
470
471`$data` is an array containing the link being saved:
472
473- id
474- title
475- url
476- shorturl
477- description
478- private
479- tags
480- created
481- updated
482
483Also [special data](#special-data).
484
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
492##### data
493
494`$data` is an array containing the link being deleted:
495
496- id
497- title
498- url
499- shorturl
500- description
501- private
502- tags
503- created
504- updated
505
506Also [special data](#special-data).
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
515##### data
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
522Also [special data](#special-data).
523
524## Guide for template designers
525
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
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.
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
544### Placeholder system
545
546In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
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
566At the end of file, before clearing floating blocks:
567
568 {if="!empty($plugin_errors) && $is_logged_in"}
569 <ul class="errors">
570 {loop="plugin_errors"}
571 <li>{$value}</li>
572 {/loop}
573 </ul>
574 {/if}
575
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```
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```