WP contact form remnants

What do contact forms leave in a site’s database when they’re deleted? How easy is it to manage the data they store? What personal data do they grab?

This is an issue for website owners, not plugin developers. It’s the website owner’s responsibility to know what’s in their database and if it contains any personal data. I mean, it’d be great for plugin developers to make that easy but it’s an impossible situation for them — they don’t want someone to accidentally delete their data so seem to have erred on the side of making deleting it a bit difficult. This is ok! They’re not doing anything wrong. If someone has a website that is collecting data* then it’s on them to make sure they understand how the form plugins they use store the data and what happens when the plugins they’ve been using are deleted.

*Anytime someone enters something on someone’s website, hits a button and something happens, there’s a decent chance that that data is going to be stored somewhere. It’s on website owners to know if it is and how to manage it.

What is considered personal data? Quoting from White & Case’s A practical handbook for the new EU data protection law:

“Personal data” means any information relating to an identified or identifiable natural person (“data subject”); an identifiable person is one who can be identified, directly or indirectly, in particular by reference to an identification number or to one or more factors specific to his physical, physiological, mental, economic, cultural or social identity.

Their handbook is a great overview; other law firms have similar ones.

When I say “data” from here on out I generally mean personal data or personally identifiable information.

Some general questions before collecting data:

  • Does it need to be stored?
  • Does it need to be stored on the site? (Why store it two places? Store newsletter signups with your newsletter marketing service, store support emails in something like Zendesk or even in a G Suite whatever they have now, collaborative inbox.)
  • Where is the server located and is it ok to store this data in that location?
  • Is the storage secure enough for the type of data collected?

Those are the questions I can’t answer for anyone else’s site but my own. This post is meant as an example of how to go about looking into data collection and storage in the WP database. It comes from a conversation with Heather Burns about contact forms.

So into the details. Here are the questions I asked:

  • Can the option to store data be turned on and off?
  • At what granularity?
  • Can the data be deleted when the plugin is deleted? (No plugin does this automatically from the plugin list page)
  • What personally identifiable data, other than the data from each form, is stored? Note that a user’s IP address can be personally identifiable data in the EU.
  • Is it possible to delete the data on an ad hoc or scheduled basis?(Heather added this question with the note “Do you have the option to automatically delete older submissions at a defined interval?” None of the plugins can do this out of the box, so I’m just going to look at deleting the data manually and see what happens.)

Before I start: I’m only looking at data stored in the WP database the site is using. There could be other ways and places to store data but in the main, this is where it’s going to live. I’ve made a little plugin that shows all tables / columns in the database. It’s called What’s in my database” and can be found here. This is all it does — list those two things, it doesn’t have any user interactions or explanation. Don’t know what tables WP core uses? I quite like the Codex page on the database here.

One thing to remember is that a plugin can’t delete its data once the plugin itself has been deleted. So even if the site is currently not storing data or there’s a plan in place on how to handle it, it’s worth having a look to see if a plugin has stashed something away some time in the past. I think, although can’t source, that this is what happened in the BPAS hacking case. My own websites have tables I forgot were there, it’s a pretty easy thing to do if you’re like me at least.

Also, I only really care about personal data. I don’t care about stuff dropped in eg ​​wp_options that the plugin uses to run. Let me know if there’s any personally identifiable info in there but there really really shouldn’t be!

Finally, I’d be super surprised if I hadn’t made an error or misunderstood something here. Find it and let me know.


Ninja Forms first because I’ve already installed it on the dev site.

Ninja Forms 3

800,000+ Active Installs

This is the free version. I mean, I think the only thing you can buy are add-ons and support — the plugin itself doesn’t change.

  • Can the option to store data be turned on and off?
  • At what granularity?
    • Yes on a per form level.
    • Turning off the “save to database” option doesn’t delete previously stored data however you can delete the data from the “submissions” screen which makes perfect sense. This is ONLY true if the form to which the submission was made still exists, otherwise they will not be listed.
    • In certain conditions — if a form has been deleted but not the submissions — it’s possible to have orphaned data in wp_posts and wp_postmeta and not be able to get to it via the “submissions” screen. It’d be great to have an “orphaned submissions” choice on the forms dropdown or a way to delete orphaned entries. This is a known issue: https://github.com/wpninjas/ninja-forms/issues/2490
  • Can the data be deleted when the plugin is deleted?
    • No. In Forms→Settings→General→Advanced Settings there is the option to delete all data when the plugin is deleted. It’s unticked by default. But even when ticked, this does not work. It doesn’t even delete the custom tables. There is an open issue here: https://github.com/wpninjas/ninja-forms/issues/2399
  • What personally identifiable data, other than the data from each form, is stored?
    • None
  • Is it possible to delete the data on an ad hoc or scheduled basis?
    • Submissions are cpts and listed in a WP List Table with the usual actions and bulk actions available. So ad-hoc yes, scheduled no.

Every time someone submits a form for which “save to database” is enabled, the submission gets stored as a post with the post_type “nf_sub” and the submission data gets stored as individual entries in wp_postmeta.

I’m looking at Ninja Forms 3.x but I think the previous versions also stored the personal data in the wp_postmeta table.

Tables created — none of them seem to contain personal data, it’s all stuff used to make the forms.

Table: wp_nf3_actions

  • Seems to be “things that a form can do” or oooh “actions a form can take” which such entries as “save”, “email”, “successmessage”.

Table: wp_nf3_action_meta 

  • This tells the form exactly how to implement the action in wp_nf3_actions — eg for the “email” action, it builds the appropriate email for that action using the data in this table. (“email” in wp_nf3_actions can result in different emails to different people.)

Table: wp_nf3_fields

  • What fields are in the form. Label, key (input name and id), type and what form it’s for.

Table: wp_nf3_field_meta

  • Lots! There’s a lot in here. Most of it is about styling I think? Maybe stuff like placeholders, that kind of thing. Default values? All the little bits input fields can have.

Table: wp_nf3_form_meta

  • All the little bits and bobs having to do with forms and their styling and whether or not to show them, that sort of thing.

Table: wp_nf3_forms

  • A lis of the forms.

Tables: wp_nf3_object_meta, wp_nf3_objects, wp_nf3_relationships


Gravity Forms

(edited, please see links to footnotes)

I have a developer license for Gravity Forms so I went ahead and included it in this list. It’s the only one I purchased though.

Gravity Forms has custom tables. It doesn’t store anything in wp_posts or wp_postmeta

  • Can the option to store data be turned on and off?
    • No. Not straight out of the box at least. There are filters.
  • At what granularity?
    • None. Everything gets saved.
  • Can the data be deleted when the plugin is deleted?
    • Yes, go to Forms→Settings→General Settings→Uninstall to delete all data. All GF tables are dropped, all options deleted and its upload folder is deleted. This looks thorough.
  • What personally identifiable data, other than the data from each form, is stored?
    • The IP address of the first non-admin to view the form each day is recorded. This has been changed in the 2.2.4.5 release and will be in 2.3 which is an auto-update.1
  • Is it possible to delete the data on an ad hoc or scheduled basis?
      • Entries are in a WP List Table so usual options there (bulk and individual entry delete) and deleting the entry deletes all its data and also any notes. You can delete form views using the bulk action “reset views” in the Forms list page. (The form views only contain ip addresses in some circumstances and only in entries made prior to the 2.2.4.5 update.)1

Tables created:

Table: wp_rg_form

  • A list of the forms and date created.

Table: wp_rg_form_meta

  • The specifics of the form, including fields, confirmations and notifications.

Table: wp_rg_form_view1

  • The following is only true for versions < 2.2.4.5
  • The IP address of the first non-admin to view the form each day is recorded. It doesn’t collect the data if I’m logged in as admin. Not sure the logic on that, let’s have a look. Ok, it only doesn’t collect the data if I’m admin like
    current_user_can( 'administrator' ) or if $view_counter_disabled === true
  • That’s a filterable variable in /gravityforms/form_display.php around line 750 or so:
    $view_counter_disabled = gf_apply_filters( array( 'gform_disable_view_counter', $form_id ), false );
  • So the only way to turn this off is via a filter.

Table: wp_rg_incomplete_submissions

  • This is used if “Save and continue” is ticked on the form settings. Those settings make it pretty clear what’s happening. There’s a unique id used and it stores user IP and partially filled out form as you’d expect. Once the form is fully filled out and submitted, this gets deleted.

Table: wp_rg_lead

  • Each form submission has an entry here. It saves user IP and user agent data as well as some details of the entry. It has details like whether an entry has been marked as read and payment status,  so not just generic submission data. It also has the user id if a user was logged on when they submitted the form.

Table: wp_rg_lead_detail

  • The field entries for each submission.

Table: wp_rg_lead_detail_long

  • Hmmm, not sure — is this used anymore? It looks like it’s similar to wp_rg_lead_detail but was only used for values which needed longtext.

Table: wp_rg_lead_meta

  • Meta for leads — this looks filterable so um maybe it’s used by add ons?

Table: wp_rg_lead_notes

  • Notes that users with the correct permissions (? I guess I could check this) can leave on individual form entries.
  1. edit 17 August 2017: I’ve updated this based on Carl Hancock’s comment and private conversation.

WP Forms Lite

200,000+ Active Installs

This is the free version. It’s called “Contact Form by WP Forms” — the paid for version might be completely different*. Well I’ve already installed it so will look at it.

  • Can the option to store data be turned on and off?
    • No — the free version doesn’t store data at all! That feature is used as an upsell: “Once you upgrade to the Pro version of WPForms, all future form entries will be stored in your WordPress database and displayed right here.” (this is what’s displayed when “Entries” is clicked so I’m guessing the pro version does by default)

So this doesn’t store any personal data from users. It stores the data necessary to make the form in wp_posts but doesn’t delete it when the plugin is deleted. There’s no option to delete this or the stuff it’s dropped into wp_options

If an upgrade is purchased, I’m guessing that the form data at least will be stored — again please note that this is the free version only.

*It’s possible to see what the pro version will add by browsing the code. But this version doesn’t do it so I’m ignoring that!


Contact Form & SMTP Plugin by PirateForms

200,000+ Active Installs

Again, this is the free version. This doesn’t allow multiple forms to be made, just one.

  • Can the option to store data be turned on and off?
    • Yes, in Settings→Pirate Forms→Options (disabling this does not delete data already stored)
  • At what granularity?
    • It just makes one form, so it’s all or nothing. Entries can be deleted from the list table.
  • Can the data be deleted when the plugin is deleted?
    • No
  • What personally identifiable data, other than the data from each form, is stored?
    • IP address in the post content
  • Is it possible to delete the data on an ad hoc or scheduled basis?
    • It’s in a WP List Table so it’s possible to bulk delete as well as individual delete.

This stores the data in wp_posts  with a cpt of “pf_contact” where the post content is, I’m guessing, the email message. (It’s a table with the data submitted, the user’s IP address, a helpful link to http://whatismyipaddress.com/ip/[user ip] and the page from which it was sent.) In the default example, the email is also stored in wp_postmeta


Contact Form 7

1+ Million Active Installs

  • Can the option to store data be turned on and off?
    • No it doesn’t store personal data from the forms
  • At what granularity?
    • It doesn’t store personal data
  • Can the data be deleted when the plugin is deleted?
    • There’s no personal data but the plugin deletes its entries in wp_posts and wp_postmeta when it’s deleted (those entries define the forms)
  • What personally identifiable data, other than the data from each form, is stored?
    • None

I’m flagging a bit, sorry these are getting shorter


Formidable Forms Form Builder for WordPress

300,000+ Active Installs

This is the free version. Form styles and actions are stored in wp_posts with the cpts “frm_form_actions” and “frm_styles”

  • Can the option to store data be turned on and off?
  • At what granularity?
    • Individual forms have the option “Do not store entries submitted from this form” which is unticked by default (ie entries are stored). There’s no global setting.
  • Can the data be deleted when the plugin is deleted?
    • On Formidable→Settings→Global Settings there’s a link to “Uninstall Formidable” in the bottom right corner. This deletes all the tables and data.
  • What personally identifiable data, other than the data from each form, is stored?
    • IP and user agent
  • Is it possible to delete the data on an ad hoc or scheduled basis?
    • One entry at a time! There are no bulk actions.

Tables created:

Table: wp_frm_fields

  • A list of the fields in each form.

Table: wp_frm_forms

  • A list of the forms.

Table: wp_frm_item_metas

  • The individual entries from each form.

Table: wp_frm_items

  • Submissions from the form. Includes user IP, user agent and user id if the user is logged in.

LAST ONE

Jetpack

1+ Million Active Installs

Not sure why you’d use Jetpack just for forms tbh. It collects a lot of data for itself and I’m just going to leave it. Don’t get me started on Gravatar.

2 thoughts on “WP contact form remnants

  1. Quick clarification: Gravity Forms does NOT store site visitor ip addresses when a form is viewed. It merely increments a view count for that form.

    Gravity Rorms does not provide analytics or form view tracking in anyway other than a simple view count increment unrelated to a specific users IP address. I’m not sure what gave you the impression it did, but the form view count is a non-user identifiable count increment and nothing more.

    This non-user identifiable view count can also easily be reset to 0 via the bulk actions on the Forms list page in the Gravity Forms admin. So yes, the count can be reset. But as it doesn’t store user information related to the count it’s not a GDRP related concern to begin with.

    You are correct that it stores the users IP address when they actually submit a form. This can easily be disable via available hooks/filters in the Gravity Forms developer documentation.

    There are multiple add-ons available that allow you to automatically delete the form entry data once it has been processed, any integrations triggered and any email notifications sent. For example, there is one available in the WordPress.org repo, one available from Gravity Wiz and the Gravity Forms developer documentation itself also has a how to on doing it yourself via hooks/filters.

  2. Thanks! I’ve updated the post. The form view table stores the IP address of the first non-admin viewer each day. I’m guessing this is an artefact of an earlier version?

    And yes! GF has a healthy ecosystem of add-ons and a lot of documentation to customise it to users’ needs. Eg I’ve used a version of this forever: https://thomasgriffin.io/prevent-gravity-forms-storing-entries-wordpress/

    I didn’t have the time or space to go into plugins’ ecosystems but site owners should definitely consider them when choosing plugins. Even if the base plugin itself doesn’t have something they need, chances are someone else has already developed something for that does it. And it’s WordPress: supply generally meets demand when people want something!

What do you think?

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s