Last modified by slauriere on 2024/09/17

Hide last authors
Manuel Smeria 85.2 1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
Manuel Smeria 85.1 4
Manuel Smeria 85.2 5 Wiki macros allow macro authors to develop reusable and distributable macro modules. There is no java code involved; hence no compiling or packaging. The macro author simply needs to create a wiki page according to a particular specification and that's all!
Asiri Rathnayake 4.1 6
Vincent Massol 94.3 7 This page is a tutorial but you can also access the [[reference documentation for the Wiki Macro feature>>doc:extensions:Extension.WikiMacroStore.WebHome]].
Vincent Massol 92.1 8
Manuel Smeria 85.2 9 = Hello Macro =
Asiri Rathnayake 5.1 10
Asiri Rathnayake 6.1 11 We are going to start with a very simple xwiki/2.0 wiki macro which prints a greeting message to the document content. It isn't a very useful macro but the idea is to get you familiarised with the wiki macro creation process.
Asiri Rathnayake 5.1 12
Manuel Smeria 85.2 13 == Definition ==
Asiri Rathnayake 5.1 14
Thomas Mortagne 120.1 15 Wiki macros are defined using objects of type ##XWiki.WikiMacroClass##. You define a wiki macro by creating a new wiki page and attaching to it an object of type ##XWiki.WikiMacroClass##. You will need to [[be advanced>>Documentation.UserGuide.Features.PageEditing||anchor="HAdvancedProfile"]] to access the [[object editor>>Documentation.UserGuide.Features.PageEditing||anchor="HObjectseditingmode"]].
Asiri Rathnayake 5.1 16
Thomas Mortagne 90.1 17 {{warning}}
18 There can be only one object of type ##XWiki.WikiMacroClass## per wiki page (if you add more only the first will be used).
19 {{/warning}}
Valdis Vitolins 89.1 20
21 This class contains the following fields:
22
Thomas Mortagne 98.1 23 * **Macro id**: Id of the macro to be used by users when invoking your macro from wiki code
24 * **Macro name**: Name of the macro to be displayed on the wysiwyg editor
25 * **Macro description**: A short description of the macro to be displayed on the WYSIWYG editor
Vincent Massol 131.3 26 * {{version since="14.4RC1"}}**Default categories**: Default categories under which this macro should be listed{{/version}} ({{version before="14.4RC1"}}It was called "Default category"{{/version}})
Vincent Massol 133.1 27 ** A list of [[default categories used is available>>Documentation.DevGuide.Tutorials.WritingMacros.MacroDefaultCategories.WebHome]].
Thomas Mortagne 98.1 28 * **Supports inline mode**: Whether the macro can be used in an inline context or not
Vincent Massol 131.2 29 * **Macro content availability**: Whether this macro should support a body or not. Valid values are "Optional", "Mandatory" and "No Content".
30 * **Macro content type**: The type of accepted content: two values are proposed, ##WIKI## if this content should be editable like a wiki content, or ##UNKNOWN## if it should be displayed like a plain text. It's also possible to specify a custom java type such as {{code language="java"}}java.util.List<java.lang.String>{{/code}}. Leaving the field blank is equivalent to ##UNKWOWN## value.
Thomas Mortagne 98.1 31 * **Content description**: A short description about the macro's content to be displayed on the WYSIWYG editor
32 * **Macro code**: The actual wiki code that will be evaluated when the macro is executed, can be any xwiki content (should be in the same syntax as the document)
Vincent Massol 131.2 33 * **Priority**: The priority of execution relative to the other Macros. The lowest values have the highest priorities and execute first. For example a Macro with a priority of 100 will execute before one with a priority of 500. The default value is 1000.
slauriere 134.1 34 * **Asynchronous rendering**: Enabled or disable asynchronous rendering of the macro. Disabled by default.
Vincent Massol 131.2 35 * **Cached**: Indicate if the result of the execution of the element should be cached. Disabled by default.
36 * **Context elements**: The context information required during the execution of the extension (current user, current document, etc.). It's also used to generate the cache key.
Manuel Smeria 85.2 37
Asiri Rathnayake 24.1 38 Now we can define our hello macro as shown below:
Manuel Smeria 85.2 39
Manuel Leduc 123.2 40 {{image reference="macro1.png" width="650px"/}}
Asiri Rathnayake 7.1 41
Manuel Smeria 85.2 42 == Invocation ==
Asiri Rathnayake 10.1 43
Manuel Leduc 125.1 44 A wiki macro can be invoked just like any other macro is invoked. Since we are writing a xwiki/2.1 wiki macro, we can invoke our **hello macro** as below:
Asiri Rathnayake 10.1 45
Thomas Mortagne 118.1 46 {{code language="none"}}
Valdis Vitolins 86.1 47 {{hello/}}
48 {{/code}}
Asiri Rathnayake 13.1 49
Asiri Rathnayake 16.1 50 And if you view the result it would say "Hello World!" (of course).
Asiri Rathnayake 13.1 51
Valdis Vitolins 86.1 52 == Content ==
53
Michael Hamann 122.1 54 The easiest way to insert the content of the wiki macro is to use a dedicated macro in the body of the wikimacro:
Simon Urli 102.1 55
Vincent Massol 117.2 56 {{code language='none'}}
Simon Urli 99.1 57 {{wikimacrocontent/}}
58 {{/code}}
59
60 Note that by default this makes the content of the macro directly editable in [[the WYSIWYG editor>>https://extensions.xwiki.org/xwiki/bin/view/Extension/CKEditor%20Integration/#HWikiMacros]].
Valdis Vitolins 87.1 61
Vincent Massol 117.4 62 For more details, see the [[Scripting Tips section below>>||anchor="HScriptingTips"]].
Vincent Massol 87.2 63
Manuel Smeria 85.2 64 == Parameters ==
Asiri Rathnayake 38.1 65
Manuel Smeria 85.2 66 Introducing a parameter to a wiki macro is pretty straight forward; you simply need to add an object of type ##XWiki.WikiMacroParameterClass## into your wiki macro document (one object per parameter). This class contains several fields that allow you to define your parameter clearly:
Asiri Rathnayake 42.1 67
Vincent Massol 132.1 68 * **Parameter name**: Name of the parameter, users will refer this name when invoking your macro with parameters
69 * **Parameter description** (optional): A short description of the parameter, this description will be made available on the WYSIWYG editor
70 * **Parameter mandatory**: Indicates if this particular parameter is mandatory, wiki macro will fail to execute if a mandatory parameter is missing
71 * **Parameter default value** (optional): The default value of the parameter when it's empty
72 * **Parameter type** (optional): Indicates to which Java type the parameter value (defined as a String). Two values are proposed, ##WIKI## if this parameter contains wiki content, or ##UNKNOWN## if it should be displayed like a plain text. It's also possible to specify a custom java type such as {{code language="java"}}java.util.List<java.lang.String>{{/code}}. Leaving the field blank is equivalent to ##UNKWOWN## value.
73 ** This is needed when using the ##{~{wikimacroparameter}}## macro (see below), which uses this type to decide how to render the macro parameter.
Anca Luca 131.1 74 ** For more information about parameter types and parameter pickers, see: [[Using pickers for XWiki Rendering Macro parameters>>Documentation.DevGuide.Tutorials.WritingMacros.Using custom pickers for XWiki Rendering Macro parameters.WebHome]]
Manuel Smeria 85.2 75
76 Now we're going to extend our **hello macro** with a parameter. We will introduce a parameter named //greetUser// that will indicate if the greeting message should be tailored for the current user viewing the page. The definition of the parameter is shown below:
77
Manuel Smeria 85.1 78 [[image:macro3.png]]
Asiri Rathnayake 42.1 79
Manuel Smeria 85.2 80 A macro parameter defined this way can be accessed from any scripting language within the macro code. For example, we are going to utilize our //greetUser// parameter within **hello macro** as shown below:
81
Thomas Mortagne 118.1 82 {{code language="none"}}
Simon Urli 113.1 83 {{velocity}}
84 #if ($wikimacro.parameters.greetUser && "XWiki.XWikiGuest" != "$xcontext.user")
Michael Hamann 121.1 85 Hello $services.rendering.escape($xwiki.user.email, 'xwiki/2.1')!
Simon Urli 113.1 86 #else
87 Hello world!
88 #end
89 {{/velocity}}
90 {{/code}}
Asiri Rathnayake 44.1 91
Vincent Massol 131.5 92 As you might have realized already, direct binding of parameters is not supported at the moment. That is, you cannot access //greetUser// parameter with **$greetUser**. Instead you must use **$wikimacro.parameters.greetUser**. We plan to introduce some form of direct parameter binding in the future.
Asiri Rathnayake 38.1 93
Vincent Massol 131.2 94 It is also possible to display the content of a macro parameter by using a dedicated macro:
95
Michael Hamann 121.1 96 {{code language="none"}}Hello {{wikimacroparameter name="greetUsers" /}}{{/code}}
Simon Urli 103.1 97
Manuel Smeria 85.2 98 Finally, we can test our new version of **hello macro** with the following invocation:
Asiri Rathnayake 42.1 99
Thomas Mortagne 118.1 100 {{code language="none"}}
Valdis Vitolins 86.1 101 {{hello greetUser="true"/}}
102 {{/code}}
Asiri Rathnayake 14.1 103
Robert 94.1 104 If you want to call the new version of the **hello macro** with a parameter from a variable you will need to wrap the call in a velocity macro like this:
105
Thomas Mortagne 118.1 106 {{code language="none"}}
Robert 94.1 107 {{velocity}}
108 #set ($greet = true)
109 {{hello greetUser="$greet"/}}
110 {{/velocity}}
Simon Urli 104.1 111 {{/code}}
Robert 94.1 112
Pascal Bastien 91.2 113 == Translations ==
Anca Luca 91.1 114
Simon Urli 132.3 115 When your macro is ready, you might want to provide the description of the macro and its parameters in different languages. For that, you need to create a set of translation keys and values (as described [[here>>xwiki:Documentation.DevGuide.InternationalizingApplications]]) and then just use the following convention for the keys you add in this storage (no modification is needed on the macro itself, the association of the translations to the macro is done based on a convention of the form of the translation keys):
Anca Luca 91.1 116
Thomas Mortagne 118.1 117 {{code language="properties"}}
Anca Luca 91.1 118 rendering.macro.<macro id>.name=Name of the macro, displayed in the macros list in the macros wizard
119 rendering.macro.<macro id>.description=Description of the macro, displayed as a help in the macros list in the macros wizard
120
121 rendering.macro.<macro id>.parameter.<parameter name>.name=Name of the macro parameter, to be displayed in the form for the macro settings in the macros wizard
122 rendering.macro.<macro id>.parameter.<parameter name>.description=Description of the macro parameter, to be displayed as a help in the form for the macro settings in the macros wizard
123 {{/code}}
124
125 Don't forget to make sure that the visibility of the translations is the same as the visibility of the macro, so that anywhere you use the macro you also have the translations.
126
127 In our example, french translations would be something like this:
128
Thomas Mortagne 118.1 129 {{code language="properties"}}
Anca Luca 91.1 130 rendering.macro.hello.name=Macro pour dire bonjour
131 rendering.macro.hello.description=Ceci est une macro qui va dire "Bonjour" a l'utilisateur
132 rendering.macro.hello.parameter.greetUser.name=Personnaliser le message
Pascal Bastien 91.2 133 rendering.macro.hello.parameter.greetUser.description=Personnaliser le message pour l'utilisateur courant en train de visualiser la page. Les valeurs possibles sont "true" (oui) et "false" (non).
Anca Luca 91.1 134 {{/code}}
135
Vincent Massol 117.5 136 = Macro Visibility and Rights =
137
138 There are 3 levels of visibility for a macro:
139
140 * ##Global##
Vincent Massol 131.2 141 ** on the main wiki, the macro will be available in all the pages of all the (sub)wikis. Requires the macro author to have **Programming Rights**
142 ** on subwikis, it's a synonym of the ##Current Wiki## visibility
Vincent Massol 117.5 143 * ##Current Wiki##, which means that the macro will be available in all the pages of the wiki the macro is in. Requires the macro author to have **Admin Rights**
144 * ##Current User##, which means that the macro will only be available to the user who is its author. No special rights required.
145
146 == Using protected API in wiki macros ==
147
Simon Urli 132.3 148 Also, if the macro needs to use [[protected API>>xwiki:Documentation.DevGuide.Scripting||anchor="HXWikiCoreAccess"]], the author of the macro will need to have programming rights. Note that the macro will always be executed with the rights of its author, and not with the rights of the author of the calling document (the document using the macro). Specifically, if the macro uses protected API, only the macro author needs to have programming rights, not all the authors of the documents that call this macro.
Vincent Massol 117.5 149
150 = Bindings =
151
Anca Luca 129.1 152 The usual XWiki [[scripting context bindings>>doc:extensions:Extension.Script Macro||anchor="HBindings"]] are available in the scripts of the wiki macros, with the mention that contextual variables (such as ##$doc##) will point to the XWiki document (page) in which the macro is called, not to the XWiki document containing the objects that define the macro. This makes it easy to write features that are contextualized to the page where they're called.
Vincent Massol 117.5 153
Anca Luca 126.1 154 Then, specific bindings for the wiki macro context are available, see [[the reference documentation page>>doc:extensions:Extension.WikiMacroStore.WebHome||anchor="HBindings"]].
155
Manuel Smeria 85.2 156 = WYSIWYG Access =
157
Manuel Smeria 85.1 158 A wiki macros is treated just like any other rendering macro in the system. As such, the moment you save your wiki macro it will be available to the users through the WYSIWYG editor's **Insert Macro** dialog box:
Manuel Smeria 85.2 159
Manuel Leduc 125.1 160 [[image:macro2.png||height="293" width="350"]]
Manuel Smeria 85.2 161
Manuel Leduc 125.1 162 [[image:macro4.png||height="149" width="350"]]
Asiri Rathnayake 15.1 163
Manuel Smeria 85.2 164 == Special code for WYSIWYG edit mode ==
Asiri Rathnayake 16.1 165
Denis Gervalle 84.1 166 Even in edit mode, the WYSIWYG editor will execute the macro and feed the result back into the document. If your macro use some JSX, these will not be loaded. But, if your macro produce some Javascript that use those JSX or manipulate the document's DOM (injecting new elements, moving existing elements, removing elements, etc.), you may want to protect the content in WYSIWYG edit mode in order to prevent the performed transformation to get saved. Here is how you can prevent this behavior:
simba 69.1 167
Thomas Mortagne 118.1 168 {{code language="velocity"}}
Denis Gervalle 84.1 169 {{velocity}}
Vincent Massol 77.1 170 #if("$xcontext.action" != "edit")
Denis Gervalle 84.1 171 {{html}}
Denis Gervalle 85.3 172 <script type="text/javascript">
Denis Gervalle 84.1 173 //<![CDATA[
174 ... some javascript ...
175 // ]]>
176 </script>
177 {{/html}}
simba 69.1 178 #end
JeromeVelociter 70.1 179 ##
180 ## Rest of the code.
Thomas Mortagne 90.1 181 {{/velocity}}
Manuel Smeria 85.1 182 {{/code}}
simba 69.1 183
Simon Urli 116.1 184 == WYSIWYG editing of macro content or parameter ==
185
Thomas Mortagne 118.1 186 As specified above you can use the dedicated macros {{code language="none"}}{{wikimacrocontent/}}{{/code}} and {{code language="none"}}{{wikimacroparameter name="foo"/}}{{/code}} to allow the users of your macro to be able to edit the values of the macro directly in the WYSIWYG editor once the macro is inserted.
Simon Urli 116.1 187 Note that this is currently only possible if you specified that the macro content (or parameter) type is ##WIKI## type.
188
189 {{info}}
Vincent Massol 131.4 190 There is also a known limitation related to CKEditor that prevents editing directly those macros if they are not used as "standalone" macro. Details can be found on the [[related issue>>https://jira.xwiki.org/browse/CKEDITOR-248]].
Simon Urli 116.1 191 {{/info}}
192
Manuel Smeria 85.2 193 = Scripting Tips =
Asiri Rathnayake 31.1 194
Manuel Smeria 85.2 195 Following are a few useful hints if you plan to do advanced scripting inside your wiki macros:
Asiri Rathnayake 33.1 196
Vincent Massol 131.2 197 * It's possible to directly return the desired list of rendering blocks without having to render them first to let them be parsed back by the macro transformation. The benefits are that it could be a lots quicker and most of all it means supporting syntax which does not provide any renderer. It also makes it possible to generate some XDOM which is impossible to write in any some syntax. For example the following wiki macro is generating a LinkBlock targeting a relative URL:(((
Thomas Mortagne 118.1 198 {{code language="groovy"}}
Thomas Mortagne 74.1 199 {{groovy}}
200 import java.util.Collections;
201 import org.xwiki.rendering.listener.Link;
202 import org.xwiki.rendering.block.WordBlock;
203 import org.xwiki.rendering.block.LinkBlock;
204
205 ref link = new Link();
206 link.setReference("/xwiki/edit/Main/WebHome");
207 link.setType(LinkType.URI);
208
209 ref linkBlock = new LinkBlock(Collections.singletonList(new WordBlock("Edit home page"))), link, false);
210
Simon Urli 111.1 211 wikimacro.result = Collections.singletonList(linkBlock)
Thomas Mortagne 74.1 212 {{/groovy}}
213
214 This text will not appear in the result.
Manuel Smeria 85.1 215 {{/code}}
Manuel Smeria 85.2 216 )))
Michael Hamann 121.1 217 * If you need to directly access the parsed XDOM of the content you may do the parsing yourself using the rendering service. Here is a small sample:(((
Thomas Mortagne 118.1 218 {{code language="velocity"}}
Denis Gervalle 81.1 219 {{velocity output="no"}}
Denis Gervalle 81.3 220 ## get the macro content in a velocity string
Simon Urli 111.1 221 #set($wikiresult = $wikimacro.content)
Denis Gervalle 81.2 222 ## Add a wrapping div as a sample of the action of this macro
223 #set($wikiresult = "(% class='newstyle' %)((($wikiresult)))")
224 ## parse the string and return the resulting blocks
Simon Urli 111.1 225 #set($wikimacro.result = $services.rendering.parse($wikiresult, $xwiki.getCurrentContentSyntaxId()).getChildren())
Denis Gervalle 81.1 226 {{/velocity}}
Manuel Smeria 85.1 227 {{/code}}
Manuel Smeria 85.2 228 )))
Valdis Vitolins 86.1 229

Get Connected