| @@ -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.6.3 | |
| 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.6.3' ); | |
| 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,20 @@ | ||
| 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. | |
| 31 | 78 | if ( ! defined( 'F12_DOI_CORE_API_VERSION' ) ) { |
| 32 | - define( 'F12_DOI_CORE_API_VERSION', '4.3.0' ); | |
| 79 | + define( 'F12_DOI_CORE_API_VERSION', '4.5.0' ); | |
| 33 | 80 | } |
| 34 | 81 | if ( ! defined( 'FORGE12_OPTIN_SLUG' ) ) { |
| 35 | 82 | define( 'FORGE12_OPTIN_SLUG', 'f12-cf7-doubleoptin' ); |
| 36 | 83 | } |
| @@ -47,14 +94,25 @@ | ||
| 47 | 94 | */ |
| 48 | 95 | require_once 'logger/logger.php'; |
| 49 | 96 | require_once 'core/helpers/uuid.php'; |
| 50 | 97 | require_once 'core/telemetry.php'; |
| 98 | + // feedback.php first: review.php, credit_nudge.php and the deactivation | |
| 99 | + // survey all build their links with it. | |
| 100 | + require_once 'core/feedback.php'; | |
| 51 | 101 | require_once 'core/review.php'; |
| 102 | + require_once 'core/confirmation_output.php'; | |
| 103 | + require_once 'core/credit_link.php'; | |
| 104 | + require_once 'core/credit_nudge.php'; | |
| 105 | + require_once 'core/deactivation_survey.php'; | |
| 106 | + require_once 'core/admin_links.php'; | |
| 52 | 107 | require_once 'core/cron.php'; |
| 53 | 108 | require_once 'core/BaseController.class.php'; |
| 54 | 109 | |
| 55 | 110 | require_once 'OnActivation.php'; |
| 56 | 111 | require_once 'OnDeactivation.php'; |
| 112 | + // OnUpdate runs at include time, before autoload.php is registered | |
| 113 | + // further down — load the one PSR-4 class it needs explicitly. | |
| 114 | + require_once 'src/Repository/FollowUpSchema.php'; | |
| 57 | 115 | require_once 'OnUpdate.php'; |
| 58 | 116 | require_once 'compatibility/OptInFrontend.class.php'; |
| 59 | 117 | require_once 'core/SpamMechanics.class.php'; |
| 60 | 118 | |
| @@ -87,10 +145,17 @@ | ||
| 87 | 145 | * |
| 88 | 146 | * @package forge12\contactform7 |
| 89 | 147 | */ |
| 90 | 148 | class CF7DoubleOptIn { |
| 91 | - private LoggerInterface $logger; | |
| 92 | 149 | /** |
| 150 | + * Deliberately untyped: a native property type is PHP 7.4 syntax and | |
| 151 | + * would make this file unparseable on older PHP, which would defeat the | |
| 152 | + * minimum-PHP guard at the top of this file. | |
| 153 | + * | |
| 154 | + * @var LoggerInterface | |
| 155 | + */ | |
| 156 | + private $logger; | |
| 157 | + /** | |
| 93 | 158 | * @var CF7DoubleOptIn|Null |
| 94 | 159 | */ |
| 95 | 160 | private static $_instance = null; |
| 96 | 161 | |
| @@ -390,11 +455,22 @@ | ||
| 390 | 455 | |
| 391 | 456 | // Register migration registry (v4.3.0+ — runs pending DB migrations on admin_init) |
| 392 | 457 | $container->addProvider( new \Forge12\DoubleOptIn\Providers\MigrationServiceProvider() ); |
| 393 | 458 | |
| 459 | + // Register follow-up coordinator (v5.6.0+ — status + retry of | |
| 460 | + // post-confirmation actions). Before AddonServiceProvider so | |
| 461 | + // the adapter registry exists when the form addons boot. | |
| 462 | + $container->addProvider( new \Forge12\DoubleOptIn\Providers\FollowUpServiceProvider() ); | |
| 463 | + | |
| 394 | 464 | // Register addon system (v4.3.0+ — public Addon API) |
| 395 | 465 | $container->addProvider( new \Forge12\DoubleOptIn\Providers\AddonServiceProvider() ); |
| 396 | 466 | |
| 467 | + // Register health checks (v5.3.0+ — Site Health surfaces for | |
| 468 | + // broken runtime preconditions such as a missing DB table). | |
| 469 | + // After AddonServiceProvider so addon-contributed checks are | |
| 470 | + // picked up by the registry's filter pass. | |
| 471 | + $container->addProvider( new \Forge12\DoubleOptIn\Providers\HealthServiceProvider() ); | |
| 472 | + | |
| 397 | 473 | // Register RateLimiter as singleton |
| 398 | 474 | $container->singleton( |
| 399 | 475 | \Forge12\DoubleOptIn\Service\RateLimiter::class, |
| 400 | 476 | function () { |
| @@ -504,8 +580,17 @@ | ||
| 504 | 580 | 'delete_unconfirmed' => 7, |
| 505 | 581 | 'delete_period' => 'months', |
| 506 | 582 | 'delete_unconfirmed_period' => 'months', |
| 507 | 583 | 'privacy_policy_page' => 0, |
| 584 | + // Must be listed even though the opt-out addon owns the | |
| 585 | + // feature: getSettings() rebuilds its return value from | |
| 586 | + // THIS array and silently drops any stored key that is | |
| 587 | + // missing here. Without the entry, every consumer of | |
| 588 | + // getSettings()['optout_page'] — OptInLinkGenerator and | |
| 589 | + // OptIn::get_link_optout(), i.e. the `[doubleoptoutlink]` | |
| 590 | + // placeholder — fell back to home_url() no matter what | |
| 591 | + // the admin had configured. | |
| 592 | + 'optout_page' => 0, | |
| 508 | 593 | 'token_expiry_hours' => 48, |
| 509 | 594 | 'rate_limit_ip' => 5, |
| 510 | 595 | 'rate_limit_email' => 3, |
| 511 | 596 | 'rate_limit_window' => 60, |
| @@ -639,9 +724,9 @@ | ||
| 639 | 724 | // Show warning for major/minor version changes |
| 640 | 725 | if ( version_compare( $new_minor, $current_minor, '>' ) ) { |
| 641 | 726 | $upgrade_notice = sprintf( |
| 642 | 727 | '</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' ), | |
| 728 | + esc_html__( 'Important: Major Update – Please backup before updating!', 'double-opt-in' ), | |
| 644 | 729 | 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 | 730 | ); |
| 646 | 731 | |
| 647 | 732 | echo wp_kses_post( $upgrade_notice ); |