# Plugin FAQ

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

Source: https://featherpanel.com/docs/plugins/faq/

## 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](https://featherpanel.com/docs/plugins/frontend/).

## 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](https://featherpanel.com/docs/plugins/settings/).

### Can I create my own tables?

Yes, with SQL files in `Migrations/`. Prefix table names with `featherpanel_<identifier>_`. See
[Migrations and storage](https://featherpanel.com/docs/plugins/database/).

### 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](https://featherpanel.com/docs/plugins/middleware-and-hooks/#worker-mode).

### 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](https://github.com/MythicalLTD/FeatherPanel/pull/365)). See
[Cron jobs and CLI commands](https://featherpanel.com/docs/plugins/cron-and-commands/#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](https://github.com/MythicalLTD/FeatherPanel/pull/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](https://featherpanel.com/docs/plugins/manifest/#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](https://featherpanel.com/docs/plugins/themes/).

## 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](https://featherpanel.com/docs/plugins/icanhasfeatherpanel/).

### 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](https://featherpanel.com/docs/plugins/quick-start/) walks through a small plugin
by hand.

## Related

- [Debugging plugins](https://featherpanel.com/docs/plugins/debugging/)
- [Plugin overview](https://featherpanel.com/docs/plugins/)

## 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.
