@opkod-france/strapi-plugin-rrule
v1.0.0
Published
A Strapi custom field plugin for managing recurrence rules (RRule/RFC 5545) for events and schedules
Readme
Features
- Custom field for defining recurrence rules using the RRule standard
- Supports daily, weekly, monthly, and yearly frequencies
- Configurable end conditions (count, until date, or never)
- Weekday selection for weekly rules
- Monthly options (by day of month or by weekday position)
- Live preview of upcoming occurrences
- Stored as JSON for easy server-side processing
Installation
yarn add @opkod-france/strapi-plugin-rruleUsage
- Install the plugin in your Strapi v5 project
- In the Content-Type Builder, add a new Custom field
- Select Recurrence Rule from the list
- Configure the field options as needed
Data Format
The custom field stores its value as a JSON object in the database (Strapi json column type). Every mutation in the admin panel produces a complete snapshot of the rule configuration alongside a pre-computed RFC 5545 RRULE string.
Schema
interface RRuleValue {
freq: number; // Frequency: 0=Yearly, 1=Monthly, 2=Weekly, 3=Daily
interval: number; // Repeat every N periods (≥ 1)
byweekday?: number[]; // Selected weekdays: 0=Mon … 6=Sun (weekly rules)
bymonthday?: number[]; // Day(s) of the month, e.g. [15] (monthly rules)
bymonth?: number[]; // Month(s) of the year, e.g. [1] for January (yearly rules)
bysetpos?: number[]; // Position in set, e.g. [1]=first, [-1]=last (monthly "nth weekday" rules)
dtstart?: string; // Start date (ISO 8601)
until?: string; // End date (ISO 8601) — mutually exclusive with count
count?: number; // Max occurrences — mutually exclusive with until
tzid: string; // IANA timezone, e.g. "Europe/Paris"
wkst?: number; // Week start day (0=Mon … 6=Sun)
rruleString: string; // Pre-computed RFC 5545 RRULE string
}Example: Weekly on Mon/Wed/Fri
{
"freq": 2,
"interval": 1,
"byweekday": [0, 2, 4],
"tzid": "Europe/Paris",
"rruleString": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,WE,FR"
}Example: Monthly on the last Friday, 5 occurrences
{
"freq": 1,
"interval": 1,
"bysetpos": [-1],
"byweekday": [4],
"count": 5,
"tzid": "America/New_York",
"rruleString": "FREQ=MONTHLY;INTERVAL=1;BYDAY=FR;BYSETPOS=-1;COUNT=5"
}How the component works internally
- Initialization — When the field is empty, the component creates a default value (weekly on Monday, interval 1, user's local timezone).
- State updates — Each UI interaction (frequency change, weekday toggle, etc.) calls an action function from
rruleActions.tsthat returns a new immutableRRuleValuewith therruleStringautomatically regenerated. - Persistence — The full JSON object is passed to Strapi's
onChangehandler, which stores it in the database. This means both the structured parameters and the ready-to-use RRULE string are always in sync and available via the API.
Using the RRULE string server-side
The rruleString field is a standard RFC 5545 RRULE string that can be parsed by any compliant library:
import { RRule } from 'rrule';
// From your Strapi API response
const entry = await strapi.documents('api::event.event').findOne({ documentId });
const { rruleString, dtstart } = entry.recurrence;
// Expand occurrences
const rule = RRule.fromString(`RRULE:${rruleString}`);
const next10 = rule.all((_, i) => i < 10);License
MIT
