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
double-opt-in / src / Providers / FollowUpServiceProvider.php

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

166 lines 4.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Follow-up Service Provider
4 *
5 * @package Forge12\DoubleOptIn\Providers
6 * @since 5.6.0
7 */
8
9 declare( strict_types=1 );
10
11 namespace Forge12\DoubleOptIn\Providers;
12
13 use Forge12\DoubleOptIn\Admin\FollowUpRestController;
14 use Forge12\DoubleOptIn\Container\BootableProviderInterface;
15 use Forge12\DoubleOptIn\Container\Container;
16 use Forge12\DoubleOptIn\FollowUp\FollowUpAdapterRegistry;
17 use Forge12\DoubleOptIn\FollowUp\FollowUpCoordinator;
18 use Forge12\DoubleOptIn\Health\DatabaseTableHealthCheck;
19 use Forge12\DoubleOptIn\Health\HealthCheckRegistry;
20 use Forge12\DoubleOptIn\Repository\FollowUpRepository;
21 use Forge12\DoubleOptIn\Repository\FollowUpRepositoryInterface;
22 use Forge12\DoubleOptIn\Repository\FollowUpSchema;
23 use Forge12\Shared\LoggerInterface;
24 use forge12\contactform7\CF7DoubleOptIn\OptIn;
25
26 if ( ! defined( 'ABSPATH' ) ) {
27 exit;
28 }
29
30 /**
31 * Wires the follow-up coordinator: container bindings, the legacy
32 * accessor, cron (single retries + hourly sweep), deletion cascade and
33 * the admin REST routes.
34 *
35 * Must be registered BEFORE AddonServiceProvider so the adapter
36 * registry exists when the form addons boot.
37 */
38 class FollowUpServiceProvider implements BootableProviderInterface {
39
40 /**
41 * {@inheritdoc}
42 */
43 public function register( Container $container ): void {
44 $container->singleton(
45 FollowUpRepositoryInterface::class,
46 function () {
47 global $wpdb;
48 return new FollowUpRepository( $wpdb );
49 }
50 );
51
52 $container->singleton(
53 FollowUpAdapterRegistry::class,
54 function () {
55 return new FollowUpAdapterRegistry();
56 }
57 );
58
59 $container->singleton(
60 FollowUpCoordinator::class,
61 function ( Container $c ) {
62 return new FollowUpCoordinator(
63 $c->get( FollowUpRepositoryInterface::class ),
64 $c->get( FollowUpAdapterRegistry::class ),
65 $c->get( LoggerInterface::class )
66 );
67 }
68 );
69 }
70
71 /**
72 * {@inheritdoc}
73 */
74 public function boot( Container $container ): void {
75 $coordinator = $container->get( FollowUpCoordinator::class );
76 FollowUpCoordinator::setInstance( $coordinator );
77
78 $loader = static function ( int $id ): ?OptIn {
79 return OptIn::get_by_id( $id );
80 };
81
82 add_action(
83 FollowUpCoordinator::CRON_RETRY_HOOK,
84 static function ( $optInId ) use ( $coordinator, $loader ) {
85 $optIn = $loader( (int) $optInId );
86 if ( $optIn ) {
87 $coordinator->run( $optIn, \Forge12\DoubleOptIn\FollowUp\FollowUpAttempt::TRIGGER_CRON );
88 }
89 },
90 10,
91 1
92 );
93
94 add_action(
95 FollowUpCoordinator::CRON_SWEEP_HOOK,
96 static function () use ( $coordinator, $loader ) {
97 if ( FollowUpSchema::exists() ) {
98 $coordinator->sweep( $loader );
99 }
100 }
101 );
102
103 add_action(
104 'init',
105 static function () {
106 if ( ! wp_next_scheduled( FollowUpCoordinator::CRON_SWEEP_HOOK ) ) {
107 wp_schedule_event( time() + 300, 'hourly', FollowUpCoordinator::CRON_SWEEP_HOOK );
108 }
109 }
110 );
111
112 // Deletion cascade. `$row` is the opt-in row (array or object)
113 // passed by every core deletion path; the sweep's orphan cleanup
114 // covers paths that do not fire this action.
115 add_action(
116 'f12_doi_optin_pre_delete',
117 static function ( $row ) use ( $coordinator ) {
118 $id = 0;
119 if ( is_array( $row ) ) {
120 $id = (int) ( $row['id'] ?? 0 );
121 } elseif ( is_object( $row ) && isset( $row->id ) ) {
122 $id = (int) $row->id;
123 }
124 $coordinator->forget( $id );
125 },
126 20,
127 1
128 );
129
130 // Dev-mode confirmation reset (WP_DEBUG only): drop the status too,
131 // otherwise the re-confirmation finds every action already done.
132 add_action(
133 'f12_doi_optin_confirmation_reset',
134 static function ( $optInId ) use ( $coordinator ) {
135 $coordinator->forget( (int) $optInId );
136 },
137 10,
138 1
139 );
140
141 ( new FollowUpRestController( $coordinator, $loader ) )->init();
142
143 // Labels are translated, so register on init — boot() runs on
144 // plugins_loaded, before translations may be loaded.
145 if ( $container->has( HealthCheckRegistry::class ) ) {
146 $healthRegistry = $container->get( HealthCheckRegistry::class );
147 add_action(
148 'init',
149 static function () use ( $healthRegistry ) {
150 $healthRegistry->register(
151 new DatabaseTableHealthCheck(
152 'f12_doi_table_followup',
153 'core',
154 FollowUpSchema::TABLE_NAME,
155 __( 'Follow-up action status', 'double-opt-in' ),
156 __( 'Open Double Opt-In', 'double-opt-in' ),
157 admin_url( 'admin.php?page=f12-doi-admin' )
158 )
159 );
160 },
161 20
162 );
163 }
164 }
165 }
166