Previously on the CogitActive Saga:
In order to fulfill the ‘explicit consent’ GDPR requirement, WordPress added a cookie consent checkbox to the comment form.
… starting from the point where the story stopped…
Generally, information only websites use browse-wraps to obtain agreement to their Terms of Use. As opposed to click-wraps, such agreements do NOT require any type of express manifestation of assent. This can be a problem, however, if the users claim not to have knowledge of your terms. Accordingly, to increase visibility, I decided to implement – in addition to the link in the footer – a click-wrap (reminder) to all my forms, including the comment form.
As alluded earlier, WordPress privacy release added a cookie consent checkbox to the comment form and made it easy to display a link to the Privacy Policy in the footer (for the supported bundled themes). However, it appears that these enhancements are not sufficient to make the comment form GDPR-compliant1. My inquiring about this issue was like opening Pandora’s Box; my GDPR compliance journey was indeed far from ending.
After establishing that using consent, as the legal basis for the processing of my comment form’s data was not practical, I opted for legitimate interest instead (see GDPR part 6 – Comment form adjustment). Then, I discovered that regardless of the lawful basis used you always have to provide the information listed in Article 13 . . . in a clearly linked privacy policy
(see GDPR part 7 – Comment form adjustment cont’d). Importantly, this should be done at the time you collect the data; hence, preferably with a link to your policy directly from the form itself. Last, but not least, it seems that using an “I agree to Privacy Policy” click-wrap (in order to obtain consent to the Privacy Policy as a whole) is invalid2 under the GDPR. This approach, however, could be implemented for the Terms of Use because such agreements do not fall under the umbrella of privacy as covered by the GDPR
(see GDPR part 8 – Comment form adjustment cont’d 2). To sum up, the last three posts invalidate the following claim (except perhaps for the agreement to terms
part):
Any form submission must obtain the user’s explicit consent, and not only that, but an agreement to terms and privacy policy, which can’t be inserted in Jetpack Comments either.johnstonesnow
After going through the legal aspects of things, it was now time to implement the aforementioned changes that is to adjust my comment form accordingly.
Not the first time
Those who follow the CogitActive Saga know that I have already customized my comment form twice. Briefly, I have, among other things, removed the Website field, changed the default “Leave a Reply title”, and added a brief synopsis of my Comment Policy as a placeholder text in the Comment field. In other words, I have already experimented with the code and I am no more a complete novice in PHP.
Needless to remind you that for this undertaking, it is best to use a child theme; you should never directly modify WordPress files.
Adding a link to the policy page to the comment form
Regardless of the lawful basis used you always have to provide the information listed in Article 13 . . . in a clearly linked privacy policy.Nils Höglund
Having a link to my Privacy Policy in the footer may be enough3; still, to make sure people know about my privacy practices and can easily access my Privacy Policy page at an opportune time, I opted to provide a similar link within the comment form, along with a clear notice:
As for data processing, please read our Privacy Policy.
This was super easy because I already modified the text before the Comment field, namely the comment_notes_before argument (see Comment form customization reloaded). Hence, I just needed to add this extra piece of information to my previous PHP code (in my functions.php file):
As for data processing, please read our <a href="https://cogitactive.com/privacy-policy/">Privacy Policy</a>.
And voilà:
All comments are moderated according to our Comment Policy. As for data processing, please read our Privacy Policy. Required fields are marked *
Click-wrap for Terms of Use
Browsewrap lacks a certain component that is essential in clickwrap: Notice.FreePrivacyPolicy
As explained in GDPR part 8 – Comment form adjustment cont’d 2, browse-wraps may be unenforceable in courts because they aren’t conspicuous enough. However, withproper and obvious notification
, such agreement should be upheld in courts. Accordingly, to provide increased visibility, I wanted to implement – in addition to the browse-wrap (i.e. the link in the footer) – a click-wrap in the comment form, if only as a reminder.
Where?
The first step was to figure out how to add this click-wrap in the same location as the cookie consent checkbox implemented by WordPress (see GDPR part 2 – WordPress privacy release). Wrongly, I thought first of using the comment_notes_after argument. Not only is the latter empty by default (‘comment_notes_after’ => ‘’), but it also uses the same filter hook as for the comment_notes_before argument, namely comment_form_defaults. However, the location (of the click-wrap) would have been below the Comment field, not where I wanted it to be.
I also thought of directly modifying the code for the cookie consent checkbox by replacing Save my name, email, and website in this browser for the next time I comment.
with my own text (using the comment_form_default_fields filter instead). However, I didn’t want to mess up with this feature (cookie consent) and, equally important, I have disabled it in the Settings > Discussion > Other comment settings, specifically with the Show comments cookies opt-in checkbox, allowing comment author cookies to be set option (as already explained in Configuring WordPress (Multisite) Settings). Thus, this checkbox is not displayed in my comment form.
So, to add my own click-wrap at the intended position (i.e. similarly to the WordPress cookie consent checkbox), I instead defined my own argument using the comment_form_default_fields filter:
function add_comment_clickwrapfield ($fields) {
$fields['clickwrap'] = ADDITIONAL CODE GOES HERE
return $fields;
}
add_filter('comment_form_defaults_fields','add_comment_clickwrapfield');
Checkbox or …
The next step was to figure out the code for implementing the click-wrap (i.e. instead of “ADDITIONAL CODE GOES HERE” in the above callback function). Not knowing where to start, I looked at the code for the aforementioned cookie consent checkbox:
$consent = empty( $commenter['comment_author_email'] ) ? '' : ' checked="checked"';
$fields['cookies'] = sprintf(
'<p class="comment-form-cookies-consent">%s %s</p>',
sprintf(
'<input id="wp-comment-cookies-consent" name="wp-comment-cookies-consent" type="checkbox" value="yes"%s />',
$consent
),
sprintf(
'<label for="wp-comment-cookies-consent">%s</label>',
__( 'Save my name, email, and website in this browser for the next time I comment.' )
)
);
Without going into details, the important part is the HTML code that specifies that the input type5 is a checkbox. The name attribute specifies the name of this <input> element and the id attribute, as you may already know, is used by CSS (see Customizing the WordPress comment form). The checked attribute (as defined in the first line of code; $consent) indicates that the checkbox should be pre-checked when the page loads. The value="yes" part defines the values associated with the input (if checked). Last, but not least, the <label> tag defines the text label to associate with the input field. Beware that the for attribute must be equal to the id attribute of the related element to bind them together.
Obviously, just replacing the text associated with the label with my own would not do the trick. First, I didn’t want the checkbox to be pre-checked by default. This, however, is as simple as removing the $consent6 part. Second, I wanted to make this click-wrap mandatory. Fortunately, there is the perfect attribute for that: required! Theoretically, adding required="required" after type="checkbox" should be enough to prevent form submission (if not checked). As you can imagine, however, things are not quite that simple (see below). Third, what about the value attribute, should I care?
My headache started with the required attribute. I was expecting something like the error message when you omit your name or email address (two mandatory fields7). However, for a reason I could not comprehend, there was no warning message when submitting the form without checking the box. Of course, replacing required="required" with required or with aria-required="true" was not helping.
Error: Please fill the required fields (name, email).
<< Back
After hours of investigations, I had a glimpse of understanding. The above error message was not the client-side validation – with error messages like You must select this checkbox
or Please check this box if you want to proceed
that appears as tooltips – but an error message specified within WordPress code, in comment.php to be specific:
if ( get_option( 'require_name_email' ) && ! $user->exists() ) {
if ( '' == $comment_author_email || '' == $comment_author ) {
return new WP_Error( 'require_name_email', __( '<strong>Error</strong>: Please fill the required fields (name, email).' ), 200 );
} elseif ( ! is_email( $comment_author_email ) ) {
return new WP_Error( 'require_valid_email', __( '<strong>Error</strong>: Please enter a valid email address.' ), 200 );
}
}
Okay, but why the client-side validation is not working?
Apparently, the problem is that the <form> element (of the comment form) has a novalidate attribute if $html5 is true ($html5 ? ‘ novalidate’ : ‘’). The former, when present, specifies that the form-data (input) should not be validated when submitted
. Effectively, this disables the required attribute and the form can now be submitted even if the checkbox is not checked. The latter is a feature that allows the use of HTML5 markup
or more accurately to output valid HTML5. In the functions.php of my theme, there is indeed a function to add support, namely add_theme_support(), to HTML5 for the comment form. Now, it seems that removing HTML5 support for my theme (as suggested by some people) is a bad idea…
So, if this not a bug, how can I have the same error message as WordPress?
Fortunately, client-side validation with the HTML5 required attribute is not the only way to enforce a mandatory checkbox. You can also use JavaScript to prevent the form to be submitted if the box is not checked. However, this method is not the most secure one as it can be bypassed. Alternatively, you can opt for a server side validation instead and use PHP (with a code similar8 to the one used by WordPress). This approach, picked by WordPress as well as many plugins, is also the one used by Christian Behrends2 (see its verify_policy_consented() function).
During my investigation, I also discovered that the value associated with the checkbox (e.g. “yes”) is normally sent to the server upon submission of the form. Here comes the proper record keeping
element, mentioned in the previous post, for your terms to be legally binding. Should I register this value in the comment meta?
… click button?
Simple “click to accept” methods are equally effective and binding if done correctly.Sara P.
Let me remind you that my initial aim was not to have an actual click-wrap, but just a notice to provide increased visibility, for my Terms of Use (browse-wrap). In other words, there is no need to mess around with additional PHP code to add a simple paragraph to my comment form:
By clicking Submit Comment, you agree
to CogitActive’s Terms of Use.
As a matter of fact, the only difficulty (with this approach) turned out to be with the apostrophe. Indeed, it is a good idea to use ' instead! In addition, I opted to force the link to open in a new window (or tab) by specifying the target attribute (i.e. _blank). I also chose to keep the same style as the WordPress cookie consent; hence, the comment-form-cookies-consent class. Yet, I added the comment-notes class to style the <a> element (see Comment form customization reloaded). Here is the final code:
function add_comment_clickwrapfield ($fields) {
$fields['clickwrap'] = sprintf(
'<p class="comment-form-cookies-consent">%s</p>',
sprintf(
'<span id="comment-clickwrap">%s</span>',
__( '<span class="comment-notes"> By clicking Submit Comment, you agree to CogitActive's <a href=https://cogitactive.com/terms-of-use/ target="_blank">Terms of Use</a>.</span>' )
)
);
return $fields;
}
add_filter('comment_form_defaults_fields','add_comment_clickwrapfield');
Conclusion
GDPR compliance is an ongoing process.
I started my GDPR part 6 – Comment form adjustment post, with this question: Was my GDPR compliance journey coming to an end? Even though this is the last installment of this mini-series on GDPR, it is worth mentioning that there is no such thing as “an end” in this journey, if only to keep the information in my Privacy Policy current and accurate.
We would also suggest reviewing your Privacy Policy from time to time, especially after installing or updating any themes or plugins. There may be changes or new suggested information for you to consider adding to your policy.WordPress
1 Thomas Kahler (2019) Consent to privacy policy – invalid. DPOblog. ^
2 Christian Behrends (2019) GDPR-compliant Comments with WordPress. webdevtrust. ^
3 Theoretically, a link in the footer should be sufficient. Not only is the footer a conspicuous location, but also it is present on every page, thus making sure that the link is always available to the visitors. In the GDPR.EU website, a resource for organizations and individuals researching the General Data Protection Regulation, Ben Wolford explains, [the Privacy Policy] should be accessible via a direct link from every webpage. If a website collects any personal data online, the privacy notice or a link to it should be provided on the same page where the data collection occurs
. Yet, it’s better to be safe than sorry, right! ^
4 However, for reasons soon to be revealed, I will have to make this long story a short one! ^
5 Briefly, as explained in this w3schools page, the <input> tag, which specifies an input field where the user can enter data
, can be displayed in several ways, depending on the type attribute
. Checkbox is one of the many options available. ^
6 A good thing anyway because its $commenter component is defined elsewhere: $commenter = wp_get_current_commenter();. ^
7 If you have chosen to! Indeed, if, and only if, you have checked “Comment author must fill out name and e-mail” in the Discussion Settings, both fields will have the required=“required” attribute in their code. ^
8 Similar, but not identical! In particular, you might want to consider using wp_die() instead of the WP_error() function if you don’t want to crash your site. ^