Skip to content
A starter for a Gatsby/Silverstripe CMS integration
JavaScript CSS
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src More improvements Oct 20, 2019
.babelrc Updates for elemental support Oct 24, 2019
.gitignore Basic template Oct 19, 2019
.prettierignore Initial commit from gatsby: (https://github.com/unclecheese/gatsby-st… Oct 18, 2019
.prettierrc Initial commit from gatsby: (https://github.com/unclecheese/gatsby-st… Oct 18, 2019
LICENSE Initial commit from gatsby: (https://github.com/unclecheese/gatsby-st… Oct 18, 2019
README.md
gatsby-browser.js Basic template Oct 19, 2019
gatsby-config.js More improvements Oct 20, 2019
gatsby-node.js Updates for elemental support Oct 24, 2019
gatsby-ssr.js Updates for elemental support Oct 24, 2019
package.json Updates for elemental support Oct 24, 2019
yarn.lock Yarn upgrades Oct 24, 2019

README.md

Gatsby Starter for Silverstripe CMS

This starter can be used for sites that source their data primarily from Silverstripe CMS.

Installation

$ gatsby new my-ss-project https://github.com/unclecheese/gatsby-starter-silverstripe

Dependencies

Getting started

You will need to install the following package on your Silverstripe site to expose your data to Gatsby:

$ composer require silverstripe/silverstripe-gatsby

Once that is installed, ensure the __gatsby/graphql endpoing is working on your Silverstripe site.

Now, edit the gatsby-config.js file, and add the host of your Silverstripe backend to the options.host node in the plugin config.

    {
    	resolve: `gatsby-source-silverstripe`,
    	options: {
    		host: `http://my-silverstripe-cms.local`
    	}
    },

Now, run gatsby develop. When the build is complete, you should have your entire site built out, with primary and secondary navigation, in a primitive template.

Error: SiteConfig not found?

This starter relies on SiteConfig to provide some basic information. By default, SiteConfig has a canView() that returns false for unauthenticated users, meaning it won't be present in your schema.

The gatsby-source-silverstripe plugin will support token-based auth in the future, but until then, you probably want to turn off filter_can_view in your Silverstripe site:

SilverStripe\Gatsby\GraphQL\Types\SyncResultTypeCreator:
  filter_can_view: false

Features

This starter provides several features that aim to maintain a high level of parity between your Gatsby project and Silverstripe in order to ease migration pain and flatten the learning curve.

Automatic site tree generation

Any dataobject exposed by your Silverstripe backend that has a Link() method will get its own page in your Gatsby site, whether it's a SiteTree or DataObject.

By default, a templates/Layout/Page.js is provided, which should resolve all your SiteTree records.

Template selection

Template selection works the same way as Silverstripe.

Example

Template inventory:

src/
  templates/
    Page.js
    Layout/
      NewsPage.js
      Page.js
  • NewsPage extends Page => src/templates/Layout/NewsPage.js (match)
  • ContactPage extends Page => src/templates/Layout/Page.js (resolves to parent class)
  • StaffMember extends DataObject => NOT FOUND (Please create a Layout/StaffMember.js file)

Helper components

The starter ships with some basic components to help with common template needs. You're free to customise these as you see fit.

  • <MainNav />
  • <Breadcrumbs />
  • <SEOTags />

Forms

You can query forms as data, as they are provided by silverstripe/silverstripe-gatsby using the silverstripe-graphql-forms module. You will need to expose these forms to your GraphQL API on your Silverstripe site.

UncleCheese\GraphQLForms\FormQueryCreator:
  registered_forms:
    ## Expose a form that is generated by a method on a controller
    ContactForm: 'MyProject\Pages\ContactPageController.ContactForm'
    ## Expose a UserDefinedForm by ID
    MyUserDefinedForm: 45

Then, you can extract the form data using helpers, and render the form out with a library like formik.

import React from 'react';
import { extractFormData } from 'silverstripe-gatsby-helpers';

const MyFormPage = ({ data: { silverStripeDataObject, silverStripeForm } }) => {
  const { title, content } = silverStripeDataObject.SilverStripeSiteTree;
  const {
    initialValues,
    fields,
    actions,
    validator,
    attributes
  } = extractFormData(silverStripeForm);

  // Render form
};

See full example below.

Elemental support

Coming soon.

Example code

Primary navigation

import React from 'react';
import classnames from 'classnames';
import { getMenu } from 'silverstripe-gatsby-helpers';
import { Link } from 'gatsby';


const MainNav = () => {
    const menuItems = getMenu(1);
    return (
        <nav className="mainNav">
            <ul>
            {menuItems.map(item => (
                <li key={item.id} className={classnames({
                    current: item.isCurrent,
                    section: item.isSection,
                })}>
                    <Link to={item.link}>
                        {item.SilverStripeSiteTree.menuTitle}
                    </Link>
                </li>
            ))}
            </ul>
        </nav>
    );
};

Subnavigation

  import React from 'react';
  import { getChildren, isLevel } from 'silverstripe-gatsby-helpers';

  const children = getChildren();
  const isLevel2 = isLevel(2);
  const hasSubnav = isLevel(2) || !!children.length;
  const navItems = isLevel2 ? getMenu(2) : children;

  const MyPage = () => (
    <div>
    {hasSubnav &&
      <div className="sidebar">
        <h2>In this section</h2>
        <ul>
        {navItems.map(child => (
          <li key={child.id} className={classnames({
            current: child.isCurrent,
          })}>
          <Link to={child.link}>{child.SilverStripeSiteTree.title}</Link>
          </li>
        ))}
        </ul>
      </div>
      }
    </div>
  );

Form Example (Formik)

import React from 'react';
import { graphql } from 'gatsby';
import { Formik, Form, Field } from 'formik';
import { extractFormData, SSFieldHolder } from 'silverstripe-gatsby-helpers';

const renderField = fieldNode => {
    const { Component } = fieldNode;
    return (
        <SSFieldHolder key={fieldNode.formFieldID} fieldNode={fieldNode}>
            <Field component={Component} />
        </SSFieldHolder>
    )
};

const MyFormPage = ({ data: { silverStripeForm } }) => {
    const {
        initialValues,
        fields,
        actions,
        validator,
        attributes
    } = extractFormData(silverStripeForm);



    return (
    <div>
        <h2>Form</h2>
        <Formik
            initialValues={initialValues}
            validate={validator}
            onSubmit={(values, { setSubmitting }) => {
                setTimeout(() => {
                alert(JSON.stringify(values, null, 2));
                setSubmitting(false);
                }, 400);
            }}
        >
        {formik => (
            <Form {...attributes}>
                <fieldset>
                {fields.map(renderField)}
                {actions.length > 0 &&
                	<div className="btn-toolbar">
                        {actions.map(action => (
                            <button key={action.formFieldID} type="submit" name={action.name} id={action.formFieldID}>
                                {action.title}
                            </button>
                        ))}
                    </div>        
                }
                </fieldset>
            </Form>
        )}
        </Formik>      
    </div>
    );
};

export const pageQuery = graphql`
    query($link: String!) {
        silverStripeForm(formName: { eq: "ContactForm" }) {
            attributes {
                name
                value
            }
            formFields {
              ...SilverStripeFormFieldsFields
              attributes {
                  name
                  value
              }
            }
            formActions {
              ...SilverStripeFormFieldsFields
                attributes {
                    name
                    value
                }
            }
        }        
    }
`;

export default MyFormPage;

For more information, see the silverstripe-gatsby-helpers package.

Magic

This starter adds some hooks to your gatsby-node.js file to inject global state that is used by most of the helper functions in silverstripe-gatsby-helpers. (See: SiteTreeProvider). Due to the nature of Gatsby's useStaticQuery, this code has to be colocated with your project. It is not recommended that you edit it.

You can’t perform that action at this time.