Content rules

Content rules let users define automated reactions to lifecycle events. Actions perform side effects when a rule triggers, while conditions gate whether a rule’s actions execute.

Interfaces

Action

interface ContentRuleAction {
  getTitle(req: Request): string;
  getDescription(req: Request): string;
  getSummary(req: Request, params: Params): string;
  schema: Json;
  handler(
    params: Params,
    context: any,
    user: any,
    contentRule: any,
    trx: Knex.Transaction,
  ): Promise<void>;
}

Condition

interface ContentRuleCondition {
  getTitle(req: Request): string;
  getDescription(req: Request): string;
  getSummary(req: Request, params: Params): string;
  schema: Json;
  handler(
    params: Params,
    context: any,
    user: any,
    contentRule: any,
    trx: Knex.Transaction,
  ): Promise<boolean>;
}

The key difference: an action handler returns void (it performs side effects), while a condition handler returns boolean (it evaluates a predicate).

Both require metadata methods (getTitle, getDescription, getSummary) and a schema for the rule configuration UI.

Creating an action

// src/content_rules/actions/my-action/my-action.ts
import type { Params, Request } from '../../types';
import { Knex } from 'knex';

export const myAction = {
  getTitle: (req: Request) => req.i18n('My Action'),
  getDescription: (req: Request) =>
    req.i18n('Description of what this action does'),
  getSummary: (req: Request, params: Params) =>
    req.i18n('My action with param {field}', {
      field: params.field || req.i18n('None'),
    }),
  schema: {
    fieldsets: [{ fields: ['field'], id: 'default', title: 'Default' }],
    properties: {
      field: {
        title: 'My Field',
        type: 'string',
      },
    },
    required: ['field'],
    type: 'object',
  },
  handler: async (
    params: Params,
    document: any,
    user: any,
    contentRule: any,
    trx: Knex.Transaction,
  ): Promise<void> => {
    // Your action logic here
  },
};

Creating a condition

// src/content_rules/conditions/my-condition/my-condition.ts
import type { Params, Request } from '../../types';

export const myCondition = {
  getTitle: (req: Request) => req.i18n('My Condition'),
  getDescription: (req: Request) =>
    req.i18n('Description of what this condition checks'),
  getSummary: (req: Request, params: Params) =>
    req.i18n('My condition: {field}', {
      field: params.field || req.i18n('None'),
    }),
  schema: {
    fieldsets: [{ fields: ['field'], id: 'default', title: 'Default' }],
    properties: {
      field: {
        title: 'My Field',
        type: 'string',
      },
    },
    required: ['field'],
    type: 'object',
  },
  handler: async (
    params: Params,
    document: any,
    user: any,
    contentRule: any,
    trx: Knex.Transaction,
  ): Promise<boolean> => {
    // Return true if the condition passes
    return params.field === document.someValue;
  },
};

Registration

In a profile’s init() function:

import contentRules from '../../content_rules';
import { myAction } from '../../content_rules/actions/my-action/my-action';
import { myCondition } from '../../content_rules/conditions/my-condition/my-condition';

// In init():
contentRules.registerAction('myAction', myAction);
contentRules.registerCondition('myCondition', myCondition);

When a content rule is evaluated, all conditions are checked (AND logic — all must pass), and if they do, all actions execute in sequence.

Initial content rules via profile

You can seed initial content rules by placing a content_rules.json file in a profile’s directory. The file is automatically loaded when the profile is installed.

{
  "purge": true,
  "content_rules": []
}
Field Type Description
purge boolean When true, all existing content rules are deleted before importing.
content_rules array List of content rule definitions to create.

Content rule items

Field Type Description
id string Unique identifier for the rule.
title string Display title.
description string Description of what the rule does.
event string The lifecycle event that triggers the rule (e.g. "onAfterAdd", "onAfterDelete").
enabled boolean Whether the rule is active.
cascading boolean Whether the rule applies to subfolders.
stop boolean Whether to stop processing further rules after this one.
actions array List of actions to execute. Each action has a type (e.g. "transition_workflow", "logger") and its configuration parameters.
conditions array List of conditions that must pass. Each condition has a type (e.g. "file_extension", "workflow_state") and its configuration parameters.

Example

Place a file like src/profiles/default/content_rules.json:

{
  "content_rules": [
    {
      "id": "auto-publish-images",
      "title": "Auto-publish images",
      "event": "onAfterAdd",
      "enabled": true,
      "cascading": true,
      "stop": false,
      "actions": [
        {
          "type": "transition_workflow",
          "transition": "publish"
        }
      ],
      "conditions": [
        {
          "type": "file_extension",
          "file_extension": "jpg"
        }
      ]
    }
  ]
}

The file is picked up automatically during seeding — no manual registration is required. When purge is false or omitted, new rules are added without removing existing ones.


This site uses Just the Docs, a documentation theme for Jekyll.