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've moved the forum!

Please use forum.silverstripe.org for any new questions (announcement).
The forum archive will stick around, but will be read only.

You can also use our Slack channel or StackOverflow to ask for help.
Check out our community overview for more options to contribute.

Customising the CMS /

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

hide ALL the pages and their children of a certain page type from SITE TREE Link to this post


Go to End


6 Posts   4060 Views

Avatar
mattconfusion

Community Member, 48 Posts

25 August 2010 at 6:29pm

Hi
i know it has been debated a couple of times on other topics but I wanted to have more solutions or suggestions. I need, due to a very very large number of pages of a certain class, to hide them from the site tree. I don't want neither one of them to be showed, as I will manage them in a custom ModelAdmin type of view.
I'm now using this code:

 

<?php
class StopHierarchy extends Hierarchy{
    
  public function stageChildren($showAll = false)
	{
		$baseClass = ClassInfo::baseDataClass($this->owner->class);
		$extraFilter = $showAll ? '' : " AND ShowInMenus = 1";
		$filter = "`{$baseClass}`.`ParentID` = " . (int)$this->owner->ID;
		$filter .= " AND `{$baseClass}`.ID != " . (int)$this->owner->ID;
		$filter .= $extraFilter;

		if(Director::urlParam("Action") == "getfilteredsubtree" && (!empty($_REQUEST['SiteTreeSearchTerm']) || !empty($_REQUEST['SiteTreeFilterDate'])))
		{
			// $staged = DataObject::get($baseClass, $filter, "Date ASC");
			$staged = DataObject::get($baseClass, $filter, "");
			if(!$staged) $staged = new DataObjectSet();
			$this->owner->extend("augmentStageChildren", $staged, $showAll);
			return $staged;
		}

	else return new DataObjectSet(); // just Stop
	}

}

?>

and then adding to the parent page type of the page type i want to hide:

static $extensions = array("StopHierarchy");

It works, but just out of curiosity: any other suggestion?

Avatar
TotalNet

Community Member, 181 Posts

8 September 2010 at 1:51pm

Hi mattconfusion,

Thanks for posting this. It's something I've taken a look at too.

Basically, I want to display pages that are managed outside of the "Page Tree" hierarchy as shown in the Pages tab of the CMS, due to quantity or other considerations. To date, I have achieved this with sub-classes of DataObject using methods on a controller to retrieve them by their own URL segment. The downside of this approach is that you lose all of the goodies inherited from SiteTree: Versioning, top-level URLs, automatic template selection, Google sitemap, static caching etc, to name a few that figure highly in my requirements. While many of these can be coded in to the DataObject, I'm not sure this is a good idea from a maintainability or a model point of view.

So, that brought me to the same place as you, managing sub-classes of Page outside of the Page Tree, they are DataObjects after all. Which left me with the same challenge, hiding them from the Page Tree hierarchy.

Like you, I followed CMSMain::SiteTreeAsUL() to look for ways of filtering certain pages out and there are a few points where this might be achieved:
1. Intercept SiteTreeAsUL() and pass a childrenMethod or filterFunction to LeftAndMain::getSiteTreeFor()
- maybe create your own CMSMain_left.ss template, and replace $SiteTreeAsUL with your own function
- or decorate/extend/sub-class CMSMain and overload SiteTreeAsUL()
2. Hide the default tree and apply a custom CMSSiteTreeFilter (probably quite a bit of Javascript)
3. Go a bit deeper, as you have, and work on Heirarchy
- subclass and overload one of the functions that returns the DataObjectSet: doAllChildrenIncludingDeleted() or stageChildren()
- can we use augmentAllChildrenIncludingDeleted or augmentStageChildren? Not too familiar with extensions at this level myself.

Those are the key places I can see anyway that would avoid hacking the cms code. Ultimately, I'd like to have a solution that is flexible and doesn't involve duplicating large amounts of code (e.g. copying CMSMain_left.ss) or having to patch a lot of code that is dependant on existing classes (e.g. sub-classing CMSMain).

Right now I'm looking at creating a new static or $db along the lines of "HideFromTree" and using its presence as the key for the filter. Now, it's deciding which approach is "best" so any views on performance, maintainability considerations etc happily received.

Cheers

Rich

Avatar
TotalNet

Community Member, 181 Posts

17 September 2010 at 12:53pm

Well, I'm feeling quote pleased with myself :)

Here's another way using the extension hooks already built into Hierarchy, it's much shorter and perhaps more easily managed?

    public function augmentStageChildren(DataObjectSet $staged, $showAll){
		if ($staged->exists()) foreach ($staged as $object) {
			if ($object->class == "MyClass") $staged->remove($object);
		}
		return $staged;
    }

Put that in a DataObjectDecorator sub class, replace MyClass with the class you want to hide and you're good to go.

This was just to prove the concept so next step is to add a db field like HideFromTree as suggested in my last post and use that to filter instead of matching the class, although this approach can be used when creating a new page type with good effect.

Only concern at this point is performance, obviously the entire tree is retrieved and then individual records (DOs) removed. I was quite surprised to see that stageChildren gets the complete object rather than just Name, Class and ID which is all that is needed for the UL, that's a lot of overhead even for a moderate size SiteTree!

Avatar
mattconfusion

Community Member, 48 Posts

17 September 2010 at 6:26pm

that's a great lil piece of code :D and it's really easy. Performance-wise, I tried with other methods with ~ 3000 automatically generated pages (with the requiredDefaultRecords trick) and the tree works correctly and doesn't get stuck up as it happened when children were not hidden. But now I abandoned this way because of many other problems of managing pages surfaced in my specific (and rather complex) case, which is involving the eCommerce module and the StoreAdmin view (now changed in the branch i am following).

Thank you so much anyway!

Avatar
mattconfusion

Community Member, 48 Posts

17 September 2010 at 6:28pm

and surely retrieving the entire object and not just what's useful to the UL (status, page type, page name) is something that gives SS sitetree performance problems when dealing with a large amount of pages.

Avatar
TotalNet

Community Member, 181 Posts

17 September 2010 at 6:44pm

My thoughts too, not sure where it all comes from so reluctant to interfere: Hierarchy::getChildrenAsUL returns a <ul> with just the Title in a <li> so not sure where all the other stuff comes from, maybe javascript ... I'm a bit over looking at it now though.

I'm just happy to figure out a little more about how Object::extend() works although in this case my fears around performance will probably mean going a different route in the end.

Would be interested to hear about your new approach, I really want to use top-level URLs that won't conflict with SiteTree and a Page sub-class is the only way I can see of doing this (easily).

Cheers,

Rich