]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - doc/md/dev/Plugin-system.md
Merge pull request #1552 from ArthurHoaro/feature/better-initializer
[github/shaarli/Shaarli.git] / doc / md / dev / Plugin-system.md
1 # Plugin system
2
3 ## Developer API
4
5 ### What can I do with plugins?
6
7 The 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
16 First, chose a plugin name, such as `demo_plugin`.
17
18 Under `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
20 You 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
33 At 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
37 This 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
39 The 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
45 A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
46
47 These functions need to be named with this pattern:
48
49 ```
50 hook_<plugin_name>_<hook_name>($data, $conf)
51 ```
52
53 Parameters:
54
55 - data: see [$data section](https://shaarli.readthedocs.io/en/master/Plugin-System/#plugins-data)
56 - conf: the `ConfigManager` instance.
57
58 For example, if my plugin want to add data to the header, this function is needed:
59
60 hook_demo_plugin_render_header
61
62 If 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
69 Every 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
77 Special additional data are passed to every hook through the
78 `$data` parameter to give you access to additional context, and services.
79
80 Complete 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
87 Example:
88
89 ```php
90 if ($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
97 Template placeholders are displayed in template in specific places.
98
99 RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
100
101 For 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
106 array_push($data['top_placeholder'], 'My', 'content');
107
108 return $data;
109 ```
110
111
112 #### Data manipulation
113
114 When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
115
116 The data contained by this array can be altered before template rendering.
117
118 For example, in linklist, it is possible to alter every title:
119
120 ```php
121 // mind the reference if you want $data to be altered
122 foreach ($data['links'] as &$value) {
123 // String reverse every title.
124 $value['title'] = strrev($value['title']);
125 }
126
127 return $data;
128 ```
129
130 ### Metadata
131
132 Every plugin needs a `<plugin_name>.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration.
133
134 Each 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
145 Use `demo_plugin` as a functional example. It covers most of the plugin system features.
146
147 If 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
172 Triggered 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
183 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
184
185 List 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
200 Triggered 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
210 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
211
212 List 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
221 Triggered on every page.
222
223 Allow 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
233 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
234
235 List 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
249 Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
250
251 It 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
262 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
263
264 List 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
285 Triggered when the link edition form is displayed.
286
287 Allow 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
298 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
299
300 List 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
309 Triggered when the "tools" page is displayed.
310
311 Allow 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
322 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
323
324 List 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
333 Triggered when picwall is displayed.
334
335 Allow 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
346 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
347
348 List 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
358 Triggered when tagcloud is displayed.
359
360 Allow 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
371 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
372
373 List of placeholders:
374
375 - `plugin_start_zone`: before displaying the template content.
376 - `plugin_end_zone`: after displaying the template content.
377
378 For 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
387 Triggered 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
398 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
399
400 List of placeholders:
401
402 - `plugin_start_zone`: before displaying the template content.
403 - `plugin_end_zone`: after displaying the template content.
404
405 For each tag, the following placeholder can be used:
406
407 - `tag_plugin`: after each tag
408
409 #### render_daily
410
411 Triggered when tagcloud is displayed.
412
413 Allow 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
425 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
426
427 List 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
439 Triggered when the ATOM or RSS feed is displayed.
440
441 Allow 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
452 Tags can be added in feeds by adding an entry in `$data['<placeholder>']` array.
453
454 List of placeholders:
455
456 - `feed_plugins_header`: used as a header tag in the feed.
457
458 For each links:
459
460 - `feed_plugins`: additional tag for every link entry.
461
462
463 #### save_link
464
465 Triggered when a link is save (new link or edit).
466
467 Allow 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
483 Also [special data](#special-data).
484
485
486 #### delete_link
487
488 Triggered when a link is deleted.
489
490 Allow 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
506 Also [special data](#special-data).
507
508 #### save_plugin_parameters
509
510 Triggered when the plugin parameters are saved from the plugin administration page.
511
512 Plugins can perform an action every times their settings are updated.
513 For 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
519 So if the plugin has a parameter called `MYPLUGIN_PARAMETER`,
520 the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
521
522 Also [special data](#special-data).
523
524 ## Guide for template designers
525
526 ### Plugin administration
527
528 Your 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
532 Use the default one as an example.
533
534 Aside 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
540 Otherwise, 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
546 In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
547
548 It's a RainTPL loop like this:
549
550 {loop="$plugin_variable"}
551 {$value}
552 {/loop}
553
554 You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
555
556 ### List of placeholders
557
558 **page.header.html**
559
560 At the end of the menu:
561
562 {loop="$plugins_header.buttons_toolbar"}
563 {$value}
564 {/loop}
565
566 At 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
578 At 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
588 At the end of your footer notes:
589
590 ```html
591 {loop="$plugins_footer.text"}
592 {$value}
593 {/loop}
594 ```
595
596 At 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
606 After search fields:
607
608 ```html
609 {loop="$plugins_header.fields_toolbar"}
610 {$value}
611 {/loop}
612 ```
613
614 Before displaying the link list (after paging):
615
616 ```html
617 {loop="$plugin_start_zone"}
618 {$value}
619 {/loop}
620 ```
621
622 For every links (icons):
623
624 ```html
625 {loop="$value.link_plugin"}
626 <span>{$value}</span>
627 {/loop}
628 ```
629
630 Before end paging:
631
632 ```html
633 {loop="$plugin_end_zone"}
634 {$value}
635 {/loop}
636 ```
637
638 **linklist.paging.html**
639
640 After the "private only" icon:
641
642 ```html
643 {loop="$action_plugin"}
644 {$value}
645 {/loop}
646 ```
647
648 **editlink.html**
649
650 After tags field:
651
652 ```html
653 {loop="$edit_link_plugin"}
654 {$value}
655 {/loop}
656 ```
657
658 **tools.html**
659
660 After the last tool:
661
662 ```html
663 {loop="$tools_plugin"}
664 {$value}
665 {/loop}
666 ```
667
668 **picwall.html**
669
670 Top:
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
680 Bottom:
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
692 Top:
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
702 Bottom:
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
714 Top:
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
724 After every link:
725
726 ```html
727 <div class="dailyEntryFooter">
728 {loop="$link.link_plugin"}
729 {$value}
730 {/loop}
731 </div>
732 ```
733
734 Bottom:
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
746 In headers tags section:
747 ```xml
748 {loop="$feed_plugins_header"}
749 {$value}
750 {/loop}
751 ```
752
753 After each entry:
754 ```xml
755 {loop="$value.feed_plugins"}
756 {$value}
757 {/loop}
758 ```