Skip to content

Commit 0179520

Browse files
committed
Added docs
1 parent 59a15c0 commit 0179520

9 files changed

Lines changed: 1454 additions & 0 deletions

docs/developer/database-schema.md

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
# Database Schema
2+
3+
FreemKit creates two tables on activation, both using the standard WordPress table prefix. The schema version is stored in the `freemkit_db_version` option and migrations run automatically on plugin update.
4+
5+
---
6+
7+
## `{prefix}freemkit_subscribers`
8+
9+
Stores one row per unique subscriber email address. This is the primary record of every customer FreemKit has processed.
10+
11+
```sql
12+
CREATE TABLE {prefix}freemkit_subscribers (
13+
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
14+
email VARCHAR(100) NOT NULL,
15+
first_name VARCHAR(50) DEFAULT '',
16+
last_name VARCHAR(50) DEFAULT '',
17+
status VARCHAR(20) NOT NULL DEFAULT 'active',
18+
marketing_optout TINYINT(1) NOT NULL DEFAULT 0,
19+
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
20+
modified DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
21+
PRIMARY KEY (id),
22+
UNIQUE KEY email (email),
23+
KEY status (status),
24+
KEY marketing_optout (marketing_optout)
25+
);
26+
```
27+
28+
### Column Descriptions
29+
30+
| Column | Type | Description |
31+
|---|---|---|
32+
| `id` | `BIGINT UNSIGNED` | Auto-increment primary key |
33+
| `email` | `VARCHAR(100)` | Subscriber email address. Unique — one row per address |
34+
| `first_name` | `VARCHAR(50)` | First name as received from Freemius |
35+
| `last_name` | `VARCHAR(50)` | Last name as received from Freemius |
36+
| `status` | `VARCHAR(20)` | `active` or `opted_out` |
37+
| `marketing_optout` | `TINYINT(1)` | `1` if the user has opted out of marketing. FreemKit will not subscribe opted-out users when the Respect Marketing Opt-Out setting is enabled |
38+
| `created` | `DATETIME` | Timestamp of first record insertion |
39+
| `modified` | `DATETIME` | Timestamp of last update (auto-managed by MySQL) |
40+
41+
### Notes
42+
43+
- The `email` unique key means records are matched and upserted by email. A subscriber who triggers multiple events is stored as a single row — only their data is updated, not duplicated.
44+
- `status` and `marketing_optout` are separate fields because `opted_out` status is a user-visible list-management state, whereas `marketing_optout` reflects Freemius's marketing consent flag specifically.
45+
46+
---
47+
48+
## `{prefix}freemkit_subscriber_events`
49+
50+
Stores one row per processed webhook event per subscriber/plugin combination. This is the event history.
51+
52+
```sql
53+
CREATE TABLE {prefix}freemkit_subscriber_events (
54+
id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
55+
subscriber_id BIGINT(20) UNSIGNED NOT NULL,
56+
plugin_id VARCHAR(50) NOT NULL DEFAULT '',
57+
plugin_slug VARCHAR(100) NOT NULL DEFAULT '',
58+
event_type VARCHAR(100) NOT NULL DEFAULT '',
59+
user_type VARCHAR(20) NOT NULL DEFAULT '',
60+
form_ids TEXT DEFAULT NULL,
61+
tag_ids TEXT DEFAULT NULL,
62+
freemius_user_id BIGINT(20) UNSIGNED NOT NULL DEFAULT 0,
63+
created DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
64+
PRIMARY KEY (id),
65+
KEY subscriber_id (subscriber_id),
66+
KEY plugin_id (plugin_id),
67+
KEY event_type (event_type),
68+
KEY user_type (user_type),
69+
KEY created (created)
70+
);
71+
```
72+
73+
### Column Descriptions
74+
75+
| Column | Type | Description |
76+
|---|---|---|
77+
| `id` | `BIGINT UNSIGNED` | Auto-increment primary key |
78+
| `subscriber_id` | `BIGINT UNSIGNED` | Foreign key to `freemkit_subscribers.id` |
79+
| `plugin_id` | `VARCHAR(50)` | Freemius numeric product ID |
80+
| `plugin_slug` | `VARCHAR(100)` | Plugin name as a slug (for human-readable reference) |
81+
| `event_type` | `VARCHAR(100)` | Freemius event type (e.g. `license.created`) |
82+
| `user_type` | `VARCHAR(20)` | User classification: `free`, `paid`, `opted_out`, or empty string for opt-in and name-change events |
83+
| `form_ids` | `TEXT` | Comma-separated list of Kit form IDs the subscriber was added to |
84+
| `tag_ids` | `TEXT` | Comma-separated list of Kit tag IDs that were applied |
85+
| `freemius_user_id` | `BIGINT UNSIGNED` | Freemius user ID as provided in the webhook payload. `0` when not present. |
86+
| `created` | `DATETIME` | Timestamp when the event was processed |
87+
88+
### Notes
89+
90+
- Each webhook that results in a Kit action produces one row here. Multiple events from the same subscriber across different plugins each produce separate rows.
91+
- `form_ids` and `tag_ids` store the IDs that were used at time of processing. If you later change the form mapping in settings, older event rows are unaffected.
92+
- There is no foreign key constraint defined at the database level (WordPress convention), but `subscriber_id` always references a valid `freemkit_subscribers.id` row.
93+
94+
---
95+
96+
## WordPress Options
97+
98+
FreemKit stores the following entries in `wp_options`:
99+
100+
| Option Key | Autoloaded | Description |
101+
|---|---|---|
102+
| `freemkit_settings` | Yes | Serialised array containing all plugin settings |
103+
| `freemkit_audit_log` | No | Serialised audit log entries array (max 200) |
104+
| `freemkit_db_version` | Yes | Installed database schema version |
105+
| `freemkit_wizard_completed` | Yes | `1` when the setup wizard has been completed |
106+
| `freemkit_wizard_current_step` | Yes | Current wizard step number (integer) |
107+
| `freemkit_show_wizard` | Yes | Whether to show the wizard on next admin load |
108+
109+
The `freemkit_settings` option contains all user-facing configuration. Sensitive values (`secret_key`, `kit_access_token`, `kit_refresh_token`) are encrypted at rest using AES-256-CBC (OpenSSL) or libsodium, depending on what is available on the server.
110+
111+
Access settings via `Options_API::get_option( $key )` rather than reading the option directly. This applies the `freemkit_get_option` filter chain and handles decryption transparently.

0 commit comments

Comments
 (0)