Components

Components are the building blocks of your website. You can drag and drop them into place to build simple pages or complex layouts. Gust comes with a whole bunch of these out of the box, but lets you create new ones or just update the ones we've give you to suit your brand.

Creating components

There are a couple of ways that you can create new components in Gust, and we'll detail both of them here.

With the editor

Creating new components in the editor is the simplest way to get started. You can drag and drop elements into place and then style them by adding CSS classes. Once you've got it to a place that you like, you can click the save icon in the active node menu. You'll be able to set a name for your component and also a category so that you can easily find it later on.

If you're saving an existing component you'll first be asked if you want to save or update the component. More on that in Editing and extending components.

With code

Creating components with code gives you the most flexibility. Almost everything is editable via the UI but there are a few options that haven't quite been added to the UI for simplicity sake.

All components are created by writing JSON and loading them into the site via a hook. All the options are outline below but if you want to get a sense of what it's really like, I suggest you take a look at some of the ones provided for you. You can find these in wp-content/themes/gust/includes/components.

Once you've got your JSON file ready you can add it all in using the following snippet. You'll need to make sure this function is named appropriately, this is just an example.

add_action('init', 'register_components');
function register_components()
{
  if (!class_exists('Gust')) return;
  $dir = trailingslashit(plugin_dir_path(__FILE__));
  $string = file_get_contents($dir . 'components/my-component.json');
  $json = json_decode($string, true);
  Gust::get_instance()->components->register_component('my-component', $json);
}

Here's an example component:

{
  "id": "button",
  "displayName": "Button",
  "category": "Buttons",
  "tag": "button",
  "classNames": "font-bold rounded bg-primary text-white p-4 inline-block",
  "content": {
    "type": "value",
    "value": "Click Me!"
  }
}

This creates a very basic, single element component called "Button" which, unsurprisingly, creates a button. You can start to see some obvious properties that go into defining this component. Below is a complete list of these properties and below that is an example component which has an example of every one of these options.

Property Required Type Description
id Yes string The ID is not to be confused with the HTML id attribute. This ID is not rendered when the page is built, it is used exclusively in the editor. This must be set on every component and every child of every component. You can leave it off if you want, but things will start to fall apart pretty quickly. We wouldn't recommend it. It can be whatever you want, just make sure that it is unique within the component. And preferably unique to the other components.
displayName Yes, top level only string The display name is used to identify a component. It is only needed for the top level, i.e. component children do not need it
category Yes, top level only string The category is used to group components in the editor. Like the displayName it is only needed for the top level component
tag Yes string The HTML tag that will used
classNames No string Any default classes that should appear on the element
content No Object
content.type Yes, when content is set string Can be either value, filter, function, or richtext. See Supported Functions for more info.
content.value Yes, when content is set string This is the value of whatever content.type is set to. E.g if it's a filter then it should be the name of the filter, a function then it's the name of the function, rich text then it's the HTML string
content.defaultValue No string When content.type is a filter, this is the default value that gets passed to the filter.
children No Array of components Children is an array of component objects. When you start nesting HTML elements, this is where they'll go.
allowChildren No boolean In the drag and drop editor, if you want to be able to drag components / elements into this specific element, set this to true
hasRepeater No boolean This marks the component as having repeatable content somewhere in its children. For example, a tabs component may have this set to true on the top level, but only implements the repeatable content in one of its children. Only set this on the top level component. There are more examples of this below.
useRepeater No boolean This marks a particular node in the component tree as being repeatable. E.g. in a tabs component this might be the tab button that repeats or in a slider component it's the slide element that repeats.
allowRepeaterContent No boolean Whether or not the content within this repeated element should be editable. E.g. In a tabs component the tab label itself might set this to true to let the user override the default content.
displayRepeated No single This controls how repeated content is displayed in the editor. Left undefined it will display the repeated items, however if you set it to single it will only show the currently active item. E.g. in a tabs component you might set the list of tabs as undefined so they are always visible, but you would set the tab content to single so that only one tabs content displayed at a time. Again, this only effects the editor and it's up to the developer to implement this on the front end. We do have some helper classes though, take a look at Repeatable content for more details.
options No Array of option Options allow you to "mask" more complex CSS classes or HTML attributes. For example, on an anchor, styled as a button, the user will likely want to add an href. That's fine for developers, but your clients are unlikely to know what an href is. So, you can add an option called "Link" that maps to the href attribute and makes it easy for the user to understand.
option.label Yes string The label for your option, shown to the user.
option.name Yes string A unique name for your option, this is used by the editor to save the property against. It should be JSON friendly.
option.type Yes select or text Should the option display as a select box or a free text input.
option.options Yes, only when option.type === 'select' Array of { label: string; value: string }
option.modify Yes className or attribute Should this option add to the CSS class names, or should it set an attribute
option.attributeName Yes, if option.modify === 'attribute' string What attribute should be added to the element?
attributes No Array of attribute You can set default HTML attributes for a tag. Note that the user can override this and set their own.
attribute.type Yes value, filter, or function What type of content should we use for the attribute. See Supported Functions for more info.
attribute.name Yes string The HTML attribute name.
attribute.value Yes, when content is set string This is the value of whatever content.type is set to. E.g if it's a filter then it should be the name of the filter, a function then it's the name of the function, rich text then it's the HTML string

Supported functions

When setting the content or attribute type as function, Gust supports a few functions out of the box. These are:

  • get_the_title
  • get_the_content
  • get_the_permalink
  • get_the_post_thumbnail
  • get_the_post_thumbnail_url
  • get_the_excerpt
  • get_post_status
  • get_the_ID

Note that these functions are all using the get_ counterparts so that the result is not immediately echo'd by PHP.

Example component

The below example is an example of how you can create your components with an example of using one of every option. We're going to be making a tabbed component and there are comments throughout the definition to help clear up some of the more obscure properties. Some key things to note here are:

  • how repeatable items are used
  • how options are used in the
{
  "id": "tabs",
  "displayName": "Tabs",
  "category": "Content",
  "tag": "div",
  // this lets the editor know that users should be able to add items, or in this case "tabs"
  "hasRepeater": true,
  "children": [
    {
      "id": "tabLabelsContainer",
      "tag": "ul",
      // class set to "flex" ( see tailwind CSS ) to make all the tabs sit inline
      "classNames": "flex",
      "children": [
        {
          "id": "tabLabel",
          "tag": "li",
          // when a new item ( i.e. tab ) is added by the user in the UI, this whole element will repeat
          "useRepeater": true,
          "classNames": "group",
          "children": [
            {
              "id": "tabButton",
              "tag": "button",
              // adds some padding and borders
              // note the group-gust-active-item:border-primary class
              // there's more detail on that in the Repeatable Content doc
              "classNames": "p-2 border-b-2 group-gust-active-item:border-primary",
              // allows the content of this element to be overwritten on a per-item basis
              // without this, every tab label would display "Tab" and the user would not be able to change it
              "allowRepeaterContent": true,
              // sets up a default value for tab label
              "content": {
                "type": "value",
                "value": "Tab",
              }
            }
          ],
          // let's the user choose whether their button has a white or primary background
          "options": [
            {
              "label": "Label Colour",
              "name": "labelColour",
              // adds the selected value to the class name list
              "modify": "className",
              "type": "select",
              "options": [
                {
                  "label": "White",
                  "value": "bg-white",
                },
                {
                  "label": "Primary",
                  "value": "bg-primary text-white",
                }
              ]
            }
          ],
          "attributes": [
            {
              // not really needed in this scenario
              // but sets the type="button" attribute on the button
              "name": "type",
              // this attribute is a "value"
              // so it gets its value from the below value property and not from a filter or function
              "type": "value",
              "value": "button",
            },
            {
              // this attribute sets a "data-post-id" attribute on the button which is the return value of calling get_the_ID()
              // See the supported functions above
              "name": "data-post-id",
              "type": "function",
              "value": "get_the_ID",
            }
          ]
        }
      ]
    },
    {
      "id": "tabContentContainer",
      "tag": "div",
      "classNames": "border-t p-4",
      "children": [
        {
          "id": "tabContent",
          "tag": "div",
          // same as above, this element will be repeated when new items are added
          "useRepeater": true,
          // in the editor only show the currently active item
          "displayRepeated": "single",
          // allow the user to drop elements into this one
          "allowChildren": true
        }
      ]
    }
  ]
}

Editing and extending components

Gust is made to be extended and made to fit your design, not the other way around, so being able to editing and extend defaults is at the core of Gust.

As usual there are two ways to edit components. Either through the UI or with code.

Editing components in the UI

Click on an element, any element, in the UI and you'll see that all its properties display in the node details panel. From here you can change classes, add attributes, etc. You can also use the node tree to select the exact node you want to change.

It's important to understand that these changes are specific only to this instance of the component. That means you could add another one of the same component beside it and it would have its original properties. If you want to make your changes affect all instances of that component you can click the "Save Component" button. You can then choose to either update this component ( will update all instances of this component ) or you can turn it into a new component.

Hooks and filters

It wouldn't be WordPress if it didn't have hooks and filters, and Gust comes with plenty to make sure you have control over what's being output.

Filter Arguments Description
gust_register_component $json, $componentName This is run before each component is registered. You can override an entire component's JSON with this filter. Great for overriding core components.
gust_render_component $component, $componentName This is called whenever Gust tries to render a component. It should return the component details. Again, you could override the implementation of a core component here, but on only when pages are being built. This does not effect the editor.
{$tagId}_tag_name $tagName, $context, $componentDetails When a component node is being rendered the tag is run through this filter so you can change it if you need to.
{$tagId}_class_names $classNames, $context, $componentDetails Modify any classes being output onto a component node.
{$tagId}_attributes $attributes, $context, $componentDetails Modify any attributes being output on a component node.
{$tagId}_output $output, $context, $componentDetails Modify the full HTML of a component node.