]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - doc/Plugin-System.md
Merge pull request #559 from ArthurHoaro/startsEndWithCase
[github/shaarli/Shaarli.git] / doc / Plugin-System.md
1 #Plugin System
2 > Note: Plugin current status - in development (not merged into master).
3
4 [**I am a developer.** Developer API.](#developer-api)[](.html)
5
6 [**I am a template designer.** Guide for template designer.](#guide-for-template-designer)[](.html)
7
8 ## Developer API
9
10 ### What can I do with plugins?
11
12 The 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
20 First, chose a plugin name, such as `demo_plugin`.
21
22 Under `plugin` folder, create a folder named with your plugin name. Then create a <plugin_name>.php file in that folder.
23
24 You 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
35 A plugin is a set of functions. Each function will be triggered by the plugin system at certain point in Shaarli execution.
36
37 These functions need to be named with this pattern:
38
39 ```
40 hook_<plugin_name>_<hook_name>
41 ```
42
43 For exemple, if my plugin want to add data to the header, this function is needed:
44
45 hook_demo_plugin_render_header()
46
47 If 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
53 Every 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
61 Template placeholders are displayed in template in specific places.
62
63 RainTPL displays every element contained in the placeholder's array. These element can be added by plugins.
64
65 For 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
70 array_push($data['top_placeholder'], 'My', 'content');[](.html)
71
72 return $data;
73 ```
74
75 #### Data manipulation
76
77 When a page is displayed, every variable send to the template engine is passed to plugins before that in `$data`.
78
79 The data contained by this array can be altered before template rendering.
80
81 For exemple, in linklist, it is possible to alter every title:
82
83 ```php
84 // mind the reference if you want $data to be altered
85 foreach ($data['links'] as &$value) {[](.html)
86 // String reverse every title.
87 $value['title'] = strrev($value['title']);[](.html)
88 }
89
90 return $data;
91 ```
92
93 ### Metadata
94
95 Every plugin needs a `<plugin_name>.meta` file, which is in fact an `.ini` file (`KEY="VALUE"`), to be listed in plugin administration.
96
97 Each 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
104 ### It's not working!
105
106 Use `demo_plugin` as a functional example. It covers most of the plugin system features.
107
108 If 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
128 Triggered on every page.
129
130 Allow 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
141 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
142
143 List 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
157 Triggered on every page.
158
159 Allow 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
170 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
171
172 List 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
180 Triggered on every page.
181
182 Allow 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
193 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
194
195 List 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
207 Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
208
209 It 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
220 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
221
222 List 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
242 Triggered when the link edition form is displayed.
243
244 Allow 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
254 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
255
256 List 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
264 Triggered when the "tools" page is displayed.
265
266 Allow 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
276 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
277
278 List 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
286 Triggered when picwall is displayed.
287
288 Allow 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
299 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
300
301 List 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
311 Triggered when tagcloud is displayed.
312
313 Allow 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
324 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
325
326 List 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
336 Triggered when tagcloud is displayed.
337
338 Allow 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
349 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
350
351 List 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
363 Triggered when a link is save (new link or edit).
364
365 Allow 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
380 ### Plugin administration
381
382 Your 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
386 Use the default one as an example.
387
388 Aside 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
394 Otherwise, 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
398 ### Placeholder system
399
400 In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
401
402 It's a RainTPL loop like this:
403
404 {loop="$plugin_variable"}
405 {$value}
406 {/loop}
407
408 You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
409
410 ### List of placeholders
411
412 **page.header.html**
413
414 At the end of the menu:
415
416 {loop="$plugins_header.buttons_toolbar"}
417 {$value}
418 {/loop}
419
420 At 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
430 **includes.html**
431
432 At 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
442 At the end of your footer notes:
443
444 ```html
445 {loop="$plugins_footer.text"}
446 {$value}
447 {/loop}
448 ```
449
450 At 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
460 After search fields:
461
462 ```html
463 {loop="$plugins_header.fields_toolbar"}
464 {$value}
465 {/loop}
466 ```
467
468 Before displaying the link list (after paging):
469
470 ```html
471 {loop="$plugin_start_zone"}
472 {$value}
473 {/loop}
474 ```
475
476 For every links (icons):
477
478 ```html
479 {loop="$value.link_plugin"}
480 <span>{$value}</span>
481 {/loop}
482 ```
483
484 Before end paging:
485
486 ```html
487 {loop="$plugin_end_zone"}
488 {$value}
489 {/loop}
490 ```
491
492 **linklist.paging.html**
493
494 After the "private only" icon:
495
496 ```html
497 {loop="$action_plugin"}
498 {$value}
499 {/loop}
500 ```
501
502 **editlink.html**
503
504 After tags field:
505
506 ```html
507 {loop="$edit_link_plugin"}
508 {$value}
509 {/loop}
510 ```
511
512 **tools.html**
513
514 After the last tool:
515
516 ```html
517 {loop="$tools_plugin"}
518 {$value}
519 {/loop}
520 ```
521
522 **picwall.html**
523
524 Top:
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
534 Bottom:
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
546 Top:
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
556 Bottom:
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
568 Top:
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
578 After every link:
579
580 ```html
581 <div class="dailyEntryFooter">
582 {loop="$link.link_plugin"}
583 {$value}
584 {/loop}
585 </div>
586 ```
587
588 Bottom:
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 ```