Zum Inhalt springen

Die Grundlagen

StudioCMS-Plugins sind ein leistungsstarkes Werkzeug, mit dem du die Funktionalität von StudioCMS erweitern kannst. Sie bieten eine einfache und flexible Möglichkeit, neue Funktionen zu deinem StudioCMS-Projekt hinzuzufügen. Im Folgenden findest du eine Übersicht über die StudioCMS-Plugins und ihre Funktionsweise.

StudioCMS-Plugins sind ähnlich wie Astro-Integrationen, aber sie haben zusätzliche Informationen, die an das Funktionsobjekt angehängt sind. Diese Informationen werden von StudioCMS verwendet, um zu bestimmen, wie das Plugin geladen und verwendet werden soll. StudioCMS-Plugins werden verwendet, um die Funktionalität von StudioCMS zu erweitern, indem neue Funktionen hinzugefügt oder bestehende geändert werden.

type
type StudioCMSPlugin = {
identifier: string;
name: string;
studiocmsMinimumVersion: string;
integration?: AstroIntegration | AstroIntegration[] | undefined;
triggerSitemap?: boolean;
sitemaps?: Array<{
pluginName: string;
sitemapXMLEndpointPath: string | URL;
}> | undefined;
dashboardGridItems?: Array<{
name: string;
span: 1 | 2 | 3;
variant: "default" | "filled";
requiresPermission?: "owner" | "admin" | "editor" | "visitor";
header?: {
title: string;
icon?: HeroIconName;
};
body?: {
html: string;
components?: Record<string, string>;
sanitizeOpts?: SanitizeOptions;
};
}> | undefined;
settingsPage: {
fields: SettingsField[];
endpoint: string;
} | undefined;
frontendNavigationLinks: Array<{
label: string;
href: string;
}>;
pageTypes: Array<{
label: string;
identifier: string;
description: string;
pageContentComponent: "studiocms/markdown" | "studiocms/html" | string;
rendererComponent: "studiocms/markdown" | "studiocms/html" | string;
fields: SettingsField[];
apiEndpoint: string;
}> | undefined;
}
StudioCMSPlugin
= {
/**
* Kennung des Plugins aus der package.json
*/
identifier: string

Kennung des Plugins aus der package.json

identifier
: string;
/**
* Bezeichnung des Plugins, die im StudioCMS Dashboard angezeigt werden soll
*/
name: string

Bezeichnung des Plugins, die im StudioCMS Dashboard angezeigt werden soll

name
: string;
/**
* Erforderliche Mindestversion von StudioCMS, damit das Plugin funktioniert
*/
studiocmsMinimumVersion: string

Erforderliche Mindestversion von StudioCMS, damit das Plugin funktioniert

studiocmsMinimumVersion
: string;
/**
* Astro-Integration(en), die das Plugin bietet
*/
integration?: AstroIntegration | AstroIntegration[] | undefined

Astro-Integration(en), die das Plugin bietet

integration
?:
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
|
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
[] | undefined;
/**
* Wenn dies der Fall ist, aktiviert das Plugin die Erstellung der Sitemap
*/
triggerSitemap?: boolean

Wenn dies der Fall ist, aktiviert das Plugin die Erstellung der Sitemap

triggerSitemap
?: boolean;
/**
* Ermöglicht es dem Plugin, Sitemap-Endpunkte hinzuzufügen
*/
sitemaps?: {
pluginName: string;
sitemapXMLEndpointPath: string | URL;
}[] | undefined

Ermöglicht es dem Plugin, Sitemap-Endpunkte hinzuzufügen

sitemaps
?:
interface Array<T>
Array
<{
/**
* Name des Plugins
*/
pluginName: string

Name des Plugins

pluginName
: string;
/**
* Pfad zur Sitemap-Xml-Endpunktdatei
*/
sitemapXMLEndpointPath: string | URL

Pfad zur Sitemap-Xml-Endpunktdatei

sitemapXMLEndpointPath
: string |
interface URL

URL class is a global reference for import { URL } from 'url' https://nodejs.org/api/url.html#the-whatwg-url-api

@sincev10.0.0

URL
;
}> | undefined;
/**
* Ermöglicht es dem Plugin, benutzerdefinierte Dashboard-Gitterelemente hinzuzufügen
*/
dashboardGridItems?: {
name: string;
span: 1 | 2 | 3;
variant: "default" | "filled";
requiresPermission?: "owner" | "admin" | "editor" | "visitor";
header?: {
title: string;
icon?: HeroIconName;
};
body?: {
html: string;
components?: Record<string, string>;
sanitizeOpts?: SanitizeOptions;
};
}[] | undefined

Ermöglicht es dem Plugin, benutzerdefinierte Dashboard-Gitterelemente hinzuzufügen

dashboardGridItems
?:
interface Array<T>
Array
<{
/**
* Name des Gitterelements
*/
name: string

Name des Gitterelements

name
: string;
/**
* Spannweite des Gitterelements
*/
span: 2 | 1 | 3

Spannweite des Gitterelements

span
: 1 | 2 | 3;
/**
* Kartenvariante des Gitterelements
*/
variant: "default" | "filled"

Kartenvariante des Gitterelements

variant
: 'default' | 'filled';
/**
* Erlaubnis erforderlich, um das Gitterelement anzuzeigen
*/
requiresPermission?: "owner" | "admin" | "editor" | "visitor"

Erlaubnis erforderlich, um das Gitterelement anzuzeigen

requiresPermission
?: "owner" | "admin" | "editor" | "visitor";
/**
* Kopfzeileninformationen des Gitterelements
*/
header?: {
title: string;
icon?: HeroIconName;
}

Kopfzeileninformationen des Gitterelements

header
?: {
/**
* Titel des Gitterelements
*/
title: string

Titel des Gitterelements

title
: string;
/**
* Symbol für das Gitterelement
*/
icon?: "code-bracket-solid" | "code-bracket-square-solid" | "exclamation-circle" | "exclamation-circle-solid" | "exclamation-triangle" | "exclamation-triangle-solid" | "viewfinder-circle" | ... 1280 more ... | "x-mark-solid"

Symbol für das Gitterelement

icon
?:
type HeroIconName = "code-bracket-solid" | "code-bracket-square-solid" | "exclamation-circle" | "exclamation-circle-solid" | "exclamation-triangle" | "exclamation-triangle-solid" | "viewfinder-circle" | ... 1280 more ... | "x-mark-solid"
HeroIconName
;
};
/**
* Körperinformationen des Gitterelements
*/
body?: {
html: string;
components?: Record<string, string>;
sanitizeOpts?: SanitizeOptions;
}

Körperinformationen des Gitterelements

body
?: {
/**
* HTML-Inhalt des Gitterelements
*/
html: string

HTML-Inhalt des Gitterelements

html
: string;
/**
* Komponente, die im Gitterelement angezeigt wird
*/
components?: Record<string, string>

Komponente, die im Gitterelement angezeigt wird

components
?:
type Record<K extends keyof any, T> = { [P in K]: T; }

Construct a type with a set of properties K of type T

Record
<string, string>;
/**
* Sanitize-Optionen für den HTML-Inhalt
*/
sanitizeOpts?: SanitizeOptions

Sanitize-Optionen für den HTML-Inhalt

sanitizeOpts
?:
(alias) interface SanitizeOptions
import SanitizeOptions
SanitizeOptions
;
};
}> | undefined;
/**
* Wenn dies der Fall ist, hat das Plugin seine eigene Einstellungsseite
*/
settingsPage: {
fields: SettingsField[];
endpoint: string;
} | undefined

Wenn dies der Fall ist, hat das Plugin seine eigene Einstellungsseite

settingsPage
: {
/**
* Felder gemäß Spezifikation
*/
fields: ({
name: string;
label: string;
input: "checkbox";
required?: boolean | undefined;
readOnly?: boolean | undefined;
color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
defaultChecked?: boolean | undefined;
size?: "sm" | "md" | "lg" | undefined;
} | ... 4 more ... | {
...;
})[]

Felder gemäß Spezifikation

fields
:
type SettingsField = {
name: string;
label: string;
input: "checkbox";
required?: boolean | undefined;
readOnly?: boolean | undefined;
color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
defaultChecked?: boolean | undefined;
size?: "sm" | "md" | "lg" | undefined;
} | ... 4 more ... | {
...;
}

Represents the type inferred from the SettingsFieldSchema schema.

This type is used to define the structure of settings fields within the application.

SettingsField
[];
/**
* Der Endpunkt für die Einstellungen
*
* Sollte eine APIRoute namens `onSave` exportieren, die ausgeführt wird, wenn die Einstellungsseite gespeichert wird
*/
endpoint: string

Der Endpunkt für die Einstellungen

Sollte eine APIRoute namens onSave exportieren, die ausgeführt wird, wenn die Einstellungsseite gespeichert wird

endpoint
: string,
} | undefined;
/**
* Navigationslinks für die Verwendung mit dem `@studiocms/blog`-Plugin und anderen Plugins zur Anzeige von Links im Frontend
*/
frontendNavigationLinks: {
label: string;
href: string;
}[]

Navigationslinks für die Verwendung mit dem @studiocms/blog-Plugin und anderen Plugins zur Anzeige von Links im Frontend

frontendNavigationLinks
:
interface Array<T>
Array
<{
label: string
label
: string;
href: string
href
: string;
}>;
/**
* Seitentyp-Definition. Wenn dies der Fall ist, möchte das Plugin den Prozess der Seitenerstellung ändern können
*/
pageTypes: {
label: string;
identifier: string;
description: string;
pageContentComponent: "studiocms/markdown" | "studiocms/html" | string;
rendererComponent: "studiocms/markdown" | "studiocms/html" | string;
fields: SettingsField[];
apiEndpoint: string;
}[] | undefined

Seitentyp-Definition. Wenn dies der Fall ist, möchte das Plugin den Prozess der Seitenerstellung ändern können

pageTypes
:
interface Array<T>
Array
<{
/**
* Beschriftung, die in der Select-Eingabe angezeigt wird
*/
label: string

Beschriftung, die in der Select-Eingabe angezeigt wird

label
: string;
/**
* Kennung, die in der Datenbank gespeichert wird
* @example
* // Einzelner Seitentyp pro Plugin
* 'studiocms'
* '@studiocms/blog'
* // Mehrere Seitentypen pro Plugin (verwende eindeutige Bezeichner für jeden Typ, um Konflikte zu vermeiden)
* '@mystudiocms/plugin:pageType1'
* '@mystudiocms/plugin:pageType2'
* '@mystudiocms/plugin:pageType3'
* '@mystudiocms/plugin:pageType4'
*/
identifier: string

Kennung, die in der Datenbank gespeichert wird

@example // Einzelner Seitentyp pro Plugin 'studiocms' '@studiocms/blog' // Mehrere Seitentypen pro Plugin (verwende eindeutige Bezeichner für jeden Typ, um Konflikte zu vermeiden) '@mystudiocms/plugin:pageType1' '@mystudiocms/plugin:pageType2' '@mystudiocms/plugin:pageType3' '@mystudiocms/plugin:pageType4'

identifier
: string;
/**
* Beschreibung, die unter der Überschrift „Seiteninhalt“ angezeigt wird, wenn dieser Typ ausgewählt ist
*/
description: string

Beschreibung, die unter der Überschrift „Seiteninhalt“ angezeigt wird, wenn dieser Typ ausgewählt ist

description
: string;
/**
* Der Pfad zu der eigentlichen Komponente, die für den Seiteninhalt angezeigt wird
*
* Die Komponente sollte eine Eigenschaft `content` haben, die ein String ist, um den aktuellen Inhalt anzeigen zu können.
*
* **HINWEIS:** Derzeit musst du die Formular-ID `page-content` für die Inhaltsausgabe verwenden. Dein Editor sollte auch in der Lage sein, die Formularübermittlung zu verarbeiten.
*
* **HINWEIS:** Du kannst `studiocms/markdown` oder `studiocms/html` als Fallback-Wert verwenden, wenn du mit HTML- oder Markdown-Inhalten arbeitest!
*
* @example
* ```ts
* import { createResolver } from 'astro-integration-kit';
* const { resolve } = createResolver(import.meta.url)
*
* {
* pageContentComponent: resolve('./components/MyContentEditor.astro'),
* }
* ```
*/
pageContentComponent: string

Der Pfad zu der eigentlichen Komponente, die für den Seiteninhalt angezeigt wird

Die Komponente sollte eine Eigenschaft content haben, die ein String ist, um den aktuellen Inhalt anzeigen zu können.

HINWEIS: Derzeit musst du die Formular-ID page-content für die Inhaltsausgabe verwenden. Dein Editor sollte auch in der Lage sein, die Formularübermittlung zu verarbeiten.

HINWEIS: Du kannst studiocms/markdown oder studiocms/html als Fallback-Wert verwenden, wenn du mit HTML- oder Markdown-Inhalten arbeitest!

@example

import { createResolver } from 'astro-integration-kit';
const { resolve } = createResolver(import.meta.url)
{
pageContentComponent: resolve('./components/MyContentEditor.astro'),
}

pageContentComponent
: 'studiocms/markdown' | 'studiocms/html' | string;
/**
* Der Pfad zu der tatsächlichen Komponente, die für den Seitenrenderer angezeigt wird
*
* **HINWEIS:** Du kannst `studiocms/markdown` oder `studiocms/html` als Fallback-Wert verwenden, wenn du mit HTML- oder Markdown-Inhalten arbeitest!
*/
rendererComponent: string

Der Pfad zu der tatsächlichen Komponente, die für den Seitenrenderer angezeigt wird

HINWEIS: Du kannst studiocms/markdown oder studiocms/html als Fallback-Wert verwenden, wenn du mit HTML- oder Markdown-Inhalten arbeitest!

rendererComponent
: 'studiocms/markdown' | 'studiocms/html' | string;
/**
* Felder gemäß Spezifikation
*/
fields: ({
name: string;
label: string;
input: "checkbox";
required?: boolean | undefined;
readOnly?: boolean | undefined;
color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
defaultChecked?: boolean | undefined;
size?: "sm" | "md" | "lg" | undefined;
} | ... 4 more ... | {
...;
})[]

Felder gemäß Spezifikation

fields
:
type SettingsField = {
name: string;
label: string;
input: "checkbox";
required?: boolean | undefined;
readOnly?: boolean | undefined;
color?: "primary" | "success" | "warning" | "danger" | "info" | "mono" | undefined;
defaultChecked?: boolean | undefined;
size?: "sm" | "md" | "lg" | undefined;
} | ... 4 more ... | {
...;
}

Represents the type inferred from the SettingsFieldSchema schema.

This type is used to define the structure of settings fields within the application.

SettingsField
[];
/**
* API-Endpunktdatei für den Seitentyp
*
* API-Endpunkte werden verwendet, um Seiten dieses Typs zu erstellen, zu bearbeiten und zu löschen,
* Endpunkte erhalten den vollständigen Astro APIContext von der Astro APIRoute.
*
* Die Datei sollte mindestens einen der folgenden Punkte exportieren:
* - `onCreate`
* - `onEdit`
* - `onDelete`
*
* @example
* ```ts
* // my-plugin.ts
* import { createResolver } from 'astro-integration-kit';
* const { resolve } = createResolver(import.meta.url)
*
* {
* apiEndpoint: resolve('./api/pageTypeApi.ts'),
* }
*
* // api/pageTypeApi.ts
* import { APIRoute } from 'astro';
*
* export const onCreate: APIRoute = async (ctx) => {
* // Custom logic here
* return new Response();
* }
* ```
*/
apiEndpoint: string

API-Endpunktdatei für den Seitentyp

API-Endpunkte werden verwendet, um Seiten dieses Typs zu erstellen, zu bearbeiten und zu löschen, Endpunkte erhalten den vollständigen Astro APIContext von der Astro APIRoute.

Die Datei sollte mindestens einen der folgenden Punkte exportieren:

  • onCreate
  • onEdit
  • onDelete

@example

// my-plugin.ts
import { createResolver } from 'astro-integration-kit';
const { resolve } = createResolver(import.meta.url)
{
apiEndpoint: resolve('./api/pageTypeApi.ts'),
}
// api/pageTypeApi.ts
import { APIRoute } from 'astro';
export const onCreate: APIRoute = async (ctx) => {
// Custom logic here
return new Response();
}

apiEndpoint
: string;
}> | undefined;
};

Um ein StudioCMS-Plugin zu definieren, musst du ein Objekt erstellen, das dem Typ StudioCMSPlugin entspricht. Dieses Objekt sollte ähnlich wie das folgende aussehen, wobei du beachten musst, dass die folgenden Eigenschaften erforderlich sind:

  • identifier: Der Bezeichner des Plugins aus der package.json-Datei.
  • name: Die Bezeichnung des Plugins, die im StudioCMS Dashboard angezeigt werden soll.
  • studiocmsMinimumVersion: Die Mindestversion von StudioCMS, die benötigt wird, damit das Plugin funktioniert.

Hier ist ein Beispiel für eine StudioCMS-Plugin-Definition, die alle erforderlichen Eigenschaften enthält und eine Astro-Integration für eigene Logik bereitstellt:

my-plugin.ts
import {
function definePlugin(options: StudioCMSPluginOptions): StudioCMSPlugin

Defines a plugin for StudioCMS.

@paramoptions - The configuration options for the plugin.

@returnsThe plugin configuration.

definePlugin
} from 'studiocms/plugins';
import {
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
} from 'astro';
// Definiere die Optionen für das Plugin und die Integration
interface
interface Options
Options
{
Options.foo: string
foo
: string;
}
// Definiere die Astro-Integration
const
const myIntegration: (options: Options) => AstroIntegration
myIntegration
= (
options: Options
options
:
interface Options
Options
):
(alias) interface AstroIntegration
import AstroIntegration
AstroIntegration
=> ({
AstroIntegration.name: string

The name of the integration.

name
: 'my-astro-integration',
AstroIntegration.hooks: {
'astro:config:setup'?: (options: {
config: AstroConfig;
command: "dev" | "build" | "preview" | "sync";
isRestart: boolean;
updateConfig: (newConfig: DeepPartial<AstroConfig>) => AstroConfig;
addRenderer: (renderer: AstroRenderer) => void;
addWatchFile: (path: URL | string) => void;
injectScript: (stage: InjectedScriptStage, content: string) => void;
injectRoute: (injectRoute: InjectedRoute) => void;
addClientDirective: (directive: ClientDirectiveConfig) => void;
addDevToolbarApp: (entrypoint: DevToolbarAppEntry) => void;
addMiddleware: (mid: AstroIntegrationMiddleware) => void;
createCodegenDir: () => URL;
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
... 10 more ...;
'astro:routes:resolved'?: (options: {
routes: IntegrationResolvedRoute[];
logger: AstroIntegrationLogger;
}) => void | Promise<void>;
} & Partial<...>

The different hooks available to extend.

hooks
: {
"astro:config:setup": () => {
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
('Hello from my Astro Integration!');
}
}
});
// Definiere das StudioCMS-Plugin
export const
const myPlugin: (options: Options) => StudioCMSPlugin
myPlugin
= (
options: Options
options
:
interface Options
Options
) =>
function definePlugin(options: StudioCMSPluginOptions): StudioCMSPlugin

Defines a plugin for StudioCMS.

@paramoptions - The configuration options for the plugin.

@returnsThe plugin configuration.

definePlugin
({
identifier: string
identifier
: 'my-plugin',
name: string
name
: 'My Plugin',
studiocmsMinimumVersion: string
studiocmsMinimumVersion
: '0.1.0-beta.8',
integration?: AstroIntegration | AstroIntegration[] | undefined
integration
:
const myIntegration: (options: Options) => AstroIntegration
myIntegration
(
options: Options
options
), // Optional, aber empfohlen
});

In diesem Beispiel definieren wir ein StudioCMS-Plugin namens My Plugin, das StudioCMS Version 0.1.0-beta.8 oder höher benötigt. Das Plugin stellt außerdem eine Astro-Integration bereit, die eine Meldung auf der Konsole protokolliert, wenn der astro:config:setup-Hook aufgerufen wird.

Weitere Informationen zur Erstellung von Plugins findest du in der „Plugins nützlich machen“-Anleitung.