Flexible content modules in Silverstripe - content-management-system

We are looking at using Silverstripe CMS and want to be able to have modules which can be reordered.
We have come from a Wordpress setup and mostly use the flexible content ACF field. Modules (e.g. text, masthead or video) need to be able to be re-ordered.
We use our CMS's as an API so these modules are output as a section to the page or post:
[
{
"id": 10,
"title": "Post title",
"slug": "post_slug",
"path": "/post_slug",
"template": "campaign",
"published": "2017-05-25 06:09:36",
"image": null,
"seo": {
"title": "",
"description": "",
"image": {
},
},
"sections": [
{
"type": "masthead",
"Title": "",
"video": false,
"image": [
],
"showCta": false,
"cta": [
]
},
{
"type": "video_text",
"video_text": [
{
"type": "video",
"video_url": "https://www.youtube.com/watch?v=asdfa",
"video_length": "07:38",
"video_preview": false
},
{
"type": "text",
"title": "Video Title",
"content": "Video text content",
"call_to_action": false,
"cta": [
]
}
]
},
{
"type": "text",
"title": "Text Title",
"content": "",
"alignment": "centre",
"call_to_action": false,
"cta": {
"text": "CTA button",
"link_type": "internal_link",
"internal_link": "about",
"external_link": "",
"section_id": [
]
}
},
]
}
]
Does Silverstripe have it's own way of handling modules / do I need to ditch this flexible content modules method? How do others handle flexible content modules in Silverstripe?

Both silverstripe-blocks and silverstripe-elemental works very well in their own regard but I don't think they will achieve what you want. These modules don't really give you the power to use pre-defined templates. You can hook the templates in but the code will be massive. I not sure if there is an open source module for that yet.
From your JSON code, in order to have those Sections to render something like this below;
<section id="Sections">
<div id="video_text" class="section">
<iframe width="560" height="315" src="https://www.youtube.com/watch?v=asdfa" frameborder="0" allowfullscreen></iframe>
</section>
<div id="text" class="section">
<h2>Text Title</h2>
<a class='text-center btn btn-default' href="/about/">CTA button</a>
</section>
</sections>
You might want to do this.
Use DataObjects (DO) for you Sections, easy for re-ordering.
Create an abstract DO, BlockSection, with fields like Title(Varchar), Content(HTMLText), Sort(Int) and most importantly has_one to Page.
For the video use can name the DO VideoBlockSection and it extends BlockSection,
TextBlockSection for the other one. Don't forget the $singular_name for each DO (useful for nice class naming in the Grid)
On Page getCMSFields add the Grid to manage the Sections. You need to add GridFieldSortableRows and GridFieldAddNewMultiClass and now you can add you Section on each Page.
Add has_many from Page to BlockSection and a method that will render the Blocks and outputs the html.
Page.php
private static $has_many = array(
"Sections" => "BlockSection",
);
function SectionContent()
$aContent = ArrayList::create();
$oSections = $this->Sections();
if (count($oSections )) {
foreach ( $oSections as $oSection ) {
$aContent->push(ArrayData::create([
"Section" => $oSection,
"Content" => $oSection->renderWith([$oSection->ClassName, get_parent_class($oSection)]),
]));
}
}
return $aContent;
For the VideoBlockSection the template array list will be VideoBlockSection and BlockSection
VideoBlockSection.ss
<div id="video_text_{$ID}" class="section">
<iframe width="560" height="315" src="{$URL}" frameborder="0" allowfullscreen></iframe>
</section>
In you specific case, because you are using an API you need to use a wrapper to render the Template.
It needs to match [section][type] to a Template (renderWith) video_text to VideoBlockSection
Lastly in Page.ss
<% loop $SectionContent %>
{$Content}
<% end_loop %>
This was a proof of concept but its working for me so refactoring, speed and memory usage was not considered (but its working).
This way I had to ditch the unnecessary so called "page types" which I find not to be reusable in most cases.
This works 100% for me and I use it together with Bootstrap 3. I use it to create CTAs, parallax scroll, Google Map Section (multiple maps on one page), Thumbnails. Specify image resize method (Cropped, ByWidth, ByHeight).
DO NOT ditch that flexible content modules method.
I am working on an open source module which works with SS4 and Bootstrap 4 (with possibilities of using any other html framework)

Related

Docsearch on subpath '/docs' not scraping side navigation

A Docusaurus documentation website: https://slovakia-atmo-plan.marvintest.vito.be/docs/ is rendered in Docs only mode.
The Algolia Docsearch scraper is not scraping root level pages, instead it logs Ignored: from start url. This issue only seems to arise when the Docusaurus build is nested under {baseUrl}/docs.
Why is this being ignored? This is my docsearch config:
{
"index_name": "atmoplan-documentation",
"start_urls": ["https://slovakia-atmo-plan.marvintest.vito.be/docs"],
"sitemap_urls": ["https://slovakia-atmo-plan.marvintest.vito.be/docs/sitemap.xml"],
"sitemap_alternate_links": true,
"stop_urls": ["/tests"],
"selectors": {
"lvl0": {
"selector": "(//ul[contains(#class,'menu__list')]//a[contains(#class, 'menu__link menu__link--sublist menu__link--active')]/text() | //nav[contains(#class, 'navbar')]//a[contains(#class, 'navbar__link--active')]/text())[last()]",
"type": "xpath",
"global": true,
"default_value": "Documentation"
},
"lvl1": "header h1",
"lvl2": "article h2",
"lvl3": "article h3",
"lvl4": "article h4",
"lvl5": "article h5, article td:first-child",
"lvl6": "article h6",
"text": "article p, article li, article td:last-child"
},
"strip_chars": " .,;:#",
"custom_settings": {
"separatorsToIndex": "_",
"attributesForFaceting": ["language", "version", "type", "docusaurus_tag"],
"attributesToRetrieve": ["hierarchy", "content", "anchor", "url", "url_without_anchor", "type"]
},
"conversation_id": ["833762294"],
"nb_hits": 46250
}
Inside your docusaurus.config.js you should set the url parameter with the actual website where you will be hosting your docs. Something like:
module.exports = {
url: 'https://slovakia-atmo-plan.marvintest.vito.be/docs',
[…]
}
This will be used by your docusaurus to generate the sitemap.xml, used by algolia to locate your pages.
REFERENCE: https://docusaurus.io/docs/docusaurus.config.js/#url
DISCLAIMER
I noted something strange inside your sitemap.xml. For example the first link was https://www.vito.be/docs/markdown-page, but defined URL for Algolia is https://slovakia-atmo-plan.marvintest.vito.be/docs.

How do I reference and create dynamic emails with Sendgrid?

I'm at a loss with the documentation here.
I'm trying to create a basic hello world email template, with some simple email substitutions - and I can't work out the syntax.
The documentation here suggests using a -igetreplaced- syntax, and gives the following example:
<html>
<head></head>
<body>
<p>Hello -name-,<br>
Thank you for your interest in our products. I have set up an appointment to call you at -time- EST to discuss your needs in more detail. If you would like to reschedule this call, please visit the following link: `reschedule`
Regards,
-salesContact-
-contactPhoneNumber-<br>
</p>
</body>
</html>
An accompanying SMTP API JSON header might look something like this:
{
"to": [
"example#example.com",
"example#example.com"
],
"sub": {
"-name-": [
"John",
"Jane"
],
"-customerID-": [
"1234",
"5678"
],
"-salesContact-": [
"Jared",
"Ben"
],
"-contactPhoneNumber-": [
"555.555.5555",
"777.777.7777"
],
"-time-": [
"3:00pm",
"5:15pm"
]
}
}
I've tried pasting these in to the template code editor, but it doesn't work.
Can someone point me to the right documentation for getting the syntax correct?
The syntax is Handlebars.
Use it like this:
Hello {{name}}
with data:
{
"name": "Bob"
}

User snippets not working in VScode

Hi guys I'm using VScode and trying to get some user snippets to work.
I've tried adding them to both the javascriptreact.json file and the javascript.json file... and even the html.json file but with no success.
I know VSCode uses Emmet, and am confused as to whether user snippets work with emmet rather than intellisense, and if so am I putting this in the wrong file?
Cheers in advance for any help!
I am trying to overwrite the default div. span. img. etc. by adding the following snippets:
"Expand ReactQL Div": {
"prefix: "div.",
"body": [
"<div className={css.:1}>:2</div>;"
],
"description": "expand div"
},
"Expand ReactQL img": {
"prefix: "img.",
"body": [
"<img src={:1} alt=":2" className={css.:3} />;"
],
"description": "expand img"
},
"Expand ReactQL span": {
"prefix: "span.",
"body": [
"<span className={css.1:}>:2</span>;"
],
"description": "expand span"
}
I'd imagine you have solved this one, but for anyone else,
There a few issues with your snippets:
Missing " within your prefix definition, the : is also enclosed in quotes.
{css.:1} syntax works like so ${1:css}
An example:
"Expand ReactQL Div": {
"prefix": "div.",
"body": [
"<div className=${1:css}>${2}</div>"
],
"description": "expand div"
},
Demo of snippet in action

How to use Template in rowexpander plugin - Ext JS 4

Can we use template as follows:
plugins: [{
ptype: 'rowexpander',
selectRowOnExpand : false,
rowBodyTpl: new Ext.XTemplate(
'<p>Qusetions: {question}</p><p>',
'<tpl for="option">',
'<p>{option[0]}</p>',
'</tpl></p>'
)
}]
I am unable to see anything. I have this JSON:
{
"total": 2,
"data": [
{
"qno":1,
"question":"What's Your Fav color",
"option":['red','green','blue']
},
{
"qno":2,
"question":"What's Your coom color",
"option":['yellow','red','green','blue']
}
]
}
Model File
Ext.define('AM.model.Question', {
extend: 'Ext.data.Model',
fields: [
{name: 'question'},
{name: 'option'},
{name: 'images'},
{name: 'qno'}
]});
I want to see the output as follows:
+ Questions: What is your fav color
<radiobutton> Red
<radiobutton> Green
<radiobutton> Blue
Am using Ext JS 4.1 version
Thanks in advance for your answers
When iterating through an array using XTemplate, the current item is referred to using {.}. Your template should look something like this:
'<p>Questions: {question}</p>',
'<p>',
'<tpl for="option">',
'<p>{.}</p>',
'</tpl>',
'</p>'
However, it gets a little more tricky if you want to do a radio group. XTemplate provides the parent property to access objects outside of the current context. So instead of a <p> tag in the middle, your radio group might look like this:
'<tpl for="option">',
'<input type="radio" name="qno_{parent.qno}" value="{.}" />{.}<br/>'
'</tpl>'

Registration plugin custom fields - Always required?

Is there any way using the facebook registration plugin custom fields, to make them NOT required? I have a "Company" and "Address 2" field that I want to make optional, however, they always seem to be required. Here is the code I am using within the iframe:
<iframe src="https://www.facebook.com/plugins/registration.php?
client_id=MY_APP_ID&
redirect_uri=MY_CALLBACK_URL&
fields=[
{ 'name':'name' },
{ 'name':'first_name' },
{ 'name':'last_name' },
{ 'name':'company', 'description':'Company Name', 'type':'text' },
{ 'name':'email' },
{ 'name':'phone', 'description':'Phone Number', 'type':'text' },
{ 'name':'address1', 'description':'Address', 'type':'text' },
{ 'name':'city', 'description':'City', 'type':'text' },
{ 'name':'state', 'description':'State/Region', 'type':'text' },
{ 'name':'zip', 'description':'Zip Code', 'type':'text' }
]"
scrolling="auto"
frameborder="no"
style="border:none"
allowTransparency="true"
width="100%"
height="600">
</iframe>
If I leave any of the fields blank, it returns that the fields must be filled in. Thoughts?
You can declare optional fields with no_submit flag and then do something with values using onvalidate function, i.e. save to cookie or send via Ajax to your server.
look at http://developers.facebook.com/docs/plugins/registration/advanced/ and goto no_submit
its not easily done but do able