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.

We're retiring the forums!

The SilverStripe forums have passed their heyday. They'll stick around, but will be read only. We'd encourage you to get involved in the community via the following channels instead:

Data Model Questions /

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

Creating a list of pages with $belongs_many_many grouped by their Parent

Go to End



Community Member, 323 Posts

24 July 2009 at 9:17pm

Edited: 24/07/2009 9:19pm


The following code is working, it's based on the SiteMap tutorial, but I'm sure the same thing can be done more easily by using functions of ComponentSet and respecting the MVC paradigm.

I have this Page_Themes many_many relationship between some pages (Articles, Links, BlogEntries) of a site and one kind of page that groups them by Theme :

class Page extends SiteTree {
	// Pages can have many themes (see ThemePage for the other side of the relation)
	public static $many_many = array(
		'Themes' => 'ThemePage'


// With class Theme it didn't worked, you had to add …Page
class ThemePage extends Page {
	static $belongs_many_many = array(
		'Pages' => 'Page'

My problem is that I wanted to give some context to the pages being classed by Themes, displaying also its parents. In I can display all pages belonging to the theme with a <% control Pages %>, where I can access the Parent of every page with $Parent.Title, for example. That's neat, but list look like:
Pages belonging to the Theme XXX:
Articles » Article1
Blog entries » BlogEntry1
Blog entries » BlogEntry2
Links » Link

I'd like to group all pages belonging to a theme by it's parent ID. I've looked to the DataObjectSet API doc and seen that there's some methods as GroupedBy, removeDuplicates… but I've not been able to work my way with the ComponentSet 'Pages'. So, I had to do this ugly thing in ThemePage.php:

/* PagesList() creates an array of unique parents for the pages of this theme,
** then it passes it to makeList()
function PagesList() {
	foreach ($this->Pages() as $page) {
		$parentIDs[$page->Parent->Title] = $page->ParentID;
	$parentIDs = array_unique($parentIDs);
	$output = $this->makeList($parentIDs);
	return $output;
	private function makeList($parentIDs) {
	$output = "";
	if(count($parentIDs)) {
		foreach($parentIDs as $parentID) {
			// Get the unique parents
			$parent = DataObject::get_by_id('Page', $parentID);
			// First level of the ul
			$output .= '<li class="newsTitle parent">' . '<a href="'.$parent->URLSegment.'" title="'. _t('SECTIONTITLE1', '') . convert::raw2xml($parent->Title). _t('SECTIONTITLE2', '') . '">' . Convert::raw2xml($parent->Title) . '</a>';
			// Then iterate through pages of this theme and class it by parent
			//Second level of the ul
			$output .= '<ul class="children">';
			foreach($this->Pages() as $page) {
				if($page->ParentID == $parentID){
					$output .= '
					<li class="newsTitle"><a href="'.$page->URLSegment.'" title="'. _t('PAGETITLE1', '') . convert::raw2xml($page->Title). _t('PAGETITLE2', '') . '">' . Convert::raw2xml($page->MenuTitle).'</a>';
					$output .= '
			$output .= '</ul></li>';
	return $output;

Getting the unique parent's ID, then using get_by_id with them to filter the pages of the ComponentSet by ParentID seems like an unnecessary long travel, isn't it? Also, I don't like the idea of mixing view and controller.

If somebody brave enough to read till here could help me cleaning this mess I'd be deeply grateful.

Best regards,