xref: /plugin/usersettings/README.md (revision 1ab406139ae52af26e6f9eaacaf1646e58521679)
1*1ab40613Stracker-user# User Settings plugin for DokuWiki
2*1ab40613Stracker-user
3*1ab40613Stracker-userA self-contained, server-side store of per-user preference toggles, with a
4*1ab40613Stracker-userself-service settings page for every logged-in user and an admin overview of
5*1ab40613Stracker-usereveryone's choices.
6*1ab40613Stracker-user
7*1ab40613Stracker-userIt is **infrastructure for other plugins**: a feature plugin (or a template's
8*1ab40613Stracker-usercompanion plugin) registers its own toggle with a single event handler, and
9*1ab40613Stracker-userthis plugin renders it, stores it, and exposes it — without ever needing to be
10*1ab40613Stracker-useredited itself.
11*1ab40613Stracker-user
12*1ab40613Stracker-user## Why this plugin exists
13*1ab40613Stracker-user
14*1ab40613Stracker-userDokuWiki core has no server-side per-user preference store. The auth backend
15*1ab40613Stracker-userholds only name, e-mail, password and groups, and DokuWiki's built-in
16*1ab40613Stracker-userinterface preferences live in a browser **cookie** — so they do not follow a
17*1ab40613Stracker-useruser from one browser or device to another.
18*1ab40613Stracker-user
19*1ab40613Stracker-userThis plugin fills that gap. Preferences are stored on the server, keyed by
20*1ab40613Stracker-useruser, so they apply wherever the person is logged in.
21*1ab40613Stracker-user
22*1ab40613Stracker-user## What a user sees
23*1ab40613Stracker-user
24*1ab40613Stracker-userA **"Preferences"** item appears in the user menu, just to the left of
25*1ab40613Stracker-user"Update Profile". It opens a settings page (`do=usersettings`) listing every
26*1ab40613Stracker-userregistered toggle as a checkbox or a drop-down. The page is a plain HTML form —
27*1ab40613Stracker-userno JavaScript — so it works in any browser.
28*1ab40613Stracker-user
29*1ab40613Stracker-user## What an admin sees
30*1ab40613Stracker-user
31*1ab40613Stracker-userAdmin → **User Settings** shows a flat, sortable table — one row per
32*1ab40613Stracker-user(user × setting): *Display name · Setting · Value · Changed by · Changed at*.
33*1ab40613Stracker-userA row shows the user's explicit choice, or the toggle's default (marked as
34*1ab40613Stracker-usersuch) when they never set one. A filter narrows the table to a single setting,
35*1ab40613Stracker-userso it stays readable however many toggles exist.
36*1ab40613Stracker-user
37*1ab40613Stracker-userClicking a display name opens an edit form for that user. This is **Model A+**:
38*1ab40613Stracker-useran admin may change anyone's preferences, and the change is recorded under the
39*1ab40613Stracker-useradmin's name — but it is *not* enforced. The user can always change it back.
40*1ab40613Stracker-userThis is how you roll out a new feature as default-on while pre-setting it off
41*1ab40613Stracker-userfor specific people (for example, keeping two conservative admins on the old
42*1ab40613Stracker-usertheme).
43*1ab40613Stracker-user
44*1ab40613Stracker-user## Storage
45*1ab40613Stracker-user
46*1ab40613Stracker-userOne JSON file per user, under `{metadir}/usersettings/`, holding
47*1ab40613Stracker-user`{key: {value, changed_at, changed_by}}`. JSON and pretty-printed, so the files
48*1ab40613Stracker-userare easy to inspect or back up. The page text and the wiki changelog are never
49*1ab40613Stracker-usertouched. `changed_by` records whoever made the change — the user, or an admin
50*1ab40613Stracker-useracting on their behalf — which is what the overview's "Changed by" column
51*1ab40613Stracker-usershows.
52*1ab40613Stracker-user
53*1ab40613Stracker-user## Registering a toggle from another plugin
54*1ab40613Stracker-user
55*1ab40613Stracker-userThis is the integration point. Your plugin hooks the
56*1ab40613Stracker-user`PLUGIN_USERSETTINGS_REGISTER` event and appends one or more toggle
57*1ab40613Stracker-userdefinitions:
58*1ab40613Stracker-user
59*1ab40613Stracker-user```php
60*1ab40613Stracker-userclass action_plugin_myfeature extends DokuWiki_Action_Plugin
61*1ab40613Stracker-user{
62*1ab40613Stracker-user    public function register(Doku_Event_Handler $controller)
63*1ab40613Stracker-user    {
64*1ab40613Stracker-user        $controller->register_hook(
65*1ab40613Stracker-user            'PLUGIN_USERSETTINGS_REGISTER', 'BEFORE', $this, 'registerToggles'
66*1ab40613Stracker-user        );
67*1ab40613Stracker-user    }
68*1ab40613Stracker-user
69*1ab40613Stracker-user    public function registerToggles(Doku_Event $event)
70*1ab40613Stracker-user    {
71*1ab40613Stracker-user        // a simple on/off toggle
72*1ab40613Stracker-user        $event->data[] = [
73*1ab40613Stracker-user            'key'     => 'myfeature_enabled',
74*1ab40613Stracker-user            'label'   => 'Enable my feature',
75*1ab40613Stracker-user            'type'    => 'checkbox',
76*1ab40613Stracker-user            'default' => 1,
77*1ab40613Stracker-user            'desc'    => 'Show my feature on wiki pages.',
78*1ab40613Stracker-user            'plugin'  => 'myfeature',
79*1ab40613Stracker-user        ];
80*1ab40613Stracker-user
81*1ab40613Stracker-user        // a choice from a fixed list
82*1ab40613Stracker-user        $event->data[] = [
83*1ab40613Stracker-user            'key'     => 'myfeature_mode',
84*1ab40613Stracker-user            'label'   => 'My feature mode',
85*1ab40613Stracker-user            'type'    => 'select',
86*1ab40613Stracker-user            'options' => ['compact' => 'Compact', 'full' => 'Full view'],
87*1ab40613Stracker-user            'default' => 'full',
88*1ab40613Stracker-user            'plugin'  => 'myfeature',
89*1ab40613Stracker-user        ];
90*1ab40613Stracker-user    }
91*1ab40613Stracker-user}
92*1ab40613Stracker-user```
93*1ab40613Stracker-user
94*1ab40613Stracker-user### Toggle definition fields
95*1ab40613Stracker-user
96*1ab40613Stracker-user| Field | Required | Notes |
97*1ab40613Stracker-user| --- | --- | --- |
98*1ab40613Stracker-user| `key` | yes | Unique identifier; `A-Z a-z 0-9 _` only. Also the storage key and HTML field name. Prefix it with your plugin name to avoid collisions. |
99*1ab40613Stracker-user| `label` | yes | Shown on the settings page and in the admin table. |
100*1ab40613Stracker-user| `type` | — | `checkbox` (default) or `select`. |
101*1ab40613Stracker-user| `default` | — | Default value. Checkbox: `0`/`1`. Select: one of the option keys. |
102*1ab40613Stracker-user| `options` | for `select` | A `value => label` map. Required and non-empty for selects. |
103*1ab40613Stracker-user| `desc` | — | Optional help text shown under the toggle. |
104*1ab40613Stracker-user| `plugin` | — | Optional identifier of the registering plugin/template. |
105*1ab40613Stracker-user
106*1ab40613Stracker-userInvalid definitions (missing key, illegal key characters, a select with no
107*1ab40613Stracker-useroptions) are silently dropped. If two plugins register the same `key`, the
108*1ab40613Stracker-userfirst registration wins.
109*1ab40613Stracker-user
110*1ab40613Stracker-userA toggle definition is plain data, so a **template** can have a toggle too —
111*1ab40613Stracker-usership a tiny companion action plugin that does nothing but register it.
112*1ab40613Stracker-user
113*1ab40613Stracker-user## Reading a preference
114*1ab40613Stracker-user
115*1ab40613Stracker-userYour plugin reads the effective value through the helper. `getPreference()`
116*1ab40613Stracker-userreturns the user's stored value, or the registered default if they never set
117*1ab40613Stracker-userone:
118*1ab40613Stracker-user
119*1ab40613Stracker-user```php
120*1ab40613Stracker-user$prefs = plugin_load('helper', 'usersettings');
121*1ab40613Stracker-user$enabled = $prefs ? $prefs->getPreference('myfeature_enabled', null) : 1;
122*1ab40613Stracker-user// pass a username as the 2nd argument, or null for the current user
123*1ab40613Stracker-user```
124*1ab40613Stracker-user
125*1ab40613Stracker-userAlways provide your own sensible fallback (`? ... : 1` above) in case the
126*1ab40613Stracker-userUser Settings plugin is not installed.
127*1ab40613Stracker-user
128*1ab40613Stracker-user## Components
129*1ab40613Stracker-user
130*1ab40613Stracker-user| File | Role |
131*1ab40613Stracker-user| --- | --- |
132*1ab40613Stracker-user| `helper.php` | Storage, the registration event, the read/write API. |
133*1ab40613Stracker-user| `action.php` | The user-menu item and the `do=usersettings` settings page. |
134*1ab40613Stracker-user| `admin.php` | The admin overview table and per-user edit form. |
135*1ab40613Stracker-user| `MenuItem.php` | The user-menu item class. |
136*1ab40613Stracker-user
137*1ab40613Stracker-user## Install
138*1ab40613Stracker-user
139*1ab40613Stracker-userDrop the folder into `lib/plugins/usersettings/`, or use Admin → Extension
140*1ab40613Stracker-userManager → Manual Install. There is nothing to configure.
141*1ab40613Stracker-user
142*1ab40613Stracker-user## Notes
143*1ab40613Stracker-user
144*1ab40613Stracker-user- The settings page and admin pages are plain HTML forms — no JavaScript — so
145*1ab40613Stracker-user  there are no old-browser concerns.
146*1ab40613Stracker-user- This is a new, locally-developed plugin with no upstream, so — unlike the
147*1ab40613Stracker-user  forked plugins on this wiki — it carries no update-suppression date.
148*1ab40613Stracker-user
149*1ab40613Stracker-user## License
150*1ab40613Stracker-user
151*1ab40613Stracker-userGPL 2, matching DokuWiki.
152