How do I list all pages with titles and, last modified by and updated date based on labels for a specific time period
Asked by Aby12345:

I have a couple of individual component status pages under a parent page. The sub pages are updated regularly with current status. I want to list all the sub pages, their last modified by user, last modified date, and If these pages were updated in the last 7 days.

This can be done easily using the SQL macro I guess.

My requirements are to list this in tabular format and Is this do-able without using the SQL macro and tweaking the recently updated macro or page properties etc?


Answers:
author: Stephen Deutsch
body: Here's the user macro:

```
## @noparams#set ( $descendantPages = $pageManager.getDescendents($content) )#set ( $compareDate = $action.dateFormatter.getCalendar() )$compareDate.setTime($content.getCurrentDate())$compareDate.add(6, -7)&lt;table&gt;  &lt;tr&gt;    &lt;th&gt;Page&lt;/th&gt;    &lt;th&gt;Last Modifier&lt;/th&gt;    &lt;th&gt;Modified Date&lt;/th&gt;    &lt;th&gt;Modified &lt; 7d?&lt;/th&gt;  &lt;/tr&gt;  #foreach ( $page in $descendantPages )  &lt;tr&gt;    &lt;td&gt;&lt;a href="${req.contextPath}$page.urlPath"&gt; $page.title &lt;/a&gt;&lt;/td&gt;    &lt;td&gt; $page.lastModifier.name &lt;/td&gt;    &lt;td&gt; $action.dateFormatter.format($page.lastModificationDate) &lt;/td&gt;    &lt;td&gt;       #set ($pageDate = $action.dateFormatter.getCalendar())       $pageDate.setTime($page.getLastModificationDate())      #if ( $pageDate.before($compareDate) )        &lt;span class="aui-lozenge aui-lozenge-error"&gt;NO&lt;/span&gt;      #else        &lt;span class="aui-lozenge aui-lozenge-success"&gt;YES&lt;/span&gt;      #end    &lt;/td&gt;  &lt;/tr&gt;  #end&lt;/table&gt;
```

comments: author: Aby12345
body: Brilliant. Thanks a lot Stephen, This is exactly what I needed. Please pardon the delay in answering as I dont have rights to directly create a user macro. Please do refer documentation where I can learn more about confluence/JIRA objects as used in the macro.


author: Stephen Deutsch
body: Hi Abhilash, glad I could help you out. Here is one resource for the Confluence objects used in user macros: <https://developer.atlassian.com/confdev/development-resources/confluence-architecture/confluence-internals/velocity-template-overview/confluence-objects-accessible-from-velocity>Other than that, it's a lot of Google searching and browsing here on Atlassian Answers. I also have a few User Macros on my bitbucket account: <https://bitbucket.org/stephendeutsch/confluence-user-macros>


author: Jim Cork
body: Is there an easy way to modify the above to have an 'Exclude Labels' parameter which will hide any child pages that have the 'meeting-notes' label?


author: Stephen Deutsch
body: This should work:

```
## @param ExcludeLabels:title=Labels to exclude|type=string|desc=Enter labels to be excluded, separate multiple labels with comma#set ( $excludedLabelsString = $paramExcludeLabels + "," )#set ( $excludedLabelsString = $excludedLabelsString.replace(" ","") )#set ( $descendantPages = $pageManager.getDescendents($content) )#set ( $compareDate = $action.dateFormatter.getCalendar() )$compareDate.setTime($content.getCurrentDate())$compareDate.add(6, -7)&lt;table&gt;  &lt;tr&gt;    &lt;th&gt;Page&lt;/th&gt;    &lt;th&gt;Last Modifier&lt;/th&gt;    &lt;th&gt;Modified Date&lt;/th&gt;    &lt;th&gt;Modified &lt; 7d?&lt;/th&gt;  &lt;/tr&gt;  #foreach ( $page in $descendantPages )    #set ( $notContainsExcludedLabel = true )	#if ( $excludedLabelsString != ",")      #foreach ( $labelling in $page.getLabellings() )        #set ( $label = $labelling.getLabel() + "," )	    #if ( $excludedLabelsString.contains($label) )	      #set ( $notContainsExcludedLabel = false )	    #end	  #end	#end    #if ( $notContainsExcludedLabel )      &lt;tr&gt;        &lt;td&gt;&lt;a href="${req.contextPath}$page.urlPath"&gt; $page.title &lt;/a&gt;&lt;/td&gt;        &lt;td&gt; $page.lastModifier.name &lt;/td&gt;        &lt;td&gt; $action.dateFormatter.format($page.lastModificationDate) &lt;/td&gt;        &lt;td&gt;           #set ($pageDate = $action.dateFormatter.getCalendar())           $pageDate.setTime($page.getLastModificationDate())          #if ( $pageDate.before($compareDate) )            &lt;span class="aui-lozenge aui-lozenge-error"&gt;NO&lt;/span&gt;          #else            &lt;span class="aui-lozenge aui-lozenge-success"&gt;YES&lt;/span&gt;          #end        &lt;/td&gt;      &lt;/tr&gt;    #end  #end&lt;/table&gt;
```


author: Jim Cork
body: Thanks so much. That worked a treat! I've modified your code slightly to show pages not modified in the last 365 days and also fixed an issue with the URLs of the pages not showing correctly.

Changing this:

```
&lt;td&gt;&lt;a href="${req.contextPath}$childPage.urlPath"&gt; $page.title &lt;/a&gt;&lt;/td&gt;
```

To this:

```
&lt;td&gt;&lt;a href="${req.contextPath}$page.urlPath"&gt; $page.title &lt;/a&gt;&lt;/td&gt;
```

Full code snippet here:

```
## @param ExcludeLabels:title=Labels to exclude|type=string|desc=Enter labels to be excluded, separate multiple labels with comma#set ( $excludedLabelsString = $paramExcludeLabels + "," )#set ( $excludedLabelsString = $excludedLabelsString.replace(" ","") )#set ( $descendantPages = $pageManager.getDescendents($content) )#set ( $compareDate = $action.dateFormatter.getCalendar() )$compareDate.setTime($content.getCurrentDate())$compareDate.add(6, -365)&lt;table&gt;  &lt;tr&gt;    &lt;th&gt;Page&lt;/th&gt;    &lt;th&gt;Author&lt;/th&gt;    &lt;th&gt;Last Modifier&lt;/th&gt;    &lt;th&gt;Modified Date&lt;/th&gt;    &lt;th&gt;Modified &lt; 365d?&lt;/th&gt;  &lt;/tr&gt;  #foreach ( $page in $descendantPages )    #set ( $notContainsExcludedLabel = true )    #if ( $excludedLabelsString != ",")      #foreach ( $labelling in $page.getLabellings() )        #set ( $label = $labelling.getLabel() + "," )        #if ( $excludedLabelsString.contains($label) )          #set ( $notContainsExcludedLabel = false )        #end      #end    #end    #if ( $notContainsExcludedLabel )      &lt;tr&gt;        &lt;td&gt;&lt;a href="${req.contextPath}$page.urlPath"&gt; $page.title &lt;/a&gt;&lt;/td&gt;        &lt;td&gt; $page.Creator.name &lt;/td&gt;        &lt;td&gt; $page.lastModifier.name &lt;/td&gt;        &lt;td&gt; $action.dateFormatter.format($page.lastModificationDate) &lt;/td&gt;        &lt;td&gt;           #set ($pageDate = $action.dateFormatter.getCalendar())           $pageDate.setTime($page.getLastModificationDate())          #if ( $pageDate.before($compareDate) )            &lt;span class="aui-lozenge aui-lozenge-error"&gt;NO&lt;/span&gt;          #else            &lt;span class="aui-lozenge aui-lozenge-success"&gt;YES&lt;/span&gt;          #end        &lt;/td&gt;      &lt;/tr&gt;    #end  #end&lt;/table&gt;
```

Thanks a bunch!


author: Jim Cork
body: One more question:

This macro lists all child pages. Is there are way to modify it to make it list all pages within a space, including all sub-spaces?

Pagination is too much of a stretch too, I'd imagine?

Thanks in advance!


author: Stephen Deutsch
body: Pagination might be a bit much, but listing all pages should be pretty easy. Just change the line

```
#set ( $descendantPages = $pageManager.getDescendents($content) )
```

to

```
#set ( $descendantPages = $pageManager.getPages($space, true) )
```


author: Jim Cork
body: Hi Stephen,

Thanks for all your help with this. Could you by any chance let me know of a way to ONLY show the list of pages that HAVE NOT been modified in the last X period, and NOT showing any pages that HAVE been modified in the last X period.

Regards,

Jim Cork


author: Doug Swartz
body: The [Confluence Reporting add-on from Service Rocket](https://marketplace.atlassian.com/plugins/net.customware.confluence.plugin.reporting).can do all this.

I don't know of a native Confluence way to do this.


author: Stephen Deutsch
body: This is certainly possible using a user macro, but your requirements are not very clear. In your title, you say "based on labels" but in your description, you say "pages under a parent page". How are you supposed to determine which pages are in the list?


author: Elina Wegner
body: Hello,

I am trying to get something similar but rather need the creation date of each child page.

I tried substituting

```
$action.dateFormatter.formatGivenString("yyyy-MM-dd", $content.getCreationDate())
```

for

```
$action.dateFormatter.format($page.lastModificationDate)
```

but because all of the child pages were initiated via a template they all have the same date...

Can you help with a marco that will provide me with a table listing all of the pages contained within a certain dashboard, who they were created by and the actual creation date knowing that the pages were created using a template?

Thank you all so much!


author: Dale Westrate
body: This sounds like just what I'm looking for (a list of all Space pages along with their created \& modified dates), but I can't get it to work; all I get is the following:

```
<table> <tr> <th>Page</th> <th>Last Modifier</th> <th>Modified Date</th> <th>Modified < 7d?</th> </tr> </table>
```

What am I doing wrong?

comments: author: Cindy
body: Also running into a similar issue! Any insight?


author: Evanna McMahon
body: I have also this error. Did anyone find out how to resolve this ?


author: jiratest
body: Me too. going through the same issue.

actually I wanted to find all the edits or creation in pages during certain frame of time. So unable to do that. Please suggest some ways to do that.


author: Ryan Severe
body: You need to make sure you have converted the HTML escape characters for \&It; and \&gt; need to be replaced with the \< \& \> to put them back into html tags. doing that corrected the issue for me


author: Stephen Deutsch
body: Thanks Ryan. These posts are originally from answers.atlassian.com, and when they were migrated here to the community, they escaped the angle brackets. Maybe if I have time I will go through all my old posts and change them, but it's quite a hassle :(


author: Sandeep Anand
body: Thanks Ryan. Appreciate that.

Running through one more error. Actually can you help me to understand how

```
$compareDate.add(6, -7)
```

this piece of code is working. Actually i am unable to figure out that how "add" method is working here by taking any random numbers.

I want to know what does this (6,-7) is indicating ?


author: Stephen Deutsch
body: Hi Sandeep,

Confluence uses the Calendar class in the background to store dates (<https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html>)

and for the add function, you need to include which part of the date you want to modify (Year, Time Zone, Month, Day, Hour, Minutes, Seconds, Milliseconds, etc.).

The number that matches the day part of the date happens to be 6 (so 5 might be month, I don't remember exactly). Adding a negative number to that subtracts that from that particular field. So in essence what this is saying is:

please remove 7 days from this date

Then it uses this date to compare against the last modification date of the page.


author: Sandeep Anand
body: Hi Stephen

Thanks a lot for your answer. Appreciate that.

Thanks And Regards

Sandeep Anand


author: al fredmi
body: Hi Stephen. This looks like a great idea. Can I create the user macro in the new confluence version today?  
Also, is it possible to have a choice inside the macro when chosen, to pick which would be the 'parent page'? then I dont have to modify the target, I could run this from a different page. Or must I always add this macro to the page that I want to check its children?

Thank you very much!


author: karen.wright40
body: Sorry to revive this, great bit of code and really helpful however is there a way to output childpages only and not child and grandchild pages as it currently does with:

```
#set ( $descendantPages = $pageManager.getDescendents($content) )
```

comments: author: Stephen Deutsch
body: You should be able to replace it with the following:

```
#set ( $descendantPages = $content.getChildren() )
```

I didn't get a chance to test it, but I think that will work.


author: Aby12345
body: Hi Stephen, Sorry my bad. Either way if it is possible, works for me. I have used the recently updated macro with labels on each sub page to aggregate information as of now. But this is restricted only to the information that the macro can retrieve. In an SQL query I am assuming I would be able to pass the Parent PageID to get all the sub pages. The recently updated macro only fetches for a space. Please let me know your feedback on how to do this using a User macro.