How do you add template variables as macro parameters or in plain text macro bodies?

Prior to Confluence 4.3, it was easy to add template variables anywhere in the template. Is this capability gone in Confluence 4.3?

Also, when editing a template and using Insert Wiki Markup, I keep getting "Wiki Markup Conversion Errors - error:Bad Request" when the inserted wiki contains a macro (like {info} for example). Same problem on Confluence 5.0.

12 answers

I have done some tinkering on this subject and have come up with a (less than perfect) user macro that will work in a lot of cases. "Less than perfect"? Well it seems the user macro rendring of $body ruins the layout of sections on the page if JIRA macros are included. In practise this makes side-by-side JIRA issue tables impossible, outside of that I have tried sections and columns with success.

Macro name: applytemplatevars
Macro Title: Apply Template Variables
Description: This macro encases other macros so that template variables can be transferred to them.
Categories: Confluence Content
 
Macro Body Processing: Rendered
Template:
## Macro title: applytemplatevars
## Macro has a body: Y
## Body processing: Rendered
## Output: body with replaced variables
##
## Developed by: Kim Poulsen
## Date created: 28/09/2015
## Installed by: <you?>
## @noparams
## Fish out the parameter section of the body:
######################################
#set ($lbody = $body)
#set ($idx = $lbody.indexOf("</p"))
#set ($params = $lbody.substring(3, $idx))
## Replace the body with the real body (without the variable section)
#set ($body = $lbody.substring($idx))
## This version accepts <name>=<value>|<name>=<value>|... type specification
#################################################################
#foreach($v in $params.split("[|]"))
  ## Fish out variable names and values:
  #######
  #set ($varArr = [])
  #foreach($i in $v.split("[=]"))
    #set ($retval = $varArr.add($i) )
  #end
  #set ($vn = $varArr.get(0) )
  #set ($vv = $varArr.get(1) )
  ## And do the replacement:
  ########
  #set ($body = $body.replaceAll($vn, $vv) )
#*
  ##  Change the page title as well (dangerous: The page will change title, and possibly get lost.)
  #set ($title = $content.getTitle() )
  #set ($title = $title.replaceAll($vn, $vv) )
  $content.setTitle($title)
*#
#end
$body

 

Use it like this:

{applyfromtemplate} mySuperTemplatevar=$mySuperTemplatevar|myOthervar=$templateVar2|myNonTemplateVAR=Yes we can substitute arbitrary strings not only template vars.   Instance other macros and use the "mySuperTemplatevar" and "myOthervar" anywhere. The macro will replace them with the template vars. The variable list will not be rendered on the view page. {/applyfromtemplate}

 

I'd appreciate any input on how to not get output ruined when using JIRA macros in a rendered $body.

Edit: Obviously the macro can also be used without template variables. Just type in the string you want to substitute and all is good too.

To add to the case it seems Confluence does more to the body after the JIRA macro: <div class="hidden"> <textarea id="refresh-wiki-2035414160"> <input id="refresh-page-id-2035414160" type="text" value="7375841" /> </div> <p /> </div> <p /><h5 id="... ... </textarea> The "class=hidden" effectively eats everything below that point on the page. And the textarea converts it all to a string, so bye bye remaining page.

@Kim Poulsen thank you for your comment. I got this working, but it replaces variables in the body-output only. It does not replace variables, I pass to the makro as parameter (as the title of this thread is suggesting). Is that correct?

@Dougi B The macro should replace all variables in text and macros put into the body of the "applytemplatevars" macro. I cannot post images here, but lets try this in text:

/applytemplatevars/
/ VAR1=Hello|VAR2=World
/ VAR1 VAR2
/-------------------------
This would print on screen:
Hello World

Another one:

/applytemplatevars/
/ VAR1=Hello|VAR2=World
/
/Panel(title=VAR1) /
/ VAR2 /
/------ /
Other text from the big VAR2 /
/----------------------------/
This would print on screen:
/-----------------------------/
/ Hello /
/----------- /
/ World /
/----------- /
Other text from the big World /
/-----------------------------/

 

So in the case I set the Title of the panel to the value "VAR1" and the body of the panel to "VAR2" I also re-use VAR2. You can use this together with template variables "$myVar" if you like. It looks like the mechanism is as simple as Confluence substituting $myVar when generating the draft page. So using them as variable values in this macro, you get to input data from the template generation stage too. It get's complicated without images, so I hope you understand the crude drawings above. The only case where I cannot get this to work is when using JIRA macros - which was actually where I started looking into this :-)

Edit: Fix formatting.

I think the title in your example was replaced in the output of the macro. In my case I pass an URL to an macro, which downloads and inspect a file. Unfortunately I don't have access to the logsfiles, but I verified this by adding the value "MyValue" of the parameter ("MyParametername") to the output. It gets replaced. but when I split the value I get "My" "Parametername" in the output. The parameter has never been replaced.

@Dougi B: Okay so you have something like: URL=http://my-fileserver.sth/filespec.txt And a Macro, where you specify an URL field with "URL" in it? I must admit that I haven't tried to use it in such a clever way :-) I've tested it out now though, and while replacement does happen as expected (i.e. URL gets substituted) it uses whatever formatting Confluence choses for links. This means wrapping stuff in <span> tags etc. I can get to the point where I need to whitelist a site by putting in the HTML include macro "http:/mysite.com/MYVAR" and define MYVAR=my/path/to/the/page.html Confluence does not do any further automatic formatting on a string like that and actually attempts to retrieve a page from mysite. Then again, this macro is not a generic solution, it manipulates the page content before rendering, and any pre-processing Confluence might think is a good idea could interfere with any good intentions here :-)

Pretty nifty macro.  One problem I'm having.  It seems to work for macros like "panel" and "info" but not for macros like "recently-updated" or "contentbylabel". The variable text doesn't get replaced in those.  Any thoughts as to why?

Sorry, I have no idea. The macro is pretty brute force in nature as it simply replaces all matching stings with the substitution string, so perhaps these macros hide their parameters in a format this macro doesn't get around to do substitutions in. If you take a look at the storage format of the page with those macros you might get a hint of this. I envision that label names are encapsulated in some extra tags for instance.

This is such a tantalizing macro, but I can't figure out how to use it. (I'm new to user macros). I created a new User Macro, cut&paste your code into the Template field, and saved it. Then in a sandbox, I typed \{applytemplatevars}  (without the forward slash). But when I previewed the page, all I saw was "Error rendering macro 'applytemplatevars' : Error occurred rendering template content". Can you please provide a step by step example of exactly how to use this code? THank you!

Hey @Kim Poulsen,

 

thanks for your user macro. Unfortunately I have a strange bug which makes it unusable to me:

The macro works in the macro preview and in the page preview, correctly replacing the variables. But once the page is saved, the substitution does not work anymore and the variable name is displayed again.

Do you have any clue what could cause such behaviour?

Hi @Kevin Mote.

  One case where the macro will throw "Error rendering" is if you are not specifying any variables in the first line of the macro body. I assume you have checked the "Rendered" button in the User Macro editor.

So when looking at the storage format, it should look like this:

<ac:structured-macro ac:macro-id="aca752e4-35f4-4534-a87d-d4d164e0ed35" ac:name="applytemplatevars" ac:schema-version="1">
<ac:parameter ac:name="atlassian-macro-output-type">INLINE</ac:parameter>
<ac:rich-text-body> <p>VAR1=Test</p> <p>Here's: VAR1</p>
</ac:rich-text-body>
</ac:structured-macro>

Here I have just defined one variable "VAR1=Test", and use it in the sentence below: "Here's VAR1".

Want more variables? Just specify them in this format:

VAR1=Tara|VAR2=Tarb|<and so on>

They just have to be in the first line, that's all.

I hope this helps you and possibly others.

Hi @Alexander Schöcke.

 The macro is quite brute force in nature, so maybe the places where you try to substitute, are not exposed in such a way that e.g. a variable VAR1 is like this in the storage format.

 If you look at the page storage format, you should be able to see what's going on. I know that drop-downs, people selectors and stuff like that is not usable with this macro for the above reason.

I have a hard time saying more, as I don't know on what you try to apply the substitution, but I hope this helps a little.

 

Hey @Kim Poulsen,

 

thank you for your answer. I basically tried this on an empty page in order to rule out any incompatibilities with other macros or the like, so the storage format ist not more than this:

 

<ac:macro ac:name="applytemplatevars">
    <ac:parameter ac:name="atlassian-macro-output-type">BLOCK</ac:parameter>
    <ac:rich-text-body>
        <p>VAR1=WARRRRR</p>
        <p>Display VAR1</p>
    </ac:rich-text-body>
</ac:macro>

Hi @Alexander Schöcke,

We're running Confluence 5.8.9 btw.

You storage format looks almost like my example above. I wonder if the "BLOCK" vs. "INLINE" makes the difference? I cannot get the macro here to use "BLOCK", so I wonder where that might come from.

The other difference is that your storage format is not a "structured-macro", but just a "macro", so something is wrong here. Also here I cannot reproduce that output.

I'm sorry, I don't think I have the insight to aid on this one.

This doesn't appear to work if the macro you insert into the body is a user macro. I suspect it is due to the order user macros are rendered in, or because there is only one render "pass", both of which are outside of our control.

Hallo Bob and Eddie

I'm not exactly sure what you're asking ;) but could it be the same as this discussion in our doc space?

https://confluence.atlassian.com/display/DOC/Confluence+4.3-RC1+Release+Notes?focusedCommentId=297669317#comment-297669317

Cheers, Sarah

Sarah that discussion is related. I'm surprised this feature is missing in 4.3 & 5 as I make use of it in many of my templates and don't want to loose that functionality when we upgrade. Is there not any other way to use variables as macro parameters? Some plugin perhaps?

Must have missed this earlier. It covers part of it. The part about variables in plain text bodies is not covered.

Is there a bug or improvement open for this issue? Is there any way to work around this problem?

I use this feature in many of my Confluence 4 templates for many reasons. Here's one example:

Enter label of projects: @PROJECT_LABEL@
{checklist:name=Project Information|parent=Home|usecanvas=false|label=@PROJECT_LABEL@|depth=4}
{checklist-input:cols=20|heading=Tech Lead|rows=1}
{checklist-input:cols=40|heading=JIRA Versions|rows=1}
{checklist-input:cols=20|heading=Bamboo Key|rows=1}
{checklist}

Any updates about this? I'm currently evaluating Confluence and I need some functionality like this one... +1

You can watch this issue, but I wouldn't hold your breath https://jira.atlassian.com/browse/CONF-3324

Just ran into this issue as well. CONF-3324 has been open a surprisingly long time with no real "desire" from Atlassian to fix it. I'm a little baffled honestly with how good their product seems to be. Not sure how this issue could be viewed by them as a "nice to have" for their Blueprints feature. To me it is just straight broken if this doesn't work, they lose all their power to be used for anything beyond a very simple formatted text page. Very disappointed right now. :(

Perhaps I am misunderstanding, but in Confluence 5 you can define variables anywhere, including inside macros like the info box.

The "insert wiki markup" (ctrl+shift+d) also seems to work for me.

Space tools > content tools > page templates

https://confluence.atlassian.com/display/DOC/Adding+a+Template

No, the question is asking about macro _parameters_. You are referring to inserting variables into the macro body.

Sorry for my confusion before. Even the former work around of declaring the variable outside the scope of the macro parameters does not make them replaced within the parameter. Have you "poked" atlassian about this, or submitted a ticket? Seems some functionality has regressed.

Yes, I poked a couple of times.

BTW, I don't think the Variables insert thing is very obvious for people that new the old way of doing things. I took me a while to notice that in the editor. So actually your post would be helpful for some other folks.

Yes, I poked a couple of times.

BTW, I don't think the Variables insert thing is very obvious for people that knew the old way of doing things. I took me a while to notice that in the editor. So actually your post would be helpful for some other folks.

We also have got a similar issue.

We want to create a page template using one variable (issue key) that will be used by the SQL macro.

This mechanism will allow the users to have a page already pre formated with a set of macros (here this is SQL macros) using the value of an issue required during the page creation.

The template will look like:


Type the value of the issue_key: $variable
{sql:dataSource=xxxx}
select i.issue_key, i.issue_type, i.timespent
from issue
where i.issue_key = 'Eval of $variable' (here I would like to have the value of the variable selected)
{sql}
......
......

Does somebody help us ?

Any updates about this? I'm currently evaluating Confluence and I need some functionality like this one...

I think the closest you'll get to this functionality is through writing your own User Macros:

https://confluence.atlassian.com/display/DOC/Adding%2C+Editing+and+Removing+User+Macros

I was able to pass a template variable to a macro in the following way:

  1. Create a new Macro 
  2. $body will be the value of the template variable. Use this however you need to. In my case I am hooking into the Content By Label macro by passing a dynamic label parameter from the template.
  3. In the page template edit mode add a new template variable 
  4. Add the macro into the page template. Click into the body of the macro and choose Insert > Your variable.
## Macro title: My Macro
##
## Developed by: My Name
## Date created: dd/mm/yyyy
## Installed by: My Name
## @noparams
&lt;ac:macro ac:name="contentbylabel"&gt;
&lt;ac:parameter ac:name="label"&gt;$body&lt;/ac:parameter&gt;
&lt;ac:parameter ac:name="operator"&gt;AND&lt;/ac:parameter&gt;
&lt;/ac:macro&gt;

Simple but it works.

This is a simple solution, and that is an advantage. The disadvantage is that it is also tailored for a single purpose because you have to insert any and all macros you want in here, or create one user macro for each type of default macro you want to use template variables with. Another disadvantage is that you can only use a single variable in this case. My solution works for any number of variables and can substitute any number of contained macros and any number of fields in those macros. The disadvantage is that JIRA macros seem to render themselves in a way that puts the remainder of the page into a hidden <textfield>. This is where your solution comes in handy because the use is them limited to e.g. the JIRA macros. Thanks for sharing.

I tried this solution in confluence 5.4.2 but it doesn't work for me. Is this working in JIRA only? I pass 4 variables as macro parameter to the macro, two of them are urls. the macro only gets $variablename. I tried both, insert to the body of the wrapper-macro: $variablename or $$variablename.

@Dougi B: The macro Kate describes only works because the $body variable contains the body of the macro, and the body of the macro becomes the label text in this case. In other words, you will not have any other variable names available to you in this example. My own solution further above splits the $body into separate variables, which are then substituted into other macros instantiated inside the body of the wrapper macro.

Suggest an answer

Log in or Sign up to answer
How to earn badges on the Atlassian Community

How to earn badges on the Atlassian Community

Badges are a great way to show off community activity, whether you’re a newbie or a Champion.

Learn more
Community showcase
Published Thursday in Confluence

Three common content challenges + how to manage them

An efficient enterprise content management system, or ECM, is a must-have for companies that create work online (cough   cough, all companies). If content calendars, marketing plans, and bu...

73 views 0 4
Read article

Atlassian User Groups

Connect with like-minded Atlassian users at free events near you!

Find a group

Connect with like-minded Atlassian users at free events near you!

Find my local user group

Unfortunately there are no AUG chapters near you at the moment.

Start an AUG

You're one step closer to meeting fellow Atlassian users at your local meet up. Learn more about AUGs

Groups near you