Create
cancel
Showing results for 
Search instead for 
Did you mean: 
Sign up Log in

Writing User Macro to list children of page limited by label - Where can I find Confluence Methods?

Alana Franklin May 19, 2014

I'm attempting to write a user macro that creates a table of children pages limited by a label parameter. Here's the outline that I have so far:

## @param Label:title=Label|type=string|desc=Label|required=true

<table>
#foreach (CHID OF THE CURRENT PAGE)
	#if ($child.label == $parmlabel)
		<tr>
			<td>
				$child.TITLE
			</td>
			<td>
				$child.AUTHOR
			</td>
			<td>
				$child.DATEMODIFIED
			</td>
		</tr>
	#end
#end
</table>

The stuff in caps are just placeholders, as I can't find any documentation on confluence methods that might help me loop through each child of the current page. Additionally, I'm not sure of the exact terminology to access the information for those children. I'm new to coding, so I'm excited to kind of figure it out myself... Could someone point me in the right direction?

Thanks,

Alana

7 answers

1 accepted

1 vote
Answer accepted
Rp Subhub
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 20, 2014
I'm not an expert but here's something I've come up with.
  1. Take a look at https://confluence.atlassian.com/display/DOC/Guide+to+User+Macro+Templates
  2. There's $content object of type ContentEntityObject and link to API docs.
  3. Traverse direct known subclasses: SpaceContentEntityObject > AbstractPage > Page.
  4. There're getChildren() and getLabels() methods there.

This will hopefully list chidlren and labels.

#foreach ($child in $content.children)
  <p>${child.title}: ${child.labels}</p>
#end

${content.children} is shortcut for ${content.getChildren()}

Alana Franklin May 22, 2014

Do you think something like this would work to filter the children by label?

## @param Label:title=Label|type=string|desc=Label|required=true
 
<table>
#foreach ($child in $content.children)
	#if ($parmlabel in $child.labels)
		<tr>
			<td>${child.getTitle()}</td>
		</tr>
	#end
#end
</table>

Also, any insight on the methods to get author and date-modified?

Thanks again!

Rp Subhub
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 22, 2014
## @param label:title=Label|type=string|desc=Label|required=true

<table>
#foreach ($child in $content.children)
  #foreach ($label in $child.labels)
    #if ($label.name == $paramlabel)
      <tr>
        <td>${child.title}</td>
        <td>${child.creator.fullName}</td>
        <td>${child.lastModificationDate}</td>
      </tr>
    #end
  #end
#end
</table>

This may work. But I'm not an expert. I'm not sure about all the edge cases and implications like page restrictions and personal labels and so on.

Alana Franklin May 26, 2014

Thanks! Very helpful! Now the only thing I need to figure out is how to get the title to link to the actual page and the author's name to link to their profile...

Rp Subhub
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 28, 2014

Something like this?

## @param label:title=Label|type=string|desc=Label|required=true
<table>
#foreach ($child in $content.children)
  #foreach ($label in $child.labels)
    #if ($label.name == $paramlabel)
      <tr>
        <td><ac:link><ri:page ri:content-title="${generalUtil.escapeXml($child.title)}" /></ac:link></td>
        <td><ac:link><ri:user ri:username="${child.creator.name}" /></ac:link></td>
        <td>${child.lastModificationDate}</td>
      </tr>
    #end
  #end
#end
</table>

2 votes
Tom Birch Hansen June 1, 2014

I've been working on something similar lately.

My macro however uses a list in stead of a table, but this could easily be fixed.

My macro has extra parameters, so you can create a list based on another page's childpages.

It also allows to look at decendants.

Here is the macro:

## Macro name: tbh_pagelist_by_label

## Macro title: Page list by label

## Macro has a body: N

## Body processing: Selected body processing option

## Output: Selected output option

##

## Developed by: Tom Birch Hansen 

## Date created: 2014-04-30

## Installed by:  ---

## Use this to list pages from children or decendents of a page that match specified labels. 

## @param Label:title=Label|type=string|required=true|desc=type label(s) to be present in child pages. Use comma to list multiple labels (pages with any of the labels will be shown)

## @param page:title=Page|type=confluence-content|required=false|desc=type page to start from. Leave blank for current page.

## @param from:title=From|type=enum|enumValues=decendants,children,children_sorted|required=true|desc=Show pages from

## @param showicon:title=Show icon|type=boolean|desc=Show icon next to page link?

## @param showspace:title=Show spacename|type=boolean|desc=Show spacename in list?

## @param class:title=Class|type=string|desc=Optional formatting using a http class for the html ul element 

##PROCESS THE label PARAMETER:

#set($pLabelArray=$paramLabel.split(","))







## PROCESS THE page PARAMETER, if empty then set to current page

#if (!$parampage || $parampage=="")

	#set($ppage=$content.getEntity())

#else

        ## get page object deducted from the page parameter

	#set ($colonpos=$parampage.indexOf(":",0))

	#if($colonpos==-1)

		#set ($xspacekey=$content.spaceKey)

		#set ($xpagename=$parampage)

	#else

		#set ($namepos=$colonpos+1)

		#set ($xspacekey=$parampage.substring(0,$parampage.indexOf(":",0)))

		#set ($xpagename=$parampage.substring($namepos))

		#end

	## get page manager...

	#set($containerManagerClass=$content.class.forName('com.atlassian.spring.container.ContainerManager'))

	#set($getInstanceMethod=$containerManagerClass.getDeclaredMethod('getInstance',null))

	#set($containerManager=$getInstanceMethod.invoke(null,null))

	#set($containerContext=$containerManager.containerContext)

	#set($pageManager=$containerContext.getComponent('pageManager'))

	## find page...

	#if ($pageManager)

		#set ($ppage= $pageManager.getPage($xspacekey, $xpagename))

		#end

	#end



## PROCESS THE from PARAMETER:

#if ($paramfrom=="children_sorted")

       #set ($objfrom=$ppage.getSortedChildren())

#elseif ($paramfrom=="children")

       #set ($objfrom=$ppage.getChildren())

#elseif ($paramfrom=="decendants")

       #set ($objfrom=$ppage.getDescendents())

       #end



## PROCESS THE class PARAMETER. set default if empty

#if (!$paramclass)

	#set($pclass="content-by-label")

        #end

#set($count = 0)

#set($showpage = 0)

<ul class="$pclass">

    #foreach ($child in $objfrom)

      #if ($count < 100) ## just display the 1st 100

                #set ($showpage=0)

		#foreach ( $label in $child.getLabels() )

			#foreach($pLabel in $pLabelArray)

                            #if  ( ($label==$pLabel) )

				#set ($showpage=1)

			        #end

                            #end

                            ## END FOR EACH labelarray

                        ##if  ( ($label==$pLabel) )

				##set ($showpage=1)

			##end

		#end

		## END FOR EAACH LABEL

		

		#if ($showpage==1)

		    <li>

			##<a href="$req.contextPath$child.urlPath"><strong>$webwork.htmlEncode($child.displayTitle)</strong></a>

			#contentLink2($child $paramshowicon $paramshowspace)

        </li>

		#end

        #set($count = $count + 1)

      #end

    #end

</ul>

voisard May 20, 2017

Hi Tom,

thank you for that handy macro. While using it (unchanged at the moment) i stumbled over a stange behaviour that I can't explain.

Wenn reporting on a page (in that case the space homepage) and all it's descendant I only get a list of some, but some are missing.

If the same thing is applied via the regular search (with same parameters, search in the space, with the space homepage as root and in all descendant pages that have a certain label) I get more results.

Do you know any occurence of that behaviour or do you have any idea where to look to fix this?

Best regards,
Ben

0 votes
Peter Andersen May 1, 2019

Great with the examples here using plain Confluence macro code (no extra plugins needed)!

All the examples use getChildren(), getSortedChildren or getDescendants().

However, in the documentation https://confluence.atlassian.com/doc/user-macro-template-syntax-223906130.html Atlassian states that you should not use these methods due to security issues.

I can confirm in my own experiments, that using getChildren will obtain all the children of a page even though the person executing the macro does not have permission for some of the subpages.

I would like to implement behavior like the built-in Children Display macro (but with changed formatting) where pages restricted from the current user is not shown at all.

However the Atlassian documentation does not point to how to how this is done.

I have found some very elaborate code that scans over a page's permitted viewers and potentially this could be compared to the current user in the macro, but I am hoping for some simpler solution.

So: how could the built-in Children Display macro behavior be expressed in the user macro code syntax?

0 votes
Mario Günter
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 20, 2014

Hi Alana,

sorry for the late reply.

Yes. You require the "Reporting Plugin". https://marketplace.atlassian.com/plugins/net.customware.confluence.plugin.reporting/versions

But i am not sure, if this can display author and modified-date. Maybe you can find something in the documentation:
https://docs.servicerocket.com/display/REPORT/Include+All+Child+Pages

The script above includes all child pages with title(+link) and expandable page content.

Cheers,

Mario

0 votes
Alana Franklin May 19, 2014

Mario,

Can you explain what's going on in that code? Does it require an additional plugin to work?

Thanks,

Alana

0 votes
Felix Grund (Scandio)
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 19, 2014

Hi Alana,

I don't think what you desire can be achieved with a user macro since you don't have the required context available. Instead, you should write a Confluence Macro like described in the official documentation.

Regards, Felix

0 votes
Mario Günter
Rising Star
Rising Star
Rising Stars are recognized for providing high-quality answers to other users. Rising Stars receive a certificate of achievement and are on the path to becoming Community Leaders.
May 19, 2014

Hi Alana,

maybe you want something like that. You can modify it up to your requirements:

{report-block}
  {content-filter:type=page,comment,news}
  {content-reporter:scope=@self > children}
    {text-sort:content:title}
  {content-reporter}
  {report-body}
h2. {report-info:content:title|link=true}
    {expand:title=Show more...}
        {report-info:content:body|render=wiki}
    {expand}
  {report-body}
{report-block}

You should be able to get author and datemodified, but I'm not sure at the moment.

Hope this helps,

Mario

Suggest an answer

Log in or Sign up to answer
TAGS
AUG Leaders

Atlassian Community Events