Skip to content

Upgrading from 0.7.x to 0.8.0

The 0.8.0 release includes significant database, structural, and frontend changes. Read every section below before upgrading.

The minimum PHP version has been raised from 8.1 to 8.3. Verify your server meets this requirement before upgrading.

The database charset has been migrated from utf8 to utf8mb4 / utf8mb4_unicode_ci. The patcher handles this automatically.

  • db.type has been renamed to db.driver and its value changed from 'mysql' to 'pdo_mysql'. The patcher migrates this for you.
  • Old api.rate_* settings (rate_span, rate_limit, throttle_delay, rate_span_login, rate_limit_login, rate_limit_whitelist) have been replaced by the new rate_limiter block. The patcher will prompt you to accept the new defaults.
  • The url setting no longer stores the protocol prefix; it is stripped on save.
  • New security.trusted_proxies block for configuring reverse proxy trust.
  • New security.session_regeneration_grace_period setting (default: 300).
  • New i18n.auto_detect_locale, i18n.date_format, i18n.time_format, i18n.datetime_pattern settings.

The following modules have been removed or replaced. The patcher handles the migration automatically, but you may need to review your configuration afterward:

ChangeDetails
Servicemembership removedMembership products and orders are migrated to the "custom" product type. Review active membership orders after updating.
Spamchecker replacedReplaced by the new Antispam module (supports Cloudflare Turnstile, hCaptcha, and honeypot fields). Review your spam-protection settings after the update.
Wysiwyg removedCKEditor 5 is now integrated directly into themes. Use the wysiwyg Twig function to initialize editors.
Paidsupport removedModule data is cleaned up.
Added AntispamNew spam-prevention module with multiple challenge providers.
Added WidgetsNew module for registering renderable widget slots in templates.

The uploads directory has moved from /uploads to /data/uploads. Files are migrated automatically. If you have web-server rules referencing the old path, update them:

# Old rule (0.7.x):
location ~* /uploads/.*\.php$ { return 403; }
# Updated for 0.8.0:
location ^~ /data/ { return 403; }

Module templates have been moved from the old html_* directory names to a templates/ structure. Theme directories (html/ and html_custom/) are unchanged.

Old pathNew path
modules/{Module}/html_admin/modules/{Module}/templates/admin/
modules/{Module}/html_client/modules/{Module}/templates/client/
modules/{Module}/html_email/modules/{Module}/templates/email/

The patcher removes the old html_* directories from modules. If you have custom modules, update your file structure before applying the patches, or the old directories will be deleted and you will lose your changes.

Shared browser assets now live in /public instead of /data/assets or theme-specific fallback paths:

AssetNew location
Gateway icons/public/gateways/
Default logo, dark logo, and favicon/public/branding/
Shared JavaScript, Markdown CSS, and CKEditor bundles/public/assets/

The patcher migrates bundled gateway icons and default branding settings automatically. If you maintain custom web-server rules, make sure /public remains publicly readable while /data remains blocked.

The front-end build system has been migrated from Webpack Encore to esbuild.

  • Bundled theme package.json scripts now call local esbuild.mjs files instead of Webpack Encore. Huraga's dev script uses node ./esbuild.mjs --watch; admin_default uses node ./esbuild.mjs for both dev and build.
  • Shared build helpers are in frontend/tools/esbuild-helpers.mjs (at the repository root).
  • Theme-specific build scripts are at src/themes/{theme}/esbuild.mjs.

If you maintain a custom theme with its own build pipeline, update it for the new asset structure and Twig loading pattern. You can keep another build tool if it outputs compatible assets, but the bundled huraga and admin_default themes now use esbuild and are the best reference implementations.

Replace encore_entry_link_tags / encore_entry_script_tags with direct CSS and JS asset tags:

{{ encore_entry_link_tags('fossbilling') }}
{{ "Api/API.js" | library_url | script_tag }}
{{ encore_entry_script_tags('fossbilling') }}

jQuery has been removed from both bundled themes. All admin and client templates have been migrated to vanilla JavaScript.

  • The old bb JavaScript object and bb.redirect() no longer exist. Use window.location instead.
  • $(function() { ... })document.addEventListener("DOMContentLoaded", function() { ... })
  • Any custom theme or module JavaScript that depends on jQuery must be rewritten.

The JS API wrapper has been rewritten and moved from library/Api/API.js to frontend/core/api.js. The browser call pattern (API.admin.post, API.client.get, API.guest.get, etc.) remains compatible, and the related Twig helpers (fb_api_form, fb_api_link) are still available, but the internal implementation is entirely new.

Load it with:

{{ 'js/fossbilling.js' | public_asset_url | script_tag }}
{{ 'js/api.js' | public_asset_url | script_tag }}

The old library_url filter used for {{ "Api/API.js" | library_url | script_tag }} has been removed.

Shared frontend source code has moved to a new frontend/ directory at the repository root:

frontend/
├── core/
│ ├── api.js # JavaScript API wrapper
│ └── fossbilling.js # Runtime helpers (message toasts, request utilities)
├── editor/
│ └── ckeditor.js # CKEditor 5 bundle
├── styles/
│ └── markdown.css # Markdown content styling
└── tools/
└── esbuild-helpers.mjs # Shared build utilities

The DebugBar_renderHead() Twig function has been renamed to debug_bar_render_head():

{{ DebugBar_renderHead() }}

The <meta name="csrf-token" content="{{ CSRFToken }}"> tag has been removed from bundled themes. CSRF tokens are now sent via cookie (csrf_token) and handled automatically by the JavaScript API wrapper. If your custom theme relies on the meta tag, switch to reading the cookie:

const token = document.cookie.match(/csrf_token=([^;]*)/)?.[1] || '';

Build output is written to theme/public asset directories such as src/public/assets, not to a tracked frontend/build directory.

Available Twig globals to review when updating custom templates include:

GlobalDescription
app_area"admin" or "client"
current_themeThe active theme code
requestQuery parameters from the current request
request_queryOriginal query parameters array
request_pathNormalized route path
request_has_filtersBoolean indicating active filters in the request
default_currencyThe default currency code
FOSSBillingVersionThe current version string

The following filters have been removed:

Removed filterReplacement
alinkurl with area: 'admin'{{ 'staff/login' | url({area: 'admin'}) }}
linkurl{{ 'order' | url }}
gravataravatar function — {{ avatar(email, 80) }} (uses DiceBear locally)
library_urlpublic_asset_url
markdownmarkdown_to_html{{ content | markdown_to_html }}
sizefile_size{{ 1048576 | file_size }}
numberformat_number (from Twig Intl Extra)
money / money_without_currencyformat_currency{{ 29.99 | format_currency('USD') }}
money_convert / money_convert_without_currencyNo direct Twig filter replacement. Convert the amount before rendering, then format it with format_currency.
img_tagUse standard <img> HTML
iplookupRemoved.
ipcountrynameRenamed to ip_country_name
autolinkRemoved.

The following filters and functions have been added:

New filter/functionDescription
public_asset_urlURL for shared core assets in /public
urlNow accepts area parameter ('admin' / 'client') to replace both old alink and link
has_permissionCheck admin module permission in templates
render_widgetsRender widgets for a named slot
svg_spriteRender the theme's SVG icon sprite
antispam_honeypotReturn honeypot configuration array
wysiwygInitialize CKEditor 5 on a textarea selector
avatarGenerate DiceBear avatar image for an email address
script_tagGenerate <script> tag with cache-busting hash
stylesheet_tagGenerate <link> stylesheet tag with cache-busting hash
file_sizeFormat bytes to human-readable size (replaces size)
hashHash a value (defaults to xxh128)
api_urlSupports role parameter to override the API area

Key template changes in both bundled themes (admin_default and huraga):

  • <html lang="en"><html lang="{{ active_locale }}"> where active_locale is derived from the active locale.
  • <meta property="bb:url"> and <meta property="bb:client_area"> removed.
  • <meta name="csrf-token"> removed (see CSRF section above).
  • encore_entry_link_tags / encore_entry_script_tags → direct asset links (see above).
  • Old admin redirect bb.redirect(...)window.location = ....
  • The macro_functions.html.twig import removed from layout files; macros are now loaded individually.
  • Language selectors use js-locale-selector class instead of js-language-selector.
  • New widget slots: {{ render_widgets('client.theme.body.start') }} in Huraga.
  • Dashboard cards rewritten with AJAX-loaded content.
  • Tables, pagination, forms, and search have been revamped with new markup and CSS.

The guest API has been hardened to expose less information publicly:

  • The guest system/version API action (guest.system_version in Twig) has been removed — versions are no longer disclosed to unauthenticated callers.
  • guest.system_company() hides extra company fields from unauthenticated callers when the hide_company_public setting is enabled.
  • guest.system_phone_codes() no longer accepts a country parameter for single-code lookups; it returns all codes.
  • guest.support_ticket_create() now requires name, email, subject, and message parameters through the RequiredParams attribute. Rate limiting is enforced.
  • Messages submitted via guest ticket creation are now sanitized to prevent XSS.

If your integration depends on any of these guest endpoints, update accordingly.

The custom HTTP and routing layer (Box_App, Box_AppAdmin, Box_AppClient) has been replaced by Symfony's HttpKernel, HttpFoundation, and Routing components.

  • Box_App still exists and exposes $app->get(), $app->post(), $app->render() for backward compatibility in module controllers.
  • Box_App::run() now returns a Symfony\Component\HttpFoundation\Response instead of a string.
  • Box_App::show404() returns a Response object instead of echoing and exiting.
  • Module controllers can return Response objects directly.
  • New HttpResponseException allows aborting with a response from anywhere in the call stack.
  • RequestFactory normalizes route paths from Symfony's Request object.

The Box_Mod class has been reworked into FOSSBilling\Module:

$mod = new Box_Mod('Example');

The new class uses Symfony Filesystem/Path components internally and supports additional methods like hasSettingsPage(), hasClientController(), and hasAdminController().

Legacy global paginator usage should be replaced with FOSSBilling\Paginator (metadata only) and FOSSBilling\Pagination (Doctrine-backed data retrieval):

$p = new \Box_Paginator($itemsCount, $currentPage, $limit, $midRange);

For Doctrine-backed pagination, use FOSSBilling\Pagination with PaginationOptions:

$pagination = $this->di['pagination'];
$options = \FOSSBilling\PaginationOptions::fromArray($data);
$result = $pagination->paginateDoctrineQuery($queryBuilder, $options);

Permissions have been expanded and enforced more strictly across all modules:

  • New checkPermissionsAndThrowException($module, $permission) method on the Staff service.
  • New has_permission Twig function for template-level permission checks.
  • Email permission keys added for finer-grained email access control.
  • Module names are now normalized in permission checks (hasManagePermission).
  • Expanded permission checks enforce 'view' and 'manage_tickets' etc. throughout modules.

If you have custom admin modules, verify your permission configurations.

The Twig system has been refactored into dedicated classes:

  • FOSSBilling\Twig\TwigFactory — Creates Twig environments for admin, client, email, adapters, and theme settings.
  • FOSSBilling\Twig\TwigLoader — New filesystem loader with proper priority: html_custom/ > html/ > module templates.
  • FOSSBilling\Twig\Extension\FOSSBillingExtension — Core filters (url, asset_url, trans, timeago, etc.).
  • FOSSBilling\Twig\Extension\ApiExtension — API-related filters/functions (api_url, fb_api_form, fb_api_link).
  • FOSSBilling\Twig\Extension\LegacyExtension — Backward-compatible filters (ip_country_name, ip_country_code, mod_asset_url, period_title).
  • FOSSBilling\Twig\Extension\DebugBarExtension — Debug bar integration.
  • FOSSBilling\Twig\EmailPolicy / FOSSBilling\Twig\AdapterPolicy — Sandbox policies for email and adapter templates.
  • FOSSBilling\Twig\SandboxedStringRenderer — Sandboxed rendering for user-provided template strings.

The old Box_TwigExtensions and Box_TwigLoader classes have been removed.

Gravatar has been removed. User avatars are now generated locally using DiceBear. The gravatar Twig filter no longer exists; use the avatar function instead:

{{ avatar(email, 80) }}

The new Antispam module enables honeypot spam prevention by default for supported forms such as signup. If you have custom signup or public submission forms, use the antispam_honeypot function to include honeypot fields:

{\% set honeypot = antispam_honeypot() %}
{\% if honeypot.enabled %}
<input type="text" name="{{ honeypot.field }}" value="" tabindex="-1" autocomplete="off">
{\% endif %}

The old api.rate_* configuration settings have been replaced by a centralized rate_limiter block:

'rate_limiter' => [
'enabled' => true,
'whitelist_ips' => [],
// Override individual policies as needed
],

The rate limiter is now enforced on guest ticket creation and other public endpoints. Policies are defined in FOSSBilling\Security\RateLimiter::getDefaultConfig().

0.8.0 introduces a new widget system for rendering dynamic content in template slots. Use render_widgets in your theme templates:

{{ render_widgets('client.theme.body.start') }}
{{ render_widgets('client.theme.body.end') }}

Widgets are registered by modules and can be created by implementing the WidgetProviderInterface.

File-backed email templates are now supported in addition to the database-stored templates. The email Twig environment is now sandboxed for security, restricting available filters and globals.

ComponentStatusNotes
Box_ModRemovedReplaced by FOSSBilling\Module
Box_PaginatorRemovedReplaced by FOSSBilling\Paginator
Box_TwigExtensionsRemovedSplit into dedicated extension classes
Box_TwigLoaderRemovedReplaced by FOSSBilling\Twig\TwigLoader
ramsey/uuidRemovedReplaced by symfony/uid
Webpack EncoreRemovedReplaced by esbuild
jQueryRemovedVanilla JS used throughout
GravatarRemovedReplaced by DiceBear
Api/API.js pathRemovedReplaced by frontend/core/api.js
DebugBar_renderHead()RemovedUse debug_bar_render_head()
alink / link filtersRemovedUse url with area parameter
gravatar filterRemovedUse avatar function
library_url filterRemovedUse public_asset_url
markdown filterRemovedUse markdown_to_html
size filterRemovedUse file_size
money / money_without_currency filtersRemovedUse format_currency
money_convert / money_convert_without_currency filtersRemovedConvert values before rendering, then use format_currency

Custom payment adapters or modules that store encrypted data using FOSSBilling's encryption may need their data re-encrypted after the update. The patcher (patch 50) handles this migration automatically for core data, but custom implementations should be verified.