Title: AI House Knowledge Chat
Author: vunguyenbh
Published: <strong>October 26, 2026</strong>
Last modified: October 27, 2026

---

Search plugins

![](https://ps.w.org/aihouse/assets/banner-772x250.png?rev=3766617)

![](https://ps.w.org/aihouse/assets/icon-256x256.png?rev=3766670)

# AI House Knowledge Chat

 By [vunguyenbh](https://profiles.wordpress.org/vunguyenbh/)

[Download](https://downloads.wordpress.org/plugin/aihouse.1.22.0.zip)

 * [Details](https://wordpress.org/plugins/aihouse/#description)
 * [Reviews](https://wordpress.org/plugins/aihouse/#reviews)
 *  [Installation](https://wordpress.org/plugins/aihouse/#installation)
 * [Development](https://wordpress.org/plugins/aihouse/#developers)

 [Support](https://wordpress.org/support/plugin/aihouse/)

## Description

AI House answers customer questions using your own website content, with two answer
branches:

 * **Quick chat** — a direct LLM call for greetings and simple questions.
 * **Deep knowledge** — searches a vector database for relevant content, then answers
   with citations.

On shared hosting the scarce resource is PHP workers, and a chat request that holds
one
 for several seconds is a real cost. This plugin is built around that limit:
every outbound call has a hard timeout, a circuit breaker, an answer cache, and 
a quota guard.

**Measured cost per chat request: 3 database queries, 1-3 outbound HTTP calls, and
zero writes to wp_options.**

#### Providers

 * **LLM:** OpenAI, Google Gemini, OpenRouter (including free models)
 * **Vector store:** Supabase (pgvector), Pinecone, Qdrant
 * API keys are stored per provider and encrypted at rest, or supplied as constants
   in wp-config.php

#### Knowledge sources

 * Any public post type you choose: posts, pages, products, custom types
 * **File import** — Markdown, CSV, JSON and plain text, with preview before importing
 * A dedicated Knowledge post type you can edit in wp-admin
 * Automatic re-index when content changes

#### Languages

 * **The chat widget ships with Vietnamese and English enabled by default.** Twelve
   languages are built in: Vietnamese, English, Simplified Chinese, Japanese, Korean,
   Thai, Indonesian, French, German, Spanish, Portuguese and Russian.
 * Visitors switch language with a button in the widget. **The bot answers in the
   language the visitor actually wrote in** — a Vietnamese question typed into a
   widget sitting on EN comes back in Vietnamese, and the widget follows the visitor’s
   language. The chosen language is what the answer falls back to when a message
   carries no signal (“ok”, “iphone”).
 * Welcome message, placeholder, system prompt and language instruction are configurable
   per language.
 * **The plugin’s own screens are translated, and you choose which translation to
   use.** Settings  General  Interface language picks the language of the AI House
   screens — the dashboard, the settings form, the notices — independently of the
   language of your WordPress profile. The choices are read from the translation
   files that ship with the plugin (English and Vietnamese today), so a locale added
   to the plugin shows up there without a code change, and “Follow WordPress” is
   the default.

#### Admin dashboard

 * **Overview** — messages, sessions, cache hit rate, latency, queue and circuit
   breaker state
 * **Conversations** — browse sessions and read full message threads
 * **Knowledge** — import from file, manage items, watch indexing progress
 * **Diagnostics** — test connections, inspect the environment and running configuration

#### Also included

 * Floating chat widget and `[mybot]` shortcode, light and dark themes
 * A AI House shortcut on the WordPress admin toolbar, with quick links to the dashboard,
   knowledge list and settings
 * Answer cache keyed per language, with question normalisation
 * Visitor feedback (helpful / not helpful) stored per message
 * Source citations returned to the widget so visitors can verify answers
 * Background queue with automatic retry and backoff
 * Automatic daily purge of old conversation logs
 * No jQuery dependency on the front end

### External services

AI House has **no server of its own**. It sends nothing to the plugin authors, and
it collects no analytics. It does call services **that you configure, with your 
own accounts**, and this section lists every one of them, what is sent, and where
to read their terms.

**The plugin does nothing until you enter a key.** With no key configured there 
is no outbound request of any kind, other than the two self-tests you can press 
yourself.

#### AI model provider — you choose one

 * **OpenRouter** — https://openrouter.ai · Terms: https://openrouter.ai/terms ·
   Privacy: https://openrouter.ai/privacy
 * **OpenAI** — https://openai.com · Terms: https://openai.com/policies/terms-of-
   use · Privacy: https://openai.com/policies/privacy-policy
 * **Google Gemini** — https://ai.google.dev · Terms: https://ai.google.dev/terms·
   Privacy: https://policies.google.com/privacy

**What is sent:** the visitor’s question, the recent turns of that conversation,
your system prompt for the current language, and — when the knowledge base has a
match — the retrieved text chunks. **What is not sent:** the visitor’s IP address,
any WordPress user data, your other plugin settings, or anything from your admin
screens.

#### Embedding provider — only when you index your own content

The same three providers can supply embeddings (OpenAI, Google and OpenRouter). **
What is sent:** the text of the content you chose to index, split into chunks. This
happens only when you press **Index knowledge**, which you do yourself; nothing 
is indexed in the background without it.

#### Vector database — optional

 * **Supabase** — https://supabase.com · Terms: https://supabase.com/terms · Privacy:
   https://supabase.com/privacy
 * **Pinecone** — https://www.pinecone.io · Terms: https://www.pinecone.io/terms/·
   Privacy: https://www.pinecone.io/privacy/
 * **Qdrant** — https://qdrant.tech (self-hosted, or the hosted service; no account
   is needed for the plugin itself)

**What is sent:** the text chunks and their vectors, plus the question’s vector 
when a search runs, so the nearest chunks can be returned. If you turn on the optional
conversation mirror, the conversation text is copied there too.

#### Webhook — optional, off until you set a URL

If you paste a webhook URL (n8n, Zapier, Make, your own endpoint) **and** switch
on the hand-over form, AI House POSTs the visitor’s question and the contact details
they typed — name, email, phone and their note — to that URL. **You** choose the
destination; the plugin has no default and sends nothing when the field is empty.

#### Your responsibilities

You are the data controller for your visitors’ conversations. Before enabling a 
provider, read its terms, and tell your visitors what you do with their messages
in your own privacy policy. WordPress’s own guidance on this is at https://wordpress.
org/documentation/article/privacy/.

### Shortcodes

Two shortcodes, for two different kinds of page.

**`[mybot]` — the chat widget, inline.** Put it on a support page when you want 
the conversation itself to be the page.

    ```
    `
    ```

[mybot title=”Support” height=”480″ theme=”light” lang=”en”]
 `

 Attribute
 Default What it does

 `title`
 the bot’s name The heading above the chat. Set by you, so the script leaves
it alone.

 `height`
 `480` Height in pixels of the inline widget.

 `theme`
 `light` `light` or `dark`.

 `mode`
 `auto` `auto` (the plugin decides), `quick` (always the model) or `deep`(
always your content).

 `lang`
 the site’s chat language Which language the chat opens in, when it is one
of the twelve.

**`[mybot_help]` — a help-centre block: search over your own pages, then a way to
reach a person.** This is the shape of a support front page: a heading, a large 
search box, results as the visitor types, topic links you choose, and a button that
opens the assistant. It searches your **published** pages and posts only — never
the knowledge base you imported, which is private on purpose.

    ```
    `
    ```

[mybot_help title=”How can we help?” subtitle=”Search the guides, or ask the assistant.”
placeholder=”Search the help pages” button=”Search” ask=”Ask the assistant instead”
topics=”Getting started|/getting-started, Billing|/billing”]
 `

 Attribute
 Default What it does

 `title`
 “How can we help?” The heading.

 `subtitle`
 empty One line under the heading.

 `placeholder`
 “Search the help pages” Text inside the search field.

 `button`
 “Search” The submit button’s label.

 `label`
 “Search the help pages” What a screen reader announces for the field.

 `ask`
 “Ask the assistant instead” The button that opens the chat.

 `topics`
 empty Comma-separated label and URL pairs, drawn as chips under the box.
A refused URL scheme is dropped.

Every visible word is an attribute, so the page can be written in your visitors’
language without touching the plugin. No template is needed: paste the shortcode
into an ordinary Page and it renders.

## Installation

 1. Upload the `mybot` folder to `/wp-content/plugins/`, or install the ZIP through
    Plugins > Add New > Upload Plugin.
 2. Activate the plugin. Five database tables are created automatically.
 3. Open **AI House** in the admin menu, then go to **Settings > Get started** — it
    lists the four things still missing, and nothing there is sent anywhere until you
    add your own API key.

#### Quick start with no cost

**AI House > Settings > Get started** walks through the four things a new install
needs, and says which are still missing. Nothing on that screen runs a test by itself.

 1. **Step 1 — connect an AI provider.** Choose OpenRouter and paste a key from https://
    openrouter.ai/keys. The key is checked as soon as you paste it. Then press **Test
    connection**: the step’s light turns green when the provider actually answers.
 2. **Step 2 — give it something to answer from.** Leave **Vector store** set to “None”
    to start with: the assistant then answers from the model alone. To answer from 
    your own content, follow _Adding your own knowledge_ below and press **Index knowledge**.
 3. **Step 3 — prove the knowledge base can be searched.** Type a question that is 
    written on your site and press **Look this up**. A score above your Minimum score
    is a pass.
 4. **Step 4 — see what it answers from.** This step reports whether the **knowledge
    lock** is on, and points at the card that shows the file it lives in. It has no
    switch on purpose — see _Answering only from your own content_ below.
 5. Visit your site and open the chat widget.

#### Answering only from your own content (the knowledge lock)

The assistant answers only from your website’s content when a file called **the 
knowledge lock** is on your server:

    ```
    `
    ```

wp-content/uploads/mybot/khoa-tri-thuc.md
 `

To switch it on, create that file with this block at the top:

    ```
    `
    ```

 `

    ```
    che-do: off on that line pauses the lock while keeping the file; **deleting the file** removes the lock completely. That is the whole interface — there is no button, no admin code, and nothing in this plugin ever writes to that file, so a plugin update cannot change it.
    ```

With the lock on, everything is searched against your knowledge base, and a question
with nothing above your **Minimum score** is refused **without calling the model**,
so it costs no tokens and the visitor is offered the “leave your email” form instead.
Short greetings are still answered. A file with no `MYBOT-LOCK` block is not a lock
file; a file that declares a lock but cannot be read properly (a missing or unknown`
che-do`) is treated as **on**, with the reason shown on the card.

⚠️ **A new install does not arrive locked** (changed in 1.10.0: earlier versions
created this file for you and handed over an admin code; that code was removed at
the request of the plugin’s author after it locked people out of their own setting).
Until you create the file, the assistant still answers questions your content cannot
cover, from the model’s own general knowledge, on your API key.

#### Adding your own knowledge

 1. Create a Supabase project in the region closest to your hosting
 2. Run the SQL file from the project `sql/supabase-schema.sql` in the SQL Editor
 3. Go to **AI House > Settings > Knowledge base**, choose Supabase, and paste your
    project URL and service_role key
 4. Go to **AI House > Knowledge**, drop in a file, click Preview, then Import
 5. Go to **Settings > Get started** and press **Index knowledge**, then let WP-Cron
    process the queue

#### What works without an account of ours

**You do not need an account with us, and there is no paid tier of this plugin.**
AI House has no server of its own: it is free, complete, and the code you install
is the whole product. No feature is locked, no trial expires, and installing it 
sends nothing to the authors.

What it does need is **your own** account with the provider you choose — an API 
key for the AI model, and optionally a vector database. That is your account, your
key, and your bill, and the plugin talks to those services directly from your site.

## FAQ

### Does this train or fine-tune a model?

No. It uses RAG. Your content is split into chunks, converted to vectors, and stored.
When
 a visitor asks something, the closest chunks are retrieved and placed in the
prompt. Nothing is trained, updates are instant, and you can see which source produced
each answer.

### Can I use it without paying for AI?

Yes. OpenRouter offers free models and Google Gemini has a free embedding tier. 
Note that
 OpenRouter free models are limited to 20 requests per minute and 50 per
day until you have purchased 10 credits. AI House checks your remaining quota before
calling and returns a friendly message instead of a raw error.

### What happens if the AI provider goes down?

The circuit breaker opens after a configurable number of consecutive failures and
serves
 your fallback message immediately, without holding a PHP worker. The real
reason is recorded and shown on the dashboard.

### Where are conversations stored?

In the `{prefix}mybot_messages` table, written in batches by a background job rather
than
 during the visitor request. Recent messages are sent as context for follow-
up questions, and old logs are purged automatically.

### Does it work on multisite?

Yes. Each site gets its own tables, options and knowledge base.

### Will my knowledge pages appear in Google?

No. The knowledge post type is not public, so it creates no front-end pages and 
is
 excluded from search. Citations therefore show the title only. If you want linked
citations, index regular pages or posts instead.

### Which file formats can I import?

Markdown, CSV, JSON and plain text. PDF and DOCX are not supported because extracting

text from them requires a PHP library that most shared hosts cannot install. Convert
those documents to Markdown first.

## Reviews

There are no reviews for this plugin.

## Contributors & Developers

“AI House Knowledge Chat” is open source software. The following people have contributed
to this plugin.

Contributors

 *   [ vunguyenbh ](https://profiles.wordpress.org/vunguyenbh/)

[Translate “AI House Knowledge Chat” into your language.](https://translate.wordpress.org/projects/wp-plugins/aihouse)

### Interested in development?

[Browse the code](https://plugins.trac.wordpress.org/browser/aihouse/), check out
the [SVN repository](https://plugins.svn.wordpress.org/aihouse/), or subscribe to
the [development log](https://plugins.trac.wordpress.org/log/aihouse/) by [RSS](https://plugins.trac.wordpress.org/log/aihouse/?limit=100&mode=stop_on_copy&format=rss).

## Changelog

#### 1.22.0 (26/10/2026)

 * **Cited links for knowledge imported from a file.** Citations have always carried
   a URL and the widget has always drawn it as a link — but the URL came from `get_permalink()`,
   which is empty for the private knowledge type and for every item imported from
   a file, so a citation showed a title with nothing to click. Each knowledge item
   now has its own **link**, set in a **Citation link** box on that item’s edit 
   screen or by a `url` column in the import file (all three templates include it).
 * **A link is accepted only inside this site:** a path such as `/dang-ky`, or a
   URL on the same host including `www.`. Another domain, `javascript:`, and an 
   empty value are refused, and the check runs when the link is **read** as well
   as when it is saved, so a bad URL already in the database cannot reach the widget.
   On a customer’s site, “the same host” is that customer’s own site.
 * No widget change, no database change: the stored link travels through chunk metadata
   into the sources list the widget already renders. The knowledge list also shows
   a Link column, so an item without one is visible without opening it.

#### 1.21.0 (18/10/2026)

 * **This plugin’s name changed.** The first submission was rejected because “MyBot”
   was too close to an existing chatbot product called MyBot.chat. It is now **AI
   House Knowledge Chat**, the slug is `aihouse`, and the text domain, plugin header
   and translation file names all follow it. If an older version is installed, delete
   that folder after activating this one.
 * **The description no longer compares this plugin to others**, and a dead link
   to a Qdrant terms page was removed. Twenty translator comments were added and
   five exception messages annotated, both at the request of the review team.
 * No setting was renamed and nothing else changed: options, knowledge base and 
   conversations are untouched.

#### 1.20.0 (18/10/2026)

 * **New: a help-centre shortcode, `[mybot_help]`.** A support front page needs 
   three things in one block: a heading, a search box over your own pages, and a
   way to reach a person. That is now one shortcode with seven attributes, and every
   visible word of it is yours to write in your visitors’ language. `[mybot]` still
   embeds the chat itself, inline, at whatever height you give it.
 * **The search finds your published pages and posts, and nothing else.** It never
   returns the knowledge base you imported — that table is private by design, and
   a public search box is exactly where an internal price list or a policy draft
   would leak. Draft, private and password-protected pages are excluded by the query
   itself, not by a list that could drift.
 * **Nothing on the help page can be turned into markup.** The title, the labels
   and the topic links are escaped when printed, a `javascript:` topic link is refused,
   results are written with `textContent`, and the excerpt the server sends has 
   its tags and shortcodes stripped — so a page title containing a script is shown
   as text.
 * **A search box that cannot be used as free workload:** at least two characters,
   at most 120, six results, and the same rate limiter as the chat. One character
   returns nothing and says why.
 * No new option, no database change: install over 1.19.0, and a page that already
   uses `[mybot]` keeps working unchanged.

#### 1.19.0 (18/10/2026)

 * **The directory gave this plugin the slug `aihouse`, not `mybot`, and WordPress.
   org requires the text domain to equal the slug.** The first submission scan came
   back with about three hundred `TextDomainMismatch` errors; they were all one 
   fact. The text domain is now `aihouse` in 976 places: 656 PHP strings, 160 in
   the admin sources, 160 in the built bundle, the plugin header, `load_plugin_textdomain()`,
   the `plugin_locale` filter, the translation file names, and the Jed key the dashboard
   reads.
 * **Renamed by tokenizer, not by search-and-replace.** 674 bare `'mybot'` literals
   exist in this codebase and most of them have to stay: the `[mybot]` shortcode,
   the admin page slug, the cache group, the menu parent, the Supabase/Pinecone 
   namespace, the folder the knowledge file lives in, `function_exists( 'mybot' )`.
   Only the ones that are the text-domain argument of a gettext call were touched—
   18 were deliberately left alone, and the tool lists them so a person can check.
 * **`Plugin URI` no longer points at `example.com`.** The automated scan rejects
   that domain outright; it now points at this plugin’s own page on WordPress.org.
   Replace it with your own homepage when you have one — a unique https URL is what
   the directory asks for.
 * **Twenty `translators:` comments added and five exception messages annotated.**
   The scanner treats a placeholder string without a translator comment as an error,
   and an exception built from a variable as unescaped output. Both were fixed at
   the source: the comments now say what each placeholder means, and each `throw`
   carries a one-line reason explaining that an exception message is not HTML.
 * **New guard: `tools/check-textdomain.mjs`** — nine rules and four injected-fault
   controls. It exists because nineteen guards all asked “do these parts agree with
   each other”, which they did, and none asked “do they agree with the slug” — a
   value that was consistent everywhere and wrong everywhere.
 * No new option, no database change: install over 1.18.4. **Your saved settings
   are untouched** — option names did not change, only the text domain used for 
   translations.

#### 1.18.4 (18/10/2026)

 * **Screenshots exist now.** Five of them, taken on a running site rather than 
   mocked up: `Get started`, the widget on a real page, `Overview`, `Knowledge`,`
   Customers`. The `== Screenshots ==` section that 1.18.2 had to remove is back,
   and its five captions match five real files (1600 px wide PNG, held in `assets/
   wp-org/`).
 * Where they go: WordPress.org reads `screenshot-1.png` … `screenshot-5.png` from**
   SVN `/assets/`**, not from the plugin ZIP — so this release carries the captions,
   and the pictures are committed separately next to the icon and banner.
 * Nothing else changed: no code, no setting, no string, no database. Install over
   1.18.3, or ignore this one if you install from the directory.

#### 1.18.3 (18/10/2026)

 * **`Contributors:` now carries the real WordPress.org username.** It held the 
   placeholder `aihouse`; the profile that a plugin page credits is read from this
   field, so a placeholder means the page credits nobody. It is `vunguyenbh` now.
   Nothing else changed: no code, no setting, no string, no database.
 * Why a new version number for one line: a ZIP that has been handed over is never
   edited in place. One line is exactly what a version number is for.

#### 1.18.2 (18/10/2026)

 * **The copy submitted to the directory, checked against the directory’s own rules.**
   Tags are down from eight to five (the directory accepts at most five, and the
   brand names of model vendors were dropped — this plugin is not affiliated with
   any of them), the short description is 123 characters instead of 165 (the submission
   form’s field holds 150), `Tested up to` says 7.1 rather than 6.6 (that is the
   WordPress this build was run on), and the Screenshots section is gone until the
   pictures exist: a tab of five broken images is worse than no tab. The five shots
   still to take are listed in `docs/19`.
 * **Two places printed without escaping, found by running the coding-standard check
   the way it is documented** (1.18.1 ran it narrowed to security sniffs, which 
   is why they were missed): the chat panel markup was echoed through a call spanning
   several lines, so a single-line `phpcs:ignore` never covered it, and the requests
   screen formatted `Request #%d` with an integer the reader could not see had been
   cast. Both now escape a finished string.
 * **A number I published was wrong, and this release corrects it.** 1.18.1 recorded“
   46 errors / 16 warnings, exactly the previous level”. Re-measured on all three
   release trees with the documented command: **1.16.0 = 46/16**, **1.18.0 = 100/
   53**, **1.18.2 = 42/16**. The 46/16 figure belonged to 1.16.0, not to 1.18.1 —
   54 errors came in with the new files and I had not measured them. The real table
   is in `docs/18`, and 92 of them were fixed mechanically with `phpcbf` (layout
   only).
 * **Evidence that the reformat changed layout and nothing else:** every string 
   literal in the three files `phpcbf` rewrote is still present the same number 
   of times (124/124, 40/40, 916/916), all 69 tone-map pairs are unchanged, the 
   189 runtime assertions still pass, and all 19 guards pass.
 * **The 42 errors and 16 warnings that remain are each accounted for** in `docs/
   18`: 20 missing translator comments, 9 block comments, 8 `current_time( 'timestamp')`
   calls, 5 exception messages (an exception is not output), 3 `meta_key` reads 
   on an indexed key, one interpolated `%s,%s,%s` built from a count rather than
   from user data, and one `$submenu` — which is how WordPress lets a plugin order
   its submenu. None of them reaches a page.
 * No new option, no database change, no new translatable string: install this over
   1.18.1.

#### 1.18.1 (16/10/2026)

 * **Security review before the WordPress.org submission**, written up in the project
   as docs/18: the measured attack surface (19 REST routes, 3 admin-post actions,**
   no upload path at all**, no wp_ajax_, 45 prepared statements, no eval/extract/
   curl_), three layers of checking, and every finding classified as fixed, verified,
   or accepted with a reason.
 * **Two real fixes.** The chat route refused an oversized picture only _after_ 
   decoding it, so a 50 MB payload cost the server about 37 MB of memory before 
   the refusal — the size is now checked on the string first, and on the bytes afterwards.
   And the hand-over route stored a question of any length; it is now capped at 
   5,000 characters (20,000 for the answer), which is far above anything the widget
   can send.
 * **New automated check (9 rules, 10 injected-fault controls)** that encodes what
   a WordPress.org reviewer looks for by hand: a REST route without a permission_callback
   is a PUBLIC route, no unprepared database read, no request value printed unescaped,
   an ABSPATH guard in every file, a nonce _and_ a capability on every admin action,
   an uninstall that removes all six tables, and the readme fields the directory
   requires.
 * **No new coding-standard violations** (46 errors / 16 warnings, exactly the previous
   level) and 189 runtime assertions still pass. No new option, no database change:
   install over 1.18.0.

#### 1.18.0 (16/10/2026)

 * **Fixed: the bot refused a thank-you.** A visitor wrote “thanks for your support”
   and received “this question is outside the information this website holds” — 
   a refusal to somebody who had just been polite. The lock recognises politeness
   only by a 15-character length rule, so it caught “Hi” and missed every polite
   sentence longer than that: the more polite the visitor, the worse the reply. 
   Politeness now has its own list in all twelve languages, with guards that keep
   it from swallowing a real question (no digits, no question mark, no question 
   word, and the rest of the message may only be filler), and a greeting is answered
   warmly with no facts in it — so the lock stays a lock.
 * **Vietnamese with or without tones is the same person:** “cam on ban da ho tro”
   matches “cảm ơn bạn đã hỗ trợ”.
 * **The default System prompt now carries the written guideline:** two or three
   sentences and never more than five, greetings and thanks answered as greetings
   and thanks, and never an invented price, a date, a policy or a phone number —
   say plainly that you do not know and offer a human instead. A prompt you have
   edited yourself is never overwritten.
 * No new option, no database change, no new translatable string: install this over
   1.17.0.

#### 1.17.0 (16/10/2026)

 * **New: the chat can now collect your visitors’ contact details, and you can read
   them on a screen of their own.** A person icon in the message box opens a short
   form (a name, and **either** a phone number **or** an email address), and after
   three questions the chat offers the form **once**, as a bubble with a button —
   never a form that opens by itself, and never anything that blocks the conversation.
 * **New screen: Customers.** Name, how to reach them (and which channel they prefer),
   whether they agreed to be contacted, their note, language and date — with **Download
   CSV** and a **Delete** button on every row. The CSV opens in Excel with Vietnamese
   characters intact, and any cell a visitor typed that begins with `=`, `+`, `-`
   or `@` is neutralised: visitor text is untrusted input, and Excel would otherwise
   run it as a formula on the computer of whoever exported it.
 * **One person is one card.** A returning visitor arrives on a new session, so 
   a card is matched by session, then by email, then by phone, and updated in place.
   Phone numbers are normalised (`+84 912-345-678` and `0912345678` are the same
   person), and an empty field never overwrites something the visitor told you earlier.
 * **Consent is recorded so that it can be proved:** not only a tick, but the exact
   sentence the visitor agreed to **and** the moment they agreed — taken from the
   plugin’s own language table and never from the browser, because a client that
   can send its own sentence can record agreement to anything.
 * **WordPress’ two privacy tools now cover this data.** Tools  **Export Personal
   Data** and Tools  **Erase Personal Data** find and remove a customer by their
   email address or phone number, including the questions they left for your team.
   Until this release, the honest answer to “what do you hold about me” was “open
   phpMyAdmin and look”.
 * **The details never leave your site:** they are not copied to Supabase, not put
   into the knowledge base, and the card records only the page path — never its 
   query string. A card is deleted when you delete it, and the whole table is dropped
   if the plugin is uninstalled.
 * **One database change** (a new table, applied automatically on upgrade) and 36
   new translatable strings, all translated. Install this over 1.16.0, deleting 
   the plugin folder first as always.

#### 1.16.0 (16/10/2026)

 * **All the tools moved to the left of the message box.** The microphone used to
   sit between the field and Send, which put one tool on each side of the box; the
   picture button and the microphone now stand together on the left, the field takes
   the rest of the row, and Send alone ends it.
 * **Send is an arrow now, not the word.** The button is a round 40-pixel control
   with a paper-plane drawn as a vector path: it takes your site’s colour, stays
   sharp at any size, and adds no page weight. The word “Send” is not gone — it 
   moved to the three places that give a button its NAME (`aria-label`, `title`,
   and a visually hidden line inside it); all three are printed in the visitor’s
   language and all three follow the language switcher, so a screen reader still
   says “Gửi” on a Vietnamese chat window.
 * **The box strengthens while there is something to send.** Empty, the pill is 
   quiet and the arrow is muted; as soon as a question is typed, the pill turns 
   white and the arrow comes up to full colour with a soft shadow; clearing the 
   field puts both back. The arrow stays clickable while it is muted — a control
   that merely looks quiet is honest, while a truly disabled one would be a button
   that does nothing.
 * **Fixed quietly on the way:** the widget used to rely on your theme for the `.
   screen-reader-text` class. On a theme that does not define it, the hidden labels
   would have become visible text — which, now that Send is an icon, would have 
   printed “Send” right next to the arrow. The widget defines that rule itself, 
   so no theme can undo it.
 * **No new option, no database change, no new translatable string** — the word “
   Send” is reused, only the place it is printed changed. Three new automated rules
   now protect exactly the three things requested (tools on the left, an icon-only
   Send with a real accessible name, and the strengthened state), and each one has
   a deliberately broken version the test must catch. Install this over 1.15.0, 
   deleting the plugin folder first as always.

#### 1.15.0 (15/10/2026)

 * **The message box has been redrawn** into the shape of the chat app composer 
   the plugin’s author sent a picture of: **flat icons in a row along the bottom**,
   and **the field as a filled pill**.
 * **The microphone and the picture button lost their outlines.** They were 36-pixel
   circles with a grey border, which reads as a form control; they are now plain
   icons in your site’s colour, and a soft round background appears only when a 
   finger or a mouse is on them, or when they are reached with the keyboard.
 * **The field lost its border and gained a background** — a filled pill that turns
   white and takes your site’s colour as a ring while it is focused. The **Send**
   button is rounded to match, and **all three controls are now exactly the same
   height**, so the row is straight instead of a pixel out here and there.
 * **The strip that shows a picture before it is sent** was redrawn to match: no
   outlines, and a round remove button with a soft red background on hover.
 * **The dark theme was corrected in the direction that is easy to get wrong:** 
   on a dark panel the pill is _lighter_ than what is behind it, because a dark 
   field on a dark panel disappears.
 * **Nothing was renamed** — not one class, attribute, label or translated string.
   That is deliberate, and it is what makes this release safe: the widget’s script,
   its twelve languages and its accessibility labels all keep working on exactly
   the same names.
 * **Two new automated rules protect the new shape**, and they are checked in a 
   real DOM rather than by reading the stylesheet: the row must stay aligned along
   the bottom (a six-line question must not leave the icons floating in the middle
   of a tall box), and the microphone, the picture button and Send must stay the
   same height. Both rules fail against 1.14.1 and pass here, which is how the change
   is proved.
 * No new option, no database change, no new translatable string: install this over
   1.14.1. As always, delete the plugin folder before uploading, so no old stylesheet
   is left behind.

#### 1.14.1 (14/10/2026)

 * **Fixed: the attach-a-picture button in 1.14.0 opened the file picker, but choosing
   a photo then did nothing.** The button was there, the picker opened, and after
   choosing a picture no preview appeared and nothing could be sent. The cause was
   one line of JavaScript in which a variable was declared inside one function and
   used in the one around it, so the script stopped with an error on the first photo
   a visitor chose.
 * **Why this release exists at all:** every automated check in this project passed
   while the button was dead. They are all _readers_ — they confirmed the button
   ships hidden, that the script reveals it, that the reveal is gated on whether
   your model can read images, that the stylesheet keeps `hidden` working, and that
   a picture travels as a data URI inside the chat request. All of that was true.
   None of it ran the code.
 * **New: a check that clicks the buttons.** The plugin now has an automated test
   that loads the shipped script into the shipped markup in a real DOM and actually
   presses the microphone and the picture button, chooses a file, removes it, tries
   to send a picture with no question, and sends one with a question — 28 assertions,
   plus four deliberately broken versions of the widget that the test must catch(
   one of them is exactly the 1.14.0 defect). It fails against 1.14.0 and passes
   against this release, which is how the fix is proved.
 * **Fixed in the same release:** the picture button is now also tested against 
   a browser that cannot shrink a picture in a canvas and against a model that cannot
   read images — in both cases the button must stay hidden rather than appear and
   refuse.
 * No new option, no database change, no new translatable string: install this over
   1.14.0.

#### 1.14.0 (14/10/2026)

 * **New: the attach-a-picture button, so a visitor can send a photo with their 
   question** — a photo of a damaged part, a screenshot of an error, a picture of
   the form they are filling in. It sits at the left of the message box, and it 
   appears only when the model configured on your site can actually read an image(
   the plugin asks first, the same question `Test connection` answers).
 * **Pictures are NOT put in the Media Library.** Anything under `uploads/` is published
   at a web address that anyone who has it can open, with no login, and a visitor’s
   photo is not that kind of file. Pictures are stored in a separate folder that
   the web server is told to deny, under a name made of 16 random bytes; nothing
   links to them, nothing lists them, and the file name is never printed on any 
   screen.
 * **Only an administrator can look at one, and only through a permission-checked
   link.** A picture is addressed by _message number_, never by file name; the request
   is refused unless you are logged in with `manage_options`; and the reply is marked“
   never cache”, so a photo the site promises to delete does not live on in a browser
   cache or a shared proxy.
 * **A picture is sent together with the question, inside the normal chat request**—
   there is no separate upload endpoint, so there are no orphan files and no second
   permission to get wrong. The question is still required: the knowledge search
   works on **text**, so a photo on its own has nothing to look up, and the widget
   says so in the visitor’s own language instead of doing nothing.
 * **Photos are shrunk in the browser before they are sent:** longest side 1024 
   pixels, JPEG. A phone photo is 3–8 MB and 4000 pixels wide, and image cost is
   charged by area — roughly a thousand tokens at 1024 pixels against about sixteen
   times that unshrunk, for detail nobody asked about. It is also what keeps a visitor
   on mobile data from waiting a minute for an upload. Small PNG and WebP pictures
   are sent untouched, because re-encoding those as JPEG would throw away their 
   transparency.
 * **Pictures are deleted with the conversation.** When the retention job removes
   old conversations it removes their files first and their rows second — a deleted
   row with a file left behind is a photo on your disk that nothing remembers, that
   no screen can show, and that no cleanup would ever find again. A guard rule checks
   that order.
 * **New on the Requests screen: “Pictures visitors sent”.** A closed list showing
   the recent photos with their size and the conversation they belong to, so a picture
   is something you can actually look at. (The Conversations screen is a React application
   whose build is not part of this repository, so it does not draw photos yet — 
   that is the honest state of it.)
 * **Fixed (my mistake, and the kind that only appears on a site already running):
   adding the new database column did not bump the database version**, and the upgrade
   step returns early while that version matches — so an existing site would have
   kept the old 13-column table while the logger now writes 14, which would have
   broken _every_ log write, not only the picture ones. The version is bumped, and
   the plugin’s own harness found this by running against a real site’s real database.
 * **Privacy, in plain words:** the picture is stored on **your** site, readable
   by **your** administrators, and deleted with the conversation it belongs to; 
   it is not copied to Supabase. On a host running **Nginx**, `.htaccess` is ignored,
   so the folder is not actively denied there — the file is still unguessable and
   still served only through the admin-only link, but that is a weaker promise, 
   and it is better said than discovered.
 * 20 new translatable strings, all translated; no new option; one database change(`
   mybot_messages` gains a column, applied automatically on upgrade).

#### 1.13.0 (14/10/2026)

 * **New: a microphone in the chat, so a visitor can speak their question instead
   of typing it.** The words are recognised by the browser’s own speech service 
   and arrive in the text box as text — they are **not** sent straight away, because
   recognition mishears and a confident answer to a misheard question is worse than
   one the visitor had to read twice. They read it, correct it if needed, then press
   Send.
 * **The button is hidden in the HTML and only revealed when the browser can actually
   recognise speech.** Firefox cannot, so on Firefox the button never appears at
   all. A visible button that does nothing is a defect this plugin has shipped before,
   and the guard tool now fails the build if the button stops being hidden — including
   the one CSS line (`display`) that would silently override `hidden` in every browser.
 * **The language is asked for properly.** The speech API wants a tag like `vi-VN`,
   while this plugin’s language codes are two letters; given `vi` it listens and
   returns nothing, with no error at all. All twelve languages now carry a proper
   tag, a site can correct one with a filter, and an unknown language falls back
   to a real tag rather than an empty one (an empty tag makes the browser listen
   in _its own_ locale, silently).
 * **No audio is recorded, stored or uploaded — only text.** The recognition happens
   inside the browser’s own speech service; the plugin never receives the sound.
   A guard rule fails the build if a recorder or an upload ever appears in the widget’s
   script. Be aware of what that sentence does and does not mean: the sound never
   reaches _your_ server or _your_ AI provider, but browsers implement this by sending
   it to their own vendor’s service (Chrome to Google).
 * **What is still missing:** the attach-an-image button. That is the next step 
   and the bigger one — the chosen design stores visitor photos privately and serves
   them through a permission-checked route, which needs a new database column, a
   private folder, and a screen to show the photo on.
 * No new option, no database change, and no new translatable admin string (the 
   two labels are per-language _content_, like the rest of the widget’s words): 
   install over the top.

#### 1.12.1 (14/10/2026)

 * **Fixed (important): 1.12.0 could take a whole site down if the plugin folder
   was only partly updated.** WordPress showed “There has been a critical error 
   on this website” on every page. The cause was mine: 1.12.0 declared two capability
   methods on a PHP _interface_, and PHP resolves an unimplemented interface method
   the moment the class file is loaded — so an OLD provider file sitting next to
   the NEW interface killed the site. That is exactly what a File Manager or FTP
   upload leaves behind when one file fails to copy (and what an opcache can serve
   even when the file on disk is new).
 * **Fixed by making those two methods optional** and routing every question through
   one defensive call that answers “no” when the method is missing. Nothing else
   changed: the three providers still declare them, and a normal question still 
   produces exactly the same request as before.
 * **The rule this leaves behind:** a provider missing a capability method must 
   mean “the feature is unavailable”, never “the site is down”. If you are on 1.12.0
   and your site is showing the critical-error page, delete the `mybot` folder and
   install this version fresh — a partly copied folder is what breaks, so removing
   it first is the fix.
 * No new option, no database change, no string change: install over the top.

#### 1.12.0 (13/10/2026)

 * **New: AI House can now be asked whether the chosen model can read an image, 
   and `Test connection` prints the answer.** This is the first step towards picture
   and voice input, and it is deliberately a question rather than a feature. Sending
   a photo to a model that only reads text fails at the provider, in English, _after_
   the request is paid for — so the plugin answers the question first, on the screen
   you already use to check the connection.
 * **New: message content can carry a picture.** Until this release a message was
   plain text, and each of the three providers turned that text into its own format
   on its own. Picture input would have meant changing all three, and one mistake
   there is invisible: a provider that does not understand a part drops it and answers
   as if you had sent words only. Content now has one canonical shape (text, image)
   with one converter per wire format.
 * **Nothing is ever dropped.** A part the destination format cannot express still
   travels — as text carrying its own JSON — instead of vanishing. A silently ignored
   photo is worse than an error, because the answer looks like an answer.
 * **The text path is unchanged, and that is measured, not promised:** for a normal
   question, OpenAI and OpenRouter still receive `content` as a plain string and
   Gemini still receives exactly one text part, byte for byte as in 1.11.1.
 * **The list of image-capable models is a hand-kept belief, not a measurement**—
   no provider publishes a field this plugin can read, and the …

## Meta

 *  Version **1.22.0**
 *  Last updated **2 days ago**
 *  Active installations **Fewer than 10**
 *  WordPress version ** 6.2 or higher **
 *  Tested up to **7.1.4**
 *  PHP version ** 7.4 or higher **
 * Tags
 * [AI](https://wordpress.org/plugins/tags/ai/)[chat](https://wordpress.org/plugins/tags/chat/)
   [chatbot](https://wordpress.org/plugins/tags/chatbot/)[LLM](https://wordpress.org/plugins/tags/llm/)
   [rag](https://wordpress.org/plugins/tags/rag/)
 *  [Advanced View](https://wordpress.org/plugins/aihouse/advanced/)

## Ratings

No reviews have been submitted yet.

[Your review](https://wordpress.org/support/plugin/aihouse/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/aihouse/reviews/)

## Contributors

 *   [ vunguyenbh ](https://profiles.wordpress.org/vunguyenbh/)

## Support

Got something to say? Need help?

 [View support forum](https://wordpress.org/support/plugin/aihouse/)