PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / trunk
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification vtrunk
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 3.0.60 3.0.61 All 39 releases
double-opt-in / src / Setup / SetupState.php

SetupState.php in Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification trunk, at src/Setup/SetupState.php

138 lines 3.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Where the setup wizard stands, and what has been entered so far.
4 *
5 * Every step saves immediately, so leaving the wizard halfway loses nothing.
6 * Forms are only switched on when the wizard finishes: the completeness gate
7 * needs recipient, subject and body together, and the body only exists after
8 * step 3.
9 *
10 * A missing option means the site was installed before the wizard existed.
11 * Such sites never see the wizard unless someone starts it from the settings.
12 *
13 * @package Forge12\DoubleOptIn\Setup
14 * @since 5.7.0
15 */
16
17 declare( strict_types=1 );
18
19 namespace Forge12\DoubleOptIn\Setup;
20
21 if ( ! defined( 'ABSPATH' ) ) {
22 exit;
23 }
24
25 class SetupState {
26
27 public const OPTION = 'f12_doi_setup';
28
29 public const PENDING = 'pending';
30 public const SKIPPED = 'skipped';
31 public const DONE = 'done';
32
33 /** Number of steps with input; the summary after them is not counted. */
34 public const STEPS = 4;
35
36 public function exists(): bool {
37 return is_array( get_option( self::OPTION, null ) );
38 }
39
40 /**
41 * @return array{status: string, step: int, draft: array<string, mixed>, updated_at: int}
42 */
43 public function get(): array {
44 $stored = get_option( self::OPTION, array() );
45 $stored = is_array( $stored ) ? $stored : array();
46
47 $status = isset( $stored['status'] ) && in_array( $stored['status'], array( self::PENDING, self::SKIPPED, self::DONE ), true )
48 ? (string) $stored['status']
49 : self::PENDING;
50
51 return array(
52 'status' => $status,
53 'step' => max( 0, min( self::STEPS, (int) ( $stored['step'] ?? 0 ) ) ),
54 'draft' => isset( $stored['draft'] ) && is_array( $stored['draft'] ) ? $stored['draft'] : array(),
55 'updated_at' => (int) ( $stored['updated_at'] ?? 0 ),
56 );
57 }
58
59 public function status(): string {
60 return $this->get()['status'];
61 }
62
63 /**
64 * @return array<string, mixed>
65 */
66 public function draft(): array {
67 return $this->get()['draft'];
68 }
69
70 /**
71 * Start tracking a fresh installation. Does nothing when a state exists.
72 */
73 public function initialize(): void {
74 if ( $this->exists() ) {
75 return;
76 }
77 $this->write( self::PENDING, 0, array() );
78 }
79
80 /**
81 * Store the values of one step and move the pointer past it.
82 *
83 * @param int $completedStep Zero-based index of the step just saved.
84 * @param array<string, mixed> $values Draft values of that step.
85 */
86 public function saveStep( int $completedStep, array $values ): void {
87 $state = $this->get();
88 $next = max( $state['step'], min( self::STEPS, $completedStep + 1 ) );
89 $this->write( $state['status'] === self::DONE ? self::DONE : self::PENDING, $next, array_merge( $state['draft'], $values ) );
90 }
91
92 /**
93 * Merge values into the draft without moving the step pointer.
94 *
95 * @param array<string, mixed> $values
96 */
97 public function remember( array $values ): void {
98 $state = $this->get();
99 $this->write( $state['status'], $state['step'], array_merge( $state['draft'], $values ) );
100 }
101
102 public function skip(): void {
103 $state = $this->get();
104 if ( $state['status'] === self::DONE ) {
105 return;
106 }
107 $this->write( self::SKIPPED, $state['step'], $state['draft'] );
108 }
109
110 public function complete(): void {
111 $state = $this->get();
112 $this->write( self::DONE, self::STEPS, $state['draft'] );
113 }
114
115 /**
116 * Run the wizard again. The draft is kept so the fields come back filled in.
117 */
118 public function restart(): void {
119 $this->write( self::PENDING, 0, $this->get()['draft'] );
120 }
121
122 /**
123 * @param array<string, mixed> $draft
124 */
125 private function write( string $status, int $step, array $draft ): void {
126 update_option(
127 self::OPTION,
128 array(
129 'status' => $status,
130 'step' => $step,
131 'draft' => $draft,
132 'updated_at' => time(),
133 ),
134 false
135 );
136 }
137 }
138