Package Development
QUIQQER extensions are Composer packages with QUIQQER-specific package types and optional XML configuration files.
For normal feature work, create or extend a package. Do not change the base system unless you are explicitly working on the platform itself.
Extension Model
A QUIQQER package can add PHP code, templates, JavaScript, CSS, images, console commands, backend entries, settings, permissions, events, widgets, and database changes. The exact behavior is declared through Composer metadata, PHP classes, assets, and optional XML files.
Package-level building blocks:
composer.jsondefines the package name, type, dependencies, autoloading, and developer scripts.package.xmldescribes package metadata, support links, images, languages, and providers.src/contains package PHP classes loaded through Composer autoloading.bin/contains browser-accessible package assets such as JavaScript, CSS, images, and administration components.- XML files register optional behavior such as events, console commands, menus, settings, permissions, widgets, and database changes.
Providers
A provider is a PHP class that a package registers for a named extension point. QUIQQER or another package reads that provider declaration and calls the class through the API expected by that extension point.
Providers are declared in package.xml:
<quiqqer>
<package>
<provider>
<desktopSearch src="\Vendor\Package\Search\Provider"/>
<installationWizard src="\Vendor\Package\Setup\Wizard"/>
</provider>
</package>
</quiqqer>The XML node name is the provider type. The src attribute points to an autoloadable PHP class. The required interface or base class depends on the provider type.
Core provider types include auth, desktopSearch, installationWizard, rest, and mcp. Packages can also define their own provider APIs. For example, a package can read provider declarations from installed packages and load classes registered for its own provider type.
Declare a provider only when the package implements the corresponding API. If a package only uses events, XML files, templates, or console commands, it does not need a provider declaration.
Package Structure
A package starts with Composer metadata and adds only the files it needs for its feature set.
Typical structure:
my-package/
├─ composer.json
├─ package.xml
├─ locale.xml
├─ permissions.xml
├─ events.xml
├─ database.xml
├─ menu.xml
├─ site.xml
├─ src/
│ └─ Vendor/
│ └─ Package/
└─ bin/
├─ images/
├─ css/
└─ js/Not every package needs every XML file. A package that only provides reusable PHP functionality may only need composer.json and PHP classes. A package that adds backend functionality may add menu.xml, permissions.xml, locale.xml, and events.xml. A template package usually focuses on presentation files, settings, and frontend assets.
Composer Metadata
Every QUIQQER package needs a valid composer.json. Use the package type that matches the package's purpose.
| Composer type | Meaning |
|---|---|
quiqqer-module | Default type for extension packages. |
quiqqer-template | Project presentation package. |
quiqqer-asset | Browser asset package generated from selected npm packages for QUIQQER. |
quiqqer-asset packages are not normal extension packages. They wrap selected browser libraries for Composer-based installation and are provided through the QUIQQER asset repository.
Use quiqqer-module for new extension packages unless the package is clearly a template package. In public documentation, use "package" as the umbrella term. The Composer type is implementation metadata and should only be discussed when it affects setup or installation.
Existing packages can use additional package types for historical or specialized reasons. New extension documentation should use quiqqer-module as the default type.
Minimal composer.json
Use Composer's standard fields plus a QUIQQER package type and dependencies. Modern packages should depend on quiqqer/core instead of the older quiqqer/quiqqer package name.
{
"name": "vendor/package-name",
"type": "quiqqer-module",
"description": "Short package description.",
"license": "GPL-3.0-or-later",
"require": {
"php": "^8.1",
"quiqqer/core": "^2"
},
"autoload": {
"psr-4": {
"Vendor\\Package\\": "src/Vendor/Package"
}
}
}Real packages often add support information, authors, development scripts, suggested packages, and additional QUIQQER or asset dependencies.
Current free packages such as quiqqer/bricks, quiqqer/cron, and quiqqer/cache are useful orientation points for real package layout: they use QUIQQER package types, depend on quiqqer/core, define PSR-4 namespaces under src/, and keep repository checks in Composer scripts.
Autoloading
QUIQQER packages use Composer autoloading. Current package examples commonly use PSR-4 namespaces that point into src/.
Example shape:
{
"autoload": {
"psr-4": {
"Vendor\\Package\\": "src/Vendor/Package"
}
}
}package.xml
Use package.xml when the package should expose package metadata to QUIQQER. Typical metadata includes:
- localized title and description
- package logo
- preview images
- support links
- copyright and license information
- provider declarations
Example shape:
<quiqqer>
<package>
<title>
<locale group="vendor/package-name" var="package.title"/>
</title>
<description>
<locale group="vendor/package-name" var="package.description"/>
</description>
<image src="URL_OPT_DIR/vendor/package-name/bin/images/logo.jpg"/>
<support>
<email>support@example.com</email>
<source>https://dev.example.com/vendor/package-name</source>
<issues>https://dev.example.com/vendor/package-name/-/issues</issues>
</support>
</package>
</quiqqer>XML Files By Use Case
Add XML files only for the behavior your package provides:
| Use case | File |
|---|---|
| Register console tools | console.xml |
| Create or update database tables | database.xml |
| Listen to events | events.xml |
| Provide translations | locale.xml |
| Add backend menu entries | menu.xml |
| Add media attributes | media.xml |
| Add permissions | permissions.xml |
| Add package or project settings | settings.xml |
| Add site-related behavior | site.xml |
| Add user-related behavior | user.xml |
| Add desktop widgets | widgets.xml |
See XML configuration files for the current XML overview.
See composer.json for detailed package metadata and Development Installs for installing Git repositories or development branches into a QUIQQER system.
Runtime Paths
QUIQQER exposes installation paths through PHP constants. Package code, templates, and frontend scripts use them when they need filesystem paths or public URLs for packages, projects, assets, runtime data, and templates.
| Constant | Purpose |
|---|---|
CMS_DIR | Root path of the installed QUIQQER system. |
LIB_DIR | Platform library path. |
BIN_DIR | Binary and asset path. |
USR_DIR | Project path. |
VAR_DIR | Runtime data path for logs, sessions, cache, lock files, temporary files, and similar data. |
OPT_DIR | Package path. |
SYS_DIR | Admin/system configuration path. |
URL constants such as URL_OPT_DIR, URL_USR_DIR, and URL_VAR_DIR are used when package assets need to be referenced publicly.
Frontend Assets
Place package assets under bin/ when they must be available to the browser. Package metadata and templates commonly reference assets through URL_OPT_DIR.
Current packages use quiqqer-asset/* dependencies for browser libraries. Older wiki pages mention npm-asset/* and bower-asset/*; do not use those examples as the default for new documentation.
Development Scripts
Many current packages expose package-local checks through Composer scripts:
{
"scripts": {
"test": [
"@dev:lint",
"@dev:phpunit"
],
"dev:phpunit": "./tools/phpunit",
"dev:lint": [
"@dev:lint:phpstan",
"@dev:lint:style"
],
"dev:lint:phpstan": "./tools/phpstan",
"dev:lint:style": "./tools/phpcs",
"dev:lint:style:fix": "./tools/phpcbf"
}
}Use these scripts when the package has the corresponding tools installed. Otherwise, document the package-specific test and lint workflow in its README.
Practical Checklist
Before publishing a package:
- Validate
composer.json. - Choose the correct
quiqqer-*package type. - Add
package.xmlif the package needs visible metadata or providers. - Add only the XML files the package actually needs.
- Keep translations in
locale.xml. - Put browser-accessible assets in
bin/. - Configure Composer autoloading for PHP classes.
- Run package linting and tests if developer tooling is available.
