PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.8.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.8.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 3.0.51 All 41 releases
double-opt-in / src / Providers / MailStatusServiceProvider.php

MailStatusServiceProvider.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification 5.8.0, at src/Providers/MailStatusServiceProvider.php

175 lines 4.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Mail Status Service Provider
4 *
5 * Records whether each confirmation mail reached the mail server and
6 * reports recent failures in Site Health.
7 *
8 * @package Forge12\DoubleOptIn\Providers
9 * @since 5.8.0
10 */
11
12 declare( strict_types=1 );
13
14 namespace Forge12\DoubleOptIn\Providers;
15
16 use Forge12\DoubleOptIn\Container\BootableProviderInterface;
17 use Forge12\DoubleOptIn\Container\Container;
18 use Forge12\DoubleOptIn\EventSystem\EventDispatcherInterface;
19 use Forge12\DoubleOptIn\FormSettings\FormSettingsService;
20 use Forge12\DoubleOptIn\Health\MailFailuresHealthCheck;
21 use Forge12\DoubleOptIn\Health\SenderDomainCheck;
22 use Forge12\DoubleOptIn\Repository\OptInMailStatusRepository;
23 use Forge12\DoubleOptIn\Repository\OptInRepositoryInterface;
24 use Forge12\DoubleOptIn\Repository\OptInStatsRepository;
25 use Forge12\DoubleOptIn\Service\ConfirmationMailResender;
26 use Forge12\DoubleOptIn\Service\DoiMailHeaders;
27 use Forge12\DoubleOptIn\Service\OptInMailTracker;
28 use Forge12\DoubleOptIn\Service\StuckOptInsReport;
29 use Forge12\DoubleOptIn\Setup\FormDefaults;
30
31 if ( ! defined( 'ABSPATH' ) ) {
32 exit;
33 }
34
35 class MailStatusServiceProvider implements BootableProviderInterface {
36
37 /**
38 * {@inheritdoc}
39 */
40 public function register( Container $container ): void {
41 $container->singleton(
42 OptInMailStatusRepository::class,
43 static function () {
44 global $wpdb;
45 return new OptInMailStatusRepository( $wpdb );
46 }
47 );
48 $container->singleton(
49 OptInStatsRepository::class,
50 static function () {
51 global $wpdb;
52 return new OptInStatsRepository( $wpdb );
53 }
54 );
55 $container->singleton(
56 StuckOptInsReport::class,
57 static function ( Container $c ) {
58 return new StuckOptInsReport( $c->get( OptInStatsRepository::class ), $c->get( OptInMailStatusRepository::class ) );
59 }
60 );
61 $container->singleton(
62 DoiMailHeaders::class,
63 static function () {
64 return new DoiMailHeaders();
65 }
66 );
67 $container->singleton(
68 ConfirmationMailResender::class,
69 static function ( Container $c ) {
70 return new ConfirmationMailResender(
71 $c->get( OptInRepositoryInterface::class ),
72 static function ( int $formId ): array {
73 return (array) \forge12\contactform7\CF7DoubleOptIn\CF7DoubleOptIn::getInstance()->getParameter( $formId );
74 },
75 $c->get( DoiMailHeaders::class )
76 );
77 }
78 );
79 $container->singleton(
80 OptInMailTracker::class,
81 static function ( Container $c ) {
82 return new OptInMailTracker( $c->get( OptInMailStatusRepository::class ) );
83 }
84 );
85 }
86
87 /**
88 * {@inheritdoc}
89 */
90 public function boot( Container $container ): void {
91 $container->get( OptInMailTracker::class )->register( $container->get( EventDispatcherInterface::class ) );
92 $container->get( DoiMailHeaders::class )->register( $container->get( EventDispatcherInterface::class ) );
93
94 // A new failure should show up in Site Health right away, not after
95 // the hourly cache runs out.
96 add_action(
97 OptInMailTracker::RESULT_ACTION,
98 static function ( $optInId, $sent ) {
99 if ( ! $sent ) {
100 delete_transient( MailFailuresHealthCheck::CACHE_KEY );
101 }
102 },
103 20,
104 2
105 );
106 add_action(
107 'wp_mail_failed',
108 static function () {
109 delete_transient( MailFailuresHealthCheck::CACHE_KEY );
110 }
111 );
112
113 // Dashboard: share of unconfirmed opt-ins, when it is high (C2).
114 add_filter(
115 'f12_doi_rest_dashboard_stats',
116 static function ( $data ) use ( $container ) {
117 return $container->get( StuckOptInsReport::class )->addToDashboard( $data );
118 }
119 );
120
121 // A changed sender should be re-checked on the next Site Health visit.
122 add_action(
123 'updated_post_meta',
124 static function ( $metaId, $postId, $metaKey ) {
125 if ( $metaKey === FormSettingsService::META_KEY ) {
126 delete_transient( SenderDomainCheck::CACHE_KEY );
127 }
128 },
129 10,
130 3
131 );
132
133 add_filter(
134 'f12_doi_health_checks',
135 static function ( $checks ) use ( $container ) {
136 $checks = is_array( $checks ) ? $checks : array();
137 $checks[] = new MailFailuresHealthCheck( $container->get( OptInMailStatusRepository::class ) );
138 $checks[] = new SenderDomainCheck(
139 static function () use ( $container ): array {
140 return self::activeSenders( $container );
141 }
142 );
143 return $checks;
144 }
145 );
146 }
147
148 /**
149 * Sender addresses of the forms with Double Opt-In switched on; the
150 * setup wizard's default when none is.
151 *
152 * Elementor forms have composite ids and are not covered.
153 *
154 * @return string[]
155 */
156 private static function activeSenders( Container $container ): array {
157 $senders = array();
158
159 if ( $container->has( FormSettingsService::class ) ) {
160 $service = $container->get( FormSettingsService::class );
161 foreach ( $service->getAllFormsFlat() as $form ) {
162 if ( ! empty( $form['enabled'] ) && is_numeric( $form['id'] ?? null ) ) {
163 $senders[] = $service->getSettings( (int) $form['id'] )->sender;
164 }
165 }
166 }
167
168 if ( $senders === array() ) {
169 $senders[] = FormDefaults::get()['sender'];
170 }
171
172 return $senders;
173 }
174 }
175