Decorates a SiteTree class with multiple named element relations through a has_many "Elements" relation.
Set up you relation types in your _config/elements.yml, e.g:
Page:
element_relations:
Elements:
- Element
- DownloadElement
Downloads:
- DownloadElement
In this example we are creating 2 element relationships to the Page, one called Elements, the other called Downloads.
To make it work Element
class should subclass ElementBase
, where all additional fields can be defined, e.g.:
class Element extends ElementBase
{
private static
$singular_name = 'Base element',
$db = [
'Title' => 'Text',
'Subtitle' => 'Text',
...
..
.
]
;
}
In the SiteTree instance the element relations are now accessable through:
$pageInst->ElementsByRelation('Elements');
$elementInst->ElementsByRelation('Elements');
To use them in a template:
<% loop $ElementsByRelation(Elements) %>
$Render($Pos, $First, $Last, $EvenOdd)
<% end_loop %>
Notice: we pass in the $Pos, $First, $Last and $EvenOdd values to have them available inside the template as $IsPos, $IsFirst, $IsLast and $IsEvenOdd.
There is also a helper function to move a gridfield into another tab if you prefer:
public function getCMSFields()
{
$fields = parent::getCMSFields();
// move the elements gridfield to a tab called 'PageElements'..
$fields = ElementsExtension::move_elements_manager($fields, 'Elements', 'Root.PageElements');
return $fields;
}
Apply the same extension to the Element instead of the Page.
TeasersElement:
element_relations:
Teasers:
- TeaserElement
If you would like to have the same elements applied to different Pagetypes you can use the element_relations_inherit_from
definition referencing a arbitrary setup in the yml file. For example if we want the HomePage and the EventsPage to inherit the same elements we can define the .yml like this:
HomePage:
element_relations_inherit_from: MainElements
EventsPage:
element_relations_inherit_from: MainElements
They both reference the MainElements defined in the yml where you have defined the element_relations, like this:
MainElements:
element_relations:
Elements:
- HeroElement
- DownloadElement
- TeasersElement
If you inherit elements you can still create your custom relations and also append new Element types to the inherited relation.
HomePage:
element_relations_inherit_from: MainElements
element_relations:
Elements:
- ImageElement
In this example ImageElement is added to the list of available Elements defined in MainElements.
Naming of Tab
and GridField
labels can be done through silverstripes i18n. There is a special key called Element_Relations
reserved to accomplish this task, e.g. in de.yml:
de:
Element_Relations:
Downloads: 'Dateien'
A button below the Element GridField called "Create default elements" will populate the default elements defined in your _config.yml as empty elements in your page. If you trigger the action again it will counter-check against the already created elements and don't add any duplicates.
You can define the element_defaults for each of your relations like this:
Page:
element_relations:
Teasers:
- TeaserElement
element_defaults:
Teasers:
- TeaserElement
To use fluent with elements just add the Fluent extensions to the ElementBase:
ElementBase:
extensions:
- FluentExtension
- FluentFilteredExtension
colymba/gridfield-bulk-editing-tools
:In some cases (e.g. slideshow elements, etc.) you may want to give content authors a way to upload many assets into a relation at once. Here we provide an example how this can be achieved.
Note: this will only work well with element relations with one single allowed child element class.
Install https://github.com/colymba/GridFieldBulkEditingTools
composer require colymba/gridfield-bulk-editing-tools
(Watch out: grab a version fitting to you silverstripe version)
You might need a to add a helper method to quickly add the gridfield component like this:
// e.g. in Element.php, feel free to change to your needs....
/**
* !!! CAUTION - only use in gridfields with one element relation !!!
* Adds a bulkuploader to element GridField
*
* @param FieldList $fields the fields to look for the gf
* @param string $elementClass the element class to create
* @param string $elementRelationName the relation name to add to the element
* @param string $assetRelationName the asset relation inside the element
* @return FieldList $fields
*/
public static function add_bulk_uploader(
FieldList $fields,
$elementClass,
$elementRelationName,
$assetRelationName,
$uploadFolder = null
) {
if ($gf = $fields->dataFieldByName($elementRelationName))
{
$gf->getConfig()
->addComponent((new GridFieldBulkUpload($assetRelationName, $elementClass))
// this is needed in onBulkUpload hook
->setUfConfig('elementRelationName', $elementRelationName)
->setUfSetup('setFolderName', $uploadFolder)
)
;
$gf->setModelClass($elementClass);
}
return $fields;
}
You also need to add an extension to your Element class to hook into the write process during bulk uploading:
// feel free to change or use it in you own extension.
class BulkUploadExtension extends Extension
{
public function onBulkUpload(GridField $gf)
{
// this is the part to apply in your code
$this->owner->RelationName = $gf
->getConfig()
->getComponentByType('GridFieldBulkUpload')
->getUfConfig('elementRelationName')
;
}
}
(This is due to the way bulk editing tools work. Right now it only works with extension hooks. That might change in the future.)
Then you can add the bulkuploader like this:
// e.g. parent page or parent element
public function getCMSFields()
{
$fields = parent::getCMSFields();
Element::add_bulk_uploader(
$fields,
'ImageElement', // element class to create
'Images', // element relation to attach to
'Image', // asset relation
'home' // folder name
);
return $fields;
}
ElementBase:
extensions:
- arillo\elements\ElementsExtension
Page:
extensions:
- arillo\elements\ElementsExtension