Porting Gutenberg to SilverStripe

A20e356db8d22f39c37df10dbede0baf?s=47 Jake Grimley
September 22, 2018

Porting Gutenberg to SilverStripe

Clients want drag and drop editing. WordPress now has Gutenberg. We ported it over to Silverstripe, it was tougher than we imagined. Maybe it has potential for you.

A20e356db8d22f39c37df10dbede0baf?s=128

Jake Grimley

September 22, 2018
Tweet

Transcript

  1. 1 Jake Grimley Founder, Made Media @madehq @jakegrimley Porting Gutenberg

    to Silverstripe
  2. 2 • Founded 2002 • Headcount 30 • Specialist in

    e-commerce sites for large cultural institutions • Offices Birmingham, London, New York • Using SilverStripe since 2012 • Professional Partner since 2017 • Niche clients, niche competition Made Media
  3. 3 • Expertise • Track Record • Creativity • Capacity

    & Compliance • CMS It started with a pitch
  4. 4 CMS Enterprisy Well Structured Open Source Wildly Popular EpiServer*

    ✔ ✔ Drupal ✔ ✔ SilverStripe ✔ ✔ ✔ WordPress ✔ ✔ CMS Positioning
  5. 5 “WordPress powers 
 27% of the Internet”

  6. 6 CMS Requirements 2.0 Before IT Focused Now User Focused

    .Net Flexible Permissions/Control Drag And Drop Workflows No Rigid Templates APIs Personalisation Enforce Structure Anti-Structure
  7. 7 CMS positioning works for us, but no longer works

    for the client.
  8. 8 What’s Gutenberg?

  9. 9 •WordPress Plug-in •New WYSIWYG Editor •Drag and drop blocks

    •A bit like SquareSpace and Wix •Replaces TinyMCE in WP5.0 •Will take over 80% of the WordPress UI
  10. 10

  11. 11 •Inevitable transition •Direct manipulation always wins

  12. 12 WP Controversy: •Breaks themes •Breaks old content •Gets in

    the way of ‘Bloggers’ •Paradigm Shift for WP
  13. 13 Why are we interested?

  14. 14 •Made hates traditional WYSIWYG Editors •Running out of steam

    with Markdown •Neutralise head-to-head CMS demos •Moving toward block paradigm anyway •Envisaged hooking in personalisation •Looked like an upgrade on Sir Trevor
  15. 15

  16. 16 How Does Gutenberg Work?

  17. 17 React

  18. 18 Define Blocks

  19. 19 const schema = { content: { type: 'array', source:

    'children', selector: 'p', default: [], }, align: { type: 'string', }, dropCap: { type: 'boolean', default: false, }, placeholder: { type: 'string', }, width: { type: 'string', }, textColor: { type: 'string', }, }; class ParagraphBlock extends paragraph.settings.edit { constructor() { super( ...arguments ); } return [ textAlignmentEnabled && isSelected && ( <BlockControls key="controls"> <AlignmentToolbar value={ align } onChange={ ( nextAlign ) => { setAttributes( { align: nextAlign } ); } } /> </BlockControls> ), inspectorEnabled && isSelected && ( <InspectorControls key="inspector"> { textSettingsEnabled && ( <PanelBody title={ __( 'Text Settings' ) }> { dropCapEnabled && ( <ToggleControl label={ __( 'Drop Cap' ) } checked={ !! dropCap } onChange={ this.toggleDropCap } /> )} </PanelBody> )} return <p style={ styles } className={ className ? className : undefined }>{ content }</p>; Define Schema Inspector View Saved HTML <div key="editable" ref={ this.bindRef }> <Autocomplete completers={ [ blockAutocompleter( { onReplace } ), userAutocompleter(), ] }> { ( { isExpanded, listBoxId, activeId } ) => ( <RichText tagName="p" className={ classnames( 'wp-block-paragraph', { 'has-background': backgroundColor, 'has-drop-cap': dropCap, } ) } style={ { backgroundColor: backgroundColor, color: textColor, fontSize: fontSize ? fontSize + 'px' : undefined, textAlign: align, } } value={ content } onChange={ ( nextContent ) => { setAttributes( { content: nextContent, } ); } } /> Editor View
  20. 20 How did we port to SilverStripe?

  21. 21 SilverStripe 4 
 React already there

  22. 22

  23. 23

  24. 24 Start looking at more complex, Silverstripe- integrated blocks

  25. None
  26. Integrated block Editor View HTML (SilverStripe Field) Save HTML Parser

    Template Related Objects/ Modules Gutenberg / React - Edit View Silverstripe / PHP - Published View HTML render function render function edit content
  27. Image Block import { __ } from '@wordpress/i18n'; import {

    withInstanceId, withState, PanelBody, BaseControl } from '@wordpress/components'; import { InspectorControls, BlockAlignmentToolbar } from '@wordpress/blocks'; import { ImageControl } from '../../components'; import { map, mapValues, extend, isEmpty } from 'lodash'; const cloudinaryImage = window.cloudinaryImage; import './style.scss'; export const name = 'madehq/image'; export const settings = { title: __( 'Image 2' ), description: __( 'This will allow you to pull an image or gallery into content' ), icon: 'format-image', category: 'common', keywords: [ __( 'text' ) ], edit({ attributes, setAttributes, isSelected }) { const { images, captions, credits } = attributes; const updateImages = value => { let newImages = mapValues(value, (item, key) => { let image = images[key]; if (!image) { return item; }
  28. Sidebar Component for Images import ReactDOM from 'react-dom'; import {

    Component } from '@wordpress/element'; import { withInstanceId } from '@wordpress/components'; import { forEach, keys, has, map, isEmpty, omit, isArray, isObject, mapValues, values, } from 'lodash'; const cloudinaryImage = window.cloudinaryImage; import './style.scss'; const fileDataCache = {}; const loadFileData = fileId => { if ( fileId in fileDataCache ) { return fileDataCache[fileId]; } fileDataCache[fileId] = fetch(`/gutenberg-api/filedata/${fileId}`, { credentials: 'same-origin' }) .then(response => response.json()) .then(fileData => { return fileData; });
  29. None
  30. None
  31. 31 •WebPack to create alias to image picker, and point

    directly at React component •Output field in format Silverstripe expects and trigger entwine •Mutation observer to see changes in image selector - onChange events didn’t work. Bridging Javascript UIs
  32. Integrated block Editor View HTML (SilverStripe Field) Save HTML Parser

    Template Related Objects/ Modules Gutenberg / React - Edit View Silverstripe / PHP - Published View HTML render function render function edit content
  33. 33 BatShit Crazy

  34. This would be cleaner… JSON Content (SilverStripe Field) JSON_decode Related

    Objects/ Modules Gutenberg / React - Edit View Silverstripe / PHP - Published View HTML render function Save Change Edit Content
  35. 35 Gutenberg doesn’t store content as JSON

  36. 36 HTML Rendering of a complex widget not necessarily identical

    in edit and view mode.
  37. 37 Never mind the batshit here’s the demo

  38. Version 1 Made Media Ltd. Prepared by Jake Grimley 97

    Icknield Street June 21, 2018 Birmingham, B186RU mademedia.co.uk brirmingham@made.media © 2018 Made Media Inc. 0121 200 2627
  39. 39 •Mission Accomplished •If there’s any technical debt; future made

    will deal with it
  40. 40 Where are we going with it?

  41. 41 •Refinement •Stability •Personalisation

  42. 42 How does this 
 compete with the 
 ContentBlocks

    Module?
  43. 43 • Blocks are the future • ContentBlocks Module has

    much better structure • Gutenberg feels more immediate and interactive • Maybe we can hook the Gutenberg front-end up to the ContentBlocks data objects… • It’s the start of a journey..
  44. 44 Want to get involved?

  45. https://github.com/MadeHQ/silverstripe-gutenberg-editor

  46. Thank you! 46 @madehq @jakegrimley