PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.5.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.5.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 3.0.70 3.0.71 3.0.72 3.1.0 All 34 releases
double-opt-in / src / Bridge / WordPressHookBridge.php

WordPressHookBridge.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification 5.5.0, at src/Bridge/WordPressHookBridge.php

282 lines 6.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * WordPress Hook Bridge
4 *
5 * Bridges existing WordPress hooks to typed events and vice versa.
6 *
7 * @package Forge12\DoubleOptIn\Bridge
8 * @since 4.0.0
9 */
10
11 namespace Forge12\DoubleOptIn\Bridge;
12
13 use Forge12\DoubleOptIn\EventSystem\EventDispatcherInterface;
14 use Forge12\DoubleOptIn\Events\Lifecycle\OptInCreatedEvent;
15 use Forge12\DoubleOptIn\Events\Lifecycle\OptInConfirmedEvent;
16 use Forge12\DoubleOptIn\Events\Lifecycle\OptInDeletedEvent;
17 use Forge12\DoubleOptIn\Events\Lifecycle\OptInExpiredEvent;
18 use Forge12\DoubleOptIn\Events\Form\FormSubmittedEvent;
19 use Forge12\DoubleOptIn\Events\Mail\MailPreparingEvent;
20 use Forge12\DoubleOptIn\Events\Mail\MailSentEvent;
21 use Forge12\Shared\LoggerInterface;
22
23 if ( ! defined( 'ABSPATH' ) ) {
24 exit;
25 }
26
27 /**
28 * Class WordPressHookBridge
29 *
30 * Ensures backward compatibility by bridging between WordPress hooks and typed events.
31 */
32 class WordPressHookBridge {
33
34 private EventDispatcherInterface $dispatcher;
35 private LoggerInterface $logger;
36
37 /**
38 * Constructor.
39 *
40 * @param EventDispatcherInterface $dispatcher The event dispatcher.
41 * @param LoggerInterface $logger The logger.
42 */
43 public function __construct( EventDispatcherInterface $dispatcher, LoggerInterface $logger ) {
44 $this->dispatcher = $dispatcher;
45 $this->logger = $logger;
46 }
47
48 /**
49 * Register all bridges between WordPress hooks and typed events.
50 *
51 * @return void
52 */
53 public function registerBridges(): void {
54 $this->logger->info(
55 'Registering WordPress hook bridges',
56 array(
57 'plugin' => 'double-opt-in',
58 'component' => 'hook-bridge',
59 )
60 );
61
62 // Register listeners for legacy hooks that should trigger typed events
63 $this->registerLegacyHookListeners();
64
65 // Register action to provide typed events to legacy hook listeners
66 $this->registerTypedEventBridges();
67 }
68
69 /**
70 * Register listeners for legacy WordPress hooks.
71 *
72 * When legacy code fires do_action(), we can react and dispatch typed events.
73 *
74 * @return void
75 */
76 private function registerLegacyHookListeners(): void {
77 // Legacy: f12_cf7_doubleoptin_sent (old hook when OptIn is created)
78 add_action(
79 'f12_cf7_doubleoptin_sent',
80 function ( $form, $formId ) {
81 $this->logger->debug(
82 'Legacy hook f12_cf7_doubleoptin_sent received',
83 array(
84 'plugin' => 'double-opt-in',
85 'form_id' => $formId,
86 )
87 );
88 // Note: The typed event should be dispatched by the new code,
89 // this is just for logging/monitoring legacy usage
90 },
91 1,
92 2
93 );
94
95 // Legacy: f12_cf7_doubleoptin_before_confirm
96 add_action(
97 'f12_cf7_doubleoptin_before_confirm',
98 function ( $hash, $optIn ) {
99 $this->logger->debug(
100 'Legacy hook f12_cf7_doubleoptin_before_confirm received',
101 array(
102 'plugin' => 'double-opt-in',
103 'hash' => $hash,
104 )
105 );
106 },
107 1,
108 2
109 );
110
111 // Legacy: f12_cf7_doubleoptin_after_confirm
112 add_action(
113 'f12_cf7_doubleoptin_after_confirm',
114 function ( $hashOrEvent, $optIn = null ) {
115 // Skip if this is already a typed event (dispatched by EventDispatcher)
116 if ( $hashOrEvent instanceof OptInConfirmedEvent ) {
117 return;
118 }
119
120 $this->logger->debug(
121 'Legacy hook f12_cf7_doubleoptin_after_confirm received',
122 array(
123 'plugin' => 'double-opt-in',
124 'hash' => is_string( $hashOrEvent ) ? $hashOrEvent : 'event',
125 )
126 );
127 },
128 1,
129 2
130 );
131 }
132
133 /**
134 * Register bridges that convert typed events to legacy hook calls.
135 *
136 * This ensures that code using add_action() on old hooks still works.
137 *
138 * @return void
139 */
140 private function registerTypedEventBridges(): void {
141 // When OptInCreatedEvent is dispatched, also fire legacy hook
142 $this->dispatcher->addListener(
143 OptInCreatedEvent::class,
144 function ( OptInCreatedEvent $event ) {
145 $this->logger->debug(
146 'Bridging OptInCreatedEvent to legacy hooks',
147 array(
148 'plugin' => 'double-opt-in',
149 'optin_id' => $event->getOptInId(),
150 )
151 );
152
153 /**
154 * Legacy action for backward compatibility.
155 *
156 * @deprecated Use OptInCreatedEvent listener instead.
157 *
158 * @param int $formId The form ID.
159 * @param string $formType The form type.
160 * @param int $optInId The opt-in ID.
161 */
162 do_action(
163 'f12_cf7_doubleoptin_optin_created_legacy',
164 $event->getFormId(),
165 $event->getFormType(),
166 $event->getOptInId()
167 );
168 },
169 5 // Low priority so typed listeners run first
170 );
171
172 // When OptInConfirmedEvent is dispatched, ensure legacy listeners get data
173 $this->dispatcher->addListener(
174 OptInConfirmedEvent::class,
175 function ( OptInConfirmedEvent $event ) {
176 $this->logger->debug(
177 'OptInConfirmedEvent dispatched',
178 array(
179 'plugin' => 'double-opt-in',
180 'optin_id' => $event->getOptInId(),
181 'hash' => $event->getHash(),
182 )
183 );
184 },
185 5
186 );
187
188 // When OptInDeletedEvent is dispatched
189 $this->dispatcher->addListener(
190 OptInDeletedEvent::class,
191 function ( OptInDeletedEvent $event ) {
192 $this->logger->debug(
193 'OptInDeletedEvent dispatched',
194 array(
195 'plugin' => 'double-opt-in',
196 'hash' => $event->getHash(),
197 'deleted_by' => $event->getDeletedBy(),
198 )
199 );
200 },
201 5
202 );
203
204 // When OptInExpiredEvent is dispatched (from cleanup)
205 $this->dispatcher->addListener(
206 OptInExpiredEvent::class,
207 function ( OptInExpiredEvent $event ) {
208 $this->logger->notice(
209 'OptInExpiredEvent dispatched',
210 array(
211 'plugin' => 'double-opt-in',
212 'cleanup_type' => $event->getCleanupType(),
213 'rows_deleted' => $event->getRowsDeleted(),
214 )
215 );
216 },
217 5
218 );
219
220 // When MailPreparingEvent is dispatched
221 $this->dispatcher->addListener(
222 MailPreparingEvent::class,
223 function ( MailPreparingEvent $event ) {
224 $this->logger->debug(
225 'MailPreparingEvent dispatched',
226 array(
227 'plugin' => 'double-opt-in',
228 'optin_id' => $event->getOptInId(),
229 'recipient' => $event->getRecipient(),
230 )
231 );
232 },
233 5
234 );
235
236 // When MailSentEvent is dispatched
237 $this->dispatcher->addListener(
238 MailSentEvent::class,
239 function ( MailSentEvent $event ) {
240 $this->logger->info(
241 'MailSentEvent dispatched',
242 array(
243 'plugin' => 'double-opt-in',
244 'optin_id' => $event->getOptInId(),
245 'success' => $event->wasSuccessful(),
246 'mail_type' => $event->getMailType(),
247 )
248 );
249 },
250 5
251 );
252
253 $this->logger->info(
254 'Typed event bridges registered',
255 array(
256 'plugin' => 'double-opt-in',
257 'component' => 'hook-bridge',
258 )
259 );
260 }
261
262 /**
263 * Get the event dispatcher.
264 *
265 * @return EventDispatcherInterface
266 */
267 public function getDispatcher(): EventDispatcherInterface {
268 return $this->dispatcher;
269 }
270
271 /**
272 * Dispatch an event and ensure legacy hooks are called.
273 *
274 * @param object $event The event to dispatch.
275 *
276 * @return object The dispatched event.
277 */
278 public function dispatch( object $event ): object {
279 return $this->dispatcher->dispatch( $event );
280 }
281 }
282