View .md

Plugin FAQ

Common questions about writing FeatherPanel plugins, from identifiers and namespaces to settings, worker mode, CLI commands and mixins.

On this page

Names and structure

Which characters can an identifier use?

Letters, digits and _ only. my-plugin is rejected. The identifier is also the folder name and the namespace segment, App\Addons\<identifier>, and all three must match exactly.

Does the entry class have to be named after plugin.name?

Yes. The loader looks for App\Addons\<identifier>\<plugin.name>. If that class does not exist it falls back to a single class in the plugin root that implements AppPlugin, but the package installer insists on the exact match, so keep the class, the file name and plugin.name identical.

Where do my other classes go?

Anywhere under the plugin folder, in a namespace that matches the path. Composer maps App\Addons\ to backend/storage/addons/. Controllers/, Chat/ (models), Services/, Middleware/ and Events/ are conventions, not requirements. A controller is not a route by itself; a file in Routes/ has to call it.

Which sidebars can a plugin add pages to?

client (the user dashboard), admin, server, vds and webspace. Other top-level keys in sidebar.json are ignored. See Frontend and Power SDK.

Settings and data

Why is my setting empty even though conf.yml has a default?

The default of a config field is the placeholder of the form field and is never saved. Write real defaults in pluginInstall() and fall back in code. See Settings.

Can I create my own tables?

Yes, with SQL files in Migrations/. Prefix table names with featherpanel_<identifier>_. See Migrations and storage.

Are my tables removed on uninstall?

No. Uninstall calls pluginUninstall(), deletes the plugin files and links, and leaves the database alone. Drop your tables and delete your settings in pluginUninstall() if that is what users expect.

Runtime

Does processEvents() run on every request?

Only in classic mode. The Docker image serves the API in FrankenPHP worker mode, where processEvents() runs once when each worker starts. Register listeners there and keep request-specific state out of it. See Middleware and router hooks.

How do I reload my PHP code while developing?

Click Resync on the plugin page or save one of its settings: a successful change under /api/admin/plugins makes every worker restart. Restarting the backend container works too. Setting FRANKENPHP_WORKER=false on the backend container turns worker mode off, so every request loads the code again.

Can a listener stop a request?

Yes. Exceptions thrown in listeners are not caught by the event manager, so the request that emitted the event fails. Catch your own exceptions.

Can a plugin add commands to php cli?

Yes, with classes in Commands/. On v1.5.2 and earlier the CLI only finds them when it runs from the repository root, so they do not show up through the Docker wrapper. Finding them from any directory is fixed in v1.5.3 (PR #365). See Cron jobs and CLI commands.

Can a plugin change core PHP classes with mixins?

Not on v1.5.2 and earlier. The panel contains a mixin framework (App\Plugins\Mixins) and conf.yml accepts a mixins map, but nothing registers mixins when the panel starts. Registration is fixed in v1.5.3 (PR #365). Even then the panel ships no built-in mixins: a mixin is a class added to backend/app/Plugins/Mixins/Custom/, not something a plugin uses to patch core classes. Use events, routes, middleware and UI packs instead. See conf.yml: mixins.

Can a plugin change the look of the panel?

Yes. Theme packs change colours and CSS, UI packs and overrides.json hide or replace parts of the layout. See Themes and UI packs.

Documentation

Where else are plugins documented?

The panel ships its own developer docs, called icanhasfeatherpanel, at /icanhasfeatherpanel/ on your panel and on GitHub Pages. See icanhasfeatherpanel developer docs.

Is there a template I can start from?

Yes. Admin > Dev > Plugins > Create Plugin generates a plugin from the Empty, Fresh, Starter, Theme pack or UI pack template. Developer mode must be on. Build your first plugin walks through a small plugin by hand.

Frequently asked questions

Can a plugin identifier contain a hyphen?

No. Identifiers may only contain letters, digits and underscores. Use my_plugin or myplugin instead of my-plugin.

Are plugin classes autoloaded?

Yes. Composer maps the App\Addons\ namespace to backend/storage/addons/, so App\Addons\myplugin\Services\Sync is loaded from storage/addons/myplugin/Services/Sync.php.

Do plugins survive a panel update?

Yes. Plugins live in storage/addons, which is the featherpanel_addons volume in Docker. The backend runs php cli migrate on start, which also runs plugin migrations that have not run yet.