]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - doc/md/Plugin-System.md
87a2638dbea73fc3ef9262ccf7bd208af3ea8d81
[github/shaarli/Shaarli.git] / doc / md / Plugin-System.md
1 [**I am a developer: ** Developer API](#developer-api)
2
3 [**I am a template designer: ** Guide for template designers](#guide-for-template-designer)
4
5 ---
6
7 ## Developer API
8
9 ### What can I do with plugins?
10
11 The plugin system let you:
12
13 - insert content into specific places across templates.
14 - alter data before templates rendering.
15 - alter data before saving new links.
16
17 ### How can I create a plugin for Shaarli?
18
19 First, chose a plugin name, such as `demo_plugin`.
20
21 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.
22
23 You should have the following tree view:
24
25 ```
26 | index.php
27 | plugins/
28 |---| demo_plugin/
29 | |---| demo_plugin.meta
30 | |---| demo_plugin.php
31 ```
32
33 ### Plugin initialization
34
35 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.
36
37 <plugin_name>_init($conf)
38
39 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.
40
41 The plugin system also looks for a `description` variable in the <plugin_name>.meta file, to be displayed in the plugin administration page.
42
43 description="The plugin does this and that."
44
45 ### Understanding hooks
46
47 A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
48
49 These functions need to be named with this pattern:
50
51 ```
52 hook_<plugin_name>_<hook_name>($data, $conf)
53 ```
54
55 Parameters:
56
57 - data: see [$data section](https://shaarli.readthedocs.io/en/master/Plugin-System/#plugins-data)
58 - conf: the `ConfigManager` instance.
59
60 For example, if my plugin want to add data to the header, this function is needed:
61
62 hook_demo_plugin_render_header
63
64 If 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
70 Every 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 #### Special data
77
78 Special additional data are passed to every hook through the
79 `$data` parameter to give you access to additional context, and services.
80
81 Complete 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
88 Example:
89
90 ```php
91 if ($data['_PAGE_'] === TemplatePage::LINKLIST && $data['LOGGEDIN'] === true) {
92 // Do something for logged in users when the link list is rendered
93 }
94 ```
95
96 #### Filling templates placeholder
97
98 Template placeholders are displayed in template in specific places.
99
100 RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
101
102 For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page:
103
104 ```php
105 $data['top_placeholder'][] = 'My content';
106 # OR
107 array_push($data['top_placeholder'], 'My', 'content');
108
109 return $data;
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 ### It's not working!
143
144 Use `demo_plugin` as a functional example. It covers most of the plugin system features.
145
146 If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).
147
148 ### Hooks
149
150 | Hooks | Description |
151 | ------------- |:-------------:|
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. |
154 | [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. |
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. |
165 | [save_plugin_parameters](#save_plugin_parameters) | Allow to manipulate plugin parameters before they're saved. |
166
167
168
169 #### render_header
170
171 Triggered on every page.
172
173 Allow plugin to add content in page headers.
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 #### render_includes
198
199 Triggered on every page.
200
201 Allow plugin to include their own CSS files.
202
203 ##### Data
204
205 `$data` is an array containing:
206
207 - [Special data](#special-data)
208
209 ##### Template placeholders
210
211 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
212
213 List of placeholders:
214
215 - `css_files`: called after loading default CSS.
216
217 > Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
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 #### render_linklist
247
248 Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
249
250 It 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
256 - All templates data, including links.
257 - [Special data](#special-data)
258
259 ##### Template placeholders
260
261 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
262
263 List of placeholders:
264
265 - `action_plugin`: next to the button "private only" at the top and bottom of the page.
266
267 ![action_plugin_example](http://i.imgur.com/Q12PWg0.png)
268
269 - `link_plugin`: for every link, between permalink and link URL.
270
271 ![link_plugin_example](http://i.imgur.com/3oDPhWx.png)
272
273 - `plugin_start_zone`: before displaying the template content.
274
275 ![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)
276
277 - `plugin_end_zone`: after displaying the template content.
278
279 ![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)
280
281 #### render_editlink
282
283 Triggered when the link edition form is displayed.
284
285 Allow to add fields in the form, or display elements.
286
287 ##### Data
288
289 `$data` is an array containing:
290
291 - All templates data.
292 - [Special data](#special-data)
293
294 ##### Template placeholders
295
296 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
297
298 List of placeholders:
299
300 - `edit_link_plugin`: after tags field.
301
302 ![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)
303
304 #### render_tools
305
306 Triggered when the "tools" page is displayed.
307
308 Allow to add content at the end of the page.
309
310 ##### Data
311
312 `$data` is an array containing:
313
314 - All templates data.
315 - [Special data](#special-data)
316
317 ##### Template placeholders
318
319 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
320
321 List of placeholders:
322
323 - `tools_plugin`: at the end of the page.
324
325 ![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)
326
327 #### render_picwall
328
329 Triggered when picwall is displayed.
330
331 Allow to add content at the top and bottom of the page.
332
333 ##### Data
334
335 `$data` is an array containing:
336
337 - All templates data.
338 - [Special data](#special-data)
339
340 ##### Template placeholders
341
342 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
343
344 List of placeholders:
345
346 - `plugin_start_zone`: before displaying the template content.
347 - `plugin_end_zone`: after displaying the template content.
348
349 ![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)
350
351 #### render_tagcloud
352
353 Triggered when tagcloud is displayed.
354
355 Allow to add content at the top and bottom of the page.
356
357 ##### Data
358
359 `$data` is an array containing:
360
361 - All templates data.
362 - [Special data](#special-data)
363
364 ##### Template placeholders
365
366 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
367
368 List of placeholders:
369
370 - `plugin_start_zone`: before displaying the template content.
371 - `plugin_end_zone`: after displaying the template content.
372
373 For each tag, the following placeholder can be used:
374
375 - `tag_plugin`: after each tag
376
377 ![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)
378
379
380 #### render_taglist
381
382 Triggered when taglist is displayed.
383
384 Allow to add content at the top and bottom of the page.
385
386 ##### Data
387
388 `$data` is an array containing:
389
390 - All templates data.
391 - [Special data](#special-data)
392
393 ##### Template placeholders
394
395 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
396
397 List of placeholders:
398
399 - `plugin_start_zone`: before displaying the template content.
400 - `plugin_end_zone`: after displaying the template content.
401
402 For each tag, the following placeholder can be used:
403
404 - `tag_plugin`: after each tag
405
406 #### render_daily
407
408 Triggered when tagcloud is displayed.
409
410 Allow 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
416 - All templates data, including links.
417 - [Special data](#special-data)
418
419 ##### Template placeholders
420
421 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
422
423 List of placeholders:
424
425 - `link_plugin`: used at bottom of each link.
426
427 ![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)
428
429 - `plugin_start_zone`: before displaying the template content.
430 - `plugin_end_zone`: after displaying the template content.
431
432 #### render_feed
433
434 Triggered when the ATOM or RSS feed is displayed.
435
436 Allow 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
442 - All templates data, including links.
443 - [Special data](#special-data)
444
445 ##### Template placeholders
446
447 Tags can be added in feeds by adding an entry in `$data['<placeholder>']` array.
448
449 List of placeholders:
450
451 - `feed_plugins_header`: used as a header tag in the feed.
452
453 For each links:
454
455 - `feed_plugins`: additional tag for every link entry.
456
457 #### save_link
458
459 Triggered when a link is save (new link or edit).
460
461 Allow to alter the link being saved in the datastore.
462
463 ##### Data
464
465 `$data` is an array containing the link being saved:
466
467 - id
468 - title
469 - url
470 - shorturl
471 - description
472 - private
473 - tags
474 - created
475 - updated
476
477 Also [special data](#special-data).
478
479
480 #### delete_link
481
482 Triggered when a link is deleted.
483
484 Allow to execute any action before the link is actually removed from the datastore
485
486 ##### Data
487
488 `$data` is an array containing the link being deleted:
489
490 - id
491 - title
492 - url
493 - shorturl
494 - description
495 - private
496 - tags
497 - created
498 - updated
499
500 Also [special data](#special-data).
501
502 #### save_plugin_parameters
503
504 Triggered when the plugin parameters are saved from the plugin administration page.
505
506 Plugins can perform an action every times their settings are updated.
507 For 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
513 So if the plugin has a parameter called `MYPLUGIN_PARAMETER`,
514 the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
515
516 Also [special data](#special-data).
517
518 ## Guide for template designer
519
520 ### Plugin administration
521
522 Your 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
526 Use the default one as an example.
527
528 Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if:
529
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.
533
534 Otherwise, 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
538 ### Placeholder system
539
540 In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
541
542 It's a RainTPL loop like this:
543
544 {loop="$plugin_variable"}
545 {$value}
546 {/loop}
547
548 You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
549
550 ### List of placeholders
551
552 **page.header.html**
553
554 At the end of the menu:
555
556 {loop="$plugins_header.buttons_toolbar"}
557 {$value}
558 {/loop}
559
560 At the end of file, before clearing floating blocks:
561
562 {if="!empty($plugin_errors) && $is_logged_in"}
563 <ul class="errors">
564 {loop="plugin_errors"}
565 <li>{$value}</li>
566 {/loop}
567 </ul>
568 {/if}
569
570 **includes.html**
571
572 At 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
582 At the end of your footer notes:
583
584 ```html
585 {loop="$plugins_footer.text"}
586 {$value}
587 {/loop}
588 ```
589
590 At 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
600 After search fields:
601
602 ```html
603 {loop="$plugins_header.fields_toolbar"}
604 {$value}
605 {/loop}
606 ```
607
608 Before displaying the link list (after paging):
609
610 ```html
611 {loop="$plugin_start_zone"}
612 {$value}
613 {/loop}
614 ```
615
616 For every links (icons):
617
618 ```html
619 {loop="$value.link_plugin"}
620 <span>{$value}</span>
621 {/loop}
622 ```
623
624 Before end paging:
625
626 ```html
627 {loop="$plugin_end_zone"}
628 {$value}
629 {/loop}
630 ```
631
632 **linklist.paging.html**
633
634 After the "private only" icon:
635
636 ```html
637 {loop="$action_plugin"}
638 {$value}
639 {/loop}
640 ```
641
642 **editlink.html**
643
644 After tags field:
645
646 ```html
647 {loop="$edit_link_plugin"}
648 {$value}
649 {/loop}
650 ```
651
652 **tools.html**
653
654 After the last tool:
655
656 ```html
657 {loop="$tools_plugin"}
658 {$value}
659 {/loop}
660 ```
661
662 **picwall.html**
663
664 Top:
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
674 Bottom:
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
686 Top:
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
696 Bottom:
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
708 Top:
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
718 After every link:
719
720 ```html
721 <div class="dailyEntryFooter">
722 {loop="$link.link_plugin"}
723 {$value}
724 {/loop}
725 </div>
726 ```
727
728 Bottom:
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 ```
737
738 **feed.atom.xml** and **feed.rss.xml**:
739
740 In headers tags section:
741 ```xml
742 {loop="$feed_plugins_header"}
743 {$value}
744 {/loop}
745 ```
746
747 After each entry:
748 ```xml
749 {loop="$value.feed_plugins"}
750 {$value}
751 {/loop}
752 ```