Hook Reference
VeloCMS plugins subscribe to lifecycle hooks by declaring them in the manifest and exporting a handler function with a matching name. Handlers receive a typed payload and a context object. The return value replaces the payload for subsequent handlers.
Handler signature
type PluginHandler<T> = (
payload: T,
context: PluginContext
) => T | Promise<T>;All hooks
| Hook | Payload type | Fires when | Modifiable |
|---|---|---|---|
| afterPostCreate | PostHookPayload | After a new post is saved (draft or scheduled) | No |
| afterPostUpdate | PostHookPayload | After any post field is updated | No |
| afterPostDelete | PostHookPayload | After a post is permanently deleted | No |
| beforePostPublish | BeforePostPublishPayload | Just before post status changes to published | Yes |
| afterPostPublish | PostHookPayload | After post is visible to readers | No |
| afterMemberSignup | MemberHookPayload | After a new reader registers | No |
| afterMemberUpdate | MemberHookPayload | After member profile or tier is updated | No |
| beforeMemberDelete | MemberHookPayload | Just before a member account is deleted | No |
| afterPageCreate | PageHookPayload | After a page builder page is created | No |
| afterPageUpdate | PageHookPayload | After a page is updated | No |
| afterPagePublish | PageHookPayload | After a page is published | No |
| afterOrderCreate | OrderHookPayload | After a new commerce order is created | No |
| afterProductCreate | ProductHookPayload | After a product is created | No |
| onAppStart | { timestamp: string } | Once on application startup | No |
| onDailySchedule | { date: string } | Once per day at 00:00 UTC | No |
"Modifiable" = return value is used by VeloCMS. For non-modifiable hooks, the return value is ignored; return the original payload unchanged.
Declaring hooks in the manifest
{
"hooks": ["afterMemberSignup", "onDailySchedule"]
}PluginContext
interface PluginContext {
tenantId: string;
pluginId: string;
log: (message: string, data?: Record<string, unknown>) => void;
warn: (message: string, data?: Record<string, unknown>) => void;
error: (message: string, data?: Record<string, unknown>) => void;
}Payload types
interface PostHookPayload {
post: {
id: string;
title: string;
slug: string;
content_json: Record<string, unknown> | null;
content_html: string | null;
content_markdown: string | null;
excerpt: string | null;
status: "draft" | "published" | "scheduled";
visibility: "public" | "members_only" | "paid";
reading_time_minutes: number | null;
published_at: string | null; // ISO 8601
tags: string[];
tenant_id: string;
};
}
interface BeforePostPublishPayload extends PostHookPayload {
suggestedTags?: string[];
seoSuggestions?: { title?: string; description?: string };
}
interface MemberHookPayload {
member: {
id: string;
email: string;
display_name: string | null;
tier: "free" | "paid";
subscribed_at: string | null;
tenant_id: string;
};
}