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