=== Bodholdt Tickets ===
Contributors: bodholdtlabs
Tags: help desk, helpdesk, support ticket, support, customer support
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.6.23
License: GPL-2.0-or-later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

A fast, friendly help desk for WordPress: front-end ticket form, customer portal, custom fields, canned replies, CSAT, and an optional AI co-pilot.

== Description ==

Bodholdt Tickets is a complete, self-hosted support desk for WordPress. Unlimited tickets, up to three people working the queue, and no monthly fee.

* **Front-end Agent Support Desk.** Work the queue from a clean, fast interface, with no wp-admin clutter.
* **Front-end ticket form + Gutenberg block.** Drop a support form on any page with a block or the `[bodholdt_support_form]` shortcode.
* **Customer portal.** Customers track and reply to their tickets through a secure magic link, with no account required (`[bodholdt_portal]`).
* **Custom fields.** Add your own fields to the ticket form (text, select, checkbox, and more).
* **Canned / saved replies.** Insert your common answers in one click.
* **Customer satisfaction (CSAT).** Collect a rating when a ticket is resolved.
* **File attachments.** Customers and agents can attach files, stored in a protected directory.
* **Gamification.** XP, levels, streaks, and a leaderboard make clearing the queue feel good.
* **AI co-pilot (optional, bring your own key).** Drafts a reply for your agent to review and edit. It never sends on its own.

Unlimited tickets, no ticket caps, and no monthly fee. Up to 3 people can be given agent access on the free edition; everything listed above is included.

Ready for translation: the plugin ships a translation template, and every customer-facing and admin surface is right-to-left ready.

== External services ==

The two services below are **optional** and are only contacted when you enable them. The Bodholdt Labs update check after them is on by default.

**1. Anthropic API (AI co-pilot)**
When you enable the AI co-pilot and paste your own Anthropic API key, the plugin sends a ticket to Anthropic's API when an agent asks for a draft or a summary, or as each ticket arrives if you turn on Auto-pilot: the subject and conversation, and the customer's name and email. For drafts and Auto-pilot, it also sends your desk and site name and any brand-voice instructions and knowledge-base notes you give it. Asking for a summary also sends the ticket's internal notes. Like every request WordPress makes, each one names your site's address in its user agent. No ticket data is sent if the AI co-pilot is disabled or no key is set; the Test button sends Anthropic only a short test request with your key.
- Terms: https://www.anthropic.com/legal/commercial-terms
- Privacy: https://www.anthropic.com/legal/privacy

**2. Browser Web Push services (agent notifications)**
If an agent opts in to background notifications, the plugin sends notification payloads to the push service operated by the agent's browser vendor (for example Mozilla, Google, or Microsoft). The endpoint is provided by the browser at subscription time. Data sent is limited to the notification content (for example "New reply on ticket #123"). No data is sent unless an agent subscribes.
- These endpoints are operated by the respective browser vendors under their own privacy policies.

= Bodholdt Labs update check =

What it is and what it is used for: you downloaded this copy from bodholdtlabs.com, so nothing else would ever tell it that a newer version exists. It asks `https://bodholdtlabs.com/wp-json/bodholdt-licensing/v1/update-check/bodholdt-support-tickets` whether there is one, and if there is, WordPress offers it on the Plugins screen like any other update. I count those update checks by site, to see how many sites run the plugin.

What data is sent and when: the version this plugin is running and this site's address, both in the request's user agent. It is a GET request with no body and no cookies, and it carries no license key, no account, and no ticket or customer data. A good answer is kept for 12 hours, so the check usually runs about twice a day. A failed check is kept for 1 hour, so while the server is unreachable it can ask again up to once an hour. WordPress also clears the kept answer whenever it installs or updates something, so a check can come sooner than that.

How to turn it off: there is no setting for this. Add `add_filter( 'bodholdt_tickets_update_check_enabled', '__return_false' );` to a must-use plugin and the check stops entirely. The filter is read before the cache, so it takes effect at once rather than waiting for a cached answer to expire.

If you accept an update: WordPress downloads the new version from bodholdtlabs.com. I count that download, as a running total for the plugin and one row recording the file, the version and the time, with no address and no identifier in it. My web server logs that request, and each update check, the way any web server logs any request.

- Terms: https://bodholdtlabs.com/terms-of-service/
- Privacy: https://bodholdtlabs.com/privacy-policy/

== Installation ==

1. Upload the plugin to `/wp-content/plugins/` or install it from the Plugins screen.
2. Activate it.
3. Visit **Bodholdt Tickets** in wp-admin to configure agents, categories, and the ticket form.
4. Add the form to a page with the Bodholdt Tickets block or the `[bodholdt_support_form]` shortcode, and the portal with `[bodholdt_portal]`.

== Frequently Asked Questions ==

= How many tickets and agents do I get? =
Tickets are unlimited, with no monthly cap. Up to 3 people can be given agent access on the free edition. If your team is bigger than that, any paid Bodholdt Tickets plan (Solo, Studio or Foundry) lifts the seat limit. The paid plans come as a separate download.

= Do I need an API key for the AI co-pilot? =
Only if you want to use it. Paste your own Anthropic API key under the AI settings. The co-pilot drafts replies and writes ticket summaries for your agents and, with Auto-pilot, sets a new ticket's priority and tags. It never sends a reply on its own: your agent reviews each draft and decides what to send.

= Does email-to-ticket work? =
The free plugin handles outbound replies and a front-end form, portal, and embeddable widget. Inbound email-to-ticket, departments and routing, and advanced reporting come with the paid edition.

= Can I run the free edition and the paid edition at the same time? =
No, and you do not need to. They are the same product, so only one should be active. If both are active, the second one to load stops and tells you which folder to deactivate. Your tickets, settings, and configuration live in the database, so switching between them loses nothing. Deleting the copy you stopped using keeps them too, as long as the other copy is still installed and the copy you delete is version 1.6.21 or later. A copy older than 1.6.21 removes everything when it is deleted, so while a newer copy is active it refuses to delete an older one. On a multisite network, that needs the newer copy to be network-activated or active on the main site. To remove an older copy, upload the latest ZIP of that edition over it first (Plugins, Add Plugin, Upload Plugin), or delete its folder from wp-content/plugins yourself, which leaves your data in place.

= Is it available in my language? =
The plugin ships a translation template, `languages/bodholdt-support-tickets.pot`. To add a translation, put your `bodholdt-support-tickets-{locale}.mo` file in `wp-content/languages/plugins/`, where plugin updates leave it alone. The .mo file translates what the plugin draws in PHP. The support desk, and parts of the customer portal and the support form, are drawn by scripts, which WordPress translates only from JSON translation files, so with a .mo file alone those parts stay in English. No translations are included.

== Screenshots ==

1. The unified Support Desk: one queue for every ticket with Open / Mine / All / Resolved filters, color-coded priority bars, category tags, and a full conversation thread in the reading pane.
2. The built-in AI co-pilot drafts a reply from the conversation using your own Anthropic key and brand voice, and you always review and edit before sending.
3. A clean, white-label front-end support form (also available as a Gutenberg block) so customers can open a ticket from any page, with optional file attachments.
4. The passwordless customer portal: visitors sign in by magic link to track "My tickets," reply, and start a new request, with no account required.
5. Configure the AI co-pilot in Settings: bring-your-own Anthropic key, choose the Claude model, and set your brand voice and knowledge base (plus channels, categories, and custom fields).
6. Built-in reports: ticket volume over time, by channel and category, first-response and resolution speed, customer satisfaction (CSAT), and what people ask about most.
7. Agent gamification: XP, levels, daily streaks, and a team leaderboard to keep support fun and responsive.

== Security ==

Found a security problem in this plugin? Please tell us before you publish it, and we
will tell you what we found and when a fix will ship.

Email support@bodholdtlabs.com with "Security" in the subject line. We acknowledge
within five business days. Full policy, including what is in scope and what we ask of
you, is at https://bodholdtlabs.com/security/

We do not run a bug bounty and cannot pay for reports. We would rather say so up front
than have you find out afterwards.

== Changelog ==

= 1.6.23 (2026-10-24) =
* Push notifications go only to people who still have agent access.
* Removing an agent also removes their permission to delete tickets, and the update clears that permission where earlier removals left it behind. Remove is no longer offered next to an administrator, whose access comes with the role.
* The customer portal shows tickets only to someone who opened a sign-in link sent to the address, signed in to the site or not. A link opened while signed in stops working when that sign-in ends. Before, anyone with an account could change its email to a customer's address and read that customer's tickets.
* The Support Desk shows customer messages as plain text. Before, a message could put live formatting, images and links into the desk.
* Signing out of the site also signs you out of the customer portal.
* Sign out in the customer portal works on a page left open for days, and the page says so when signing out did not go through. Before, a failed sign-out looked like it worked and left the portal open to the next person at that browser.
* The support panel now links to your portal page, where visitors get their sign-in link. It had no such link before. Without a portal page, visitors no longer see the panel, and administrators see a note saying why. The settings screen, the portal's New request link and the support form's link to the portal no longer take a page that only quotes a shortcode for your form or portal page.

= 1.6.22 (2026-10-20) =
* The External services section now lists everything the AI co-pilot sends to Anthropic. It used to name only the ticket's conversation and your brand-voice instructions. It now also names the ticket's subject, the customer's name and email, your desk and site name, your knowledge-base notes, the summaries agents ask for (a summary also sends the ticket's internal notes), and the site address WordPress puts in every request's user agent. It also says what the Test button sends. Apart from the waitlist change below, the co-pilot works exactly as before.
* This readme now also says what the update checks this copy makes are used for: I count them by site, to see how many sites run the plugin.
* The AI co-pilot no longer sends a waitlist visitor's IP address to Anthropic. A waitlist signup (the `bt/v1/waitlist` route) opens a ticket whose first message records the visitor's IP address, kept for invitations and abuse triage only. Until now, a draft, a summary or Auto-pilot on that ticket sent the address along with the rest of the conversation. The co-pilot now leaves that line out, and the ticket still keeps it.
* The AI Co-pilot settings screen said "Nothing is sent automatically", but with Auto-pilot on, each new ticket goes to Anthropic as it arrives. It now says what it meant: the co-pilot never sends a reply to a customer on its own.
* The FAQ said the co-pilot only ever drafts a reply. It also writes ticket summaries for your agents and, with Auto-pilot, sets a new ticket's priority and tags, and the FAQ now says so. It still never sends a reply on its own.

= 1.6.21 (2026-10-06) =
* Deleting one edition of Bodholdt Tickets on the Plugins screen no longer deletes what the other edition runs on. Both editions keep their tickets, settings and agent access in the same place, so until now deleting the free edition after installing a paid plan, or the reverse, removed all of it. From this release, a copy you delete while the other edition is still installed leaves everything in place, and the last copy you delete still removes everything. WordPress runs the cleanup of the copy being deleted, so a copy older than 1.6.21 would still remove everything. While this release is active, it refuses to delete such a copy and says how to remove it safely. On a multisite network it can do that only when it is network-activated or active on the main site, because those are the copies the Network Admin screens load.
* The support form's name and email fields now tell the browser what they hold, so it can offer to fill them in for your customers.
* Dropdown menus on the support form, for categories and for any custom field you made a dropdown, now match the text fields around them: the same width, border and focus highlight.
* If the customer portal cannot load, it now shows a Try again button under its message, so a customer can retry without reloading the page.
* With JavaScript turned off, the customer portal now says that it needs JavaScript and asks the customer to turn it on and reload, in place of a Loading message that never finished.
* This edition now goes by the product's own name. The Plugins screen shows Bodholdt Tickets (free edition), and this readme is titled Bodholdt Tickets.
* The FAQ now describes the paid edition as it is sold: any paid Bodholdt Tickets plan (Solo, Studio or Foundry) lifts the 3-agent limit and adds inbound email-to-ticket, departments and routing, and advanced reporting.
* The description on the Plugins screen now lists only what this edition includes: the front-end desk, the ticket form, the customer portal, canned replies and the optional AI co-pilot.
* This readme now describes translations as they are: the plugin ships a translation template and no translations, and the FAQ says where to put your own translation file so plugin updates leave it alone.
* This copy now names bodholdtlabs.com as its update source in its own header, so WordPress.org will not offer it an update, even if a plugin there ever shares its folder name.
* This readme now describes the check for a newer version that this copy makes to bodholdtlabs.com: what it sends, how often it runs, and how to switch it off. You will find it under External services.

= 1.6.20 (2026-09-05) =
* The Manage account link in the license screen now points at the address that answers directly, instead of one that redirects first.

= 1.6.19 (2026-09-05) =
* The customer portal page now tells browsers and proxies not to store it. It carried no caching instruction at all, while the account pages beside it did, so a signed-in customer's ticket list and their session token could be kept by a shared browser and shown to whoever opened the page next. A page that merely quotes the shortcode in documentation is left alone, because it is not an account page.

= 1.6.18 (2026-09-05) =
* You can now use any Claude model your key has access to, instead of only the three this plugin was built with. The Model setting was a fixed dropdown, and the save handler refused anything that was not one of those three, so when Anthropic released something newer there was no way to select it: the field quietly fell back to the default and the plugin treated its own age as your mistake. It is now a text field with the same three offered as suggestions, and it accepts any model id. Use Test connection after changing it.
* The model id also used to be written down in seven places across three files, which is how a list like that ends up half updated. It is written down once now, and the shipped suggestions are unchanged in this release.

= 1.6.17 (2026-09-05) =
* An email with no plain-text part became a blank ticket. Inbound email-to-ticket read only the plain-text body a message carries, and mail sent as HTML alone has none, so the ticket was created with nothing in it while the endpoint reported success. The agent alert then said "(no message body)" and the customer receipt quoted nothing back, which reads at both ends like the desk lost the message. The HTML part is now used when there is no text part, converted to readable text so a message looks the same however it was sent.

= 1.6.16 (2026-09-04) =
* **The customer portal says what your support actually is.** The sign-in line and the support card used to mention support credits whether or not you had switched the paid support model on, which on a fresh install is off. They now describe opening and replying to a ticket, and the payment-return banner no longer announces a credit.

= 1.6.15 =
* **Tested with WordPress 7.1.**
* **The arcade panel now filters the markup it draws through an allowlist** instead of printing it as given. Nothing about how it looks or behaves changes, and the progress bar keeps the labels a screen reader reads out. The small script behind the milestone popups was tightened the same way.

= 1.6.14 =
* **Ticket attachments are now encrypted on disk.** Attachments live in your uploads folder, and whether that folder can be read directly over the web is decided by your web server, not by this plugin: Apache and LiteSpeed honour the rule the plugin writes, nginx and Caddy do not. Encrypting the files means a direct request returns unreadable data, so the support desk, which checks whether you are an agent or the customer who owns the ticket, is the only way to the file again. Existing attachments are converted quietly in the background, and files from before this release keep working either way. A new entry under Tools, Site Health tells you whether your server exposes the folder.

= 1.6.13 =
* **Attachment filenames now come from a cryptographic random source.** They were generated with a WordPress helper that other plugins are allowed to filter, which meant another plugin could decide how unguessable your attachment names were. Stored files are also written with tighter permissions.

= 1.6.12 =
* **Plainer writing.** A few messages used long dashes where a full stop or a separator reads more easily. Nothing functional changed.

= 1.6.11 =
* **The free contact widget no longer offers the categories that cost a support credit.** If you have turned the paid support model on, a question about one of your products was a tracked ticket on the Support page and a free message one click away on the same page. The widget now asks Tickets which categories are credited and simply leaves those out, so each door offers what it is for. Nothing changes if you have not turned the paid model on, because then nothing is credited.

= 1.6.10 =
* **There is now a plain list of every ticket inside WordPress admin.** The Support Desk is an app, and when an app fails it takes the whole queue with it. That is exactly what happened when the desk stopped loading on sites using Plain permalinks: for as long as it lasted there was no other way to see a single ticket. Under Tickets you will now find All Tickets, a straightforward table of every ticket with its status, the customer and their email address, which filters, searches and pages. WordPress builds it directly, with no JavaScript of its own, so it keeps working when the desk does not and it works with JavaScript switched off. It is read only on purpose. It is there so you can see the queue and answer people from your own mail, not to become a second desk. Your agents can open it too, not just administrators.
* **The desk no longer names the wrong plan beside a locked report.** Per-agent and per-department reporting unlocks on the first paid plan, but the reports screen said Studio: in the badge, on the button, and in three separate sentences. Anyone who saw those sections was being pointed at a plan more expensive than the feature actually needs. The plan name now comes from the same place as the check that unlocks the feature, so the two cannot drift apart again.

= 1.6.9 =
* **Everything the desk and the forms say can now be translated.** The plugin's JavaScript asks WordPress for translations exactly as its PHP does, but the translation catalog was built by scanning PHP only, so not one of those strings was ever offered to a translator. A fully translated site still showed the Support Desk, the customer portal, the support form and the widget in English, with no way to tell why. The catalog now includes them: 331 more strings, the desk among them. Nothing changed in the code that shows them, so an untranslated site looks exactly as it did.

= 1.6.8 =
* **The support paywall no longer throws away what you typed.** A customer who filled in the form, attached a file, and pressed Send watched the whole message vanish and be replaced by a request for payment. The form now stays where it was, the buy panel appears alongside it, and "Back to your message" returns everything untouched. The Send button is restored too, instead of staying stuck on "Sending...".
* **The paywall stopped claiming something that was not true.** It said an active subscription or an in-window license includes support. Under the credits model the in-window allowance is deliberately not used, so half that sentence was dead on arrival for the stores most likely to show it. It now states only what is true wherever it appears.
* **"New request" in the customer portal goes to the support form again.** The portal took whichever published page the database returned first for the shortcode, which could be a documentation page that merely quotes it. The plugin now records the pages it creates and prefers them, and the fallback lookup is ordered instead of arbitrary.

= 1.6.7 =
* **The arcade is fully translatable now, and its toasts can be dismissed.** Several labels the arcade shows (the dismiss button, the "Nice" message on a plain points toast, and the level badge) stayed in English no matter what language your site runs in, because the shared arcade code never passed them through for translation. They now translate like everything else, the level number is formatted for your locale, and every celebration has a close button. Toasts also pause while you hover or focus them, and skip their timer entirely if you have asked your system to reduce motion.
* **A site that cannot create the arcade tables now keeps trying.** On a host where the database user is not allowed to create tables, the plugin recorded the arcade as installed anyway and never tried again, so the arcade stayed silently broken forever. It now confirms the tables really exist before recording success, and retries later if they do not.

= 1.6.6 =
* **The arcade now has an off switch, and it covers the Support Desk too.** Since 1.6.5 the arcade has been off by default, but there was no control for it anywhere, so there was no way to turn it back on. There is now one under Appearance, alongside confetti and sound. It also does more than it used to: the Support Desk kept showing agents the XP chip, the leaderboard, and a points toast on every reply no matter what, because only the WordPress admin scoreboard honored the switch. One control now covers both. If you want the arcade on your desk, turn it on under Appearance.

= 1.6.5 =
* The arcade (XP, ranks, HUD, confetti) is now off by default. Turn it on any time under the plugin's Arcade settings. Nothing else changes.

= 1.6.4 =
* **A new ticket now emails somebody.** Agent email alerts are on by default, so the team hears about a new ticket or a customer reply even when nobody has the Support Desk open. Fresh installs used to ship with alerts off, which meant a complaint could sit unseen for days. Sites with saved Tickets settings keep them exactly as they are; the new default applies where the settings were never saved.
* **Customers get a receipt.** When a customer opens a ticket through the form, the widget, or the portal, they now receive one confirmation email with their ticket reference and a copy of their message, so they have a written record and something to reply to. You can turn this off under Tickets, General, "Send customers a receipt."
* **Receipts cannot start mail loops.** The receipt declares itself machine-sent (RFC 3834), is never sent to bounce or no-reply addresses, skips inbound mail that identifies itself as automatic, and is capped at two per address per hour. Bounce handlers and other helpdesks cannot ping-pong with it.
* **Alerts reach a one-person shop.** On a site where the support address is also the owner's own address, alerts used to be silently skipped by a safeguard this edition never needed. The owner now actually gets the alert.

= 1.6.3 =
* **The Support Desk now works on default permalinks.** On a fresh WordPress site set to Plain permalinks, the agent Support Desk could not load its ticket queue: it showed an empty inbox with a "No route was found" error while real tickets waited unseen. The desk now builds its addresses correctly under every permalink setting, so the queue loads and agents can answer tickets straight away.
* **A clear heads-up when permalinks need changing.** If your site is on Plain permalinks, administrators now see one dismissible notice explaining that setting Permalinks to Post name makes the Support Desk and the support pages work. This is the same setting that lets the /support/ and /my-tickets/ pages open instead of your blog.

= 1.6.2 =
* **American spellings throughout.** The plugin and this changelog used British spellings in places (licence, colour, behaviour, cancelled). They now match the rest of Bodholdt Labs. Wording only, nothing behaves differently.

= 1.6.1 =
* **Privacy requests now hand over the whole record.** A personal-data export includes every field on a ticket, the customer snapshot stored with it, private notes, activity history, tags, attachment details, and any web-push registrations, without ever exposing the secret that authenticates a push subscription. An erase request removes message content, activity, attachments, tags, stored customer snapshots, and push registrations. If you answer a request under GDPR, CCPA, or a similar law, what you produce is now complete.
* The other two changes in this release only affect the paid edition, so nothing else here is different.

= 1.6.0 =
The worldwide-readiness release. It also folds in every fix that shipped as 1.5.4 in the paid edition, because the free edition went from 1.5.3 straight to 1.6.0.
* **Translations finally load.** Earlier free builds shipped a correct translation template and correct headers but never told WordPress to read the plugin's `languages` folder, so no translation could ever apply. Fixed, and the build now fails if that call ever goes missing again.
* **Right-to-left support.** Arabic, Hebrew, Farsi, and other RTL languages lay out correctly across the admin screens, the support form, the portal, and the widget. No separate stylesheet is needed.
* **Times are correct outside UTC.** Dates and times in the Support Desk, the customer portal, and email now read correctly on sites that are not set to UTC. They previously drifted by your timezone offset.
* **Accessibility (WCAG 2.1 AA).** Fixed low-contrast headings, buttons, and focus rings; every focus indicator is now clearly visible; status and error messages are announced to screen readers; failed actions say what went wrong instead of silently reverting; animation honors the reduced-motion setting.
* **Free and paid can no longer collide.** Activating Bodholdt Tickets Pro while this edition is active used to end in a raw PHP fatal error. Now the second copy stops cleanly and an admin notice names the folder to deactivate.
* **Privacy.** The erase tool under Tools, Erase Personal Data now clears everything it should in the free edition, including data it previously left behind. Uninstall now also removes web-push subscriptions and per-user settings, on every site of a multisite network.
* **Security and reliability (from 1.5.4).** The erase tool fully drains customers with large ticket histories instead of stopping after the first batch. Internal agent notes and their attachments can no longer be reached from the customer portal. Portal actions carry a per-session token. Rate limiting keys on the real client address. Web-push endpoints must be HTTPS and are validated before use, and the stored push key is encrypted at rest. Legacy Office document uploads are accepted again, and a queue-search edge case no longer errors.
* **Attribution.** The bundled canvas-confetti library now ships with its ISC copyright and permission notice and a full license file, as its license requires.
* **Honest limits.** This readme previously said the free edition had no agent-seat limit. It does: 3 seats. The copy now says so plainly, and the FAQ explains it.

= 1.5.3 =
* **Privacy tools (GDPR export and erase).** The plugin answers data-subject requests through the built-in WordPress privacy tools. Export returns a customer's tickets, messages, and attachments; erase deletes the messages and attachments and anonymizes the ticket history. Suggested privacy-policy text is added to Settings, Privacy. No change to how the support desk works.

= 1.5.2 =
* **Arcade engine polish.** XP counts correctly when several events land at the same moment, the on-screen HUD labels are fully translatable, and celebration cards always stay within the screen. No change to how the support desk works.

= 1.5.1 =
* **The Support Desk now names your rank.** The desk's top-bar scoreboard shows your Response Ops rank (Rookie through Desk Legend) next to your level and XP, matching the wp-admin HUD, so your progress reads the same on both surfaces. Your stats panel shows it too.

= 1.5.0 =
* **Response Ops.** A HUD in wp-admin tracks your level, rank, and XP as you work tickets, and agents get the same on the Support Desk itself, with a celebration when a customer rates a reply or you reach a new rank. Trophies unlock as you go. All optional, sound stays off by default, and the desk works exactly as before.

= 1.1.0 =
* Settings redesign. The one long settings page is now a set of tabs (General, Channels, Notifications, Team, AI Co-pilot, Appearance), each with its own Save, so you configure one thing at a time. Every setting is exactly where it was, just grouped.
* A new setup status card at the top tells you at a glance whether your desk is ready, and links straight to the step that still needs doing.
* Custom fields now have a friendly row editor instead of a type-the-syntax text box. The plain text editor is still there under "Edit as text" if you prefer it.
* The widget embed snippet hides its secret token until you click Reveal, and has a one-click Copy button.
* The database table list collapses to a single "all tables ready" line unless something needs attention.
* Support Desk: every emoji is replaced with original brand icons, including the achievement badges. No functional change.

= 1.0.0 =
* **Out of beta.** Bodholdt Tickets graduates to 1.0 after 30 or more shipped releases. No breaking changes; this marks the product as production-stable.
* Added an "External services" section to this readme (Anthropic, Web Push) and self-hosted the admin font, so no admin request is sent to Google Fonts.

= 0.33.4 =
First public release of the free edition. A complete, self-hosted help desk with unlimited tickets, up to 3 agent seats, and no monthly fee:
* Unified front-end Support Desk with Open / Mine / All / Resolved filters, priority and category, and a full conversation thread.
* Front-end support form as a Gutenberg block or the `[bodholdt_support_form]` shortcode, with optional file attachments.
* Passwordless customer portal (`[bodholdt_portal]`). Visitors sign in by magic link to track, reply to, and open tickets, with no account required.
* Custom fields, canned/saved replies, and customer satisfaction (CSAT) ratings on resolved tickets.
* Built-in reports: ticket volume over time, by channel and category, response and resolution speed, CSAT, and top topics.
* Agent gamification: XP, levels, daily streaks, and a team leaderboard.
* Optional AI co-pilot. Bring your own Anthropic API key; it only ever drafts a reply for an agent to review and edit, and never sends on its own.

== Upgrade Notice ==

= 1.6.0 =
Recommended for everyone. Translations now load at all, times are correct outside UTC, right-to-left languages are supported, accessibility failures are fixed, privacy erase is complete, and installing the paid edition alongside this one no longer causes a fatal error. Carries the security fixes released as 1.5.4 in the paid edition.

= 0.33.4 =
First public release of the free edition.
