]> git.immae.eu Git - github/shaarli/Shaarli.git/blame_incremental - doc/md/Plugin-System.md
Document about the .meta file at the plugin creation/initialization
[github/shaarli/Shaarli.git] / doc / md / Plugin-System.md
... / ...
CommitLineData
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
11The 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
19First, chose a plugin name, such as `demo_plugin`.
20
21Under `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
23You 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
35At 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
39This 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
41The 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
45A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
46
47These functions need to be named with this pattern:
48
49```
50hook_<plugin_name>_<hook_name>($data, $conf)
51```
52
53Parameters:
54
55- data: see [$data section](https://shaarli.readthedocs.io/en/master/Plugin-System/#plugins-data)
56- conf: the `ConfigManager` instance.
57
58For example, if my plugin want to add data to the header, this function is needed:
59
60 hook_demo_plugin_render_header
61
62If 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
68Every 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
76Template placeholders are displayed in template in specific places.
77
78RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
79
80For 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
85array_push($data['top_placeholder'], 'My', 'content');
86
87return $data;
88```
89
90#### Data manipulation
91
92When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
93
94The data contained by this array can be altered before template rendering.
95
96For exemple, in linklist, it is possible to alter every title:
97
98```php
99// mind the reference if you want $data to be altered
100foreach ($data['links'] as &$value) {
101 // String reverse every title.
102 $value['title'] = strrev($value['title']);
103}
104
105return $data;
106```
107
108### Metadata
109
110Every plugin needs a `<plugin_name>.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration.
111
112Each 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
122Use `demo_plugin` as a functional example. It covers most of the plugin system features.
123
124If 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
149Triggered on every page.
150
151Allow 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
162Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
163
164List 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
178Triggered on every page.
179
180Allow 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
191Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
192
193List 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
201Triggered on every page.
202
203Allow 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
214Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
215
216List 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
229Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
230
231It 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
242Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
243
244List 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
264Triggered when the link edition form is displayed.
265
266Allow 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
276Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
277
278List 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
286Triggered when the "tools" page is displayed.
287
288Allow 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
298Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
299
300List 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
308Triggered when picwall is displayed.
309
310Allow 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
321Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
322
323List 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
332Triggered when tagcloud is displayed.
333
334Allow 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
345Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
346
347List of placeholders:
348
349- `plugin_start_zone`: before displaying the template content.
350- `plugin_end_zone`: after displaying the template content.
351
352For 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
361Triggered when taglist is displayed.
362
363Allow 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
374Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
375
376List of placeholders:
377
378- `plugin_start_zone`: before displaying the template content.
379- `plugin_end_zone`: after displaying the template content.
380
381For each tag, the following placeholder can be used:
382
383- `tag_plugin`: after each tag
384
385#### render_daily
386
387Triggered when tagcloud is displayed.
388
389Allow 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
400Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.
401
402List 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
413Triggered when the ATOM or RSS feed is displayed.
414
415Allow 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
427Tags can be added in feeds by adding an entry in `$data['<placeholder>']` array.
428
429List of placeholders:
430
431- `feed_plugins_header`: used as a header tag in the feed.
432
433For each links:
434
435- `feed_plugins`: additional tag for every link entry.
436
437#### save_link
438
439Triggered when a link is save (new link or edit).
440
441Allow 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
460Triggered when a link is deleted.
461
462Allow 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
481Triggered when the plugin parameters are saved from the plugin administration page.
482
483Plugins can perform an action every times their settings are updated.
484For 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
490So if the plugin has a parameter called `MYPLUGIN_PARAMETER`,
491the array will contain an entry with `MYPLUGIN_PARAMETER` as a key.
492
493
494## Guide for template designer
495
496### Plugin administration
497
498Your 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
502Use the default one as an example.
503
504Aside 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
510Otherwise, 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
516In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
517
518It's a RainTPL loop like this:
519
520 {loop="$plugin_variable"}
521 {$value}
522 {/loop}
523
524You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
525
526### List of placeholders
527
528**page.header.html**
529
530At the end of the menu:
531
532 {loop="$plugins_header.buttons_toolbar"}
533 {$value}
534 {/loop}
535
536At 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
548At 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
558At the end of your footer notes:
559
560```html
561{loop="$plugins_footer.text"}
562 {$value}
563{/loop}
564```
565
566At 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
576After search fields:
577
578```html
579{loop="$plugins_header.fields_toolbar"}
580 {$value}
581{/loop}
582```
583
584Before displaying the link list (after paging):
585
586```html
587{loop="$plugin_start_zone"}
588 {$value}
589{/loop}
590```
591
592For every links (icons):
593
594```html
595{loop="$value.link_plugin"}
596 <span>{$value}</span>
597{/loop}
598```
599
600Before end paging:
601
602```html
603{loop="$plugin_end_zone"}
604 {$value}
605{/loop}
606```
607
608**linklist.paging.html**
609
610After the "private only" icon:
611
612```html
613{loop="$action_plugin"}
614 {$value}
615{/loop}
616```
617
618**editlink.html**
619
620After tags field:
621
622```html
623{loop="$edit_link_plugin"}
624 {$value}
625{/loop}
626```
627
628**tools.html**
629
630After the last tool:
631
632```html
633{loop="$tools_plugin"}
634 {$value}
635{/loop}
636```
637
638**picwall.html**
639
640Top:
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
650Bottom:
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
662Top:
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
672Bottom:
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
684Top:
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
694After every link:
695
696```html
697<div class="dailyEntryFooter">
698 {loop="$link.link_plugin"}
699 {$value}
700 {/loop}
701</div>
702```
703
704Bottom:
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
716In headers tags section:
717```xml
718{loop="$feed_plugins_header"}
719 {$value}
720{/loop}
721```
722
723After each entry:
724```xml
725{loop="$value.feed_plugins"}
726 {$value}
727{/loop}
728```