PluginProbe
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress / 8.5.71
WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress v8.5.71
9.1.3 9.1.2 9.1.1 9.1.0 9.0.3 9.0.2 9.0.1 9.0.0 8.5.79 8.5.78 8.5.77 8.5.76 8.5.75 8.5.74 8.5.73 8.5.72 8.5.71 8.5.70 8.5.69 8.5.68 8.5.35 8.5.36 8.5.37 8.5.38 8.5.39 All 222 releases
wpvr / vendor / linno / telemetry / src / TriggerManager.php

TriggerManager.php in WPVR – 360 Panorama viewer and Virtual Tour Builder for WordPress 8.5.71, at vendor/linno/telemetry/src/TriggerManager.php

511 lines 14.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Trigger Manager Class
4 *
5 * Handles automatic event tracking through configured triggers.
6 * Supports setup and KUI events with threshold-based tracking.
7 *
8 * @package LinnoSDK\Telemetry
9 * @since 1.0.0
10 */
11
12 namespace LinnoSDK\Telemetry;
13
14 class TriggerManager {
15 /**
16 * Client instance
17 *
18 * @var Client
19 */
20 private Client $client;
21
22 /**
23 * Plugin slug
24 *
25 * @var string
26 */
27 private string $slug;
28
29 /**
30 * Registered triggers configuration
31 *
32 * @var array
33 */
34 private array $triggers = [];
35
36 /**
37 * KUI counter storage option key
38 *
39 * @var string
40 */
41 private string $kui_counter_key;
42
43 /**
44 * Constructor
45 *
46 * @param Client $client Client instance
47 */
48 public function __construct( Client $client ) {
49 $this->client = $client;
50 $this->slug = $client->get_slug();
51 $this->kui_counter_key = $this->slug . '_telemetry_kui_counters';
52 }
53
54 /**
55 * Register setup trigger
56 *
57 * Fires once when the specified hook is triggered.
58 *
59 * @param string $hook WordPress action hook to listen to
60 * @param callable $callback Optional callback to generate properties
61 * @return self
62 */
63 public function on_setup( string $hook, ?callable $callback = null ): self {
64 $this->triggers['setup'] = [
65 'type' => 'setup',
66 'hook' => $hook,
67 'callback' => $callback,
68 'fired' => false,
69 ];
70
71 return $this;
72 }
73
74
75
76 /**
77 * Register KUI (Key Usage Indicator) trigger
78 *
79 * Can be threshold-based (fire after N events in a period) or simple hook-based.
80 *
81 * @param string $name KUI indicator name (e.g., 'order_received', 'student_enrolled')
82 * @param array $config Configuration array with:
83 * - hook: WordPress action hook to listen to (optional if using check_callback)
84 * - threshold: array with 'count' and 'period' (e.g., ['count' => 2, 'period' => 'week'])
85 * - callback: callable to generate properties (optional)
86 * - check_callback: callable that returns true when KUI condition is met (alternative to hook)
87 * @return self
88 */
89 public function on_kui( string $name, array $config ): self {
90 $this->triggers['kui_' . $name] = [
91 'type' => 'kui',
92 'name' => $name,
93 'hook' => $config['hook'] ?? null,
94 'threshold' => $config['threshold'] ?? null,
95 'callback' => $config['callback'] ?? null,
96 'check_callback' => $config['check_callback'] ?? null,
97 ];
98
99 return $this;
100 }
101
102 /**
103 * Register feature used trigger
104 *
105 * Fires every time the hook is triggered.
106 *
107 * @param string $feature_name Feature name to track
108 * @param string $hook WordPress action hook to listen to
109 * @param callable $callback Optional callback to generate properties
110 * @return self
111 */
112 public function on_feature_used( string $feature_name, string $hook, ?callable $callback = null ): self {
113 $this->triggers['feature_used_' . $feature_name] = [
114 'type' => 'feature_used',
115 'feature' => $feature_name,
116 'hook' => $hook,
117 'callback' => $callback,
118 ];
119
120 return $this;
121 }
122
123 /**
124 * Register custom event trigger
125 *
126 * Fires every time the hook is triggered.
127 *
128 * @param string $event_name Event name to track
129 * @param string $hook WordPress action hook to listen to
130 * @param callable $callback Optional callback to generate properties
131 * @return self
132 */
133 public function on( string $event_name, string $hook, ?callable $callback = null ): self {
134 $this->triggers['custom_' . $event_name] = [
135 'type' => 'custom',
136 'event' => $event_name,
137 'hook' => $hook,
138 'callback' => $callback,
139 ];
140
141 return $this;
142 }
143
144 /**
145 * Initialize all registered triggers
146 *
147 * Sets up WordPress hooks for all configured triggers.
148 *
149 * @return void
150 */
151 public function init(): void {
152 foreach ( $this->triggers as $key => $trigger ) {
153 $this->register_trigger( $key, $trigger );
154 }
155
156 if ( $this->has_kui_triggers() ) {
157 $this->schedule_kui_check();
158 }
159 }
160
161 /**
162 * Register a single trigger
163 *
164 * @param string $key Trigger key
165 * @param array $trigger Trigger configuration
166 * @return void
167 */
168 private function register_trigger( string $key, array $trigger ): void {
169 if ( empty( $trigger['hook'] ) && empty( $trigger['check_callback'] ) ) {
170 return;
171 }
172
173 if ( ! empty( $trigger['hook'] ) ) {
174 $priority = $trigger['priority'] ?? 10;
175 // Always accept up to 10 arguments to be safe with any WordPress hook
176 $accepted_args = 10;
177
178 add_action(
179 $trigger['hook'],
180 function( ...$args ) use ( $key, $trigger ) {
181 $this->handle_trigger( $key, $trigger, $args );
182 },
183 $priority,
184 $accepted_args
185 );
186 }
187
188 if ( ! empty( $trigger['check_callback'] ) && $trigger['type'] === 'kui' ) {
189 add_action( $trigger['hook'] ?? 'init', function() use ( $key, $trigger ) {
190 $this->handle_kui_check( $key, $trigger );
191 }, 5 );
192 }
193 }
194
195 /**
196 * Handle trigger execution
197 *
198 * @param string $key Trigger key
199 * @param array $trigger Trigger configuration
200 * @param array $args Hook arguments
201 * @return void
202 */
203 private function handle_trigger( string $key, array $trigger, array $args ): void {
204 switch ( $trigger['type'] ) {
205 case 'setup':
206 $this->handle_setup( $key, $trigger, $args );
207 break;
208
209 case 'kui':
210 $this->handle_kui( $key, $trigger, $args );
211 break;
212 case 'feature_used':
213 $this->handle_feature_used( $key, $trigger, $args );
214 break;
215 case 'custom':
216 $this->handle_custom( $key, $trigger, $args );
217 break;
218 }
219 }
220
221 /**
222 * Handle setup trigger
223 *
224 * @param string $key Trigger key
225 * @param array $trigger Trigger configuration
226 * @param array $args Hook arguments
227 * @return void
228 */
229 private function handle_setup( string $key, array $trigger, array $args ): void {
230 if ( $this->client->has_sent_event( 'onboarding_completed' ) ) {
231 return;
232 }
233
234 $properties = $this->execute_callback( $trigger['callback'], $args );
235 $this->client->track_setup( $properties ?: [] );
236 }
237
238
239
240 /**
241 * Handle KUI trigger
242 *
243 * @param string $key Trigger key
244 * @param array $trigger Trigger configuration
245 * @param array $args Hook arguments
246 * @return void
247 */
248 private function handle_kui( string $key, array $trigger, array $args ): void {
249 $name = $trigger['name'];
250
251 // If threshold count is defined, track progress
252 if ( ! empty( $trigger['threshold']['count'] ) ) {
253 $this->increment_kui_counter( $name );
254
255 // If current count is >= threshold, send the event
256 if ( $this->should_fire_kui( $name, $trigger['threshold'] ) ) {
257 $properties = $this->execute_callback( $trigger['callback'], $args );
258 $this->client->track_kui( $name, $properties ?: [] );
259 }
260 } else {
261 // No threshold count defined - fire on every hit
262 $properties = $this->execute_callback( $trigger['callback'], $args );
263 $this->client->track_kui( $name, $properties ?: [] );
264 }
265 }
266
267 /**
268 * Handle feature used trigger
269 *
270 * @param string $key Trigger key
271 * @param array $trigger Trigger configuration
272 * @param array $args Hook arguments
273 * @return void
274 */
275 private function handle_feature_used( string $key, array $trigger, array $args ): void {
276 $properties = $this->execute_callback( $trigger['callback'], $args );
277 $this->client->track_feature_used( $trigger['feature'], $properties ?: [] );
278 }
279
280 /**
281 * Mark a KUI as fired for a specific period
282 *
283 * @param string $name KUI name
284 * @param string $period_key The period key (e.g., YYYY-WW)
285 * @return void
286 */
287 private function mark_kui_fired( string $name, string $period_key ): void {
288 $counters = $this->get_kui_counters();
289
290 if ( ! isset( $counters[ $name ] ) ) {
291 $counters[ $name ] = [];
292 }
293
294 $counters[ $name ]['last_fired_period'] = $period_key;
295 $this->save_kui_counters( $counters );
296 }
297
298 /**
299 * Handle custom event trigger
300 *
301 * @param string $key Trigger key
302 * @param array $trigger Trigger configuration
303 * @param array $args Hook arguments
304 * @return void
305 */
306 private function handle_custom( string $key, array $trigger, array $args ): void {
307 $properties = $this->execute_callback( $trigger['callback'], $args );
308 $this->client->track( $trigger['event'], $properties ?: [] );
309 }
310
311 /**
312 * Handle KUI check callback
313 *
314 * @param string $key Trigger key
315 * @param array $trigger Trigger configuration
316 * @return void
317 */
318 private function handle_kui_check( string $key, array $trigger ): void {
319 if ( ! is_callable( $trigger['check_callback'] ) ) {
320 return;
321 }
322
323 $result = call_user_func( $trigger['check_callback'] );
324
325 if ( $result ) {
326 $name = $trigger['name'];
327 $properties = [];
328
329 if ( is_array( $result ) ) {
330 $properties = $result;
331 }
332
333 if ( $this->client->has_sent_event( 'aha_reached_' . $name ) ) {
334 return;
335 }
336
337 $this->client->track_kui( $name, $properties );
338 $this->client->mark_event_sent( 'aha_reached_' . $name );
339 }
340 }
341
342 /**
343 * Execute callback with arguments
344 *
345 * @param callable|null $callback
346 * @param array $args
347 * @return mixed
348 */
349 private function execute_callback( ?callable $callback, array $args ) {
350 if ( ! $callback ) {
351 return null;
352 }
353
354 return call_user_func_array( $callback, $args );
355 }
356
357 /**
358 * Increment KUI counter
359 *
360 * @param string $name KUI name
361 * @return void
362 */
363 private function increment_kui_counter( string $name ): void {
364 $counters = $this->get_kui_counters();
365
366 if ( ! isset( $counters[ $name ] ) ) {
367 $counters[ $name ] = [
368 'count' => 0,
369 'start_time' => time(),
370 ];
371 }
372
373 $counters[ $name ]['count']++;
374 $this->save_kui_counters( $counters );
375 }
376
377 /**
378 * Reset all KUI counters for this plugin.
379 *
380 * Called after successful telemetry reporting.
381 *
382 * @return void
383 */
384 public function reset_all_counters(): void {
385 update_option( $this->kui_counter_key, [] );
386 }
387
388 /**
389 * Get period from threshold config
390 *
391 * @param array $threshold Threshold config
392 * @return string
393 */
394 private function get_period_from_threshold( array $threshold ): string {
395 return $threshold['period'] ?? 'week';
396 }
397
398 /**
399 * Check if KUI should fire based on threshold
400 *
401 * @param string $name KUI name
402 * @param array $threshold Threshold config with 'count' and 'period'
403 * @return bool
404 */
405 private function should_fire_kui( string $name, array $threshold ): bool {
406 $counters = $this->get_kui_counters();
407 $count = $counters[ $name ]['count'] ?? 0;
408 $required = $threshold['count'] ?? 1;
409
410 return $count >= $required;
411 }
412
413 /**
414 * Reset KUI counter
415 *
416 * @param string $name KUI name
417 * @return void
418 */
419 private function reset_kui_counter( string $name ): void {
420 $counters = $this->get_kui_counters();
421
422 if ( isset( $counters[ $name ] ) ) {
423 $counters[ $name ]['count'] = 0;
424 $this->save_kui_counters( $counters );
425 }
426 }
427
428 /**
429 * Get KUI counters from database
430 *
431 * @return array
432 */
433 private function get_kui_counters(): array {
434 return get_option( $this->kui_counter_key, [] );
435 }
436
437 /**
438 * Save KUI counters to database
439 *
440 * @param array $counters
441 * @return void
442 */
443 private function save_kui_counters( array $counters ): void {
444 update_option( $this->kui_counter_key, $counters );
445 }
446
447 /**
448 * Get period key based on period type
449 *
450 * @param string $name KUI name
451 * @return string
452 */
453 private function get_period_key( string $name ): string {
454 $counters = $this->get_kui_counters();
455 $period = $counters[ $name ]['period'] ?? 'week';
456
457 return $this->get_period_key_for_period( $period );
458 }
459
460 /**
461 * Check if there are any KUI triggers
462 *
463 * @return bool
464 */
465 private function has_kui_triggers(): bool {
466 foreach ( $this->triggers as $trigger ) {
467 if ( $trigger['type'] === 'kui' && ! empty( $trigger['check_callback'] ) ) {
468 return true;
469 }
470 }
471 return false;
472 }
473
474 /**
475 * Schedule KUI check
476 *
477 * @return void
478 */
479 private function schedule_kui_check(): void {
480 $hook = $this->slug . '_telemetry_kui_check';
481
482 add_action( $hook, [ $this, 'run_kui_checks' ] );
483
484 if ( ! wp_next_scheduled( $hook ) ) {
485 wp_schedule_event( time(), 'daily', $hook );
486 }
487 }
488
489 /**
490 * Run all KUI checks
491 *
492 * @return void
493 */
494 public function run_kui_checks(): void {
495 foreach ( $this->triggers as $key => $trigger ) {
496 if ( $trigger['type'] === 'kui' && ! empty( $trigger['check_callback'] ) ) {
497 $this->handle_kui_check( $key, $trigger );
498 }
499 }
500 }
501
502 /**
503 * Get all registered triggers
504 *
505 * @return array
506 */
507 public function get_triggers(): array {
508 return $this->triggers;
509 }
510 }
511