Bitcart plugins are modular components that can extend the functionality of your Bitcart instance. A plugin can consist of one or more of the following components:
- Backend: Server-side logic, database models, and API endpoints
- Admin: Extensions to the admin panel UI
- Store: Customizations for the store frontend
- Docker: Docker compose deploy customizations
To create a new plugin, use the Bitcart CLI:
bitcart-cli plugin init .
This will guide you through creating a new plugin by asking for:
- Plugin name
- Author
- Description
- Component types to include
To install plugin to develop alongside bitcart, you can use bitcart-cli plugin install .
It is recommended to pass --dev
flag to install plugin in development mode. It uses symlinks to link the plugin to the bitcart source code, so when you make changes to the plugin, they are reflected immediately.
It asks for paths where you cloned bitcart, bitcart-admin and other repositories. You can pass --save
flag to save paths to config, so that it is never asked again.
After you are done developing and want to remove it from codebase:
bitcart-cli plugin uninstall your_plugin_name
A backend plugin must have a plugin.py
file which as a Plugin
class that implements the BasePlugin
class from api.plugins
. The basic structure is:
from api.plugins import BasePlugin
class Plugin(BasePlugin):
name = "your_plugin_name"
def setup_app(self, app):
# Configure FastAPI app, add routes
pass
async def startup(self):
# Initialize plugin, register hooks
pass
async def shutdown(self):
# Cleanup resources
pass
async def worker_setup(self):
# Setup background tasks
pass
To add custom database tables:
- Create a
models.py
file in your plugin directory - Define SQLAlchemy models
- Manage migrations using alembic:
python scripts/pluginmigrate.py your_plugin_name revision --autogenerate -m "Migration message"
python scripts/pluginmigrate.py your_plugin_name upgrade head
Basically same commands as alembic, but you provide your plugin name.
This will create a new migration in the versions/
directory. Migrations are automatically applied when the plugin is loaded.
Bitcart provides two extension mechanisms:
- Hooks: Execute actions at specific points
- Filters: Modify data as it flows through the system
from api.plugins import register_hook, register_filter
# Register a hook
register_hook("event_name", async_handler_function)
# Register a filter
register_filter("filter_name", async_filter_function)
To find hooks and filters, you can search the codebase for apply_filters
and run_hook
.
For example, db_modify_wallet
would be called right after wallet is saved in db.
So you can use it like this:
from api.plugins import register_hook
class Plugin(BasePlugin):
...
async def startup(self):
register_hook("db_modify_wallet", self.my_hander)
async def my_handler(self, wallet):
print(wallet)
And in filters first argument you receive is the value which you can return unmodified or modify. Other arguments are optional data
Example:
from api.plugins import register_filter, SKIP_PAYMENT_METHOD
class Plugin(BasePlugin):
...
async def startup(self):
register_filter("create_payment_method", self.create_payment_method)
async def create_payment_method(self, method, wallet, coin, amount, invoice, product, store, lightning):
# multiple options:
# return SKIP_PAYMENT_METHOD # skip this method, e.g. if error occured
# return method # fallback to bitcart default code, e.g. call add_request on the daemon
return {
"payment_address": "youraddress",
"payment_url": "willbeinsideqrcode",
"lookup_field": "for your reference",
"metadata": {"somekey": "somevalue"},
}
To add custom settings for your plugin:
from pydantic import BaseModel
from api.plugins import register_settings
class PluginSettings(BaseModel):
setting1: str = ""
setting2: bool = False
register_settings("your_plugin_name", PluginSettings)
Settings are automatically available in the admin panel and can be accessed via:
from api.plugins import get_plugin_settings
settings = await get_plugin_settings("your_plugin_name")
If you need to add backend dependencies, create a requirements.txt file in your plugin directory, it will be installed automatically.
your_plugin_name/
├── requirements.txt
Admin plugins can extend the UI using the our plugin system based on vuems. The basic structure is in e.g. admin/your_plugin_name
:
your_plugin_name/
├── config/
│ ├── extends.js # Component and dictionary registration
│ ├── index.js # Plugin configuration
│ └── routes.js # Custom routes
├── pages/ # Custom pages
└── components/ # Custom components
└── package.json # dependencies
- Register custom components in
extends.js
:
export default {
extendComponents: {
// Add components to specific UI slots
'dashboard-widgets': [MyWidget],
'invoice-details': [CustomInvoiceInfo]
},
dictionaries: {
// Add custom data dictionaries
'my-data': { /* ... */ }
}
}
- Add custom routes in
routes.js
:
import CustomPage from '../pages/CustomPage'
export default [
{
name: 'custom-page',
path: '/custom',
component: CustomPage
}
]
- Add dependencies to
package.json
Store plugins follow a similar structure to admin plugins but are specifically for the store frontend. They can:
- Add custom pages
- Extend existing components
- Add new payment methods
- Customize the checkout process
To package your plugin:
bitcart-cli plugin package .
This creates a .bitcart
file that can be installed on any Bitcart instance.
- Use descriptive names for hooks and filters
- Document your plugin's requirements and dependencies
- Handle errors gracefully
- Clean up resources in the shutdown method
- Follow the existing code style
- Test your plugin thoroughly before distribution
- Plugin discovery and loading
- Database migrations
- Plugin initialization (startup)
- Hook/filter registration
- Settings registration
- UI component registration (if applicable)
- Background worker setup (if needed)
- Shutdown cleanup on server stop