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