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.

General Questions /

General questions about getting started with SilverStripe that don't fit in any of the categories above.

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

Design Critiques Requested - Remote Content Wrapper Page

Go to End


Ben Gribaudo

Community Member, 181 Posts

20 May 2009 at 4:15am

Edited: 20/05/2009 4:17am


I am working on a custom page type that allows a remote web resource (say, a forum) to be mounted in a SilverStripe site. To the end user, the mounted resource looks and feels like it is apart of the SS site (consistent template and navigation).

If the wrapper page is inserted at http://mysite/mount/ and is set to wrap content from http://othersite/forum/, a request for http://mysite/mount/page1/ will be forwarded to http://othersite/forum/page1/. When content is received back from othersite, the page wraps that content in the appropriate SS template.

Would you have time to critique this code?

In particular, some thoughts/questions I have:

  • In WrapperPage's Children() method, how do I set the Page's URL?
  • Do I need to define stageChilden() and liveChildren() in WrapperPage?
  • In case you're wondering, I would like to eliminate the multiple calls to $this->loadRemotePage() by calling it once from WrapperPage's constructor, however, when I define a __construct() method on WrapperPage, the PHP script hangs. I have yet to debug this problem.
  • Is there a way to eliminate the overriding of handleAction in the controller? Right now, without that override, only requests for http://mysite/mount/ will work. Requests for pages like http://mysite/mount/page1/ will return a not-found error.

FYI, I'm developing against nestedurls.

Thank you,

// Code by:  Ben Gribaudo -
require_once 'HTTP/Request.php';

class WrapperPage extends Page {
	public static $db = array(
		'SourceURL' => 'Varchar(500)',
		'ContentSelector' => 'Varchar(100)'
	public static $has_one = array();
	public static $allowed_children = array();
	private $remotePageLoaded = false;
	public function getCMSFields() {
		$fields = parent::getCMSFields();
		$fields->removeFieldFromTab("Root.Content.Main", "Title");
		$fields->removeFieldFromTab("Root.Content.Main", "Content");
		$fields->addFieldToTab('Root.Content.Main', new TextField('SourceURL', 'Source URL (No Query Strings)'));
		$fields->addFieldToTab('Root.Content.Main', new TextField('ContentSelector', 'Content Selector (XPath)'));
		return $fields;
	public function onBeforeWrite() {
		$this->Title = $this->MenuTitle;
		return parent::onBeforeWrite();

	public function Children() {
		$children = new DataObjectSet(); 
		foreach ($this->Children as $childTitle => $childLink) {
			$page = new Page();
			$page->Title = $childTitle;
			// Doesn't work!
			//$page->URL = $this->Link() . $childLink;
		return $children;

	public function Title() {
		return $this->Title;
	public function Content() {
		return $this->Content;
	private function loadRemotePage() {
		if (!$this->remotePageLoaded) {
			$currentURL = '/' . $this->CurrentPage()->request->getVar('url');
			if (preg_match('/^' . preg_quote($this->Link(), '/') . '/i', $currentURL)) {
				$subUrl = str_ireplace($this->Link(), '', $currentURL);
			} else {
				$subUrl = '';
			$remotePage = new RemotePage(new WebPageLoader(new HTTP_Request()), $this->SourceURL, $this->Link(), create_function('$url', 'header("Location: $url"); exit();'), create_function('$cookie, $expires', 'setcookie($cookie["name"], $cookie["value"], $expires, $cookie["path"]);'));
			$xPathDoc = $remotePage->load($subUrl, $_GET, $_POST, $_COOKIE);
			$this->Title = $xPathDoc->queryFirstAsHTML('/html/head/title');
			$this->Content = $xPathDoc->queryFirstAsHTML($this->getField('ContentSelector'));
			// children eventually will be populated from data contained in the xPathDoc
			$this->Children = array('Topic1' => 'topic1', 'Topic2' => 'topic2');
			$this->remotePageLoaded = true;

class WrapperPage_Controller extends Page_Controller {
	// $action parameter is ignored
	public function handleAction($action) {
		try {
			return $this->renderWith($this->getViewer('index'), $this->dataRecord);
		} catch (RemotePageLoadError $exception) {
			return $this->httpError(500, '500 Internal Server Error');