Getting started

  1. Install PressLess in your Gatsby project by running npm i gatsby-plugin-pressless.,immediately both PressLess and the Gatsby glue code into your project.
  2. You can then proceed to download the PressLess WordPress plugin from the Audal Org, and install that inside the client's WordPress site.
  3. Once you've installed the plugin inside WordPress, you must set your site URLs - where your dev server will run, and where your production URL will be. This can be done inside WordPress by going to Settings > PressLess Settings. Typically while developing you should set both to https://localhost:8000 or wherever your Gatsby instance runs, but once in production, make sure to change the Production URL to the URL for your Netlify/Gatsby Cloud/Vercel etc site.
  4. After you've got everything set up and you're ready to start developing, run this Gatsby Develop function - gatsby develop -https. You must run your Gatsby development in HTTPS for PressLess to work locally. If you don't, PressLess will infinitely load inside WordPress as it can't establish a secure connection to your site.

Creating your templates in Gatsby

Once you've finished your initial setup, it's time to make some templates!

With PressLess, the Gatsby glue code will automatically generate PressLess enabled pages and editors based on whatever files are inside your Gatsby project's /src/templates folder.

So if you have a WordPress post type of 'Page', you can enable PressLess for this post type by adding a Gatsby template at /src/templates/page.js|jsx|tsx. How easy!

It gets easier - PressLess will automatically run relevant Gatsby queries for any PressLess template that works on a Default Wordpress Post Type. This means for you Pages and Posts within WP, you'll never have to write a custom Gatsby Query again for them.

Adding BlockAreas

When you've created your template, it's time to create your Block Areas. The <BlockArea /> JSX component is the default export of gatsby-plugin-pressless, and this is where you will put the blocks you want PressLess to consume.

Import this into your template with: import BlockArea from 'gatsby-plugin-pressless'.

Once you've done this, it's time to set our BlockArea up. This is what you need to do:

  1. Add a unique ID to the BlockArea via the id prop. It is a string. This will allow PressLess to uniquely identify this block area within your template (which means you can run multiple BlockAreas on every template without issue!).
  2. Add your SSR generated data to the BlockArea, with the data prop. When PressLess is working in WP, it'll ignore this prop, but when live on your Gatsby site, it'll need this prop to create the views. This data prop ingests your entire Gatsby page's data prop to keep things simple, and will find what it needs on its own.

    Your template should therefore look something like this:

    export default function Page({data}) {
     return (
       <div>
         <BlockArea id="content" data={data}>
           {/* your blocks will go here, keep reading */}
         </BlockArea>
       </div>
     )
    }
    

    If you are using PressLess with a default WordPress post type (i.e. page, or post) then you don't need to write a query, and this will work in PressLess and on SSR!

    If you are using Custom post types, you'll need to make sure your Gatsby GraphQL post query includes the content field of wpPost/wpPage/etc. You must also give rename your query to give it a name of pressLessExport - this is what PressLess looks for internally when ingesting your data. The following is an example query with a Custom post type.

    import {graphql} from "gatsby";
    import React from "react";
    import {Seo} from "gatsby-plugin-wpgraphql-seo";
    import {decodeHTML} from "entities";
    
    export default function Page(props) {
    
       let post = props.data.pressLessExport
    
       return (
           <>
               <Seo post={post} title={decodeHTML(post.seo.title)} />
                <BlockArea id="content" data={props.data}>
                 {/* your blocks will go here, keep reading */}
               </BlockArea>
           </>
       )
    }
    
    export const query = graphql`
       query($id: String!) {
           pressLessExport: wpPage(id: { eq: $id }) {
               title
               content
               seo {
                   breadcrumbs {
                       text
                       url
                   }
                   title
                   metaDesc
                   focuskw
                   metaKeywords
                   metaRobotsNoindex
                   metaRobotsNofollow
                   opengraphTitle
                   opengraphDescription
                   opengraphImage {
                       altText
                       sourceUrl
                       srcSet
                   }
                   twitterTitle
                   twitterDescription
                   twitterImage {
                       altText
                       sourceUrl
                       srcSet
                   }
                   canonical
                   cornerstone
                   schema {
                       articleType
                       pageType
                       raw
                   }
               }
           }
       }
    `;
    
  3. Add your blocks! PressLess accepts your React components and allows you to easily turn them into live-editable pages. With one catch - your PressLess enabled components must be in React.forwardRef format, not functional components or classes. After we change our component into a forwardRef, we must then add a small bit of PressLess schema, that will allow PressLess to detect this component as something it should use. You attach this schema as a property of your forwardRef component. This is an example of what your new PressLess component should look like:

    const MyNewComponent = React.forwardRef((props, ref) => {
    
     return (
       <div ref={ref}>
         Hello from Gatsby!
       </div>
     )
    })
    
    MyNewComponent.pressless = {
     name: 'My New Component' // Must be unique and never change
     attributes: {
       // We'll fill these in later!
     }
    }
    

    The use of forwardRefs allows PressLess to track your component in the DOM, allowing things like Drag and Drop, copy and paste, and other goodies. Once you've turned your components into React.forwardRef components, it's time to put them into the BlockArea for use in WordPress.

    export default function Page({data}) {
     return (
       <div>
         <BlockArea id="content" data={data}>
           <MyNewComponent />
         </BlockArea>
       </div>
     )
    }
    

    That's it! Our component is now usable by WordPress, and editors can now add multiple <MyNewComponent /> blocks, and drag and drop them, and server side render it all. How great!

    Bonus tip! - just because your PressLess component will be mostly controlled by the PressLess instance, doesn't mean you can't still use regular props on it. If you ever find yourself needing to add class names, or ids, or any custom props, you can still do that without issue.

    export default function Page({data}) {
     
     const [myState, setMyState] = React.useState()
    
     return (
       <div>
         <BlockArea id="content" data={data}>
           <MyNewComponent className="some-class" myState={myState} />
         </BlockArea>
       </div>
     )
    }
    

Adding data to your PressLess components

So far, we've learnt how to create a new static component and how to make it work with PressLess. But what about when we want to add data to our PressLess components that ourselves and our content editors can edit live? PressLess makes it super easy!

We start by going back to our PressLess schema on our component and adding some attributes. Attributes are the PressLess name for props - so anything that you would like to give the component as a prop, you define as an attribute. This following example shows how we'd define a WYSIWYG text editor within our component.

const MyNewComponent = React.forwardRef((props, ref) => {

  return (
    <div ref={ref}>
      Hello from Gatsby!
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    wysiwygText: {
      name: 'WYSIWYG Text Area!',
      type: 'RichText'
    }
  }
}

With this, we've defined a new attribute called wysiwygText, with a type of RichText. We've also set the name, which appears in the PressLess editor, to WYSIWYG Text Area!. It's important to give the name a sensible name so that content editors understand what they're actually editing.

Now how do we actually consume this prop inside the component?

const MyNewComponent = React.forwardRef(({wysiwygText}, ref) => {

  return (
    <div ref={ref}>
      {wysiwygText}
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    wysiwygText: {
      name: 'WYSIWYG Text Area!',
      type: 'RichText',
      placeholder: 'Hello from PressLess!'
    }
  }
}

All of our attributes will be given to your components as props! In the above example, we've changed our props to destructured, and now we can access wysiwygEditor inside our component. Super easy. We've also added a placeholder to our wysiwygText prop, which can be useful to help content editors visualise their content on the page.

So that's cool, but what about other types? Glad you asked! Here's a summary of all the available types within PressLess as current.

RichText

This is a contenteditable span, that'll allow your editors to create WYSIWYG style content, paste in HTML, other typical WYSIWYG stuff. It is unique in that it is the only component editable both on the page itself, and within the WordPress sidebar. The following is an example:

const MyNewComponent = React.forwardRef(({wysiwygText}, ref) => {

  return (
    <div ref={ref}>
      {wysiwygText}
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    wysiwygText: {
      name: 'WYSIWYG Text Area!',
      type: 'RichText',
      placeholder: 'Hello from PressLess!'
    }
  }
}

PlainText

This is a string. Use this wherever you don't want content editors to create multi-line/HTML-style content, or wherever your use of animations etc prohibits you from doing so. (i.e. if you've got a letter typing animation for example. It returns a plain string, with no wrapping tags at all, so you can safely use it like any other string content. The following is an example:

const MyNewComponent = React.forwardRef(({plainString}, ref) => {

  return (
    <div ref={ref}>
      {plainString}
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    plainString: {
      name: 'Plain Text!',
      type: 'PlainText',
      placeholder: 'Hello from PressLess!'
    }
  }
}

Image

This is an object with an src and an alt tag as provided by WordPress - i.e. { src: "", alt: "" }. In a future version of PressLess, this will likely include GatsbyImageData wherever possible, as well as the original src and alt tags, to speed up images. You also currently cannot set a placeholder for this type. The intended use of this is to destructure the prop onto any image DOM tags you might have:

const MyNewComponent = React.forwardRef(({image}, ref) => {

  return (
    <div ref={ref}>
      <img {...image} />
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    image: {
      name: 'An Image',
      type: 'Image',
    }
  }
}

Audio/Video

These attribute types currently work exactly the same as the Image type, and have the same syntax, uses, and current issues. This is how you'd use both of them:

const MyNewComponent = React.forwardRef(({audio, video}, ref) => {

  return (
    <div ref={ref}>
      <audio controls {...audio} />
      <video controls {...video} />
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    audio: {
      name: 'An Audio File',
      type: 'Audio',
    },
    video: {
      name: 'An Video File',
      type: 'Video',
    }
  }
}

Color

This attribute type allows you to have user set colors within your PressLess components! It will show a color picker within WordPress when focused, and return the colour as an rgba string, for use with your favourite CSS framework or the JSX style prop. This is how you might use it in combination with the RichText type:

const MyNewComponent = React.forwardRef(({text, textColor}, ref) => {

  return (
    <div ref={ref}>
      <div style={{color: textColor}}>{text}</div>
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    text: {
      name: 'Text',
      type: 'RichText',
    },
    textColor: {
      name: 'Choose your Text Color',
      type: 'Color',
    }
  }
}

Repeater

No self-respecting WordPress plugin (or page builder for that matter!) would be complete without some sort of Repeater type. Repeaters allow your users to create lists of things (arrays), and in PressLess, you can use any field as a nested attribute within a repeater (even another Repeater! - though we wouldn't recommend that). On this special type, you will be able to define attributes, inside which you can define your repeatable types. Repeaters return always as an array of objects. The following is an example of a Repeater for links (maybe for a sidebar menu!).

const MyNewComponent = React.forwardRef(({links, textColor}, ref) => {

  // Our links repeater will return an array of objects like
  // [{linkName: 'My Link', linkUrl: 'https://google.com'}]

  return (
    <div ref={ref}>
      {links.map(({linkName, linkUrl}) => (
        <a href={linkUrl}>{linkName}</a>
      ))}
    </div>
  )
})

MyNewComponent.pressless = {
  name: 'My New Component' // Must be unique and never change
  attributes: {
    links: {
      name: 'Sidebar Links'
      type: 'Repeater',
      attributes: {
        linkName: {
          name: 'Link Name',
          type: 'PlainText',
        },
        linkUrl: {
          name: 'Link URL',
          type: 'PlainText',
        }
      }
    }
  }
}

FAQ: This (x) Type isn't working

You've likely got the incorrect casing for the type. All types must be cased in the form of PlainText, Repeater, etc.

FAQ: This (x) Component isn't working

Firstly, check if you've got the correct syntax for a Forward Ref on your component. This will be the cause of 99% of the issues. When this is valid and the issue is elsewhere, PressLess should throw helpful error messages when it can't work. Hot reload during development is supported in both WordPress and Gatsby with PressLess (though you may need to refresh manually occasionally). The best approach for finding the source of your issue is likely to move your component outside of the PressLess block area and check if it works. If it doesn't you've found your issue, and will likely have more helpful error messages. If it does, and you're still having issues, please talk to your supervisor.

FAQ: I changed the Name of my component and now my content is broken.

Please do not do this!!!! PressLess uses the name inside every component's schema to work out which component is which when hydrating your content, both in WordPress and on SSR. The minute you change this, PressLess will error as it does not know how to re-hydrate your content (as the function it needed couldn't be found via this name). The only way as of current to fix this, is to revert your name to its original name. Once you do this, your content will work again. There is currently no way to change the name and have you existing content not be affected.

FAQ: I want to contribute!

PressLess is just one of many cool tools we're currently working on. If you think you've got something you want to contribute, or you just need a break from client projects, just ask your supervisor about it. You will be paid for any work you do on PressLess and other internal tools.

FAQ: I have more questions!

This is by no means a definitive guide to PressLess, and will likely be out of date at many points in the future. If you have more questions, just ask!