]> git.immae.eu Git - github/shaarli/Shaarli.git/blob - doc/Plugin-System.md
Fix blocking namespace issue
[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 * `endofpage`: called at the end of the page.
199
200 ![text_example](http://i.imgur.com/L5S2YEH.png)[](.html)
201
202 * `js_files`: called at the end of the page, to include custom JS scripts.
203
204 > Note: only add the path of the JS file. E.g: `plugins/demo_plugin/custom_demo.js`.
205
206 #### render_linklist
207
208 Triggered when `linklist` is displayed (list of links, permalink, search, tag filtered, etc.).
209
210 It allows to add content at the begining and end of the page, after every link displayed and to alter link data.
211
212 ##### Data
213
214 `$data` is an array containing:
215
216 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
217 * All templates data, including links.
218
219 ##### Template placeholders
220
221 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
222
223 List of placeholders:
224
225 * `action_plugin`: next to the button "private only" at the top and bottom of the page.
226
227 ![action_plugin_example](http://i.imgur.com/Q12PWg0.png)[](.html)
228
229 * `link_plugin`: for every link, between permalink and link URL.
230
231 ![link_plugin_example](http://i.imgur.com/3oDPhWx.png)[](.html)
232
233 * `plugin_start_zone`: before displaying the template content.
234
235 ![plugin_start_zone_example](http://i.imgur.com/OVBkGy3.png)[](.html)
236
237 * `plugin_end_zone`: after displaying the template content.
238
239 ![plugin_end_zone_example](http://i.imgur.com/6IoRuop.png)[](.html)
240
241 #### render_editlink
242
243 Triggered when the link edition form is displayed.
244
245 Allow to add fields in the form, or display elements.
246
247 ##### Data
248
249 `$data` is an array containing:
250
251 * All templates data.
252
253 ##### Template placeholders
254
255 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
256
257 List of placeholders:
258
259 * `edit_link_plugin`: after tags field.
260
261 ![edit_link_plugin_example](http://i.imgur.com/5u17Ens.png)[](.html)
262
263 #### render_tools
264
265 Triggered when the "tools" page is displayed.
266
267 Allow to add content at the end of the page.
268
269 ##### Data
270
271 `$data` is an array containing:
272
273 * All templates data.
274
275 ##### Template placeholders
276
277 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
278
279 List of placeholders:
280
281 * `tools_plugin`: at the end of the page.
282
283 ![tools_plugin_example](http://i.imgur.com/Bqhu9oQ.png)[](.html)
284
285 #### render_picwall
286
287 Triggered when picwall is displayed.
288
289 Allow to add content at the top and bottom of the page.
290
291 ##### Data
292
293 `$data` is an array containing:
294
295 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
296 * All templates data.
297
298 ##### Template placeholders
299
300 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
301
302 List of placeholders:
303
304 * `plugin_start_zone`: before displaying the template content.
305
306 * `plugin_end_zone`: after displaying the template content.
307
308 ![plugin_start_end_zone_example](http://i.imgur.com/tVTQFER.png)[](.html)
309
310 #### render_tagcloud
311
312 Triggered when tagcloud is displayed.
313
314 Allow to add content at the top and bottom of the page.
315
316 ##### Data
317
318 `$data` is an array containing:
319
320 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
321 * All templates data.
322
323 ##### Template placeholders
324
325 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
326
327 List of placeholders:
328
329 * `plugin_start_zone`: before displaying the template content.
330
331 * `plugin_end_zone`: after displaying the template content.
332
333 ![plugin_start_end_zone_example](http://i.imgur.com/vHmyT3a.png)[](.html)
334
335 #### render_daily
336
337 Triggered when tagcloud is displayed.
338
339 Allow to add content at the top and bottom of the page, the bottom of each link and to alter data.
340
341 ##### Data
342
343 `$data` is an array containing:
344
345 * `_LOGGEDIN_`: true if user is logged in, false otherwise.
346 * All templates data, including links.
347
348 ##### Template placeholders
349
350 Items can be displayed in templates by adding an entry in `$data['<placeholder>']` array.[](.html)
351
352 List of placeholders:
353
354 * `link_plugin`: used at bottom of each link.
355
356 ![link_plugin_example](http://i.imgur.com/hzhMfSZ.png)[](.html)
357
358 * `plugin_start_zone`: before displaying the template content.
359
360 * `plugin_end_zone`: after displaying the template content.
361
362 #### savelink
363
364 Triggered when a link is save (new link or edit).
365
366 Allow to alter the link being saved in the datastore.
367
368 ##### Data
369
370 `$data` is an array containing the link being saved:
371
372 * title
373 * url
374 * description
375 * linkdate
376 * private
377 * tags
378
379 ## Guide for template designer
380
381 ### Plugin administration
382
383 Your theme must include a plugin administration page: `pluginsadmin.html`.
384
385 > Note: repo's template link needs to be added when the PR is merged.
386
387 Use the default one as an example.
388
389 Aside from classic RainTPL loops, plugins order is handle by JavaScript. You can just include `plugin_admin.js`, only if:
390
391 * you're using a table.
392 * you call orderUp() and orderUp() onclick on arrows.
393 * you add data-line and data-order to your rows.
394
395 Otherwise, you can use your own JS as long as this field is send by the form:
396
397 <input type="hidden" name="order_{$key}" value="{$counter}">
398
399 ### Placeholder system
400
401 In order to make plugins work with every custom themes, you need to add variable placeholder in your templates.
402
403 It's a RainTPL loop like this:
404
405 {loop="$plugin_variable"}
406 {$value}
407 {/loop}
408
409 You should enable `demo_plugin` for testing purpose, since it uses every placeholder available.
410
411 ### List of placeholders
412
413 **page.header.html**
414
415 At the end of the menu:
416
417 {loop="$plugins_header.buttons_toolbar"}
418 {$value}
419 {/loop}
420
421 At the end of file, before clearing floating blocks:
422
423 {if="!empty($plugin_errors) && isLoggedIn()"}
424 <ul class="errors">
425 {loop="plugin_errors"}
426 <li>{$value}</li>
427 {/loop}
428 </ul>
429 {/if}
430
431 **includes.html**
432
433 At the end of the file:
434
435 ```html
436 {loop="$plugins_includes.css_files"}
437 <link type="text/css" rel="stylesheet" href="{$value}#"/>
438 {/loop}
439 ```
440
441 **page.footer.html**
442
443 At the end of your footer notes:
444
445 ```html
446 {loop="$plugins_footer.text"}
447 {$value}
448 {/loop}
449 ```
450
451 At the end of file:
452
453 ```html
454 {loop="$plugins_footer.js_files"}
455 <script src="{$value}#"></script>
456 {/loop}
457 ```
458
459 **linklist.html**
460
461 After search fields:
462
463 ```html
464 {loop="$plugins_header.fields_toolbar"}
465 {$value}
466 {/loop}
467 ```
468
469 Before displaying the link list (after paging):
470
471 ```html
472 {loop="$plugin_start_zone"}
473 {$value}
474 {/loop}
475 ```
476
477 For every links (icons):
478
479 ```html
480 {loop="$value.link_plugin"}
481 <span>{$value}</span>
482 {/loop}
483 ```
484
485 Before end paging:
486
487 ```html
488 {loop="$plugin_end_zone"}
489 {$value}
490 {/loop}
491 ```
492
493 **linklist.paging.html**
494
495 After the "private only" icon:
496
497 ```html
498 {loop="$action_plugin"}
499 {$value}
500 {/loop}
501 ```
502
503 **editlink.html**
504
505 After tags field:
506
507 ```html
508 {loop="$edit_link_plugin"}
509 {$value}
510 {/loop}
511 ```
512
513 **tools.html**
514
515 After the last tool:
516
517 ```html
518 {loop="$tools_plugin"}
519 {$value}
520 {/loop}
521 ```
522
523 **picwall.html**
524
525 Top:
526
527 ```html
528 <div id="plugin_zone_start_picwall" class="plugin_zone">
529 {loop="$plugin_start_zone"}
530 {$value}
531 {/loop}
532 </div>
533 ```
534
535 Bottom:
536
537 ```html
538 <div id="plugin_zone_end_picwall" class="plugin_zone">
539 {loop="$plugin_end_zone"}
540 {$value}
541 {/loop}
542 </div>
543 ```
544
545 **tagcloud.html**
546
547 Top:
548
549 ```html
550 <div id="plugin_zone_start_tagcloud" class="plugin_zone">
551 {loop="$plugin_start_zone"}
552 {$value}
553 {/loop}
554 </div>
555 ```
556
557 Bottom:
558
559 ```html
560 <div id="plugin_zone_end_tagcloud" class="plugin_zone">
561 {loop="$plugin_end_zone"}
562 {$value}
563 {/loop}
564 </div>
565 ```
566
567 **daily.html**
568
569 Top:
570
571 ```html
572 <div id="plugin_zone_start_picwall" class="plugin_zone">
573 {loop="$plugin_start_zone"}
574 {$value}
575 {/loop}
576 </div>
577 ```
578
579 After every link:
580
581 ```html
582 <div class="dailyEntryFooter">
583 {loop="$link.link_plugin"}
584 {$value}
585 {/loop}
586 </div>
587 ```
588
589 Bottom:
590
591 ```html
592 <div id="plugin_zone_end_picwall" class="plugin_zone">
593 {loop="$plugin_end_zone"}
594 {$value}
595 {/loop}
596 </div>
597 ```