PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.6.2
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.6.2
5.6.2 5.6.3 5.6.1 5.6.0 5.5.0 5.4.0 5.3.2 5.3.1 5.1.6 5.1.5 trunk 2.1.5 2.11 2.12 2.13 2.15 3.0.0 3.0.1 3.0.2 3.0.3 3.0.5 3.0.51 3.0.60 3.0.61 3.0.62 All 38 releases
← All changes | compatibility/cf7/CF7Frontend.class.php +220 -141 3.0.62 → 5.6.2 View file →
@@ -5,8 +5,9 @@
5 5 exit;
6 6 }
7 7
8 8 use forge12\plugins\ContactForm7;
9 + use Forge12\Shared\LoggerInterface;
9 10
10 11 /**
11 12 * Class Frontend
12 13 * Responsible to handle the frontend of the Double OptIn
@@ -11,19 +12,35 @@
11 12 * Class Frontend
12 13 * Responsible to handle the frontend of the Double OptIn
13 14 *
14 15 * @package forge12\contactform7\CF7DoubleOptIn
16 + *
17 + * @deprecated 4.0.0 Use \Forge12\DoubleOptIn\Integration\CF7Integration instead.
18 + * This class is maintained for backward compatibility only.
19 + * @see \Forge12\DoubleOptIn\Integration\CF7Integration
15 20 */
16 21 class CF7Frontend extends OptInFrontend {
22 + protected $OptIn = null;
23 +
17 24 /**
18 25 * Admin constructor.
19 26 */
20 - public function __construct() {
27 + public function __construct( LoggerInterface $logger ) {
28 + parent::__construct( $logger, 'cf7' );
21 29
22 - parent::__construct( 'cf7' );
23 - add_action( 'wpcf7_before_send_mail', array( $this, 'onSubmit' ), 5, 3 );
30 + $this->get_logger()->debug( 'CF7 integration constructor called', [
31 + 'plugin' => 'double-opt-in',
32 + 'class' => __CLASS__,
33 + 'method' => __METHOD__,
34 + ] );
35 +
36 + add_action( 'wpcf7_before_send_mail', [ $this, 'onSubmit' ], 5, 3 );
37 + $this->get_logger()->debug( 'Action wpcf7_before_send_mail registered', [
38 + 'plugin' => 'double-opt-in',
39 + ] );
24 40 }
25 41
42 +
26 43 /**
27 44 * Get the recipient email address
28 45 *
29 46 * @param string $recipient The recipient email address
@@ -32,31 +49,89 @@
32 49 *
33 50 * @return string The sanitized recipient email address
34 51 */
35 52 public function getRecipient( string $recipient, array $formParameter, array $postParameter ): string {
36 - /**
37 - * Ensure the recipient has been defined in the settings
38 - */
53 + $this->get_logger()->debug( 'getRecipient called', [
54 + 'plugin' => 'double-opt-in',
55 + 'class' => __CLASS__,
56 + 'method' => __METHOD__,
57 + 'formParameter' => $formParameter,
58 + ] );
59 +
60 + // Ensure the recipient has been defined in the settings
39 61 if ( ! isset( $formParameter['recipient'] ) ) {
62 + $this->get_logger()->warning( 'Recipient not defined in form parameters, returning fallback', [
63 + 'plugin' => 'double-opt-in',
64 + 'recipient' => $recipient,
65 + ] );
66 +
40 67 return $recipient;
41 68 }
42 69
43 70 $recipient = $formParameter['recipient'];
44 71
45 - $recipient = str_replace( '[', '', $recipient );
46 - $recipient = str_replace( ']', '', $recipient );
72 + $recipient = str_replace( [ '[', ']' ], '', $recipient );
47 73
48 - /**
49 - * Get the Recipient from the post parameter
50 - */
74 + // Get the Recipient from the post parameter
51 75 if ( isset( $postParameter[ $recipient ] ) ) {
52 - $recipient = sanitize_email( $_POST[ $recipient ] );
76 + $recipient = sanitize_email( $_POST[ $recipient ] ); // phpcs:ignore WordPress.Security.NonceVerification
77 + $this->get_logger()->debug( 'Recipient resolved from post parameter', [
78 + 'plugin' => 'double-opt-in',
79 + 'recipient' => $recipient,
80 + ] );
81 + } else {
82 + $this->get_logger()->warning( 'Recipient not found in postParameter, using fallback', [
83 + 'plugin' => 'double-opt-in',
84 + 'recipient' => $recipient,
85 + ] );
53 86 }
54 87
55 88 return $recipient;
56 89 }
57 90
91 +
58 92 /**
93 + * Add File after submission and confirming opt in.
94 + *
95 + * @param $form
96 + * @param $abort
97 + * @param $submission
98 + *
99 + * @return void
100 + */
101 + public function attachExtraAttachments( $form, $abort, $submission ) {
102 + $this->get_logger()->debug( 'attachExtraAttachments called', [
103 + 'plugin' => 'double-opt-in',
104 + 'class' => __CLASS__,
105 + 'method' => __METHOD__,
106 + ] );
107 +
108 + if ( $this->OptIn !== null && $this->OptIn->get_files() !== null ) {
109 + $fileWrapper = maybe_unserialize( $this->OptIn->get_files() );
110 +
111 + if ( is_array( $fileWrapper ) ) {
112 + foreach ( $fileWrapper as $file ) {
113 + $submission->add_extra_attachments( $file );
114 +
115 + $this->get_logger()->debug( 'Extra attachment added', [
116 + 'plugin' => 'double-opt-in',
117 + 'file' => $file,
118 + ] );
119 + }
120 + } else {
121 + $this->get_logger()->warning( 'File wrapper is not an array, skipping attachments', [
122 + 'plugin' => 'double-opt-in',
123 + ] );
124 + }
125 + } else {
126 + $this->get_logger()->debug( 'No OptIn files found, skipping attachments', [
127 + 'plugin' => 'double-opt-in',
128 + ] );
129 + }
130 + }
131 +
132 +
133 + /**
59 134 * Send the default email for the given OptIn. (Original Mail after Opt-In Confirmation)
60 135 *
61 136 * @param OptIn $OptIn The OptIn object containing the email content and form ID.
62 137 *
@@ -62,32 +137,78 @@
62 137 *
63 138 * @return void
64 139 */
65 140 public function sendDefaultMail( OptIn $OptIn ): void {
66 - if(!function_exists('wpcf7')) {
141 + $this->get_logger()->debug( 'sendDefaultMail called', [
142 + 'plugin' => 'double-opt-in',
143 + 'class' => __CLASS__,
144 + 'method' => __METHOD__,
145 + 'optin_id' => $OptIn->get_id(),
146 + 'form_id' => $OptIn->get_cf_form_id(),
147 + ] );
148 +
149 + if ( ! function_exists( 'wpcf7' ) ) {
150 + $this->get_logger()->warning( 'wpcf7 function not available, aborting sendDefaultMail', [
151 + 'plugin' => 'double-opt-in',
152 + ] );
153 +
67 154 return;
68 155 }
69 - /**
70 - * Prepare the Post Data
71 - */
72 - $data = maybe_unserialize( $OptIn->get_content() );
73 156
74 - /**
75 - * Sanitize the Data
76 - */
157 + $this->OptIn = $OptIn;
158 +
159 + $data = maybe_unserialize( $OptIn->get_content() );
77 160 $_POST = SanitizeHelper::sanitize_array( $data );
78 161
79 - /**
80 - * Prepare the Contact Form
81 - */
82 162 $ContactForm = \WPCF7_ContactForm::get_instance( $OptIn->get_cf_form_id() );
163 + if ( ! $ContactForm ) {
164 + $this->get_logger()->warning( 'Contact form not found, aborting sendDefaultMail', [
165 + 'plugin' => 'double-opt-in',
166 + 'form_id' => $OptIn->get_cf_form_id(),
167 + 'optin_id' => $OptIn->get_id(),
168 + ] );
83 169
84 - /**
85 - * Prepare the Submission Instance
86 - */
170 + return;
171 + }
172 +
173 + add_action( 'wpcf7_before_send_mail', [ $this, 'attachExtraAttachments' ], 10, 3 );
174 + $this->get_logger()->debug( 'Hook wpcf7_before_send_mail registered for attachments', [
175 + 'plugin' => 'double-opt-in',
176 + ] );
177 +
178 + // Disable CF7 validation and spam checks for confirmation mail resend.
179 + // CF7 re-runs all form validations (required fields, quiz, acceptance checkboxes)
180 + // when creating a WPCF7_Submission instance, which fails in a GET request context.
181 + $clearValidation = function( $result ) {
182 + return new \WPCF7_Validation();
183 + };
184 + add_filter( 'wpcf7_validate', $clearValidation, 999 );
185 + add_filter( 'wpcf7_spam', '__return_false', 0 );
186 + add_filter( 'wpcf7_skip_spam_check', '__return_true', 0 );
187 +
87 188 $submission = \WPCF7_Submission::get_instance( $ContactForm );
189 +
190 + // Re-enable validation and spam checks
191 + remove_filter( 'wpcf7_validate', $clearValidation, 999 );
192 + remove_filter( 'wpcf7_spam', '__return_false', 0 );
193 + remove_filter( 'wpcf7_skip_spam_check', '__return_true', 0 );
194 +
195 + if ( $submission ) {
196 + $this->get_logger()->info( 'WPCF7 submission prepared for sendDefaultMail', [
197 + 'plugin' => 'double-opt-in',
198 + 'form_id' => $OptIn->get_cf_form_id(),
199 + 'optin_id' => $OptIn->get_id(),
200 + ] );
201 + } else {
202 + $this->get_logger()->warning( 'Failed to prepare WPCF7 submission', [
203 + 'plugin' => 'double-opt-in',
204 + 'form_id' => $OptIn->get_cf_form_id(),
205 + 'optin_id' => $OptIn->get_id(),
206 + ] );
207 + }
88 208 }
89 209
210 +
90 211 /**
91 212 * On Form Submit add the double optin if enabled
92 213 *
93 214 * @param $form \WPCF7_ContactForm
@@ -94,81 +215,73 @@
94 215 * @param bool
95 216 * @param $submission \WPCF7_Submission
96 217 */
97 218 public function onSubmit( $form, &$abort, $submission ) {
219 + $this->get_logger()->debug( 'onSubmit called', [
220 + 'plugin' => 'double-opt-in',
221 + 'class' => __CLASS__,
222 + 'method' => __METHOD__,
223 + 'form_id' => $form->id(),
224 + ] );
225 +
98 226 $parameter = CF7DoubleOptIn::getInstance()->getParameter( $form->id() );
99 227
100 228 if ( $this->isOptinEnabled( $form->id() ) ) {
229 + $this->get_logger()->debug( 'Opt-in enabled, processing', [
230 + 'plugin' => 'double-opt-in',
231 + 'form_id' => $form->id(),
232 + ] );
233 +
101 234 // Remove Contact Form 7 DB hook to ensure the optin mail is not saved
102 235 remove_action( 'wpcf7_before_send_mail', 'cfdb7_before_send_mail' );
103 236
104 - if(apply_filters('f12_cf7_doubleoptin_skip_option', false, $form->id(), $submission->get_posted_data(), $this->type)){
105 - return; // Skip if requested
237 + if ( apply_filters( 'f12_cf7_doubleoptin_skip_option', false, $form->id(), $submission->get_posted_data(), $this->type ) ) {
238 + $this->get_logger()->info( 'Opt-in skipped by filter', [
239 + 'plugin' => 'double-opt-in',
240 + 'form_id' => $form->id(),
241 + ] );
242 +
243 + return;
106 244 }
107 245
108 - // Get the OptIn Object
109 - $OptIn = $this->maybeCreateOptIn( $form->id(), $form->form_html(), $submission->get_posted_data(), $submission->uploaded_files() );
246 + $OptIn = $this->maybeCreateOptIn(
247 + $form->id(),
248 + $form->form_html(),
249 + $submission->get_posted_data(),
250 + $submission->uploaded_files()
251 + );
110 252
111 - /**
112 - * Skip if OptIn not created
113 - */
114 253 if ( ! $OptIn ) {
254 + $this->get_logger()->warning( 'OptIn object could not be created', [
255 + 'plugin' => 'double-opt-in',
256 + 'form_id' => $form->id(),
257 + ] );
258 +
115 259 return;
116 260 }
117 261
118 - // Add the Form URL to the parameters
119 262 $parameter['formUrl'] = $submission->get_meta( 'url' );
120 263
121 - // Get the Body content
122 - $body = $parameter['body'];
123 -
124 - // Replace the Placeholders within the body content.
125 - $body = $this->addPlaceholders( $body, $OptIn, $parameter );
126 -
127 264 /**
128 - * Body
265 + * Filter to render custom email templates.
129 266 *
130 - * Filters the Body of the OptIn Mail. Allows developers to adjust the content
131 - * before transmission.
267 + * Allows replacing the email body with content from custom templates.
132 268 *
133 - * @param string $body The content of the OptIn Mail.
269 + * @since 4.0.0
134 270 *
135 - * @since 2.3.3
271 + * @param string $body The email body content.
272 + * @param string $template The template key (e.g., 'blank', 'custom_123').
273 + * @param array $parameter The form parameters.
274 + * @param OptIn $OptIn The OptIn object.
136 275 */
276 + $body = apply_filters( 'f12_cf7_doubleoptin_template_body', $parameter['body'], $parameter['template'], $parameter, $OptIn );
277 +
278 + $body = $this->addPlaceholders( $body, $OptIn, $parameter );
137 279 $body = apply_filters( 'f12_cf7_doubleoptin_body', $body );
138 280
139 - /**
140 - * Set the OptIn Mail Content to the OptIn Object.
141 - */
142 281 $OptIn->set_mail_optin( $body );
143 282 $OptIn->save();
144 283
145 - /**
146 - * Recipient
147 - */
148 - $additional_headers = '';
149 -
150 - /**
151 - * OptIn Mail Arguments
152 - *
153 - * Filters the Arguments for the OptIn Mail. This hook allows developers
154 - * to add additional content to the Mail.
155 - *
156 - * @formatter:off
157 - *
158 - * @param $args {
159 - * @type string $subject The Subject of the OptIn Mail
160 - * @type string $body The Body of the OptIn Mail,
161 - * @type string $sender The Sender of the OptIn Mail
162 - * @type string $recipient The recipient of the OptIn Mail
163 - * @type bool $use_html Enable/Disable HTML for the OptIn Mail. Default: true
164 - * @type string $additional_headers Additional Header Information for the Mail.
165 - * }
166 - *
167 - * @formatter:on
168 - *
169 - * @since 2.3.3
170 - */
171 284 $args = apply_filters( 'f12-cf7-doubleoptin-cf7-args', [
172 285 'subject' => $parameter['subject'],
173 286 'body' => $body,
174 287 'sender' => $parameter['sender'],
@@ -174,107 +287,73 @@
174 287 'sender' => $parameter['sender'],
175 288 'sender_name' => $parameter['sender_name'],
176 289 'recipient' => $parameter['recipient'],
177 290 'use_html' => true,
178 - 'additional_headers' => $additional_headers
291 + 'additional_headers' => '',
179 292 ] );
180 293
181 - /**
182 - * Set the Header
183 - */
184 294 if ( ! empty( $parameter['sender_name'] ) ) {
185 295 $args['additional_headers'] .= 'From: ' . $args['sender_name'] . ' <' . $args['sender'] . '>';
186 296 }
187 297
188 - // Prepare the Opt-In Mail
189 298 \WPCF7_Mail::send( $args, 'mail' );
299 + $this->get_logger()->info( 'OptIn mail sent', [
300 + 'plugin' => 'double-opt-in',
301 + 'form_id' => $form->id(),
302 + 'recipient' => $args['recipient'],
303 + 'subject' => $args['subject'],
304 + ] );
190 305
191 - // Skip all mails following
306 + $telemetry = new Telemetry( $this->get_logger() );
307 + $telemetry->increment( 'total_optins' );
308 + $telemetry->increment( 'cf7_optins' );
309 +
192 310 add_filter( 'wpcf7_skip_mail', '__return_true' );
193 -
194 - /**
195 - * Action after the OptIn Mail has been sent.
196 - *
197 - * Allows other developers to do additional tasks after the OptIn Mail has been submitted.
198 - *
199 - * @formatter:off
200 - *
201 - * @param \WPCF7_ContactForm $form The Contact Form 7 Form Object
202 - * @param int $formId The Post ID of the CF7 Form.
203 - *
204 - * @formatter:on
205 - *
206 - * @since 2.3.3
207 - */
208 311 do_action( 'f12_cf7_doubleoptin_sent', $form, $form->id() );
209 312
210 - } else if ( isset( $_GET['optin'] ) ) {
211 - /**
212 - * Add Files / Attachments to the OptIn Mail.
213 - */
214 - $hash = sanitize_text_field( $_GET['optin'] );
313 + } elseif ( isset( $_GET['optin'] ) ) {
314 + $hash = sanitize_text_field( $_GET['optin'] );
315 + $OptIn = OptIn::get_by_hash( $hash );
215 316
216 - /**
217 - * Get the OptIn Object
218 - */
219 - $OptIn = OptIn::get_by_hash( $hash );
317 + if ( $OptIn === null ) {
318 + $this->get_logger()->warning( 'OptIn not found for hash', [
319 + 'plugin' => 'double-opt-in',
320 + 'hash' => $hash,
321 + ] );
220 322
221 - /**
222 - * Skip if the OptIn has not been found.
223 - */
224 - if ( null == $OptIn ) {
225 323 return;
226 324 }
227 325
228 - /**
229 - * Get the Files from the OptIn Object
230 - */
231 326 $files = maybe_unserialize( $OptIn->get_files() );
232 327
233 - /**
234 - * Skip if no files has been found
235 - */
236 328 if ( empty( $files ) ) {
329 + $this->get_logger()->debug( 'No files found for OptIn', [
330 + 'plugin' => 'double-opt-in',
331 + 'optinId' => $OptIn->get_id(),
332 + ] );
333 +
237 334 return;
238 335 }
239 336
240 - /**
241 - * Loop through all attachments/files.
242 - */
243 337 foreach ( $files as $file ) {
244 - /**
245 - * Skip file if the name is empty
246 - */
247 - if ( ! empty( $file ) ) {
338 + if ( empty( $file ) ) {
248 339 continue;
249 340 }
250 341
251 - /**
252 - * Enable / Disable the OptIn Mail Attachment for Mail 1.
253 - *
254 - * Allows Developers to Enable/Disable Mail attachments dynamically.
255 - *
256 - * @param bool $status Either add attachments (true) or not (false). Default: true
257 - * @param OptIn $OptIn The OptIn Object.
258 - *
259 - * @since 2.3.3
260 - */
261 342 if ( apply_filters( 'f12_cf7_doubleoptin_files_mail_1', true, $OptIn ) ) {
262 343 $submission->add_extra_attachments( $file );
344 + $this->get_logger()->debug( 'Attachment added to mail_1', [
345 + 'plugin' => 'double-opt-in',
346 + 'file' => $file,
347 + ] );
263 348 }
264 349
265 - /**
266 - * Enable / Disable the OptIn Mail Attachment for Mail 2.
267 - *
268 - * Allows Developers to Enable/Disable Mail attachments dynamically.
269 - *
270 - * @param bool $status Either add attachments (true) or not (false). Default: true
271 - * @param OptIn $OptIn The OptIn Object.
272 - *
273 - * @since 2.3.3
274 - */
275 350 if ( apply_filters( 'f12_cf7_doubleoptin_files_mail_2', true, $OptIn ) ) {
276 351 $submission->add_extra_attachments( $file, 'mail_2' );
352 + $this->get_logger()->debug( 'Attachment added to mail_2', [
353 + 'plugin' => 'double-opt-in',
354 + 'file' => $file,
355 + ] );
277 356 }
278 357 }
279 358 }
280 359 }