Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Porting Gutenberg to SilverStripe

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.

Jake Grimley

September 22, 2018
Tweet

Transcript

  1. 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
  2. 3 • Expertise • Track Record • Creativity • Capacity

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

    ✔ ✔ Drupal ✔ ✔ SilverStripe ✔ ✔ ✔ WordPress ✔ ✔ CMS Positioning
  4. 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
  5. 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
  6. 10

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

    the way of ‘Bloggers’ •Paradigm Shift for WP
  8. 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
  9. 15

  10. 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
  11. 22

  12. 23

  13. 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
  14. 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; }
  15. 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; });
  16. 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
  17. 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
  18. 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
  19. Version 1 Made Media Ltd. Prepared by Jake Grimley 97

    Icknield Street June 21, 2018 Birmingham, B186RU mademedia.co.uk [email protected] © 2018 Made Media Inc. 0121 200 2627
  20. 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..