I have a page type
ProductPage
that $has_one FeatureImage
There is a virtual page that references one of the ProductPages
When I am in a page that loops the children where one of the children is the virtual page I can render all fields except the FeatureImage field.
class ProductPage extends Page
{
private static $db = [
'TeaserText'=>'Varchar'
];
private static $has_one = [
'LinkedProduct'=>'Product',
'FeatureImage'=>Image::Class
];
private static $many_many = [
];
private static $owns = [
'FeatureImage'
];
public function getCMSFields(){
$fields = parent::getCMSFields();
$featureField = UploadField::create('FeatureImage', 'Feature Image')->setFolderName('FeatureImages')->setDescription("This image appears in the category pages. 400x400px");
$teaserField = TextField::create('TeaserText', 'Teaser Text')->setDescription("This text appears in the category pages");
$fields->addFieldToTab('Root.Main', $featureField, 'Metadata');
$fields->addFieldToTab('Root.Main', $teaserField, 'Metadata');
$productLinkField = DropdownField::create('LinkedProductID', 'Link a Product', Product::get()->map('ID', 'ProductName'));
$productLinkField->setEmptyString('(Select one)');
$fields->addFieldToTab('Root.Main', $productLinkField, 'Content');
$productLinkField->addExtraClass('stacked');
$featureField->addExtraClass("stacked");
$teaserField->addExtraClass("stacked");
return $fields;
}
}
The SS template
<% loop $Children %>
<div class="category-card mb-5">
<div class="row">
<div class="col-md-4">
<img src="$FeatureImage.URL" class="fluid-image"/>
//This renders for standard ProductPage children
</div>
<div class="col-md-8 category-card-body">
<h4 class="category-card-title"><a href="$Link">$MenuTitle</a></h4>
<p class="category-card-text">$TeaserText</p>
//This TeaserText renders fine.
<a href="$Link" class="category-card-link btn btn-info">view details</a>
</div>
</div>
</div>
<% end_loop %>
This may be an edge use case but I think it is valid and will post my solution for anyone else needing to do the same thing.
VirtualPage class will pull all database fields but it will not pull has_one relations so you can not access it from the virtual page.
From VirtualPage.php:
* Note: This Only duplicates $db fields and not the $has_one etc..
My solution is to include a method in the virutal page class that will return the actual parent page object using <% with %>
public function getTheParentPageObject(){
$page = DataObject::get_by_id(SiteTree::class, $this->getField('CopyContentFromID'));
return $page;
}
This allows me to call the method inside my loop in the template and pull all fields that were left out of virtualization
<% loop $Children %>
<div class="category-card mb-5">
<div class="row">
<div class="col-md-4">
<% if $ClassName == "SilverStripe\CMS\Model\VirtualPage" %>
<% with $getTheFeaturedImageById() %>
<img src="$FeatureImage.URL" class="fluid-image"/>
<% end_with %>
<% else %>
<img src="$FeatureImage.URL" class="fluid-image"/>
<% end_if %>
</div>
<div class="col-md-8 category-card-body">
<h4 class="category-card-title"><a href="$Link">$MenuTitle</a></h4>
<p class="category-card-text">$TeaserText</p>
<a href="$Link" class="category-card-link btn btn-info">view details</a>
</div>
</div>
</div>
<% end_loop %>