PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.8.1
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.8.1
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 / Setup / SetupRedirect.php

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

145 lines 4.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Send a new user to the setup wizard once, right after activation.
4 *
5 * WordPress.org's guideline 11 allows this only within limits: once, never on
6 * bulk or network activation, never in a way that traps the user. The rules
7 * live in shouldRedirect(), a pure function, so each of them is testable.
8 *
9 * Sites that already use Double Opt-In (any form with it switched on) are not
10 * redirected, and neither is a site where the wizard was finished or skipped.
11 *
12 * @package Forge12\DoubleOptIn\Setup
13 * @since 5.7.0
14 */
15
16 declare( strict_types=1 );
17
18 namespace Forge12\DoubleOptIn\Setup;
19
20 use Forge12\DoubleOptIn\Integration\FormIntegrationRegistry;
21
22 if ( ! defined( 'ABSPATH' ) ) {
23 exit;
24 }
25
26 class SetupRedirect {
27
28 public const TRANSIENT = 'f12_doi_setup_redirect';
29
30 public const TARGET = 'admin.php?page=f12-doi-admin#/setup';
31
32 /**
33 * Called from the activation hook.
34 */
35 public static function onActivation( bool $networkWide, ?bool $cli = null ): void {
36 $cli = $cli ?? ( defined( 'WP_CLI' ) && WP_CLI );
37 // A CLI activation has no browser to redirect; the transient would
38 // ambush whoever opens wp-admin next (provisioning scripts, E2E runs).
39 if ( $networkWide || $cli ) {
40 return;
41 }
42 set_transient( self::TRANSIENT, 1, 60 );
43 }
44
45 public static function register(): void {
46 add_action( 'admin_init', array( self::class, 'maybeRedirect' ), 5 );
47 }
48
49 /**
50 * @param array{
51 * transient: bool,
52 * bulk: bool,
53 * network: bool,
54 * ajax: bool,
55 * rest: bool,
56 * cli: bool,
57 * canManage: bool,
58 * status: ?string,
59 * hasActiveForm: bool
60 * } $context
61 */
62 public static function shouldRedirect( array $context ): bool {
63 if ( empty( $context['transient'] ) ) {
64 return false;
65 }
66 if ( ! empty( $context['bulk'] ) || ! empty( $context['network'] ) ) {
67 return false;
68 }
69 if ( ! empty( $context['ajax'] ) || ! empty( $context['rest'] ) || ! empty( $context['cli'] ) ) {
70 return false;
71 }
72 if ( empty( $context['canManage'] ) ) {
73 return false;
74 }
75 $status = $context['status'] ?? null;
76 if ( $status === SetupState::DONE || $status === SetupState::SKIPPED ) {
77 return false;
78 }
79 // No wizard state yet: only a site without any configured form counts as new.
80 if ( $status === null && ! empty( $context['hasActiveForm'] ) ) {
81 return false;
82 }
83
84 /**
85 * Filter whether to open the setup wizard after activation.
86 *
87 * @param bool $redirect Whether to redirect.
88 * @param array $context The facts the decision was based on.
89 *
90 * @since 5.7.0
91 */
92 return (bool) apply_filters( 'f12_doi_setup_should_redirect', true, $context );
93 }
94
95 public static function maybeRedirect(): void {
96 if ( ! get_transient( self::TRANSIENT ) ) {
97 return;
98 }
99 // Whatever happens next, the redirect is spent.
100 delete_transient( self::TRANSIENT );
101
102 $state = new SetupState();
103 $context = array(
104 'transient' => true,
105 // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only check of WordPress' own bulk-activation marker.
106 'bulk' => isset( $_GET['activate-multi'] ),
107 'network' => is_network_admin(),
108 'ajax' => wp_doing_ajax(),
109 'rest' => defined( 'REST_REQUEST' ) && REST_REQUEST,
110 'cli' => defined( 'WP_CLI' ) && WP_CLI,
111 'canManage' => current_user_can( 'manage_options' ),
112 'status' => $state->exists() ? $state->status() : null,
113 'hasActiveForm' => false,
114 );
115 if ( $context['status'] === null ) {
116 $context['hasActiveForm'] = self::hasActiveForm();
117 }
118
119 if ( ! self::shouldRedirect( $context ) ) {
120 return;
121 }
122
123 $state->initialize();
124 wp_safe_redirect( admin_url( self::TARGET ) );
125 exit;
126 }
127
128 /**
129 * Whether any form of any available integration has Double Opt-In on.
130 */
131 private static function hasActiveForm(): bool {
132 if ( ! class_exists( FormIntegrationRegistry::class ) ) {
133 return false;
134 }
135 foreach ( FormIntegrationRegistry::getInstance()->getAvailable() as $integration ) {
136 foreach ( $integration->getForms() as $form ) {
137 if ( ! empty( $form['enabled'] ) ) {
138 return true;
139 }
140 }
141 }
142 return false;
143 }
144 }
145