Plugin Development: Getting Started
Learn how to create plugins that extend LusterCMS functionality.
Overview
Plugins in LusterCMS can:
- ✅ Add new admin pages and UI components
- ✅ Extend the GraphQL and REST APIs
- ✅ Create database tables and models
- ✅ Hook into content lifecycle events
- ✅ Add custom editor blocks
- ✅ Integrate with external services
Prerequisites
- Python 3.11+
- Familiarity with FastAPI and SQLAlchemy
- Basic understanding of GraphQL (Strawberry)
- React/TypeScript for frontend components
Creating Your First Plugin
Step 1: Create Plugin Directory
mkdir -p plugins/my_plugin
cd plugins/my_plugin
Step 2: Create Plugin Manifest
Create plugin.json:
{
"name": "my_plugin",
"version": "1.0.0",
"description": "My awesome plugin",
"author": "Your Name",
"entry_point": "plugin.py",
"frontend_entry": "frontend/index.ts",
"dependencies": [],
"permissions": ["content.read", "content.write"]
}
Step 3: Create Main Plugin File
Create plugin.py:
from core.hooks import hookimpl
from core.plugins.base import PluginBase
class MyPlugin(PluginBase):
"""My awesome plugin."""
name = "my_plugin"
version = "1.0.0"
@hookimpl
def after_content_save(self, entry_id: str) -> None:
"""Called after content is saved."""
print(f"Content saved: {entry_id}")
@hookimpl
def after_content_publish(self, entry_id: str) -> None:
"""Called after content is published."""
print(f"Content published: {entry_id}")
# Plugin instance
plugin = MyPlugin()
Step 4: Add GraphQL Schema (Optional)
Create resolvers.py:
import strawberry
from typing import List
@strawberry.type
class MyPluginData:
id: str
name: str
value: int
@strawberry.type
class MyPluginQuery:
@strawberry.field
def my_plugin_items(self) -> List[MyPluginData]:
"""Get all items from my plugin."""
return [
MyPluginData(id="1", name="Item 1", value=100),
MyPluginData(id="2", name="Item 2", value=200),
]
@strawberry.type
class MyPluginMutation:
@strawberry.mutation
def create_my_plugin_item(self, name: str, value: int) -> MyPluginData:
"""Create a new item."""
# Your logic here
return MyPluginData(id="new", name=name, value=value)
Step 5: Add Frontend Components (Optional)
Create frontend/index.ts:
// Export your plugin's frontend components
export { MyPluginPage } from './pages/MyPluginPage';
export { MyPluginWidget } from './components/MyPluginWidget';
Create frontend/pages/MyPluginPage.tsx:
import React from 'react';
import { Box, Typography, Card } from '@mui/material';
export const MyPluginPage: React.FC = () => {
return (
<Box sx={{ p: 3 }}>
<Typography variant="h4" gutterBottom>
My Plugin
</Typography>
<Card sx={{ p: 2 }}>
<Typography>
This is my custom plugin page!
</Typography>
</Card>
</Box>
);
};
Step 6: Register the Plugin
The plugin is automatically discovered when placed in the plugins/ directory. Enable it via:
Admin UI:
- Go to Plugins
- Find "My Plugin"
- Click Enable
GraphQL:
mutation EnablePlugin {
setPluginEnabled(name: "my_plugin", enabled: true)
}
CLI:
python -m cli.cms_cli enable-plugin my_plugin
Plugin Structure
Complete plugin structure:
plugins/my_plugin/
├── __init__.py # Package init
├── plugin.py # Main plugin class with hooks
├── plugin.json # Plugin manifest
├── models.py # SQLAlchemy models (optional)
├── resolvers.py # GraphQL resolvers (optional)
├── routes.py # REST endpoints (optional)
├── services.py # Business logic (optional)
├── migrations/ # Database migrations (optional)
│ ├── __init__.py
│ └── 0001_init.sql
├── frontend/ # React components (optional)
│ ├── index.ts
│ ├── pages/
│ └── components/
└── tests/ # Plugin tests (optional)
└── test_plugin.py
Next Steps
- Plugin Anatomy — Detailed structure explanation
- Hooks Reference — Available lifecycle hooks
- GraphQL Extensions — Extend the API
- Frontend Components — Build UI
💡 Pro Tip
Check out the plugins/example/ directory for a reference implementation.