Skip to main content

This site requires you to update your browser. Your browsing experience maybe affected by not having the most up to date version.

Customising the CMS /

Moderators: martimiz, Sean, Ed, biapar, Willr, Ingo, swaiba

compile sub pages on one page

Go to End



126 Posts

16 April 2009 at 4:26pm

Edited: 16/04/2009 4:29pm


just in case this is useful for someone: I'm working on a Silverstripe site that is set up like a book with chapters and sub-chapters etc... each of them on an individual Silverstripe page. I also wanted to have a version that's easy to print; it's not much fun to go to every individual page, print, waste time and paper and possibly forget a few pages in the process. Thanks to the fantastic Silverstripe framework it only took a few minutes to create a 'compile' function to display the content of a parent and all it's children on one page. Here is how:

add this to the Page_Controller class in /mysite/code/Page.php

// a variable that stores if the current view is compiled or not - this is useful for the template (see below)
public $isCompiled = false;

// the 'compiled' method that is called when a user e.g. goes to the URL /a-page-with-subpages/compiled/
public function compiled() {
	$data = array('Content' => $this->getChildrenContent($this));
	$this->isCompiled = true;
	return $this->customise($data)->renderWith(array('Page', 'Page'));

// same as above but this one compiles all pages of your website including all pages on the root level (e.g. /home/all_compiled/ )
public function all_compiled() {
	$rootLevel = DataObject::get("Page", "ParentID = 0");
	$data = array('Content' => $this->getChildrenContent($rootLevel));
	$this->isCompiled = true;
	return $this->customise($data)->renderWith(array('Page', 'Page'));

// a method to get all the content of the current and child pages (recursive)
private function getChildrenContent($pages) {
	$output = '';
	if(count($pages)) {
		foreach($pages as $page) {
			if(!($page instanceof ErrorPage) && $page->ShowInMenus){
				if ($page->Title != $this->Title) {
					$output .= '<h2 id="'.$page->URLSegment.'">'.$page->Title.'</h2>'; // you can use the 'id' to use anchors
				$output .= $page->Content;
				$whereStatement = "ParentID = ".$page->ID;
				$childPages = DataObject::get("Page", $whereStatement);
				$output .= $this->getChildrenContent($childPages);
	return $output;

That's it. Try to access a page and add /compiled/ to the URL and you will get the page plus all content of the sub pages on one page. For a compiled version of all page content including all root level pages add /all_compiled/ to the URL

All that's left to do is to add a link to the template:

<% if Children %>
	<% if isCompiled %>
		<a href="$URLSegment/">view parent page only</a>
	<% else %>
		<a href="$URLSegment/compiled/">view all sub pages</a>
	<% end_if %>
<% end_if %>


<a href="home/all_compiled/">view all content of this website</a>

In a similar way as above you can build a menu with text anchors. See the site-map tutorial and just create links with a '#' to jump to the anchor. Thanks for the site-map tutorial - I borrowed heavily for the compile functions above.

(This is for the default 'Page' page type. If you want to use this for other page types you probably need to do some tweaking.)