Medusa/developer documentation/Placeholders

Placeholders

Contribute live values to the bot activity status and add placeholder buttons to configuration fields.

Medusa has two placeholder systems:

  • Placeholder providers in resources/placeholders/ contribute live values (such as %tickets_open%) to the bot activity status. Every provider shows up as a button under the status text on the dashboard Bot page.
  • Field placeholders declared with placeholders on a string or text configuration field render buttons under that input that insert the token at the cursor.

Placeholder Providers

Providers reside in resources/placeholders/ and load from every *.js file located directly in that directory. One provider can supply several keys.

modules/example/resources/placeholders/tickets.js
import { Placeholders } from "#medusa/modules";

export class TicketPlaceholders extends Placeholders {
    constructor(medusa) {
        super(medusa, { name: "tickets" });
    }

    keys() {
        return [
            { key: "tickets_open", label: "Open Tickets", sample: "7" },
            { key: "tickets_total", label: "Total Tickets", sample: "319" }
        ];
    }

    async values() {
        const model = this.medusa.modules.models.get("ticket", "ticket_tickets");
        return { tickets_open: await model.count({ status: "open" }), tickets_total: await model.count() };
    }
}

Constructor Options

PropertyTypeDefaultDescription
namestringRequiredProvider identifier, unique within the module.
ordernumber0Sort priority between providers of the same module. Core providers are always listed first.

Methods

MethodReturnsDescription
keys()Array<{ key, label, sample }>The tokens this provider fills. key is used as %key%. Prefix keys with the module id (tickets_open, giveaways_active) so they never collide.
values(context)Promise<Record<string, string | number>>Resolves every key. context holds client (the Discord.js client of the bot whose status is being set) and bot.

values only runs when the status text contains one of the provider's keys, so a provider can query the database without slowing down statuses that do not use it. A provider that throws is logged and its keys stay unresolved.

Translating Labels

The dashboard reads button labels from placeholder.<module>.<key> in the module's resources/lang/<code>/common.json, falling back to the English label:

modules/example/resources/lang/de/common.json
{
    "placeholder.ticket.tickets_open": "Offene Tickets"
}

Built-in Keys

Core ships these keys, and the global placeholders from embeds.fill (custom Placeholders settings, %server%, %version%, %name%) also work in the status:

KeyValue
%servers%Servers the bot is in.
%members%Total members across those servers.
%channels%Cached channels.
%ping%Gateway ping in milliseconds.
%uptime%Uptime such as 2d 4h or 3h 12m.
%modules%Loaded modules.
%bot_name%The bot's username.

Refresh

When any status line contains %, the bot re-applies the current line every 60 seconds so the values stay current. Rotation between several lines keeps its own interval.

Placeholder Manager Methods

const keys = this.medusa.placeholders.list();

const text = await this.medusa.placeholders.fill("Watching %tickets_open% tickets", { client, bot });
MethodReturnsDescription
list()Array<{ key, label, sample, module }>Every key from enabled modules, Core first. Served at GET /api/placeholders.
fill(text, context)Promise<string>Resolves the providers used in text, then runs embeds.fill for global placeholders and custom emojis.

Field Placeholders

Add placeholders to a string or text field, top-level or inside a list item, to render insert buttons under the input. The value is only a hint for the dashboard; your code still fills the tokens, usually through this.medusa.embeds.fill(template, tokens).

modules/example/resources/config/settings.js
naming: {
    type: "string",
    default: "ticket-%number%",
    label: "Channel Naming",
    placeholders: [
        { key: "number", label: "Ticket Number", sample: "42" },
        { key: "user", label: "Username", sample: "muffiny" }
    ]
}

Button labels translate through schema.<module>.config.<group>.<field>.placeholders.<key> for top-level fields and schema.<module>.config.<group>.<list>.<field>.placeholders.<key> for list item fields.

Keep the placeholders list in sync with the tokens your code passes to embeds.fill. A button for a token the code never fills leaves the raw %key% in the output.