Stretch0
Stretch0

Reputation: 9251

Flexible content modules in Silverstripe

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?

Upvotes: 0

Views: 351

Answers (1)

patJnr
patJnr

Reputation: 174

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)

Upvotes: 1

Related Questions