Show last authors
1 {{box cssClass="floatinginfobox" title="**Contents**"}}
2 {{toc/}}
3 {{/box}}
4
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!
6
7 This page is a tutorial but you can also access the [[reference documentation for the Wiki Macro feature>>doc:extensions:Extension.WikiMacroStore.WebHome]].
8
9 = Macro Visibility and Rights =
10
11 There are 3 levels of visibility for a macro:
12
13 * ##Global##
14 ** on main wiki (or {{info}}before XWiki 10.4RC1{{/info}}) the macro will be available in all the pages of all the (sub)wikis. Requires the macro author to have **Programming Rights**
15 ** on subwiki {{info}}in 10.4RC1+{{/info}} synonym of ##Current Wiki## visibility
16 * ##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**
17 * ##Current User##, which means that the macro will only be available to the user who is its author. No special rights required.
18
19 == Using protected API in wiki macros ==
20
21 Also, if the macro needs to use [[protected API>>platform: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.
22
23 = Hello Macro =
24
25 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.
26
27 == Definition ==
28
29 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##.
30
31 {{warning}}
32 There can be only one object of type ##XWiki.WikiMacroClass## per wiki page (if you add more only the first will be used).
33 {{/warning}}
34
35
36 This class contains the following fields:
37
38 * **Macro id**: Id of the macro to be used by users when invoking your macro from wiki code
39 * **Macro name**: Name of the macro to be displayed on the wysiwyg editor
40 * **Macro description**: A short description of the macro to be displayed on the WYSIWYG editor
41 * **Default category**: Default category under which this macro should be listed
42 * **Supports inline mode**: Whether the macro can be used in an inline context or not
43 * **Macro Content availability**: {{warning}}before 11.5RC1 this was called **Macro Content Type**{{/warning}} whether this macro should support a body or not
44 * **Macro content type**: {{warning}}this field has been renamed **Macro Content Availability** since 11.5RC1{{/warning}} the type of accepted content: two values are proposed, {{code}}WIKI{{/code}} if this content should be editable like a wiki content, or {{code}}UNKNOWN{{/code}} if it should be displayed like a plain text. It's also possible to specify a custom java type such as {{code}}java.util.List<java.lang.String>{{/code}}. Leaving the field blank is equivalent to {{code}}UNKWOWN{{/code}} value.
45 * **Content description**: A short description about the macro's content to be displayed on the WYSIWYG editor
46 * **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)
47 * **Asynchronous rendering**: {{info}}Since 10.10{{/info}} Enabled or disable asynchronous rendering of the panel. Disabled by default.
48 * **Cached**: {{info}}Since 10.10{{/info}} Indicate if the result of the execution of the element should be cached. Disabled by default.
49 * **Context elements**: {{info}}Since 10.10{{/info}} The context information required during the execution of the extension (current user, current document, etc.). It's also used to generate the cache key.
50
51 Now we can define our hello macro as shown below:
52
53 [[image:macro1.png]]
54
55 == Invocation ==
56
57 A wiki macro can be invoked just like any other macro is invoked. Since we are writing a xwiki/2.0 wiki macro, we can invoke our **hello macro** as below:
58
59 {{code}}
60 {{hello/}}
61 {{/code}}
62
63 And if you view the result it would say "Hello World!" (of course).
64
65 == Content ==
66
67 Starting with {{code}}XWiki 11.4RC1{{/code}} there are two ways to insert the content of the wiki macro.
68
69 * The easiest way is to use a dedicated macro in the body of the wikimacro:(((
70 {{code language="none"}}
71 {{wikimacrocontent/}}
72 {{/code}}
73
74 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]].
75 )))
76 * Another way to manipulate the content is to use the wikimacro binding. For example, when using Velocity, you can write the following script in the macro body:(((
77 {{code language="none"}}
78 {{velocity}}$wikimacro.content{{/velocity}}
79 {{/code}}
80 )))
81
82 For more details, see the [[Scripting Tips section below>>platform:DevGuide.WikiMacroTutorial||anchor="HScriptingTips"]].
83
84 == Parameters ==
85
86 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:
87
88 * Parameter name: Name of the parameter, users will refer this name when invoking your macro with parameters
89 * Parameter description (optional): A short description of the parameter, this description will be made available on the WYSIWYG editor
90 * Parameter mandatory: Indicates if this particular parameter is mandatory, wiki macro will fail to execute if a mandatory parameter is missing
91 * Parameter default value (optional): {{info}}Since 10.10{{/info}} The default value of the parameter when it's empty
92 * Parameter type (optional): {{info}}Since 10.10{{/info}} Indicates to which Java type the parameter value (defined as a String) must be converted to (##java.lang.String## by default).
93
94 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:
95
96 [[image:macro3.png]]
97
98 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:
99
100 {{code}}
101 {{velocity}}
102 #if ($wikimacro.parameters.greetUser && "XWiki.XWikiGuest" != "$xcontext.user")
103 Hello $xwiki.user.email!
104 #else
105 Hello world!
106 #end
107 {{/velocity}}
108 {{/code}}
109
110 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 near future.
111
112 Since {{info}}11.5RC1{{/info}}, it is also possible to display the content of a macro parameter by using a dedicated macro:
113 {{code language="none"}}Hello {{wikimacroparameter name="greeUsers" /}}{{/code}}
114
115 Finally, we can test our new version of **hello macro** with the following invocation:
116
117 {{code language="none"}}
118 {{hello greetUser="true"/}}
119 {{/code}}
120
121 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:
122
123 {{code language="none"}}
124 {{velocity}}
125 #set ($greet = true)
126 {{hello greetUser="$greet"/}}
127 {{/velocity}}
128 {{/code}}
129
130 == Translations ==
131
132 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>>platform: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):
133
134 {{code}}
135 rendering.macro.<macro id>.name=Name of the macro, displayed in the macros list in the macros wizard
136 rendering.macro.<macro id>.description=Description of the macro, displayed as a help in the macros list in the macros wizard
137
138 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
139 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
140 {{/code}}
141
142 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.
143
144 In our example, french translations would be something like this:
145
146 {{code}}
147 rendering.macro.hello.name=Macro pour dire bonjour
148 rendering.macro.hello.description=Ceci est une macro qui va dire "Bonjour" a l'utilisateur
149 rendering.macro.hello.parameter.greetUser.name=Personnaliser le message
150 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).
151 {{/code}}
152
153 = WYSIWYG Access =
154
155 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:
156
157 [[image:macro2.png]]
158
159 [[image:macro4.png]]
160
161 == Special code for WYSIWYG edit mode ==
162
163 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:
164
165 {{code language="velocity"}}
166 {{velocity}}
167 #if("$xcontext.action" != "edit")
168 {{html}}
169 <script type="text/javascript">
170 //<![CDATA[
171 ... some javascript ...
172 // ]]>
173 </script>
174 {{/html}}
175 #end
176 ##
177 ## Rest of the code.
178 {{/velocity}}
179 {{/code}}
180
181 = Scripting Tips =
182
183 Following are a few useful hints if you plan to do advanced scripting inside your wiki macros:
184
185 * Old and new bindings: please note that the ##$wikimacro## binding is only available since {{info}}XWiki 10.11.9, 11.3.2 and 11.6RC1{{/info}}, before that the ##$xcontext.macro## binding should be used. You can get more information on [[the reference documentation page>>doc:extensions:Extension.WikiMacroStore.WebHome||anchor="HBindings"]]
186 * Access parameters: Use the wikimacro object (Ex. ##$wikimacro.params.param1##)
187 * Access macro body (if your macro defines one): Use the wikimacro object (Ex. ##$wikimacro.content##)
188 * Access [[MacroTransformationContext>>https://github.com/xwiki/xwiki-rendering/blob/master/xwiki-rendering-transformations/xwiki-rendering-transformation-macro/src/main/java/org/xwiki/rendering/transformation/MacroTransformationContext.java]]: Use the wikimacro object (Ex. ##$wikimacro.context##)
189 * Since 2.4M1, 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:(((
190 {{code language="groovy"}}
191 {{groovy}}
192 import java.util.Collections;
193 import org.xwiki.rendering.listener.Link;
194 import org.xwiki.rendering.block.WordBlock;
195 import org.xwiki.rendering.block.LinkBlock;
196
197 ref link = new Link();
198 link.setReference("/xwiki/edit/Main/WebHome");
199 link.setType(LinkType.URI);
200
201 ref linkBlock = new LinkBlock(Collections.singletonList(new WordBlock("Edit home page"))), link, false);
202
203 wikimacro.result = Collections.singletonList(linkBlock)
204 {{/groovy}}
205
206 This text will not appear in the result.
207 {{/code}}
208 )))
209 * If you are using ##$wikimacro.content## in your velocity macro, that content will not be able to support scripting, since nested scripting is not supported. To workaround that limitation, thanks to the above, you may do the parsing yourself using the rendering service. Here is a small sample:(((
210 {{code languege="velocity"}}
211 {{velocity output="no"}}
212 ## get the macro content in a velocity string
213 #set($wikiresult = $wikimacro.content)
214 ## Add a wrapping div as a sample of the action of this macro
215 #set($wikiresult = "(% class='newstyle' %)((($wikiresult)))")
216 ## parse the string and return the resulting blocks
217 #set($wikimacro.result = $services.rendering.parse($wikiresult, $xwiki.getCurrentContentSyntaxId()).getChildren())
218 {{/velocity}}
219 {{/code}}
220 )))
221 * Since 9.1RC1 you can access the macro descriptor using ##$xcontext.macro.descriptor## binding. It returns a ##org.xwiki.rendering.macro.descriptor.MacroDescriptor## Java object.
222
223 = Troubleshooting =
224
225 == A Pitfall of Optional Parameters ==
226
227 {{info}}
228 This pitfall has been fixed in XWiki 2.2
229 {{/info}}
230
231 There is a common pitfall for using optional paramters. The following macro code contains a not so obvious bug:
232
233 {{code languege="velocity"}}
234 {{velocity}}
235 #set($greetUser=$xcontext.macro.params.greetUser)
236 #if ("true" == $greetUser && "XWiki.XWikiGuest" != "$xcontext.user" )
237 Hello $xwiki.user.email!
238 #else
239 Hello world!
240 #end
241 <img src="$image" width="$width" />
242 {{/code}}
243
244 If we invoke it twice in a row:
245
246 {{code}}
247 {{hello greetUser="true" /}}
248 {{hello /}}
249 {{/code}}
250
251 The second invocation will not print "Hello World!" as we'd expect. But it will print the same result as the first invocation. The reasons are:
252
253 * Macro parameters are implemented as global parameters. So, they remain the same across multiple macro invocations.
254 * If ##$xcontext.macro.params.greetUser## contains "null", it will not be assigned to ##$greetUser##. This is different from C/C++ or Java.
255
256 So in order to get around it, you can use:
257
258 {{code}}
259 #set($greetUser="$!xcontext.macro.params.greetUser")
260 {{/code}}

Get Connected