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