Using Fred with GPM in MODX 3

Update

I've released a sample project using Fred + GPM to create a theme. You are welcome to use this as an example for setting up your own project!

Getting Started | Set Up | Formatting GPM | Packaging Themes

Getting Started with GPM

GPM stands for Git Package Management, and is a powerful tool to build installable packages in MODX. I use GPM almost every day to create and update packages for projects I'm working on.

To get started with GPM, you can follow my guide on creating a new package in MODX 3 using GPM.

The basics that you will need to know is that GPM uses a configuration file called gpm.yml to define the package. In addition to this file, you will need to create a directory structure that matches the MODX file structure. E.g.

_build
  gpm.yml

assets
  components
    packagename

core
  components
    packagename
      elements
      src
      bootstrap.php

Following the guide linked above will help you get the basic structure of a GPM package in place.

Setting up a theme build

GPM can be incorporated into your current theme build process. I'll go over how I set up my own build process to illustrate an example of how you can modify your own.

In the majority of my themes I will use a combination of TailwindCSS, PostCSS, and Webpack to compile my CSS and JS. In order to keep the final install of the package as small as possible, I will place all of my source files in a separate directory from the final assets directory. This allows me to compile the source files into the assets directory, and then include the assets directory into the final package.

My recommendation for where to place the source files is in the _build directory. I generally will structure it like this:

_build
  gpm.yml
  src
    css
      main.css
    js
      index.ts
    images
    home.html
    inside.html

On my webpack configuration, I'll set my entry point as:

entry: [
      "./_build/src/css/main.css",
      "./_build/scr/js/index.ts",
    ],

Then I will set my output directory to the assets directory:

output: {{
      path: path.resolve(__dirname, "./assets/components/packagename/web"),
      clean: true,
      library: {
        name: "PackageName",
        type: "umd",
      },
      filename: "packagename.min.js",
      assetModuleFilename: "static/[name][ext][query]",
    },

Notice that I set the output path to ./assets/components/packagename/web. This is because I set webpack to clean the directory on compile. This will allow me to include non-compiled assets in the package as well.

You can adapt this flow to your own build process, but the key is to keep the source files separate from the final assets directory that will be included in the package.

Format for GPM Elements

GPM elements are a way to include MODX elements in your package. This can be anything from snippets, chunks, plugins, templates, TVs, or even FRED THEMES! The elements are defined in the gpm.yml file, and are placed in the ./core/components/packagename/elements directory.

The elements directory structure will look something like this:

core
  components
    packagename
      elements
        snippets
          snippetname.php
        chunks
          chunkname.tpl
        plugins
          pluginname.php
        templates
          templatename.html
        templateVars
          tvname.tpl
        fred
          elements
            Category
              elementname.twig
              elementname.override.json
          optionsets
            optionsetname.json
          rteconfigs
            rteconfigname.json

The gpm.yml file will define the elements that are included in the package. Here is an example of what the elements section of the gpm.yml file might look like:

name: 'Package Name'
version: 0.0.1
description: 'A description of the package'
lowCaseName: packagename
namespace: 'PackageName'
author: 'Author Name'
templates:
    - name: templatename
      description: 'A description of the template'
chunks:
    - name: chunkname
      description: 'A description of the chunk'
snippets:
    - name: snippetname
      description: 'A description of the snippet'
plugins:
    - name: pluginname
      description: 'A description of the plugin'
      events:
        - 'OnWebPageInit'
tvs:
    - name: tvname
      caption: 'A description of the TV'
      type: listbox
      file: tvname.tpl
      inputOptionsValues: 'Option 1==1||Option 2==2'
      templates:
        - 'templatename'
      properties:
        - name: fred
          value: '1'
        - name: fred.type
          value: select
        - name: fred.options
          value: '{"Option 1":1,"Option 2":2}'
fred:
    templates:
       - name: templatename
         defaultBlueprint: null
    elementCategories:
       - name: 'Category'
    elements:
       - name: elementname
         category: 'Category'
         description: 'A description of the element'
         image: '{{theme_dir}}generated/elementname.png'
         option_set: optionsetname
    rteConfigs:
        - name: rteconfigname
    optionSets:
        - name: optionsetname
systemSettings:
    - key: theme_dir.custom_path
      value: '{{pkg_assets_path}}/'
    - key: theme_dir.custom_url
      value: '{{pkg_assets_url}}/'

This is a basic example of what the gpm.yml file might look like. You can include as many elements as you need in the package. The key is to make sure that the elements are defined in the gpm.yml file, and that the elements are placed in the correct directory structure.

One other thing to note in the configuration is the systemSettings section. This is where you can define general system settings for the package. For a custom Fred theme, you will need to define the theme_dir.custom_path and theme_dir.custom_url settings. This will allow the theme to be installed correctly in the MODX manager without Fred trying to load the theme from the wrong location.

Packaging a Fred Theme

Packaging a Fred theme is mostly the same as packaging any other GPM package. The main difference is that to see updated changes to the Fred elements, you will need to update the package using either GPM's CLI or the MODX Manager. If using CLI, you would run the command gpm packagename:update to update the package. If using the MODX, you would go to the GPM section of the manager and click the update button for the package.

You would follow the same steps as above to create the package, except it would be gpm packagename:build or clicking the build button.

One important thing to note is that when you run gpm packagename:update, it will update your gpm.yml file if it detects new Fred theme elements. It does this to associate the theme element with the uuid  generated by Fred.

Depending on your workflow, you can either build the package using a locally hosted MODX instance, or you can set up GPM on a MODX Cloud instance. I generally will use a MODX Cloud instance to build the package, and then download the package to install on other instances for testing.

If you are already using GitHub actions or another CI/CD pipeline, you can set up a workflow SSH in and build the package on your remote MODX Cloud instance. This will allow you to automate the build process and keep your package up to date with the latest changes.