We've been struggling with getting Virtual Pages working on our SilverStripe install. We can successfully use the built in SilverStripe Virtual Page just fine. The challenge is that we are using a number of custom fields to build a right column menu and a bunch of other parts of the page. When we create the Virtual Pages though it only copies over the Content and Title fields, not all of our custom fields.
So what I've done is I have copied the Sapphire code for Virtual Pages to make our own "Virtual Content Page" for handling this. I'm at the point where I have the "Virtual Content Page" working in exactly the same way as the default "Virtual Page" works. If I uncomment the code below it even shows the needed fields:
/*
$fields->addFieldToTab('Root.Content.Main', new TextField('BannerImage'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip1'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip2'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip3'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip4'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip5'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('BizToolkit'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Licenses'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Workshops'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Books'), '');
*/
But I'm stumped as to how I would make those fields populate from the original page and be linked to the original page (In the same way as the content field is).
I've done a heap of searching and the closest I've been able to find to my problem is this topic:
http://ssorg.bigbird.silverstripe.com/archive/show/33497
I'm sure this is within spitting distance of a solution and would be INCREDIBLY thankful to anyone that could help point me in the direction of a solution. I've included both the content of ContentPage.php (Where the extra fields are defined for normal pages) and the full contents of VirtualContentPage.php (A clone of the Sapphire version with a few of my own tweaks).
Contents of /mysite/code/ContentPage.php
<?php
/**
* Defines the ContentPage page type
*/
class ContentPage extends Page {
static $db = array(
'BannerImage' => 'Text',
'TopTip1' => 'HTMLText',
'TopTip2' => 'HTMLText',
'TopTip3' => 'HTMLText',
'TopTip4' => 'HTMLText',
'TopTip5' => 'HTMLText',
'BizToolkit' => 'HTMLText',
'Licenses' => 'HTMLText',
'Workshops' => 'HTMLText',
'Books' => 'HTMLText'
);
static $has_one = array(
);
function getCMSFields() {
$fields = parent::getCMSFields();
$fields->addFieldToTab('Root.Content.Main', new TextField('BannerImage'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip1'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip2'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip3'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip4'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip5'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('BizToolkit'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Licenses'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Workshops'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Books'), '');
return $fields;
}
}
class ContentPage_Controller extends Page_Controller {
}
?>
Contents of /mysite/code/VirtualContentPage.php
<?php
/**
* @package cms
*/
/**
* Virtual Page creates an instance of a page, with the same fields that the original page had, but readonly.
* This allows you can have a page in mulitple places in the site structure, with different children without duplicating the content
* Note: This Only duplicates $db fields and not the $has_one etc..
* @package cms
*/
class VirtualContentPage extends Page {
static $add_action = "Virtual content page (another page's content)";
static $icon = array("cms/images/treeicons/page-shortcut-gold","file");
public static $virtualFields;
static $has_one = array(
"CopyContentFrom" => "SiteTree",
'BannerImage' => 'Text',
'TopTip1' => 'HTMLText',
'TopTip2' => 'HTMLText',
'TopTip3' => 'HTMLText',
'TopTip4' => 'HTMLText',
'TopTip5' => 'HTMLText',
'BizToolkit' => 'HTMLText',
'Licenses' => 'HTMLText',
'Workshops' => 'HTMLText',
'Books' => 'HTMLText'
);
static $db = array(
"VersionID" => "Int",
);
/**
* Generates the array of fields required for the page type.
*/
function getVirtualFields() {
$nonVirtualFields = array(
"SecurityTypeID",
"OwnerID",
"AssignedToID",
"RequestedByID",
"URLSegment",
"Sort",
"Status",
'ShowInMenus',
'ShowInSearch'
);
$allFields = $this->db();
if($hasOne = $this->has_one()) foreach($hasOne as $link) $allFields[$link . 'ID'] = "Int";
foreach($allFields as $field => $type) {
if(!in_array($field, $nonVirtualFields)) $virtualFields[] = $field;
}
return $virtualFields;
}
function ContentSource() {
return $this->CopyContentFrom();
}
/**
* Generate the CMS fields from the fields from the original page.
*/
function getCMSFields($cms = null) {
$fields = parent::getCMSFields($cms);
// Setup the linking to the original page.
$copyContentFromField = new TreeDropdownField(
"CopyContentFromID",
_t('VirtualContentPage.CHOOSE', "Choose a page to link to"),
"SiteTree"
);
$copyContentFromField->setFilterFunction(create_function('$item', 'return $item->ClassName != "VirtualContentPage";'));
// Setup virtual fields
if($virtualFields = $this->getVirtualFields()) {
$roTransformation = new ReadonlyTransformation();
foreach($virtualFields as $virtualField) {
if($fields->dataFieldByName($virtualField))
{
$fields->replaceField($virtualField, $fields->dataFieldByName($virtualField)->transform($roTransformation));
//$fields->addFieldToTab('Root.Content.Main', $fields->dataFieldByName($virtualField), '');
}
}
}
// Add fields to the tab
$fields->addFieldToTab("Root.Content.Main",
new HeaderField(_t('VirtualContentPage.HEADER', "This is a virtual content page")),
"Title"
);
$fields->addFieldToTab("Root.Content.Main", $copyContentFromField, "Title");
/*
$fields->addFieldToTab('Root.Content.Main', new TextField('BannerImage'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip1'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip2'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip3'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip4'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('TopTip5'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('BizToolkit'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Licenses'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Workshops'), '');
$fields->addFieldToTab('Root.Content.Main', new TextField('Books'), '');
*/
// Create links back to the original object in the CMS
if($this->CopyContentFromID) {
$linkToContent = "<a class=\"cmsEditlink\" href=\"admin/show/$this->CopyContentFromID\">" .
_t('VirtualContentPage.EDITCONTENT', 'click here to edit the content') . "</a>";
$fields->addFieldToTab("Root.Content.Main", new LabelField($linkToContent, null, true), "Title");
}
return $fields;
}
/**
* We have to change it to copy all the content from the original page first.
*/
function onBeforeWrite() {
// Don't do this stuff when we're publishing
if(!$this->extension_instances['Versioned']->migratingVersion) {
if(isset($this->changed['CopyContentFromID']) && $this->changed['CopyContentFromID']
&& $this->CopyContentFromID != 0 && $this->class == 'VirtualContentPage' ) {
$CopyContentFromID = $this->CopyContentFromID;
$source = DataObject::get_one("SiteTree","`SiteTree`.`ID`='$CopyContentFromID'");
$this->copyFrom($source);
$this->URLSegment = $source->URLSegment . '-' . $this->ID;
}
}
parent::onBeforeWrite();
}
/**
* Ensure we have an up-to-date version of everything.
*/
function copyFrom($source) {
if($source) {
foreach($this->getVirtualFields() AS $virtualField)
$this->$virtualField = $source->$virtualField;
}
}
}
/**
* Controller for the virtual page.
* @package cms
*/
class VirtualContentPage_Controller extends Page_Controller {
/**
* Reloads the content if the version is different ;-)
*/
function reloadContent() {
$this->failover->copyFrom($this->failover->CopyContentFrom());
$this->failover->write();
return;
}
/**
* When the VirtualContentPage is loaded, check to see if the versions are the same
* if not, reload the content.
* NOTE: Virtual page must have a container object of subclass of sitetree.
* We can't load the content without an ID or record to copy it from.
*/
function init(){
if($this->record->ID){
if($this->record->VersionID != $this->failover->CopyContentFrom()->Version){
$this->reloadContent();
$this->VersionID = $this->failover->CopyContentFrom()->VersionID;
}
}
parent::init();
}
function loadcontentall() {
$pages = DataObject::get("VirtualContentPage");
foreach($pages as $page) {
$page->copyFrom($page->CopyContentFrom());
$page->write();
$page->publish("Stage", "Live");
echo "<li>Published $page->URLSegment";
}
}
}
?>
Thanks in advance!