Skip to content

Instantly share code, notes, and snippets.

@hdodov
Last active January 16, 2023 06:33
Show Gist options
  • Save hdodov/bbb2e380aa587a100272b298e12e493a to your computer and use it in GitHub Desktop.
Save hdodov/bbb2e380aa587a100272b298e12e493a to your computer and use it in GitHub Desktop.
Payload CMS dynamic variables with `{{` and `}}`. You can also add modifiers, e.g. `{{ my_var:millions }}` and divide the value by 1e6.
import payload from "payload";
import { CollectionAfterReadHook } from "payload/types";
import { Variable } from "../payload-types";
const pattern = /{{\s*(.*?)\s*}}/g;
const modifiers: { [key: string]: (input: string) => string } = {
millions: (value) => Math.floor(parseInt(value) / 1e6).toString(),
};
/**
* Recursively loops over all properties of the `input` object and invokes
* `callback` for each one of them. If the callback returns a string, the looped
* value is also replaced with that string.
*/
function deepIterate(
input: object,
callback: (value: string) => void | string
) {
for (let k in input) {
if (!input.hasOwnProperty(k)) {
continue;
}
let val: string = input[k];
if (typeof val === "string") {
let result = callback(val);
if (typeof result === "string") {
input[k] = result;
}
} else if (val && typeof val === "object") {
deepIterate(val, callback);
}
}
}
export const replaceVariablesHook: CollectionAfterReadHook = async ({
doc,
req,
}) => {
// Don't do anything if `?replace` is missing from the request URL.
if (!req.query.replace) {
return doc;
}
let variables: string[] = [];
deepIterate(doc, (value) => {
for (let matches of value.matchAll(pattern)) {
variables.push(matches[1].split(":")[0]);
}
});
const query = await payload.find<Variable>({
collection: "variables",
limit: 0,
where: {
key: {
in: variables,
},
},
});
deepIterate(doc, (value) => {
return value.replace(pattern, (_, name: string) => {
const parts = name.split(":");
const key = parts.shift();
let value = query.docs.find((doc) => doc.key === key)?.value;
if (!value) {
return "";
}
if (parts.length) {
parts.forEach((modifierName) => {
if (modifiers[modifierName]) {
value = modifiers[modifierName](value);
}
});
}
return value;
});
});
return doc;
};
import { CollectionConfig } from "payload/types";
export const Variables: CollectionConfig = {
slug: "variables",
admin: {
useAsTitle: "key",
},
fields: [
{
name: "key",
type: "text",
},
{
name: "value",
type: "text",
},
],
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment