]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - doc/md/Plugin-System.md
Merge pull request #1547 from ArthurHoaro/fix/daily-visibility
[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
80b708a8
A
76#### Special data
77
78Special additional data are passed to every hook through the
79`$data` parameter to give you access to additional context, and services.
80
81Complete list:
82
83 * `_PAGE_` (string): if the current hook is used to render a template, its name is passed through this additional parameter.
84 * `_LOGGEDIN_` (bool): whether the user is logged in or not.
85 * `_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/`).
86 * `_BOOKMARK_SERVICE_` (`BookmarkServiceInterface`): bookmark service instance, for advanced usage.
87
88Example:
89
90```php
91if ($data['_PAGE_'] === TemplatePage::LINKLIST && $data['LOGGEDIN'] === true) {
92 // Do something for logged in users when the link list is rendered
93}
94```
95
992af0b9
V
96#### Filling templates placeholder
97
98Template placeholders are displayed in template in specific places.
99
100RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
101
102For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page:
103
104```php
53ed6d7d 105$data['top_placeholder'][] = 'My content';
992af0b9 106# OR
53ed6d7d 107array_push($data['top_placeholder'], 'My', 'content');
992af0b9
V
108
109return $data;
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
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
992af0b9
V
142### It's not working!
143
144Use `demo_plugin` as a functional example. It covers most of the plugin system features.
145
53ed6d7d 146If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).
992af0b9
V
147
148### Hooks
149
150| Hooks | Description |
151| ------------- |:-------------:|
53ed6d7d 152| [render_header](#render_header) | Allow plugin to add content in page headers. |
153| [render_includes](#render_includes) | Allow plugin to include their own CSS files. |
1a8ac737 154| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. |
53ed6d7d 155| [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. |
156| [render_editlink](#render_editlink) | Allow to add fields in the form, or display elements. |
157| [render_tools](#render_tools) | Allow to add content at the end of the page. |
158| [render_picwall](#render_picwall) | Allow to add content at the top and bottom of the page. |
159| [render_tagcloud](#render_tagcloud) | Allow to add content at the top and bottom of the page, and after all tags. |
160| [render_taglist](#render_taglist) | Allow to add content at the top and bottom of the page, and after all tags. |
161| [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. |
162| [render_feed](#render_feed) | Allow to do add tags in RSS and ATOM feeds. |
163| [save_link](#save_link) | Allow to alter the link being saved in the datastore. |
164| [delete_link](#delete_link) | Allow to do an action before a link is deleted from the datastore. |
a8fb97a0 165| [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
b230bf20 166
992af0b9
V
167
168
169#### render_header
170
171Triggered on every page.
172
173Allow plugin to add content in page headers.
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
V
196
197#### render_includes
198
199Triggered on every page.
200
201Allow plugin to include their own CSS files.
202
203##### Data
204
205`$data` is an array containing:
206
80b708a8 207 - [Special data](#special-data)
992af0b9
V
208
209##### Template placeholders
210
53ed6d7d 211Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
212
213List of placeholders:
214
43ad7c8e 215- `css_files`: called after loading default CSS.
992af0b9
V
216
217> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
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
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
246#### render_linklist
247
248Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
249
250It allows to add content at the begining and end of the page, after every link displayed and to alter link data.
251
252##### Data
253
254`$data` is an array containing:
255
80b708a8
A
256 - All templates data, including links.
257 - [Special data](#special-data)
992af0b9
V
258
259##### Template placeholders
260
53ed6d7d 261Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
262
263List of placeholders:
264
43ad7c8e 265- `action_plugin`: next to the button "private only" at the top and bottom of the page.
992af0b9 266
53ed6d7d 267![action_plugin_example](http://i.imgur.com/Q12PWg0.png)
992af0b9 268
43ad7c8e 269- `link_plugin`: for every link, between permalink and link URL.
992af0b9 270
53ed6d7d 271![link_plugin_example](http://i.imgur.com/3oDPhWx.png)
992af0b9 272
43ad7c8e 273- `plugin_start_zone`: before displaying the template content.
992af0b9 274
53ed6d7d 275![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)
992af0b9 276
43ad7c8e 277- `plugin_end_zone`: after displaying the template content.
992af0b9 278
53ed6d7d 279![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)
992af0b9
V
280
281#### render_editlink
282
283Triggered when the link edition form is displayed.
284
285Allow to add fields in the form, or display elements.
286
287##### Data
288
289`$data` is an array containing:
290
80b708a8
A
291 - All templates data.
292 - [Special data](#special-data)
992af0b9
V
293
294##### Template placeholders
295
53ed6d7d 296Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
297
298List of placeholders:
299
43ad7c8e 300- `edit_link_plugin`: after tags field.
992af0b9 301
53ed6d7d 302![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)
992af0b9
V
303
304#### render_tools
305
306Triggered when the "tools" page is displayed.
307
308Allow to add content at the end of the page.
309
310##### Data
311
312`$data` is an array containing:
313
80b708a8
A
314 - All templates data.
315 - [Special data](#special-data)
992af0b9
V
316
317##### Template placeholders
318
53ed6d7d 319Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
320
321List of placeholders:
322
43ad7c8e 323- `tools_plugin`: at the end of the page.
992af0b9 324
53ed6d7d 325![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)
992af0b9
V
326
327#### render_picwall
328
329Triggered when picwall is displayed.
330
331Allow to add content at the top and bottom of the page.
332
333##### Data
334
335`$data` is an array containing:
336
80b708a8
A
337 - All templates data.
338 - [Special data](#special-data)
992af0b9
V
339
340##### Template placeholders
341
53ed6d7d 342Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
343
344List of placeholders:
345
43ad7c8e
V
346- `plugin_start_zone`: before displaying the template content.
347- `plugin_end_zone`: after displaying the template content.
992af0b9 348
53ed6d7d 349![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)
992af0b9
V
350
351#### render_tagcloud
352
353Triggered when tagcloud is displayed.
354
355Allow to add content at the top and bottom of the page.
356
357##### Data
358
359`$data` is an array containing:
360
80b708a8
A
361 - All templates data.
362 - [Special data](#special-data)
992af0b9
V
363
364##### Template placeholders
365
53ed6d7d 366Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
367
368List of placeholders:
369
43ad7c8e
V
370- `plugin_start_zone`: before displaying the template content.
371- `plugin_end_zone`: after displaying the template content.
992af0b9 372
b230bf20
A
373For each tag, the following placeholder can be used:
374
43ad7c8e 375- `tag_plugin`: after each tag
b230bf20 376
53ed6d7d 377![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)
992af0b9 378
b230bf20
A
379
380#### render_taglist
381
382Triggered when taglist is displayed.
383
384Allow to add content at the top and bottom of the page.
385
386##### Data
387
388`$data` is an array containing:
389
80b708a8
A
390 - All templates data.
391 - [Special data](#special-data)
b230bf20
A
392
393##### Template placeholders
394
53ed6d7d 395Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
b230bf20
A
396
397List of placeholders:
398
43ad7c8e
V
399- `plugin_start_zone`: before displaying the template content.
400- `plugin_end_zone`: after displaying the template content.
b230bf20
A
401
402For each tag, the following placeholder can be used:
403
43ad7c8e 404- `tag_plugin`: after each tag
b230bf20 405
992af0b9
V
406#### render_daily
407
408Triggered when tagcloud is displayed.
409
410Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.
411
412##### Data
413
414`$data` is an array containing:
415
80b708a8
A
416 - All templates data, including links.
417 - [Special data](#special-data)
992af0b9
V
418
419##### Template placeholders
420
53ed6d7d 421Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
992af0b9
V
422
423List of placeholders:
424
43ad7c8e 425- `link_plugin`: used at bottom of each link.
992af0b9 426
53ed6d7d 427![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)
992af0b9 428
43ad7c8e
V
429- `plugin_start_zone`: before displaying the template content.
430- `plugin_end_zone`: after displaying the template content.
992af0b9 431
b230bf20
A
432#### render_feed
433
434Triggered when the ATOM or RSS feed is displayed.
435
436Allow to add tags in the feed, either in the header or for each items. Items (links) can also be altered before being rendered.
437
438##### Data
439
440`$data` is an array containing:
441
80b708a8
A
442 - All templates data, including links.
443 - [Special data](#special-data)
b230bf20
A
444
445##### Template placeholders
446
53ed6d7d 447Tags can be added in feeds by adding an entry in `$data['<placeholder>']` array.
b230bf20
A
448
449List of placeholders:
450
43ad7c8e 451- `feed_plugins_header`: used as a header tag in the feed.
b230bf20
A
452
453For each links:
454
43ad7c8e 455- `feed_plugins`: additional tag for every link entry.
b230bf20
A
456
457#### save_link
992af0b9
V
458
459Triggered when a link is save (new link or edit).
460
461Allow to alter the link being saved in the datastore.
462
463##### Data
464
465`$data` is an array containing the link being saved:
466
43ad7c8e
V
467- id
468- title
469- url
470- shorturl
471- description
472- private
473- tags
474- created
475- updated
b230bf20 476
80b708a8
A
477Also [special data](#special-data).
478
b230bf20
A
479
480#### delete_link
481
482Triggered when a link is deleted.
483
484Allow to execute any action before the link is actually removed from the datastore
485
486##### Data
487
80b708a8 488`$data` is an array containing the link being deleted:
b230bf20 489
43ad7c8e
V
490- id
491- title
492- url
493- shorturl
494- description
495- private
496- tags
497- created
498- updated
992af0b9 499
80b708a8 500Also [special data](#special-data).
a8fb97a0
A
501
502#### save_plugin_parameters
503
504Triggered when the plugin parameters are saved from the plugin administration page.
505
506Plugins can perform an action every times their settings are updated.
507For example it is used to update the CSS file of the `default_colors` plugins.
508
509##### Data
510
511`$data` input contains the `$_POST` array.
512
513So if the plugin has a parameter called `MYPLUGIN_PARAMETER`,
514the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
515
80b708a8 516Also [special data](#special-data).
a8fb97a0 517
992af0b9
V
518## Guide for template designer
519
5409ade2
A
520### Plugin administration
521
522Your theme must include a plugin administration page: `pluginsadmin.html`.
523
524> Note: repo's template link needs to be added when the PR is merged.
525
526Use the default one as an example.
527
528Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if:
529
43ad7c8e
V
530- you're using a table.
531- you call orderUp() and orderUp() onclick on arrows.
532- you add data-line and data-order to your rows.
5409ade2
A
533
534Otherwise, you can use your own JS as long as this field is send by the form:
535
536<input type="hidden" name="order_{$key}" value="{$counter}">
537
992af0b9
V
538### Placeholder system
539
1a8ac737 540In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
992af0b9
V
541
542It's a RainTPL loop like this:
543
544 {loop="$plugin_variable"}
545 {$value}
546 {/loop}
547
548You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
549
550### List of placeholders
551
552**page.header.html**
553
554At the end of the menu:
555
556 {loop="$plugins_header.buttons_toolbar"}
557 {$value}
558 {/loop}
559
5409ade2
A
560At the end of file, before clearing floating blocks:
561
1a8ac737 562 {if="!empty($plugin_errors) && $is_logged_in"}
5409ade2
A
563 <ul class="errors">
564 {loop="plugin_errors"}
565 <li>{$value}</li>
566 {/loop}
567 </ul>
568 {/if}
569
992af0b9
V
570**includes.html**
571
572At the end of the file:
573
574```html
575{loop="$plugins_includes.css_files"}
576<link type="text/css" rel="stylesheet" href="{$value}#"/>
577{/loop}
578```
579
580**page.footer.html**
581
582At the end of your footer notes:
583
584```html
585{loop="$plugins_footer.text"}
586 {$value}
587{/loop}
588```
589
590At the end of file:
591
592```html
593{loop="$plugins_footer.js_files"}
594 <script src="{$value}#"></script>
595{/loop}
596```
597
598**linklist.html**
599
600After search fields:
601
602```html
603{loop="$plugins_header.fields_toolbar"}
604 {$value}
605{/loop}
606```
607
608Before displaying the link list (after paging):
609
610```html
611{loop="$plugin_start_zone"}
612 {$value}
613{/loop}
614```
615
616For every links (icons):
617
618```html
619{loop="$value.link_plugin"}
620 <span>{$value}</span>
621{/loop}
622```
623
624Before end paging:
625
626```html
627{loop="$plugin_end_zone"}
628 {$value}
629{/loop}
630```
631
632**linklist.paging.html**
633
634After the "private only" icon:
635
636```html
637{loop="$action_plugin"}
638 {$value}
639{/loop}
640```
641
642**editlink.html**
643
644After tags field:
645
646```html
647{loop="$edit_link_plugin"}
648 {$value}
649{/loop}
650```
651
652**tools.html**
653
654After the last tool:
655
656```html
657{loop="$tools_plugin"}
658 {$value}
659{/loop}
660```
661
662**picwall.html**
663
664Top:
665
666```html
667<div id="plugin_zone_start_picwall" 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_picwall" class="plugin_zone">
678 {loop="$plugin_end_zone"}
679 {$value}
680 {/loop}
681</div>
682```
683
684**tagcloud.html**
685
686Top:
687
688```html
689 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
690 {loop="$plugin_start_zone"}
691 {$value}
692 {/loop}
693 </div>
694```
695
696Bottom:
697
698```html
699 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
700 {loop="$plugin_end_zone"}
701 {$value}
702 {/loop}
703 </div>
704```
705
706**daily.html**
707
708Top:
709
710```html
711<div id="plugin_zone_start_picwall" class="plugin_zone">
712 {loop="$plugin_start_zone"}
713 {$value}
714 {/loop}
715</div>
716```
717
718After every link:
719
720```html
721<div class="dailyEntryFooter">
722 {loop="$link.link_plugin"}
723 {$value}
724 {/loop}
725</div>
726```
727
728Bottom:
729
730```html
731<div id="plugin_zone_end_picwall" class="plugin_zone">
732 {loop="$plugin_end_zone"}
733 {$value}
734 {/loop}
735</div>
736```
b230bf20
A
737
738**feed.atom.xml** and **feed.rss.xml**:
739
740In headers tags section:
741```xml
742{loop="$feed_plugins_header"}
743 {$value}
744{/loop}
745```
746
747After each entry:
748```xml
749{loop="$value.feed_plugins"}
750 {$value}
751{/loop}
752```