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