]> git.immae.eu Git - github/shaarli/Shaarli.git/blame - doc/Plugin-System.md
Markdown: inline code background color
[github/shaarli/Shaarli.git] / doc / Plugin-System.md
CommitLineData
992af0b9 1#Plugin System
5409ade2 2> Note: Plugin current status - in development (not merged into master).
992af0b9 3
5409ade2 4[**I am a developer.** Developer API.](#developer-api)[](.html)
992af0b9
V
5
6[**I am a template designer.** Guide for template designer.](#guide-for-template-designer)[](.html)
7
5409ade2 8## Developer API
992af0b9
V
9
10### What can I do with plugins?
11
12The plugin system let you:
13
14 * insert content into specific places across templates.
15 * alter data before templates rendering.
16 * alter data before saving new links.
17
18### How can I create a plugin for Shaarli?
19
20First, chose a plugin name, such as `demo_plugin`.
21
22Under `plugin` folder, create a folder named with your plugin name. Then create a <plugin_name>.php file in that folder.
23
24You should have the following tree view:
25
26```
27| index.php
28| plugins/
29|---| demo_plugin/
30| |---| demo_plugin.php
31```
32
33### Understanding hooks
34
35A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
36
37These functions need to be named with this pattern:
38
39```
40hook_<plugin_name>_<hook_name>
41```
42
43For exemple, if my plugin want to add data to the header, this function is needed:
44
45 hook_demo_plugin_render_header()
46
47If this function is declared, and the plugin enabled, it will be called every time Shaarli is rendering the header.
48
49### Plugin's data
50
51#### Parameters
52
53Every hook function has a `$data` parameter. Its content differs for each hooks.
54
55**This parameter needs to be returned every time**, otherwise data is lost.
56
57 return $data;
58
59#### Filling templates placeholder
60
61Template placeholders are displayed in template in specific places.
62
63RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
64
65For example, let's add a value in the placeholder `top_placeholder` which is displayed at the top of my page:
66
67```php
68$data['top_placeholder'[] = 'My content';](]-=-'My-content';.html)
69# OR
70array_push($data['top_placeholder'], 'My', 'content');[](.html)
71
72return $data;
73```
74
75#### Data manipulation
76
77When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
78
79The data contained by this array can be altered before template rendering.
80
81For exemple, in linklist, it is possible to alter every title:
82
83```php
84// mind the reference if you want $data to be altered
85foreach ($data['links'] as &$value) {[](.html)
86 // String reverse every title.
87 $value['title'] = strrev($value['title']);[](.html)
88}
89
90return $data;
91```
92
5409ade2
A
93### Metadata
94
95Every plugin needs a `<plugin_name>.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration.
96
97Each file contain two keys:
98
99 * `description`: plugin description
100 * `parameters`: user parameter names, separated by a `;`.
101
102> Note: In PHP, `parse_ini_file()` seems to want strings to be between by quotes `"` in the ini file.
103
992af0b9
V
104### It's not working!
105
106Use `demo_plugin` as a functional example. It covers most of the plugin system features.
107
108If it's still not working, please [open an issue](https://github.com/shaarli/Shaarli/issues/new).[](.html)
109
110### Hooks
111
112| Hooks | Description |
113| ------------- |:-------------:|
114| [render_header](#render_header) | Allow plugin to add content in page headers. |[](.html)
115| [render_includes](#render_includes) | Allow plugin to include their own CSS files. |[](.html)
116| [render_footer](#render_footer) | Allow plugin to add content in page footer and include their own JS files. | [](.html)
117| [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)
118| [render_editlink](#render_editlink) | Allow to add fields in the form, or display elements. |[](.html)
119| [render_tools](#render_tools) | Allow to add content at the end of the page. |[](.html)
120| [render_picwall](#render_picwall) | Allow to add content at the top and bottom of the page. |[](.html)
121| [render_tagcloud](#render_tagcloud) | Allow to add content at the top and bottom of the page. |[](.html)
122| [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)
123| [savelink](#savelink) | Allow to alter the link being saved in the datastore. |[](.html)
124
125
126#### render_header
127
128Triggered on every page.
129
130Allow plugin to add content in page headers.
131
132##### Data
133
134`$data` is an array containing:
135
136 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
137 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
138
139##### Template placeholders
140
141Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
142
143List of placeholders:
144
145 * `buttons_toolbar`: after the list of buttons in the header.
146
147![buttons_toolbar_example](http://i.imgur.com/ssJUOrt.png)[](.html)
148
149 * `fields_toolbar`: after search fields in the header.
150
151> Note: This will only be called in linklist.
152
153![fields_toolbar_example](http://i.imgur.com/3GMifI2.png)[](.html)
154
155#### render_includes
156
157Triggered on every page.
158
159Allow plugin to include their own CSS files.
160
161##### Data
162
163`$data` is an array containing:
164
165 * `_PAGE_`: current target page (eg: `linklist`, `picwall`, etc.).
166 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
167
168##### Template placeholders
169
170Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
171
172List of placeholders:
173
174 * `css_files`: called after loading default CSS.
175
176> Note: only add the path of the CSS file. E.g: `plugins/demo_plugin/custom_demo.css`.
177
178#### render_footer
179
180Triggered on every page.
181
182Allow plugin to add content in page footer and include their own JS 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
193Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
194
195List of placeholders:
196
197 * `text`: called after the end of the footer text.
198
199![text_example](http://i.imgur.com/L5S2YEH.png)[](.html)
200
201 * `js_files`: called at the end of the page, to include custom JS scripts.
202
203> Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`.
204
205#### render_linklist
206
207Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
208
209It allows to add content at the begining and end of the page, after every link displayed and to alter link data.
210
211##### Data
212
213`$data` is an array containing:
214
215 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
216 * All templates data, including links.
217
218##### Template placeholders
219
220Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
221
222List of placeholders:
223
224 * `action_plugin`: next to the button "private only" at the top and bottom of the page.
225
226![action_plugin_example](http://i.imgur.com/Q12PWg0.png)[](.html)
227
228 * `link_plugin`: for every link, between permalink and link URL.
229
230![link_plugin_example](http://i.imgur.com/3oDPhWx.png)[](.html)
231
232 * `plugin_start_zone`: before displaying the template content.
233
234![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)[](.html)
235
236 * `plugin_end_zone`: after displaying the template content.
237
238![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)[](.html)
239
240#### render_editlink
241
242Triggered when the link edition form is displayed.
243
244Allow to add fields in the form, or display elements.
245
246##### Data
247
248`$data` is an array containing:
249
250 * All templates data.
251
252##### Template placeholders
253
254Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
255
256List of placeholders:
257
258 * `edit_link_plugin`: after tags field.
259
260![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)[](.html)
261
262#### render_tools
263
264Triggered when the "tools" page is displayed.
265
266Allow to add content at the end of the page.
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.[](.html)
277
278List of placeholders:
279
280 * `tools_plugin`: at the end of the page.
281
282![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)[](.html)
283
284#### render_picwall
285
286Triggered when picwall is displayed.
287
288Allow to add content at the top and bottom of the page.
289
290##### Data
291
292`$data` is an array containing:
293
294 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
295 * All templates data.
296
297##### Template placeholders
298
299Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
300
301List of placeholders:
302
303 * `plugin_start_zone`: before displaying the template content.
304
305 * `plugin_end_zone`: after displaying the template content.
306
307![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)[](.html)
308
309#### render_tagcloud
310
311Triggered when tagcloud is displayed.
312
313Allow to add content at the top and bottom of the page.
314
315##### Data
316
317`$data` is an array containing:
318
319 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
320 * All templates data.
321
322##### Template placeholders
323
324Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
325
326List of placeholders:
327
328 * `plugin_start_zone`: before displaying the template content.
329
330 * `plugin_end_zone`: after displaying the template content.
331
332![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)[](.html)
333
334#### render_daily
335
336Triggered when tagcloud is displayed.
337
338Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.
339
340##### Data
341
342`$data` is an array containing:
343
344 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
345 * All templates data, including links.
346
347##### Template placeholders
348
349Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
350
351List of placeholders:
352
353 * `link_plugin`: used at bottom of each link.
354
355![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)[](.html)
356
357 * `plugin_start_zone`: before displaying the template content.
358
359 * `plugin_end_zone`: after displaying the template content.
360
361#### savelink
362
363Triggered when a link is save (new link or edit).
364
365Allow to alter the link being saved in the datastore.
366
367##### Data
368
369`$data` is an array containing the link being saved:
370
371 * title
372 * url
373 * description
374 * linkdate
375 * private
376 * tags
377
378## Guide for template designer
379
5409ade2
A
380### Plugin administration
381
382Your theme must include a plugin administration page: `pluginsadmin.html`.
383
384> Note: repo's template link needs to be added when the PR is merged.
385
386Use the default one as an example.
387
388Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if:
389
390 * you're using a table.
391 * you call orderUp() and orderUp() onclick on arrows.
392 * you add data-line and data-order to your rows.
393
394Otherwise, you can use your own JS as long as this field is send by the form:
395
396<input type="hidden" name="order_{$key}" value="{$counter}">
397
992af0b9
V
398### Placeholder system
399
400In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
401
402It's a RainTPL loop like this:
403
404 {loop="$plugin_variable"}
405 {$value}
406 {/loop}
407
408You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
409
410### List of placeholders
411
412**page.header.html**
413
414At the end of the menu:
415
416 {loop="$plugins_header.buttons_toolbar"}
417 {$value}
418 {/loop}
419
5409ade2
A
420At the end of file, before clearing floating blocks:
421
422 {if="!empty($plugin_errors) && isLoggedIn()"}
423 <ul class="errors">
424 {loop="plugin_errors"}
425 <li>{$value}</li>
426 {/loop}
427 </ul>
428 {/if}
429
992af0b9
V
430**includes.html**
431
432At the end of the file:
433
434```html
435{loop="$plugins_includes.css_files"}
436<link type="text/css" rel="stylesheet" href="{$value}#"/>
437{/loop}
438```
439
440**page.footer.html**
441
442At the end of your footer notes:
443
444```html
445{loop="$plugins_footer.text"}
446 {$value}
447{/loop}
448```
449
450At the end of file:
451
452```html
453{loop="$plugins_footer.js_files"}
454 <script src="{$value}#"></script>
455{/loop}
456```
457
458**linklist.html**
459
460After search fields:
461
462```html
463{loop="$plugins_header.fields_toolbar"}
464 {$value}
465{/loop}
466```
467
468Before displaying the link list (after paging):
469
470```html
471{loop="$plugin_start_zone"}
472 {$value}
473{/loop}
474```
475
476For every links (icons):
477
478```html
479{loop="$value.link_plugin"}
480 <span>{$value}</span>
481{/loop}
482```
483
484Before end paging:
485
486```html
487{loop="$plugin_end_zone"}
488 {$value}
489{/loop}
490```
491
492**linklist.paging.html**
493
494After the "private only" icon:
495
496```html
497{loop="$action_plugin"}
498 {$value}
499{/loop}
500```
501
502**editlink.html**
503
504After tags field:
505
506```html
507{loop="$edit_link_plugin"}
508 {$value}
509{/loop}
510```
511
512**tools.html**
513
514After the last tool:
515
516```html
517{loop="$tools_plugin"}
518 {$value}
519{/loop}
520```
521
522**picwall.html**
523
524Top:
525
526```html
527<div id="plugin_zone_start_picwall" class="plugin_zone">
528 {loop="$plugin_start_zone"}
529 {$value}
530 {/loop}
531</div>
532```
533
534Bottom:
535
536```html
537<div id="plugin_zone_end_picwall" class="plugin_zone">
538 {loop="$plugin_end_zone"}
539 {$value}
540 {/loop}
541</div>
542```
543
544**tagcloud.html**
545
546Top:
547
548```html
549 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
550 {loop="$plugin_start_zone"}
551 {$value}
552 {/loop}
553 </div>
554```
555
556Bottom:
557
558```html
559 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
560 {loop="$plugin_end_zone"}
561 {$value}
562 {/loop}
563 </div>
564```
565
566**daily.html**
567
568Top:
569
570```html
571<div id="plugin_zone_start_picwall" class="plugin_zone">
572 {loop="$plugin_start_zone"}
573 {$value}
574 {/loop}
575</div>
576```
577
578After every link:
579
580```html
581<div class="dailyEntryFooter">
582 {loop="$link.link_plugin"}
583 {$value}
584 {/loop}
585</div>
586```
587
588Bottom:
589
590```html
591<div id="plugin_zone_end_picwall" class="plugin_zone">
592 {loop="$plugin_end_zone"}
593 {$value}
594 {/loop}
595</div>
596```