WORKING 'FLEXIBLE CONTENT FIELD’
WHAT YOU NEED TO DO TO IMPLEMENT THIS:
- Extend your theme to add/load some css & js into the admin
- Add the css & js file in the theme folder
- Add the
<templateName>.yaml
file to display the Flexible Content Field in the admin
- Loop through the ‘Flexible Content Field’ inside your
<templateName>.html.twig
file to display the data.
MORE DETAILED EXPLANATION:
#1. Extend your theme
Inside your theme folder you have a <themename>.php
file. Add the code:
(In this example my theme name is ‘Base’, change this name to your theme name.)
<?php
namespace Grav\Theme;
use Grav\Common\Theme;
class Base extends Theme
{
// Add assets to the Admin
public function onAssetsInitialized() {
if ($this->isAdmin()) {
// add JS
$this->grav['assets']->addJs('theme://js/admin.js');
// add CSS
$this->grav['assets']->addCss('theme://css/admin.css');
}
}
}
#2. Add css & js files.
Your theme has a css folder and a js folder.
- In the css folder create a file named ‘admin.css’.
- In the js folder create a file named ‘admin.js’
Add this CSS:
/* Hide form-fieldset by default */
ul.field-selection > li > .form-fieldset {
display: none;
}
/* Show form-fieldset that is selected */
ul.field-selection > li > .form-fieldset.field-selection--show {
display: block;
}
Add this JS:
var flexibleContentField = (function (w, d, $, undefined) {
'use strict';
var s = {
selectors: {
theRepeater: '.field-selection',
theSelect: '.field-selection__select'
}
},
els = {},
init = function () {
// define elements
els.theRepeater = $(s.selectors.theRepeater);
// no elements
if (!els.theRepeater.length) { return; }
// theloop
els.theRepeater.each(function() {
// the bind
$(this).on('change', checkTarget);
// adjust existing selections
var theRepeaterItems = $(this).children('li');
theRepeaterItems.each(function(index, element) {
var theRepeaterItem = $(element),
theSelect = theRepeaterItem.find(s.selectors.theSelect);
showHide(theRepeaterItem, theSelect);
});
});
},
checkTarget = function(event) {
// The vars
var theRepeaterItem = $(event.target).closest('li'),
theSelect = event.target;
// Target is Select?
theSelect.nodeName.toLowerCase() === 'select' ? showHide(theRepeaterItem, theSelect) : '';
},
showHide = function (theRepeaterItem, theSelect) {
// the vars
var theRepeaterItem = $(theRepeaterItem),
theSelect = $(theSelect),
theSelectParent = theSelect.closest('.form-field'),
theValue = theSelect.val(),
theRefererPrefix = 'field-selection__',
theReferer = theRefererPrefix + theValue,
theSelectedFields = theRepeaterItem.find('input[type="hidden"][value="'+theReferer+'"]'),
theFieldToShow = theSelectedFields.closest('.form-fieldset');
// Exeption - default selected
if (theValue === 'default') { return; }
// show the selected field
theFieldToShow.addClass('field-selection--show');
// hide the select
theSelectParent.css('display','none');
}
return {
init: init
};
}(window, window.document, window.jQuery));
// theCall - on window loaded
(function (w, d, undefined) {
"use strict";
var raf = requestAnimationFrame || mozRequestAnimationFrame || webkitRequestAnimationFrame || msRequestAnimationFrame,
init = function () { w.flexibleContentField.init(); };
// when all is loaded
raf ? raf(function () { w.setTimeout(init, 0); }) : w.addEventListener('load', init);
}(window, window.document));
#3. Define the fields
Define the fields for your ‘Flexible Content Field’ inside a <templateName>.yaml
file.
As example, you could need this Flexible Content Field inside an article.html.twig
template, so the yaml file for this template would be article.yaml
.
Inside your <templateName>.yaml
file add this code to display the Flexible Content Field.
As example this Flexible Content Field code is used to let a user choose between a tinyMCE, a slideshow, a testimonial and a video.
Where is states # Define your grouped field here...
, thats where you define the fields you need for your pre-designed components.
# - Flexible Content Field -
#
# The Flexible Content Field is used to let a user
# define groups of sub fields (layouts) that he/she can add, edit,
# and re-order to create highly customized content.
fieldSeletion:
type: fieldset
title: Field selection
text: Flexible Content Fields
icon: puzzle-piece
collapsed: false
collapsible: false
fields:
# Flexible Content Field - Repeater
#
# requirements:
# - classes: field-selection
header.fieldSelection:
type: list
style: vertical
label: Repeater/list with conditional field selection
classes: field-selection
fields:
# Flexible Content Field - Selector
#
# requirements:
# - type: select
# - classes: field-selection__select
# - the 'keys' of the options are the 'field option' names.
# - 'default' option is required
.select:
type: select
size: long
classes: field-selection__select
label: Select the type of field you would like to add
default: 'default'
options:
default: Maak een keuze
tinymce: Text editor
slideshow: Slideshow
testimonial: Testimonial
video: Video
# Field Option
#
# requirements:
# - type: fieldset
.tinymce:
type: fieldset
title: Text editor
collapsed: true
collapsible: true
fields:
# Field Option Referer
#
# requirements:
# - type: hidden
# - default: field-selection__<Field Option>
referer:
type: hidden
default: field-selection__tinymce
# Fields
#
# Define your grouped field here...
.tinymce.title:
type: text
label: title
# Field Option
.slideshow:
type: fieldset
title: Slideshow
collapsed: true
collapsible: true
fields:
# Field Option Referer
referer:
type: hidden
default: field-selection__slideshow
# Fields
.slideshow.title:
type: text
label: title
# Field Option
.testimonial:
type: fieldset
title: Testimonial
collapsed: true
collapsible: true
fields:
# Field Option Referer
referer:
type: hidden
default: field-selection__testimonial
# Fields
.testimonial.title:
type: text
label: title
# Field Option
.video:
type: fieldset
title: Video
collapsed: true
collapsible: true
fields:
# Field Option Referer
referer:
type: hidden
default: field-selection__video
# Fields
.video.title:
type: text
label: title
This is what the ‘Flexible Content Field’ looks like in the admin:
When the user add an item:
When the user selected a component:
The user can add/remove/replace his selected components:
#4. The Markdown file
This is an example output in the markdown file.
You can loop throught the fieldSelection
and use the select
to determine which type of component you have to render, and in which order.
In this example the user whats to use:
- a slideshow firlst
- then a video
- and finally a text editor
---
fieldSelection:
-
select: slideshow
tinymce:
title: ''
slideshow:
title: 'Example user input'
testimonial:
title: ''
video:
title: ''
-
select: video
tinymce:
title: ''
slideshow:
title: ''
testimonial:
title: ''
video:
title: 'Example user input'
-
select: tinymce
tinymce:
title: 'Example user input'
slideshow:
title: ''
testimonial:
title: ''
video:
title: ''
---
IF YOU MANAGE TO IMPROVE ON THIS CODE, AND/OR MAKE A PLUGIN OUT OF IT. PLEASE SHARE