PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.9.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.9.0
5.9.0 5.8.0 5.8.1 5.7.0 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 All 42 releases
← All changes | CF7DoubleOptIn.class.php +104 -5 5.1.5 → 5.9.0 View file →
@@ -14,14 +14,51 @@
14 14 * Plugin URI: https://www.forge12.com/blog/so-verwendest-du-das-double-opt-in-fuer-contact-form-7/
15 15 * Description: This plugin allows you to add a double OptIn System to your Contact Form 7 & Avada Forms.
16 16 * Text Domain: double-opt-in
17 17 * Domain Path: /languages
18 - * Version: 5.1.5
18 + * Version: 5.9.0
19 + * Requires at least: 6.0
20 + * Requires PHP: 7.4
19 21 * Author: Forge12 Interactive GmbH
20 22 * Author URI: https://www.forge12.com
21 23 */
24 +
25 + /**
26 + * Minimum-PHP fail-safe.
27 + *
28 + * The "Requires PHP" header above makes WordPress refuse *activation* and
29 + * *updates* on an unsupported version, but it is not re-checked when a host
30 + * later moves an already-active site to an older PHP. Without this guard the
31 + * next request would fatal on 7.4-only syntax inside the files required
32 + * below, leaving the site with a white screen and no explanation.
33 + *
34 + * Everything above this point must stay parseable by old PHP — a parse error
35 + * happens before any code runs, so a guard in an unparseable file is dead
36 + * weight. That is also why CF7DoubleOptIn::$logger carries its type in a
37 + * DocBlock instead of a native (PHP 7.4) property type.
38 + */
39 + if ( PHP_VERSION_ID < 70400 ) {
40 + add_action(
41 + 'admin_notices',
42 + function () {
43 + echo '<div class="notice notice-error"><p>';
44 + echo esc_html(
45 + sprintf(
46 + /* translators: 1: minimum required PHP version, 2: PHP version currently running */
47 + __( 'Double Opt-In requires PHP %1$s or newer. This server is running PHP %2$s, so the plugin was stopped to prevent a fatal error. Please ask your host to update PHP.', 'double-opt-in' ),
48 + '7.4',
49 + PHP_VERSION
50 + )
51 + );
52 + echo '</p></div>';
53 + }
54 + );
55 +
56 + return;
57 + }
58 +
22 59 if ( ! defined( 'FORGE12_OPTIN_VERSION' ) ) {
23 - define( 'FORGE12_OPTIN_VERSION', '5.1.5' );
60 + define( 'FORGE12_OPTIN_VERSION', '5.9.0' );
24 61 }
25 62
26 63 // Addon API version — semver-independent from the plugin's marketing
27 64 // version. Bumped only on breaking changes to the Addon API surface
@@ -27,10 +64,28 @@
27 64 // version. Bumped only on breaking changes to the Addon API surface
28 65 // (AddonInterface, AddonRegistry, AddonLicenseRegistry, FormIntegrationInterface,
29 66 // event payloads). Addons declare their requirement against this constant,
30 67 // not FORGE12_OPTIN_VERSION.
68 + //
69 + // 4.4.0 (additive): FollowUp\FollowUpAdapterInterface, FollowUpCoordinator,
70 + // FollowUpAdapterRegistry. Addons that implement follow-up adapters
71 + // require ^4.4; everything else keeps working against 4.3.
72 + //
73 + // 4.5.0 (additive): AbstractFormIntegration::refusedConsentBeforeSubmit(),
74 + // OptInError::isAlwaysShown()/shouldShowToVisitor(),
75 + // OptInFrontend::getLastCreationError(), ErrorNotification::forget().
76 + // The Elementor, WPForms and Gravity Forms add-ons call them only when they
77 + // exist (method_exists), so their requirement stays ^4.4.
78 + //
79 + // 4.6.0 (additive): Service\ConfirmationMailResender, Service\DoiMailHeaders
80 + // (filter f12_doi_mail_headers), filter f12_doi_submit_notice_data,
81 + // Events\Lifecycle\OptInOptedOutEvent / OptInReOptedInEvent,
82 + // FollowUp\GlobalFollowUpAdapterInterface, OptInStatsRepository::activity(),
83 + // OptInMailStatusRepository::countFailedBetween(). Opt-Out and Reminder use them
84 + // only when they exist (class_exists), so their requirement does not change;
85 + // the Welle-2 add-ons that build on them require ^4.6.
31 86 if ( ! defined( 'F12_DOI_CORE_API_VERSION' ) ) {
32 - define( 'F12_DOI_CORE_API_VERSION', '4.3.0' );
87 + define( 'F12_DOI_CORE_API_VERSION', '4.6.0' );
33 88 }
34 89 if ( ! defined( 'FORGE12_OPTIN_SLUG' ) ) {
35 90 define( 'FORGE12_OPTIN_SLUG', 'f12-cf7-doubleoptin' );
36 91 }
@@ -47,14 +102,25 @@
47 102 */
48 103 require_once 'logger/logger.php';
49 104 require_once 'core/helpers/uuid.php';
50 105 require_once 'core/telemetry.php';
106 + // feedback.php first: review.php, credit_nudge.php and the deactivation
107 + // survey all build their links with it.
108 + require_once 'core/feedback.php';
51 109 require_once 'core/review.php';
110 + require_once 'core/confirmation_output.php';
111 + require_once 'core/credit_link.php';
112 + require_once 'core/credit_nudge.php';
113 + require_once 'core/deactivation_survey.php';
114 + require_once 'core/admin_links.php';
52 115 require_once 'core/cron.php';
53 116 require_once 'core/BaseController.class.php';
54 117
55 118 require_once 'OnActivation.php';
56 119 require_once 'OnDeactivation.php';
120 + // OnUpdate runs at include time, before autoload.php is registered
121 + // further down — load the one PSR-4 class it needs explicitly.
122 + require_once 'src/Repository/FollowUpSchema.php';
57 123 require_once 'OnUpdate.php';
58 124 require_once 'compatibility/OptInFrontend.class.php';
59 125 require_once 'core/SpamMechanics.class.php';
60 126
@@ -87,10 +153,17 @@
87 153 *
88 154 * @package forge12\contactform7
89 155 */
90 156 class CF7DoubleOptIn {
91 - private LoggerInterface $logger;
92 157 /**
158 + * Deliberately untyped: a native property type is PHP 7.4 syntax and
159 + * would make this file unparseable on older PHP, which would defeat the
160 + * minimum-PHP guard at the top of this file.
161 + *
162 + * @var LoggerInterface
163 + */
164 + private $logger;
165 + /**
93 166 * @var CF7DoubleOptIn|Null
94 167 */
95 168 private static $_instance = null;
96 169
@@ -384,8 +457,14 @@
384 457
385 458 // Register admin REST API and audit services (v4.2.0+)
386 459 $container->addProvider( new \Forge12\DoubleOptIn\Providers\AdminServiceProvider() );
387 460
461 + // Setup wizard (v5.7.0+)
462 + $container->addProvider( new \Forge12\DoubleOptIn\Providers\SetupServiceProvider() );
463 +
464 + // Confirmation mail delivery status (v5.8.0+)
465 + $container->addProvider( new \Forge12\DoubleOptIn\Providers\MailStatusServiceProvider() );
466 +
388 467 // Register licensing registry (v4.3.0+ — entitlement state for paid addons)
389 468 $container->addProvider( new \Forge12\DoubleOptIn\Providers\LicensingServiceProvider() );
390 469
391 470 // Register migration registry (v4.3.0+ — runs pending DB migrations on admin_init)
@@ -390,11 +469,22 @@
390 469
391 470 // Register migration registry (v4.3.0+ — runs pending DB migrations on admin_init)
392 471 $container->addProvider( new \Forge12\DoubleOptIn\Providers\MigrationServiceProvider() );
393 472
473 + // Register follow-up coordinator (v5.6.0+ — status + retry of
474 + // post-confirmation actions). Before AddonServiceProvider so
475 + // the adapter registry exists when the form addons boot.
476 + $container->addProvider( new \Forge12\DoubleOptIn\Providers\FollowUpServiceProvider() );
477 +
394 478 // Register addon system (v4.3.0+ — public Addon API)
395 479 $container->addProvider( new \Forge12\DoubleOptIn\Providers\AddonServiceProvider() );
396 480
481 + // Register health checks (v5.3.0+ — Site Health surfaces for
482 + // broken runtime preconditions such as a missing DB table).
483 + // After AddonServiceProvider so addon-contributed checks are
484 + // picked up by the registry's filter pass.
485 + $container->addProvider( new \Forge12\DoubleOptIn\Providers\HealthServiceProvider() );
486 +
397 487 // Register RateLimiter as singleton
398 488 $container->singleton(
399 489 \Forge12\DoubleOptIn\Service\RateLimiter::class,
400 490 function () {
@@ -504,8 +594,17 @@
504 594 'delete_unconfirmed' => 7,
505 595 'delete_period' => 'months',
506 596 'delete_unconfirmed_period' => 'months',
507 597 'privacy_policy_page' => 0,
598 + // Must be listed even though the opt-out addon owns the
599 + // feature: getSettings() rebuilds its return value from
600 + // THIS array and silently drops any stored key that is
601 + // missing here. Without the entry, every consumer of
602 + // getSettings()['optout_page'] — OptInLinkGenerator and
603 + // OptIn::get_link_optout(), i.e. the `[doubleoptoutlink]`
604 + // placeholder — fell back to home_url() no matter what
605 + // the admin had configured.
606 + 'optout_page' => 0,
508 607 'token_expiry_hours' => 48,
509 608 'rate_limit_ip' => 5,
510 609 'rate_limit_email' => 3,
511 610 'rate_limit_window' => 60,
@@ -639,9 +738,9 @@
639 738 // Show warning for major/minor version changes
640 739 if ( version_compare( $new_minor, $current_minor, '>' ) ) {
641 740 $upgrade_notice = sprintf(
642 741 '</p><div class="notice inline notice-warning notice-alt" style="margin: 10px 0; padding: 10px; border-left-color: #ffb900;"><p><strong>%s</strong></p><p>%s</p></div><p style="display:none;">',
643 - esc_html__( '⚠️ Important: Major Update – Please backup before updating!', 'double-opt-in' ),
742 + esc_html__( 'Important: Major Update – Please backup before updating!', 'double-opt-in' ),
644 743 esc_html__( 'This version includes significant changes to the form management system, email templates, and database structure. We strongly recommend creating a full site backup before updating.', 'double-opt-in' )
645 744 );
646 745
647 746 echo wp_kses_post( $upgrade_notice );