You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When an extension registers a boolean setting via the settings registry with a default: true value, it is impossible for the administrator to permanently turn the switch off. Upon saving and refreshing the page, the switch always reverts back to ON.
The Root Cause
This is caused by how JavaScript handles falsy values when initializing setting streams, combined with how PHP casts booleans:
When an admin turns off a <Switch> component, the onchange event passes the boolean false into the setting Stream.
The backend receives false in the JSON payload. The Settings repository casts this to a string for the database, converting false into an empty string "".
On page reload, app.data.settings[key] returns the empty string "".
In AdminPage.tsx (and historically ExtensionPage), the setting stream is initialized using the logical OR operator: this.settings[key] = this.settings[key] || Stream(app.data.settings[key] || fallback);
Because "" is a falsy value in JavaScript, "" || fallback completely ignores the saved empty string and evaluates to the fallback value (which is true).
1.x vs 2.x Impact
This logic bug exists in both 1.x and 2.x. However, it is primarily noticeable in 2.x because the 2.x buildSettingComponent was updated to correctly pass the default property into the fallback argument. Now that truthy defaults are respected by the UI, this || bug forces those settings to be permanently on.
Current Behavior
When an extension registers a boolean setting via the settings registry with a
default: truevalue, it is impossible for the administrator to permanently turn the switch off. Upon saving and refreshing the page, the switch always reverts back to ON.The Root Cause
This is caused by how JavaScript handles falsy values when initializing setting streams, combined with how PHP casts booleans:
<Switch>component, theonchangeevent passes the booleanfalseinto the setting Stream.falsein the JSON payload. The Settings repository casts this to a string for the database, convertingfalseinto an empty string"".app.data.settings[key]returns the empty string"".AdminPage.tsx(and historicallyExtensionPage), the setting stream is initialized using the logical OR operator:this.settings[key] = this.settings[key] || Stream(app.data.settings[key] || fallback);""is a falsy value in JavaScript,"" || fallbackcompletely ignores the saved empty string and evaluates to the fallback value (which istrue).1.x vs 2.x Impact
This logic bug exists in both 1.x and 2.x. However, it is primarily noticeable in 2.x because the 2.x
buildSettingComponentwas updated to correctly pass thedefaultproperty into thefallbackargument. Now that truthy defaults are respected by the UI, this||bug forces those settings to be permanently on.Steps to Reproduce
type: 'boolean'anddefault: true.e.g. (https://github.com/huoxin233/flarum-ext-filter-rule-manager/blob/7f6531043dabf9b012651f93aba8b3efc8ae0234/js/src/admin/components/RulesetManagerPage.tsx#L248-L254)
Expected Behavior
The switch state should save correctly when OFF.
Screenshots
Extension tested in the video is on commit huoxin233/flarum-ext-filter-rule-manager@db5d5cd
PixPin_2026-06-26_17-45-31.mp4
Environment
Output of
php flarum infoFlarum core: 2.0.0-rc.4
PHP version: CLI: 8.3.8, Web: 8.3.8
PHP memory limit: CLI: 512M, Web: 128M
MariaDB version: 10.11.6
Loaded extensions: Core, date, libxml, pcre, hash, json, SPL, session, openssl, random, Reflection, xml, cli_server, bcmath, calendar, curl, ctype, dom, standard, fileinfo, filter, ftp, gd, gettext, gmp, iconv, imap, intl, ldap, mbstring, mysqlnd, mysqli, zlib, pcntl, PDO, pdo_mysql, PDO_ODBC, pdo_pgsql, pdo_sqlite, pgsql, posix, readline, exif, SimpleXML, sockets, soap, sodium, sysvsem, sqlite3, tokenizer, xmlreader, xmlwriter, zip, Phar, Zend OPcache, xdebug
+------------------------------+---------------+------------------------------------------+-------+
| Flarum Extensions | | | |
+------------------------------+---------------+------------------------------------------+-------+
| ID | Version | Commit | Notes |
+------------------------------+---------------+------------------------------------------+-------+
| flarum-flags | v2.0.0-rc.1 | | |
| flarum-approval | v2.0.0-rc.1 | | |
| flarum-suspend | v2.0.0-rc.1 | | |
| flarum-tags | v2.0.0-rc.1 | | |
| flarum-likes | v2.0.0-rc.1 | | |
| fof-default-user-preferences | 2.0.0-beta.2 | | |
| fof-byobu | 2.0.0-beta.11 | | |
| pianotell-flamoji | v2.2.1 | | |
| ianm-log-viewer | 2.0.0-beta.2 | | |
| huoxin-relative-url | 2.x-dev | 9d21286bbca19017285cdd97b466013685fa1354 | |
| huoxin-money-with-history | 2.x-dev | ee1ac54ffb2dc962feb7efa165d87ef701cfee0b | |
| huoxin-filter-rule-manager | 2.x-dev | 8689b9f0d5c0ecd95a2e77a331bad0505a6ff68c | |
| fof-links | 2.0.0-beta.3 | | |
| fof-drafts | dev-main | | |
| flarum-subscriptions | dev-main | | |
| flarum-sticky | v2.0.0-rc.1 | | |
| flarum-statistics | v2.0.0-rc.1 | | |
| flarum-messages | v2.0.0-rc.1 | | |
| flarum-mentions | v2.0.0-rc.1 | | |
| flarum-markdown | v2.0.0-rc.1 | | |
| flarum-lock | v2.0.0-rc.1 | | |
| flarum-lang-english | v2.0.0-rc.1 | | |
| flarum-extension-manager | v2.0.0-rc.1 | | |
| flarum-emoji | v2.0.0-rc.1 | | |
| flarum-bbcode | v2.0.0-rc.1 | | |
| ernestdefoe-calendar | 2.0.3 | | |
+------------------------------+---------------+------------------------------------------+-------+
Base URL: https://xxxxx
Installation path: /home/user/test/public
Queue driver: sync
Session driver: file
Scheduler status: Active
Mail driver: null
Debug mode: ON
Don't forget to turn off debug mode! It should never be turned on in a production system.
Possible Solution
No response
Additional Context
No response