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.