I have an Idea for a custom widget. It is based mostly on Advanced Custom Fields "Flexible Field" which allows for dynamic lists of layouts that are sort-able and "design-able".
The widget it self would be very similar to the list widget except instead of adding another of the same item, you get to choose which "layout" would work best for that specific content. Basically its a list that lets you choose predefined objects that contain other widgets.
Say I wanted to make a post. I have body copy, an image, a quote and gallery of images. Sure I could hard code all of those widgets to a post or use a the WYSIWYG (which will spit out what its going to spit out!), but wouldn't it be nicer If I could just add them on the fly for each post?
This will aid when creating templates for posts as we can loop through the flexible widget and wrap and know exactly what html its going to produce.
Example template (Go/Hugo):
// layouts/posts/single.html
<div>
{{ range $content := .Params.FlexWidget }}
{{ if $content.type === 'body' }}
<div class="body-copy">
{{ $content }}
</div>
{{ end }}
{{ if $content.type === 'fullWidthImage' }}
<div class="full-width-image">
{{ $content }}
</div>
{{ end }}
{{ if $content.type === 'anotherLayout' }}
<div class="anotherLayout">
{{ $content }}
</div>
{{ end }}
{{ end }}
</div>
I'm guessing this could take advantage of the list widget and tweak it to allow different objects to be used. Not sure though. Lemme know what y'all think. Cheers!
Also very similar. Prismic calls them "slices".
https://prismic.io/feature/dynamic-layout-content-components
Porting my thoughts from #565:
So I've been considering how this might look. We're now focusing heavily on the extensibility story around the CMS, and a big part of that is making widget authoring simpler, and the available API's more robust.
For this particular issue, we should have a widget as I mentioned in my last comment, but I want it to just be a button with configurable text. In the OP case you would configure the label to "Add content", and it's appearance would simply be that of a dropdown, which editors can use to add one of the widgets configured in the "fields" array. The UI around this could be further enhanced by passing control of labels (optionally) to widget authors (currently all widgets automatically receive a label in the UI direct through the CMS). This means an entry could consist of nothing more than this widget and be entirely dynamic, very similar to what ACF provides to WordPress users.
Furthermore, if the added widgets are themselves draggable, we'd have all that's needed for site building. Doing all of this in a widget is pretty compelling.
Hey, so I've been looking for something like this for a while now. So, I had a go at spiking out 2 possible solutions although I'm not familiar with this codebase so excuse any of the mess I caused 😜
Solution 1: FlexibleLayout Widget
The config is essentially a list with only objects as fields. I duplicated the list widget and added some logic in to the renderItem function that adds in a field to handle the type and handles it behind the scenes for you.
Can be seen here: https://github.com/JoshAntBrown/netlify-cms/commit/42cf77dd362316aad417fbe5277cdd43aa74d1a2
Solution 2: Conditional Fields
This was an alternative solution which came to me after seeing @erquhart comment about extensibility which made me wonder whether this even needs to be a widget. If all fields had the option to be conditional in some way then you could configure them in a way to achieve the same result of the flexible layout widget but have something that could potentially be used in other ways whilst also keeping the code simple.
Can be seen here: https://github.com/JoshAntBrown/netlify-cms/commit/0591b595f32c17dcbb564d647d13025c262a5873
Hope that helps! I really need this kind of functionality on a project I'm working on so looking forward to see how this develops.
@JoshAntBrown I like the second solution about the conditional fields! Maybe you should open a PR for this if you already got this working? ;)
If you have conditional fields you could also go for a "module" collection and just place a selection field to create different kind of modules. Then to build pages you could just create a list of relation fields to reference those modules. Just an idea.
@JoshAntBrown great work man, I think these are both useful concepts.
Toward an ideal custom layout widget, your first option seems closest to me - more code, but a more sensible UI (once the dropdown is customized and folded into the widget top bar) and a much better configuration scheme. It's honestly better than the concept I described above, because it's going to be far more useful. Implementors won't generally be looking to just add random fields to an entry, but they will want to be able to allow various objects, like in your "sections" example, that can each have a set of configured fields and be re-ordered via drag and drop.
If you're up for PR'ing this approach, that'd be awesome.
P.S. your code looks fine, no "mess" there :)
Update: this could totally just be a key on the existing list widget - as an alternative to "fields", you could have "types", and just use the config outlined in your example under that key:
- label: Sections
name: sections
widget: list
types:
- label: Generic Section
name: generic-section
fields:
- label: Title
name: title
- label: Content
name: content
widget: markdown
- label: Team Section
name: team-section
fields:
- label: People
name: people
widget: list
fields:
- label: Name
name: name
I've just added a PR to address this. Let me know what you think! Go easy, it's my first one :)
Edit: preview component added!
@anthonysapp rock on, checking it out soon!
Just realizing the concepts of flexible layout and conditional fields are completely different, not sure how I missed it. For anyone seeking conditional fields, check out #1267.
Looked like this had quite a lot of momentum and then nothing… is this still in the works? Would love to see flexible content here. The only thing preventing me from using netlify cms.
I reckon we really just need to update the relation field to :
Then you'd have page types that have a content-area ( a relation to _blocks/layouts )
_blocks/layouts are an object with :
Something like this:
collections:
- label: "Content Area"
name: "content-areas"
folder: "_blocks/layout"
create: true
extension: yaml
format: yml
fields:
- {label: "title", name: "title", widget: "string"}
- {label: "Layout", name: "layout", widget: "select",
options: ["One column", "Two column"]}
- {label: "Blocks", name: "blocks", widget: "relation",
many: true,
collections: [
'block-wysiwyg',
'block-map',
'block-testimonial',
'block-image',
'block-hero'
]}
- label: "Wysiwyg Block"
name: 'block-wysiwyg'
fields:
- {label: "content", name: "content", widget: "markdown"}
- label: "Map Block"
name: 'block-map'
fields:
- {label: "title", name: "title", widget: "string"}
- {label: "address", name: "address", widget: "string"}
- {label: "lat", name: "lat", widget: "string"}
- {label: "lng", name: "lng", widget: "string"}
- label: "Testimonial Block"
name: 'block-testimonial'
fields:
- {label: "title", name: "title", widget: "string"}
- {label: "address", name: "address", widget: "string"}
- {label: "lat", name: "lat", widget: "string"}
- {label: "lng", name: "lng", widget: "string"}
- label: "Image Block"
name: 'block-image'
fields:
- {label: "title", name: "title", widget: "string"}
- {label: "image", name: "image", widget: "image"}
- label: "Hero Block"
name: 'block-hero'
fields:
- {label: "title", name: "title", widget: "string"}
- {label: "subtitle", name: "subtitle", widget: "string"}
- {label: "background", name: "background", widget: "image"}
- label: "Page"
name: "page"
folder: "_pages/page"
create: true
extension: yaml
format: yml
fields:
- {label: "Title", name: "title", widget: "string"}
- {label: "Publish Date", name: "date", widget: "datetime"}
- {label: "Featured Image", name: "thumbnail", widget: "image"}
- {label: "Summary", name: "summary", widget: "markdown"}
- {label: "Body", name: "body", widget: "relation",
many: true,
collections: ['content-areas']}
I think this relates to #1061, but that only talks about selecting many items from a single collection, I propose selecting many items from many collections.
@benjaminsehl There is a PR in progress, but it stalled out. If anyone wants to create a new PR or pick up the existing one (https://github.com/netlify/netlify-cms/pull/1169), please comment here and it will be yours!
I think this issue was closed with https://github.com/netlify/netlify-cms/pull/1857
Yep, you're right 👍
Most helpful comment
I've just added a PR to address this. Let me know what you think! Go easy, it's my first one :)
Edit: preview component added!