Title: Terms &amp; Conditions Consent Log
Author: Fernando Tellado
Published: <strong>May 17, 2026</strong>
Last modified: October 3, 2026

---

Search plugins

![](https://ps.w.org/terms-conditions-consent-log/assets/banner-772x250.jpg?rev=
3535064)

![](https://ps.w.org/terms-conditions-consent-log/assets/icon-256x256.jpg?rev=3535064)

# Terms & Conditions Consent Log

 By [Fernando Tellado](https://profiles.wordpress.org/fernandot/)

[Download](https://downloads.wordpress.org/plugin/terms-conditions-consent-log.1.8.0.zip)

[Live Preview](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/?preview=1)

 * [Details](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/#description)
 * [Reviews](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/#reviews)
 *  [Installation](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/#installation)
 * [Development](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/#developers)

 [Support](https://wordpress.org/support/plugin/terms-conditions-consent-log/)

## Description

WordPress stores consent as a yes. Nothing about when, from where, or which version
of your terms was on screen. The day somebody disputes it, that yes is worth very
little.

Terms & Conditions Consent Log fills the gap on any acceptance checkbox of your 
site: WooCommerce checkout (classic and blocks), Contact Form 7, WPForms, Gravity
Forms, Fluent Forms, comments, login and registration, or a stand-alone shortcode
or block.

Every accepted consent writes a row to a dedicated indexed table with the timestamp,
the IP, the user agent, the document version in force and the exact text shown, 
sealed with a SHA-256 hash so any later change is detectable. Exactly what Article
7.1 of the GDPR requires you to be able to demonstrate.

Filter, search, export to CSV, integrate with the native WordPress Privacy Tools
and open a printable A4 certificate for any record, one click to save it as PDF.

#### Works with or without WooCommerce

The admin menu lives under Users  Consent log on every install, with or without 
WooCommerce. The WooCommerce-specific bits (checkout capture for both the classic
and the block checkout, order metabox, “Consent” column on the orders list, optional
consent line in the order emails) load only when WooCommerce is active; everything
else (Records, Settings, CSV export, PDF certificate, Privacy Tools integration)
works the same way on any WordPress site.

#### Sources of consent

 * **WooCommerce classic checkout** (auto when WC is active): captures the native
   terms checkbox. Stored as `terms_and_privacy`.
 * **WooCommerce block checkout** (auto when WC is active): captures purchases made
   through the block checkout, which is what WooCommerce builds for new stores since
   version 8.3 and which the classic hooks never see. Stores the exact wording of
   the Terms and Conditions block. Recorded as `terms_and_privacy` when that block
   requires a checkbox, or as `terms_notice` when it only shows the informational
   paragraph WooCommerce ships by default, so acceptance by conduct is never logged
   as explicit consent. An opt-in toggle adds a required checkbox of the plugin’s
   own, validated server-side, for evidence that does not depend on browser-side
   validation. On by default.
 * **Contact Form 7** (auto): detects [acceptance] fields automatically and the 
   first email field of the form. Stored as `cf7_form_{ID}`, one type per form. 
   No snippets required. On by default; turn off in Settings if it does not apply.
 * **WPForms** (auto): detects GDPR Agreement fields automatically and the first
   email field of the form. Stored as `wpforms_form_{ID}`, one type per form. Works
   with WPForms Lite and Pro. No snippets required. On by default; turn off in Settings
   if it does not apply.
 * **Gravity Forms** (auto): detects Consent fields automatically and the first 
   email field of the form. Stored as `gravityforms_form_{ID}`, one type per form.
   No snippets required. On by default; turn off in Settings if it does not apply.
 * **Fluent Forms** (auto): detects GDPR Agreement and Terms & Conditions fields
   automatically and the first email field of the form. Stored as `fluentforms_form_{
   ID}`, one type per form. Works with Fluent Forms Lite and Pro. No snippets required.
   On by default; turn off in Settings if it does not apply.
 * **WordPress comments** (auto): logs the native `wp-comment-cookies-consent` checkbox(
   introduced in WP 4.9.6) when the visitor opts in. Stored as `comment_consent`.
   On by default; turn off in Settings if your site uses Disqus, Jetpack or another
   third-party comments system. Note that this native checkbox is a cookie preference,
   not consent to store the commenter’s data.
 * **Privacy consent on comments and WooCommerce reviews** (opt-in): adds a required
   privacy checkbox to the comment form, blocks the submission server-side if it
   is left unticked, and stores the acceptance as `comment_privacy`. This is the
   Article 7.1 consent to processing the name and email a commenter hands over, 
   as opposed to the cookie preference above. WooCommerce product reviews share 
   the comment form, so they are covered by the same option. Off by default.
 * **Membership, course and custom sign-up forms** (opt-in): captures accounts created
   outside the standard WordPress and WooCommerce forms, such as those from MemberPress,
   LearnDash, Ultimate Member or Paid Memberships Pro, and multisite sign-ups. Stored
   as `user_register`. Accounts created from the admin Users screen are never recorded.
   Off by default.
 * **WordPress login and registration** (auto): captures successful logins and registrations
   through wp-login.php when a consent checkbox is ticked on the form. Stored as`
   wp_login` and `wp_register`. Registration is on by default; login is off by default(
   a normal login form has no consent checkbox, so login only matters for re-consent
   flows). The “Remember me” checkbox is excluded by design (ePrivacy / cookie preference,
   not GDPR consent).
 * **WooCommerce login and registration** (auto when WC is active): same idea for
   the My Account page. Stored as `wc_login` and `wc_register`. Registration is 
   on by default; login is off by default, like the WordPress rows above. An opt-
   in toggle can inject the consent checkbox into the WC register form, since WooCommerce
   does not ship one natively.
 * **`[tccl_consent_box]` shortcode and Gutenberg block**: drop a self-contained
   consent checkbox in any page, post or widget area as a stand-alone block. Submission
   posts to a REST endpoint and writes a record. Always available.

For anything else (Elementor Forms, Forminator, custom flows), call `tccl_save_consent()`
from the appropriate hook.

#### Why a dedicated table

Storing thousands of consent records in `wp_postmeta` is wasteful and slow. The 
plugin uses its own indexed table and exposes a public function (`tccl_save_consent`)
that you can call from anywhere to log additional consents in the same place.

#### Main features

 * Records timestamp UTC, IP, user agent, document version, source URL and full 
   consent text per acceptance.
 * Custom database table with the right indexes (no `wp_postmeta` bloat).
 * **Tamper-evident**: each record is sealed with a SHA-256 hash. Any later change
   to the stored text is detected and reported as TAMPERED in the records list.
 * **Sealed copies of your legal pages**: every time your privacy policy, terms 
   or refund page change, a copy of what they said is kept and sealed, and each 
   record points to the copies in force when the consent was given.
 * **Printable A4 certificate** per record, with a built-in “Print / Save as PDF”
   button — the browser exports the certificate to PDF natively, no external library
   bundled.
 * **Native Privacy Tools integration**: `Tools > Export Personal Data` and `Tools
   > Erase Personal Data` both include consent records (erasure anonymises rather
   than deletes — the record itself is the lawful basis to keep it).
 * WooCommerce checkout texts are **optional** — leave them empty and the WooCommerce
   native text is shown to the customer and stored verbatim.
 * Automatic version bump when the text changes (suggests `MAJOR.MINOR-YYYY-MM-DD`).
 * Optional opt-out of IP and/or user agent tracking.
 * Configurable retention with a one-click anonymise button (records kept; PII scrubbed).
 * **Configurable access by role**: grant the consent log to extra roles (for example
   a DPO) from Settings  Access, without making them administrators.
 * **One record per ticked box**: a form with a required privacy checkbox and an
   optional marketing one produces two separate records, so the optional consent
   is evidenced on its own instead of being swallowed by the required one.
 * **Per-form consent wording**: the WordPress login, WordPress registration, WooCommerce
   login and WooCommerce registration forms can each store their own text, falling
   back to a site-wide default.
 * Live partial-match filters (email, order, date range, type, full-text search 
   inside the accepted text) + filtered CSV export with UTF-8 BOM (opens cleanly
   in Excel).
 * (When WooCommerce is active) Order metabox with the consent summary, integrity
   badge and outdated-version indicator. “Consent” column on the orders list (legacy
   and HPOS) with a quick visual status. Optional consent line in the New order 
   email (admin) and the order confirmation email (customer) — both off by default.
 * Optional `delete_data_on_uninstall` setting (off by default) — uninstalling does
   not destroy consent evidence unless you explicitly opt in.
 * HPOS (custom order tables) compatible.
 * Public `tccl_save_consent()` function to log consents from anywhere.

#### Translation ready

All strings use the `terms-conditions-consent-log` text domain. Translations are
managed through translate.wordpress.org.

### Support

Need private support or custom development?

Do you need one-on-one help, priority troubleshooting, or a custom feature, integration,
or tweak built specifically for your site? I offer private support and custom development.
Just [contact me](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/terms-conditions-consent-log@ayudawp.com?output_format=md)
and tell me what you need.

Need help or have suggestions?

 * [Official website](https://servicios.ayudawp.com)
 * [WordPress support forum](https://wordpress.org/support/plugin/terms-conditions-consent-log/)
 * [YouTube channel](https://www.youtube.com/AyudaWordPressES)
 * [Documentation and tutorials](https://ayudawp.com)

Love the plugin? Please leave us a 5-star review and help spread the word!

### About AyudaWP.com

We are specialists in WordPress security, SEO, AI and performance optimization plugins.
We create tools that solve real problems for WordPress site owners while maintaining
the highest coding standards and accessibility requirements.

## Screenshots

[⌊Records list with live filters, integrity column and CSV export.⌉⌊Records list
with live filters, integrity column and CSV export.⌉[

Records list with live filters, integrity column and CSV export.

[⌊Settings tab with editable texts, version control, retention, email options and
uninstall control.⌉⌊Settings tab with editable texts, version control, retention,
email options and uninstall control.⌉[

Settings tab with editable texts, version control, retention, email options and 
uninstall control.

[⌊Order metabox with consent summary, integrity badge and printable-certificate 
button.⌉⌊Order metabox with consent summary, integrity badge and printable-certificate
button.⌉[

Order metabox with consent summary, integrity badge and printable-certificate button.

[⌊Consent column on the orders list.⌉⌊Consent column on the orders list.⌉[

Consent column on the orders list.

[⌊Printable A4 certificate ready to be saved as PDF from the browser.⌉⌊Printable
A4 certificate ready to be saved as PDF from the browser.⌉[

Printable A4 certificate ready to be saved as PDF from the browser.

[⌊Exported CSV file with filtered records (metadata header + nice column names).⌉⌊
Exported CSV file with filtered records (metadata header + nice column names).⌉[

Exported CSV file with filtered records (metadata header + nice column names).

## Blocks

This plugin provides 1 block.

 *   Consent box A self-contained consent checkbox that records each acceptance 
   in the consent log.

## Installation

 1. Upload the plugin folder to `/wp-content/plugins/terms-conditions-consent-log/`
    or install through Plugins > Add New.
 2. Activate the plugin.
 3. Open the plugin admin page: Users > Consent log.
 4. In the Settings tab, the integrations (WordPress comments, Contact Form 7, WPForms,
    Gravity Forms, Fluent Forms, WP/WooCommerce registration) are on by default to 
    support GDPR Article 7.1 (proof of consent) — turn off any that do not apply to
    your site. Login capture is off by default and only needs turning on if your login
    form carries a consent checkbox (for example a re-consent prompt). The privacy 
    checkbox for comments and reviews, and the capture of sign-ups from membership 
    plugins, are also off by default: enable them if they apply to your site. You can
    also paste `[tccl_consent_box]` in any page or post.
 5. (Optional, WooCommerce only) Override the checkbox text or add a pre-checkout informational
    paragraph. Leave them empty to keep the WooCommerce native text.
 6. Every accepted consent from any of the enabled sources will be logged automatically
    from now on.

## FAQ

### Can I use the plugin without WooCommerce?

Yes. Activate it on any WordPress site and the Records, Settings, CSV export, PDF
certificate and Privacy Tools integration all work the same way. The WooCommerce-
specific bits (checkout capture, order metabox, order list column, order email line)
only load when WooCommerce is active.

### How do I capture consents from Contact Form 7?

Open Consent log > Settings > Integrations and tick “Log every CF7 form submission
that ticks an [acceptance] field”. Then make sure your CF7 forms include an [acceptance]
field, e.g.:

    ```
    [acceptance privacy] I have read and agree to the privacy policy. [/acceptance]
    ```

The plugin uses the form ID as part of the consent_type (cf7_form_{ID}), so each
form is filterable separately. The first email field of the form is used as the 
subject email. No snippets, no functions.php edits.

### How do I capture consents from WPForms?

Open Consent log > Settings > Integrations and tick “Log every WPForms submission
that ticks a GDPR Agreement field”. Then add a GDPR Agreement field to your form
from the WPForms builder (Fancy Fields  GDPR Agreement) and edit its label to the
exact wording you want recorded (e.g. “I have read and agree to the privacy policy.”).

The plugin uses the form ID as part of the consent_type (wpforms_form_{ID}), so 
each form is filterable separately. The first email field of the form is used as
the subject email, and the GDPR Agreement field label is what gets stored as the
accepted text. Works with WPForms Lite and Pro. No snippets, no functions.php edits.

### How do I capture consents from Gravity Forms?

Open Consent log > Settings > Integrations and tick “Log every Gravity Forms submission
that ticks a Consent field”. Then add a Consent field to your form from the Gravity
Forms editor (Advanced Fields  Consent) and set its checkbox label to the exact 
wording you want recorded (e.g. “I have read and agree to the privacy policy.”).

The plugin uses the form ID as part of the consent_type (gravityforms_form_{ID}),
so each form is filterable separately. The first email field of the form is used
as the subject email, and the Consent field’s checkbox label is what gets stored
as the accepted text. No snippets, no functions.php edits.

### How do I capture consents from Fluent Forms?

Open Consent log > Settings > Integrations and tick “Log every Fluent Forms submission
that ticks a GDPR Agreement or Terms & Conditions field”. Then add a GDPR Agreement
or a Terms & Conditions field to your form from the Fluent Forms editor.

The plugin uses the form ID as part of the consent_type (fluentforms_form_{ID}),
so each form is filterable separately. The first email field of the form is used
as the subject email, and the field’s agreement text is what gets stored as the 
accepted text. Works with Fluent Forms Lite and Pro. No snippets, no functions.php
edits.

One setting to check on the field itself: the Terms & Conditions field has a checkbox
toggle, and it is what makes the field an act of consent. With it turned off, Fluent
Forms shows your terms as plain text and renders no checkbox at all, so the visitor
never accepts anything and there is nothing to record. Open the field in the Fluent
Forms editor and make sure the checkbox is enabled.

### I added a consent field but nothing is recorded. Why?

The most common reason is that the form has no email field. The consent log identifies
the subject of every record by their email address, and the form integrations take
it from the first email field of the form. Without one, an anonymous visitor cannot
be identified and the submission is skipped on purpose, because a record that cannot
be attributed to anybody is not evidence of anything.

If the person submitting the form is logged in, the plugin falls back to the email
address on their WordPress profile, so forms behind a login (members areas, course
enrolments) are recorded even with no email field on the form. For public forms,
add an email field.

The other thing to check is that the consent field is really a consent field of 
the form builder, ticked by the visitor: an [acceptance] tag in Contact Form 7, 
a GDPR Agreement field in WPForms, a Consent field in Gravity Forms, or a GDPR Agreement
or Terms & Conditions field in Fluent Forms. A plain checkbox or an HTML block with
your terms in it is not detected.

### How does the [tccl_consent_box] shortcode work?

It renders a self-contained consent checkbox + submit button, with optional email
field for visitors who are not logged in. Submission posts to a REST endpoint that
records the consent through tccl_save_consent(). Drop it in any page, post or widget
area as a stand-alone block, e.g.:

    ```
    [tccl_consent_box text="I have read and agree to the privacy policy." consent_type="newsletter_signup"]
    ```

The same functionality is also available as a Gutenberg block called “Consent box”.

Important: the shortcode renders its own `<form>` with a submit button, so it should
NOT be nested inside another form builder’s form (Contact Form 7, WPForms, Gravity
Forms, Fluent Forms, Elementor Forms, etc.). If you embed it inside another form
you will end up with two submit buttons and conflicting submit flows. For form builders,
use the dedicated integration (Contact Form 7, WPForms, Gravity Forms and Fluent
Forms are built in; for the rest, hook tccl_save_consent() from the relevant submission
action — see the FAQ below).

Also: do NOT use this shortcode as a substitute for the cookie checkbox of a cookie/
banner plugin (Complianz, CookieYes, Real Cookie Banner, etc.). The legal context
is different — cookie banners cover ePrivacy/cookies, this consent log covers GDPR
art. 7.1 specific consents to specific personal-data processing. Mixing them yields
ambiguous evidence.

### How are WordPress and WooCommerce login / registration consents logged?

The plugin hooks into the standard `wp_login` event (which covers both wp-login.
php and the WooCommerce My Account login) and into the public registration events(`
register_new_user` for the WP form and `woocommerce_created_customer` for the WC
form). For each event, it inspects the submission `$_POST` for a ticked consent 
checkbox and, if one is present, writes a record with `consent_type` set to `wp_login`,`
wp_register`, `wc_login` or `wc_register` accordingly.

A few specifics worth knowing:

 * **“Remember me” is excluded by design.** It is an ePrivacy preference about extending
   the session cookie, not a GDPR Article 7.1 consent. Logging it would contaminate
   the audit trail with non-consent events. The exclusion is hard-coded.
 * **No checkbox in the form, no record.** The plugin does not log “raw logins” —
   it only writes a row when there is something resembling an explicit consent checkbox
   to record. A login or registration without a consent field never produces a record.
 * **The detector is heuristic.** Field names containing `consent`, `gdpr`, `privacy`,`
   terms`, `acceptance`, `agreement`, `accept`, `rgpd`, `politica`, `privacidad`
   or `terminos` (case-insensitive) are treated as the consent checkbox. If your
   GDPR / privacy plugin uses a different name, list it in Settings  Integrations“
   Custom consent field names” (comma-separated, exact match).
 * **The injected checkbox option fills the WooCommerce gap.** WooCommerce does 
   not include a consent checkbox in its register form out of the box — only a privacy-
   policy paragraph. If your site does not run a separate GDPR plugin, enable “Add
   a required consent checkbox to the WooCommerce registration form” in Settings;
   the plugin will render the checkbox above the submit button and reject the registration
   if it is left unticked. The same option exists for the WP register form.
 * **Social logins are not captured on their own.** Plugins like Nextend Social 
   Login bypass the WP login form entirely (OAuth callback), so there is no submission`
   $_POST` for the detector to inspect. See the dedicated FAQ below for the two 
   ways to cover them.
 * **Every ticked box is recorded, not just the first one.** Registration forms 
   often carry a required privacy checkbox plus an optional marketing or newsletter
   one. Both are written as separate records. The first one detected keeps the plain
   flow type (`wp_register`, `wc_register`…) so your existing records and saved 
   filters stay comparable, and each additional one appends its field name, for 
   example `wp_register_newsletter_consent`. That way an optional marketing consent,
   which is exactly the kind a regulator asks you to evidence separately, never 
   gets swallowed by the required one.
 * **The stored `consent_text` comes from Settings.** Paste in “Consent text for
   login / registration” the exact wording that the visitor sees on the form (whether
   it comes from your GDPR plugin or from the injected checkbox), so the record 
   reflects what was actually shown. HTML is allowed in that field, so you can include
   a link to your privacy policy. If your forms do not all say the same thing, open“
   Use a different wording per form” underneath and fill in only the ones that differ;
   anything left empty falls back to the site-wide text.
 * **Creating an account at the WooCommerce checkout does not produce a registration
   record.** The box ticked there is the order’s terms checkbox, which is already
   recorded as `terms_and_privacy` for the order itself, so counting it again as
   a registration consent would put something in your log the shopper never agreed
   to. If your checkout carries a separate consent checkbox of its own, that one
   is still recorded normally.

### How do I record consent from social logins (Nextend Social Login and similar)?

Not automatically, and that is on purpose. A social login ends in an OAuth callback
coming back from Google, Facebook or Apple: there is no form submission, so there
is no ticked checkbox anywhere in the request. A record written there would be a
record of something nobody saw the visitor do, which is the opposite of what a consent
log is for.

What you can do is hand the plugin the acceptance your social login plugin already
collected. Enable “Also record sign-ups created by membership, course or custom 
registration forms” in Settings > Integrations (that is the option covering account
creation outside the WP and WooCommerce forms) and use the `tccl_consent_detection_payload`
filter, which lets you feed the detector a payload of your own for one specific 
flow:

    ```
    add_filter( 'tccl_consent_detection_payload', function ( $payload, $context ) {
        if ( 'user_register' !== $context ) {
            return $payload; // Never touch the other flows.
        }
        // Read the acceptance wherever your social login plugin left it before
        // sending the visitor to the provider: a transient, a cookie, a session.
        if ( get_transient( 'my_social_consent' ) ) {
            $payload['privacy_consent'] = '1';
        }
        return $payload;
    }, 10, 2 );
    ```

Two things to respect. The key you add has to look like a consent field to the detector(
any name containing `consent`, `privacy`, `terms`, `gdpr`…) or be listed in “Custom
consent field names”. And `$payload` must come back untouched for every other context,
or you will contaminate the detection of logins, comments and everything else running
in the same request.

If your social login plugin fires its own “after register” hook and you would rather
write the record yourself, call `tccl_save_consent()` from there instead, exactly
like the custom-form example further down.

### Are WordPress comment opt-ins logged automatically?

Yes, by default. Only comments where the visitor ticks the native “Save my name,
email, and website…” checkbox are recorded. You can opt out in Consent log > Settings
> Integrations if your site uses Disqus, Jetpack Comments or any other third-party
comments system where the native checkbox is not rendered.

Be aware of what that native checkbox actually is, though: it asks permission to
leave a cookie so the browser remembers the commenter next time. That is an ePrivacy
cookie preference, the same nature as the “Remember me” box on the login form, and
it is not the GDPR Article 7.1 consent to processing the name and email the commenter
is handing you. For that, use the separate option described in the next FAQ.

### How do I record a real privacy consent on comments and product reviews?

Open Consent log > Settings > Integrations and tick “Add a required privacy checkbox
to the comment form and record who accepts it”. From then on:

 * A privacy checkbox is rendered on the comment form, for both logged-out and logged-
   in visitors.
 * A comment submitted without ticking it is rejected on the server, not just in
   the browser, so it cannot be bypassed.
 * Each acceptance is stored as `consent_type = comment_privacy`, which keeps it
   clearly separate from the `comment_consent` cookie opt-in. Both can coexist on
   the same comment.
 * WooCommerce product reviews go through the very same comment form and hooks, 
   so enabling the option covers them too. There is nothing extra to configure for
   a shop.

The wording lives in “Privacy text for comments” and accepts HTML, so you can link
to your privacy policy. Whatever you write there is what gets stored with every 
record as the text the commenter agreed to. Leave the option off if you already 
run a privacy plugin that adds its own checkbox to the comment form, otherwise your
visitors will see two.

### My users register through MemberPress, LearnDash or another membership plugin. Are those sign-ups logged?

Only if you enable “Also record sign-ups created by membership, course or custom
registration forms” in Consent log > Settings > Integrations.

The WordPress and WooCommerce options above hook the events those two fire on their
own forms. A membership, LMS or custom registration plugin creates the account through
the generic WordPress user-creation path instead, which those options never see.
This setting adds a safety net over that generic path and stores the record as `
consent_type = user_register`. It still requires a ticked consent checkbox in the
submission, exactly like every other flow, and it never records an account you create
yourself from Users > Add New, because no consent is given there.

It is off by default because most sites do not need it, and because the sign-up 
forms of those plugins vary enough that you will want to check the first record 
it produces before relying on it.

### Does it work with the WooCommerce block checkout?

Yes, since 1.7.0. Both checkouts are supported, and the Settings screen tells you
what your own checkout page will record.

There is one difference worth understanding, because it is a limitation of WooCommerce
and not of this plugin. The checkbox in the native “Terms and Conditions” block 
is validated in the browser only: its value is never sent to the server, so no plugin
can read it. What the plugin records depends on how that block is configured:

 * **Block with “Require checkbox” enabled**: recorded as `terms_and_privacy`, the
   same type the classic checkout uses. The order could not have been placed without
   ticking the box, so acceptance is certain, and the stored text is the exact wording
   of the block.
 * **Block without a checkbox** (the WooCommerce default): the block only shows 
   an informational paragraph, so the shopper accepted by proceeding rather than
   by an affirmative act. That is contractually meaningful but it is not the explicit
   consent of Article 7.1, so it is recorded as `terms_notice` to keep the two apart
   in your evidence trail.
 * **No Terms and Conditions block on the page**: nothing is recorded for the purchase,
   because nothing was shown.

If you want evidence the server itself validated, turn on “Inject required checkbox”
under Settings > Block checkout. It adds its own required checkbox through the official
WooCommerce additional-checkout-fields API, so the value travels with the request,
is validated server-side and is stored on the order. WooCommerce renders those labels
as plain text, so that checkbox cannot contain links; keep the Terms and Conditions
block on the page for the linked wording.

### Why does my block checkout record “terms_notice” instead of “terms_and_privacy”?

Because your Terms and Conditions block has no checkbox, which is how WooCommerce
ships it. The customer was shown a sentence saying that continuing implies acceptance,
and never ticked anything.

The plugin could record that as ordinary consent, but it would be putting an affirmative
act in your log that never happened, and a consent log that overstates its evidence
is worse than one that does not.

This is not the plugin telling you your shop is non-compliant, and the distinction
is not a warning. Processing an order rests on performing the contract (GDPR Article
6.1.b), not on consent, and accepting the terms of sale by placing the order is 
contractually meaningful in its own right. Whether you need an affirmative act on
top of that depends on what you ask your customers to agree to, and that is your
call, not the plugin’s. What the plugin does is refuse to file the two under the
same name.

If you do want the explicit tick, enable “Require checkbox” on that block in the
editor, or turn on the injected checkbox in Settings. Records already stored as `
terms_notice` keep that type: they are the accurate account of what those customers
actually saw.

### My site is not in English. Will the record match what my customers read?

Only if you write your own wording into the Terms and Conditions block, which is
what the Settings screen recommends when it detects this situation.

The reason is a limitation of where WooCommerce keeps that text. The default wording
of the block is assembled in JavaScript and its translations live in WooCommerce’s
script-translation files, which PHP cannot read, so no plugin can fetch the exact
sentence your visitor was shown. This plugin therefore reproduces the same sentence
under its own text domain. In English both are the same string. In any other language
the stored text is this plugin’s translation of that sentence, which may differ 
word for word from WooCommerce’s.

Anything you type into the block is stored verbatim, in any language, with no translation
involved. For a consent log that is the difference between a transcription and a
reconstruction, so it is worth the two minutes in the editor. The same applies to
the injected checkbox: its text comes from your own setting.

### The “Terms checkbox text” setting does nothing on my checkout. Why?

That setting, and the pre-checkout informational text next to it, only apply to 
the classic checkout. In the block checkout the wording lives in the Terms and Conditions
block, which you edit on the checkout page itself.

This is deliberate. Those records store what the block shows, not what you type 
in Settings, because the point of the log is to prove what the customer read.

### Does a record prove what my terms said that day?

Yes, for records taken from now on. The plugin keeps a sealed copy of your legal
pages every time they change, and each record points to the copies in force when
the consent was given.

 * Copied without any setup: the privacy policy page of the site, and the WooCommerce
   terms and refund pages.
 * Anything else, such as a cookie policy or a legal notice: add it in Settings 
   > Documents in force.
 * Each copy holds the text as it is read, so pages built with a shortcode or a 
   block are covered.
 * The certificate of a record lists its documents and says whether they have changed
   since.

Older records have no copies. WordPress revisions are not a substitute: they can
be limited or switched off.

### The consent box says the form is out of date. Why?

The page was rendered before the plugin was updated and is being served from a page
cache. Purge the cache and it will work again.

The form carries a payload signed by the server with the exact text it shows, and
the plugin only records what that payload says. A form with no payload, or with 
one that has been altered, is rejected.

### The consent box fails for visitors who are not logged in. Why?

Something is closing the WordPress REST API to anonymous visitors, usually a security
plugin set to allow it only for logged-in users. The consent box sends its form 
to `/wp-json/tccl/v1/consent`, so that route has to stay public. Allow the `tccl/
v1` namespace in that plugin, or switch it to a mode that only blocks the routes
you choose.

### Where is the data stored?

In a custom indexed table called `wp_tccl_consents` (with your site prefix). The
sealed copies of your legal pages live in a second table, `wp_tccl_snapshots`. When
WooCommerce is active, each order also gets three meta entries (`_tccl_terms_accepted`,`
_tccl_terms_version`, `_tccl_recorded_at`) so the order edit screen can show the
summary without querying the table.

### How do I bump the document version when I change my terms?

Edit the version field in Consent log > Settings, or simply check “Bump version 
on save”. The plugin can also bump it automatically if it detects the checkbox text
has changed but the version field has not.

Three things to keep in mind:

 1. The version string in Settings must match the version label of your terms document
    character by character (e.g. `1.1-2026-05-17`). It is a free-text identifier and
    the plugin just compares strings, so a trailing space or a different separator 
    will be treated as a different version.
 2. Once you bump the version, every record stored under the previous version is automatically
    flagged as “Outdated” in the records list. This is on purpose — it is the GDPR 
    audit trail showing which exact wording each subject accepted at that moment. “
    Outdated” is a feature, not a bug.
 3. Do NOT delete or “clean up” Outdated records. They are the legal proof of consent
    for the version that was in force when the subject accepted it. If the user retires
    the terms and a regulator later asks for evidence, those rows are what you show
    them.

### How do I delete or anonymise data for a specific customer?

Use the WordPress native Tools > Erase Personal Data screen. The plugin registers
an eraser that anonymises records linked to the requested email (it does not delete
them, since the record itself is the lawful basis to keep the proof of consent).
You can also anonymise filtered records from the Records tab.

### How do I export a customer’s consent history?

Use Tools > Export Personal Data. The plugin registers an exporter that returns 
every consent record linked to the requested email.

### Will an uninstall destroy my data?

Only if you explicitly opt in. The setting “Delete all data on uninstall” is off
by default. Even if you uninstall accidentally, your consent evidence will survive.

If you need to clean up a handful of test rows you generated while configuring the
plugin (and you do not yet have the upcoming bulk-delete UI), you can remove them
with a direct SQL statement against the consent table, e.g.:

    ```
    DELETE FROM wp_tccl_consents WHERE id IN (1, 2, 3);
    ```

Replace `wp_` with your site’s actual table prefix. This is an escape hatch for 
legitimate clean-up after a misconfigured form; it is not a recommended day-to-day
flow — to handle real subject requests, use Tools > Erase Personal Data (anonymises)
instead.

### How do I capture consents from Elementor Forms, Forminator or any other source?

Contact Form 7, WPForms, Gravity Forms and Fluent Forms are captured automatically
once you enable their toggle in Settings > Integrations; no code is needed for those
four. For any other source, call the public `tccl_save_consent()` function from 
that plugin’s submission hook. Always read the document version from the plugin 
setting (`tccl_get_setting( 'consent_version', '1.0' )`) so all records line up 
with the current version in Settings — if you hardcode a date that differs from 
the one in Settings, every record will be flagged as “Outdated” forever.

    ```
    add_action( 'the_submission_hook_of_your_form_plugin', function ( $submission ) {
        tccl_save_consent( array(
            'email'           => sanitize_email( $submission['email'] ), // however your plugin exposes the email
            'consent_type'    => 'my_custom_form',
            'consent_version' => tccl_get_setting( 'consent_version', '1.0' ),
            'consent_text'    => 'I have read and agree to the privacy policy.',
            'consent_value'   => 1,
        ) );
    } );
    ```

Common hooks to adapt this to: `elementor_pro/forms/new_record`, `forminator_custom_form_after_submission`,`
user_register`. Adjust the callback signature and how you read the email and the
acceptance to each plugin’s documented arguments.

### Does the IP detection work behind Cloudflare or other reverse proxies?

The plugin reads `REMOTE_ADDR` only and does not trust forwarded headers, which 
can be spoofed without a verified proxy. If your hosting puts the proxy IP in `REMOTE_ADDR`
instead of the real client IP, all entries will record the proxy IP. Most WordPress-
friendly hostings pass the real IP correctly.

### What does “Tamper-evident” mean here?

When a consent is written, the plugin computes a SHA-256 hash of the exact accepted
text and stores it alongside the record. On every read, the stored hash is compared
against a freshly computed one — any difference is reported as TAMPERED in the records
list, the order metabox and the certificate view. This is a cryptographic integrity
check, not an electronic signature.

### Is the certificate a real PDF?

The plugin renders a one-page A4 view with print-optimised CSS and a “Print / Save
as PDF” button. Modern browsers (Chrome, Safari, Firefox, Edge) export that view
to a real PDF natively — same fidelity as a server-side library would produce, with
the added benefit that it respects your site’s language and fonts. No external library
bundled, so the plugin stays small.

To be clear: the plugin does NOT store any PDFs on disk and does NOT create an uploads
folder of its own. The certificate is generated on demand as HTML each time you 
open it, and only becomes a PDF if you (or the customer) clicks “Print / Save as
PDF” in the browser. There is nothing to clean up on the server. If the site has
a Site Icon defined in Settings > General (the same option block themes and classic
themes share), it is shown in the certificate header next to the site name — including
on certificates of consents recorded before this version, since the icon is added
at render time, not at storage time.

## Reviews

![](https://secure.gravatar.com/avatar/2b7212087bdf643796dcc0843b33201285d6dc326275ece7bddd6e788af15993?
s=60&d=retro&r=g)

### 󠀁[Fantastic, feature-rich plugin](https://wordpress.org/support/topic/fantastic-feature-rich-plugin/)󠁿

 [Atom Adam](https://profiles.wordpress.org/adampaine/) October 1, 2026 1 reply

This plugin does an outstanding job of maintaining consent records in a simple yet
legally defensible manner. Disclaimer: I'm not an attorney, so I can't verify that
it is "legally defensible," but it sure makes a lot of sense to me! 🙂 I've already
implemented this on two of my sites with no problems whatsoever and I'm going to
start using it on all of the sites I manage. Terrific work!

![](https://secure.gravatar.com/avatar/5bda330e5ef8511089e4f7d964d4454a2178a4dad4ffc342f11561ab23f0e1fc?
s=60&d=retro&r=g)

### 󠀁[El plugin que permite cumplir al 100%](https://wordpress.org/support/topic/el-plugin-que-permite-cumplir-al-100/)󠁿

 [marinabrocca](https://profiles.wordpress.org/marinabrocca/) May 30, 2026 1 reply

Errata: había puesto la reseña para otro plugin en el lugar equivocado y no sé como
borrarla 😅

![](https://secure.gravatar.com/avatar/c31ce65cff2146c8a045b8e8834d0c5294a5204cbda9b9a56e169c183e3500b5?
s=60&d=retro&r=g)

### 󠀁[Excelente plugin gratuito para tratar el RGPD](https://wordpress.org/support/topic/excelente-plugin-gratuito-para-tratar-el-rgpd/)󠁿

 [lofersop](https://profiles.wordpress.org/lofersop/) May 20, 2026 1 reply

Excelente plugin gratuito para tratar el RGPD que está integrado para funcionar 
con woocommerce y los principales plugins de formularios.Pensado en no afectar en
el rendimiento no generando un PDF por cada consentimiento firmado.

 [ Read all 3 reviews ](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/)

## Contributors & Developers

“Terms & Conditions Consent Log” is open source software. The following people have
contributed to this plugin.

Contributors

 *   [ Fernando Tellado ](https://profiles.wordpress.org/fernandot/)
 *   [ Ayuda WordPress ](https://profiles.wordpress.org/ayudawp/)

“Terms & Conditions Consent Log” has been translated into 2 locales. Thank you to
[the translators](https://translate.wordpress.org/projects/wp-plugins/terms-conditions-consent-log/contributors)
for their contributions.

[Translate “Terms & Conditions Consent Log” into your language.](https://translate.wordpress.org/projects/wp-plugins/terms-conditions-consent-log)

### Interested in development?

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

## Changelog

#### 1.8.0

Important fix for the consent box, which stored whatever the browser sent. Purge
your page cache after updating: forms rendered before the update are rejected until
the page is rendered again. Also new: sealed copies of your legal pages for every
record.

 * New: sealed copies of your legal pages. Every time the privacy policy, the WooCommerce
   terms page or the refund page change, the plugin keeps a copy of what they said,
   sealed with a SHA-256 hash, and every new record points to the copies that were
   in force when the consent was given. Until now a record proved that somebody 
   ticked “I accept the terms”, but not what those terms said that day. The copy
   holds the text as it is read, with where each link points, so a page that is 
   nothing but a shortcode or a block from the plugin that generates the document
   is covered too. A new copy is only taken when the title, the text or the destination
   of a link change, not when the editor merely rewrites the markup of the page,
   and pages are checked once a day as well, to catch a document whose text changes
   without the page being saved. Other pages (a cookie policy, a legal notice) can
   be added in Settings > Documents in force, where every copy can be opened. The
   certificate lists the documents in force for the record and says whether they
   have changed since, and the CSV export gains a “Documents in force” column. Records
   taken before this version have no copies, and say so. If the plugin is uninstalled
   with the option to delete its data turned on, the copies are removed as well.
 * New: the pre-checkout informational text is now part of the evidence. It was 
   shown to the customer before the terms checkbox of the classic checkout but never
   stored anywhere. It is now copied like any other document, and every classic 
   checkout record points to the copy the customer saw.
 * Improved: the version label now moves on its own when any consent wording changes
   in Settings, not only the classic checkout checkbox text. Changing the registration,
   login, comments, block checkout or consent box wording used to leave new records
   under the old version.
 * Improved: the daily integrity check also verifies the document copies, and the
   admin alert tells you if one no longer matches its seal.
 * Fix: the consent box (shortcode and block) stored whatever the browser sent. 
   The endpoint behind it took the consent type, the version and the text from the
   request, so a visitor could file a record with any wording, under any type and
   for any email address, and it showed up in the log with a valid seal. The form
   now carries those three values in a payload signed by the server when the page
   is rendered, and the endpoint only stores what it reads from a payload whose 
   signature is valid. A consent box can no longer claim a consent type used by 
   the plugin’s own integrations (checkout, registration, comments, forms): it is
   recorded as `consent_box`. Its type is also stored as a key from now on, in lowercase
   and with nothing but letters, digits, dashes and underscores, so a box whose 
   type had capitals or spaces will record under the tidied-up name. If you use 
   a page cache, purge it after updating: a form rendered before the update carries
   no signed payload and is rejected until the page is rendered again.
 * Fix: the consent box stopped working for visitors on pages kept in a page cache
   for longer than 12 to 24 hours. The form carried a WordPress nonce that had expired
   by then, and WordPress answers 403 to an expired nonce before the plugin even
   runs. Anonymous visitors no longer send one. Logged-in visitors still do.
 * Fix: the CSV export no longer carries PHP deprecation notices inside the file
   on PHP 8.4 and later.

For older changelog entries, please check the [changelog.txt](https://plugins.svn.wordpress.org/terms-conditions-consent-log/trunk/changelog.txt)
file.

## Meta

 *  Version **1.8.0**
 *  Last updated: **2 weeks ago**
 *  Active installations: **100+**
 *  WordPress Version: ** 6.0 or higher **
 *  Tested up to: **7.1.3**
 *  PHP Version: ** 7.4 or higher **
 *  Language:
 * [English (US)](https://wordpress.org/plugins/terms-conditions-consent-log/), 
   [Spanish (Chile)](https://cl.wordpress.org/plugins/terms-conditions-consent-log/),
   and [Spanish (Spain)](https://es.wordpress.org/plugins/terms-conditions-consent-log/).
 *  [Translate into your language](https://translate.wordpress.org/projects/wp-plugins/terms-conditions-consent-log)
 * Tags:
 * [consent](https://en-ca.wordpress.org/plugins/tags/consent/)[contact form 7](https://en-ca.wordpress.org/plugins/tags/contact-form-7/)
   [GDPR](https://en-ca.wordpress.org/plugins/tags/gdpr/)[woocommerce](https://en-ca.wordpress.org/plugins/tags/woocommerce/)
   [WPForms](https://en-ca.wordpress.org/plugins/tags/wpforms/)
 *  [Advanced View](https://en-ca.wordpress.org/plugins/terms-conditions-consent-log/advanced/)

## Ratings

 5 out of 5 stars.

 *  [  3 5-star reviews     ](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/?filter=5)
 *  [  0 4-star reviews     ](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/?filter=4)
 *  [  0 3-star reviews     ](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/?filter=3)
 *  [  0 2-star reviews     ](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/?filter=2)
 *  [  0 1-star reviews     ](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/?filter=1)

[Your review](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/#new-post)

[See all reviews](https://wordpress.org/support/plugin/terms-conditions-consent-log/reviews/)

## Contributors

 *   [ Fernando Tellado ](https://profiles.wordpress.org/fernandot/)
 *   [ Ayuda WordPress ](https://profiles.wordpress.org/ayudawp/)

## Support

Issues resolved in last two months:

     1 out of 1

 [View support forum](https://wordpress.org/support/plugin/terms-conditions-consent-log/)