Skip to main content

Rentiva v5.2.3 / Pro v5.2.3 — A table WordPress was never really looking at, and a privacy notice that named the wrong things

· 5 min read
MaxHandMade
Maintainer

Another patch on the way to the WordPress.org submission, and another release where the interesting part is not the bug we fixed but what we found while checking whether we had described it honestly.

The table update that could never have landed

WordPress has a function, dbDelta(), that takes a CREATE TABLE statement and works out the difference between it and the table you already have — adding columns you have introduced since the last release, without touching the data already in them. It is how a plugin evolves its own schema safely.

It does not execute the statement. It parses it. And the way it finds the table's name is to take the first thing after the words CREATE TABLE.

Our background-job table was created with CREATE TABLE IF NOT EXISTS. So dbDelta() had been tracking, for as long as that table has existed, a table called IF.

The table itself was fine — the database executed the raw statement correctly and always had. Nothing was lost, and nothing is wrong on your site today. But dbDelta() runs DESCRIBE against the name it parsed, DESCRIBE IF fails, and a table it cannot describe is skipped entirely. Any column we added to that table in a future release would have been silently ignored: no error, no warning, dbDelta() reporting success while doing nothing.

We measured it rather than reasoning about it. Adding a column to the schema and re-running the migration before the fix: the column was not created. After the fix: it was.

The same defect was in two more CREATE TABLE statements in the paid add-on. One of them — the reports background-job table — is created on activation and genuinely had the problem. The other belongs to a monitoring subsystem that nothing currently starts; we fixed it anyway so both read the same way, and we would rather say that plainly than let a changelog imply we repaired something that was never running.

The privacy notice, rewritten because it was wrong

The readme's Privacy section is the part of a plugin page that a site owner copies into their own privacy policy. Ours said that every booking record stores the visitor's IP address and browser user-agent.

That turned out to be almost exactly backwards.

The code that writes an IP onto a booking sits behind an endpoint that nothing in the plugin posts to. The real booking flow — the form, the cart, WooCommerce checkout — records no IP at all. So the one store we disclosed was the one that, in practice, barely exists.

Meanwhile three that do exist were not mentioned:

  • The contact form. Every submission is kept with the sender's name, e-mail, telephone, company, the message, a link to any file they attached, and the IP and user-agent it came from. There is no retention setting on these records and nothing ever deletes them. The attached file goes to your ordinary uploads folder, reachable by anyone with the URL, and stays there even if you delete the message.
  • The rating form. Reviews are stored as ordinary WordPress comments, so WordPress itself records the reviewer's IP and user-agent — as it does for any comment. Guest reviews are reachable through Tools → Erase Personal Data, which matches comments by e-mail address. A review left by a logged-in customer is saved against their user ID with no e-mail on the comment, so those tools will not find it; you have to delete it from the Comments screen.
  • The e-mail log. Alongside the recipient and subject, it keeps the booking details each message was built from — customer name, contact details, rental dates. Not the assembled message body. It has its own retention setting, 30 days by default.

The activity log, which we had described correctly, keeps IP, user-agent and user ID per entry on a configurable retention, also 30 days by default.

Nothing about what the plugin stores has changed in this release. What changed is that the description of it is now true. If you have a privacy policy that was written from our old text, it is worth re-reading it against the new section.

How we found it, which is the part worth writing down

None of this came out of the fix. It came out of putting the fix in front of an independent model and asking it to disprove our own description, five times over. Each round found something in the text we had just written to correct the previous round: a list read as a delete-list when it was a keep-list; a test's normalised key names mistaken for the real ones; a count of ten where the code has a hundred and sixty-one.

The pattern in every one of them was the same — assuming what something meant instead of reading it. That is worth naming publicly, because it is the failure mode that produces confident, well-written documentation that happens to be false, and a privacy notice is exactly the kind of document where that does real harm.

The same rounds turned up a scratch file that had been shipping inside our release ZIPs since 5.2.1. The build now holds an allow-list of what may sit in the archive root and refuses to build otherwise, because the exclusion list we had could only ever catch the files somebody had thought of.

Upgrading

Nothing to do. There is no pending column for the corrected table, so nothing changes on your site on update; the fix is what makes the next schema change actually apply. Pro 5.2.3 ships alongside and requires Lite 5.2.3.