PluginProbe
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification / 5.8.0
Double Opt-In for Contact Form 7 – Secure, GDPR-Compliant Email Verification v5.8.0
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
← All changes | core/review.php +178 -144 5.7.0 → 5.8.0 View file →
@@ -1,144 +1,178 @@
1 -<?php
2 -
3 -namespace forge12\contactform7\CF7DoubleOptIn;
4 -
5 -if ( ! defined( 'ABSPATH' ) ) {
6 - exit;
7 -}
8 -
9 -// Prevent double-registration when Free + Pro are both active
10 -if ( ! function_exists( __NAMESPACE__ . '\\f12_cf7_doubleoptin_maybe_show_review_notice' ) ) {
11 -
12 - add_action( 'admin_notices', __NAMESPACE__ . '\\f12_cf7_doubleoptin_maybe_show_review_notice' );
13 - add_action( 'admin_init', __NAMESPACE__ . '\\f12_cf7_doubleoptin_handle_review_actions' );
14 -
15 - /**
16 - * Show review notice if conditions are met.
17 - */
18 - function f12_cf7_doubleoptin_maybe_show_review_notice() {
19 - if ( ! current_user_can( 'manage_options' ) ) {
20 - return;
21 - }
22 -
23 - $installed_at = (int) get_option( 'f12_cf7_doubleoptin_installed_at', time() );
24 - $optin_counters = get_option( 'f12_cf7_doubleoptin_telemetry_counters', [] );
25 - $confirmed_optins = isset( $optin_counters['confirmed_optins'] ) ? (int) $optin_counters['confirmed_optins'] : 0;
26 -
27 - $dismissed = get_option( 'f12_cf7_doubleoptin_review_dismissed', false );
28 - $remind_later = (int) get_option( 'f12_cf7_doubleoptin_review_remind_later', 0 );
29 - $remind_count = (int) get_option( 'f12_cf7_doubleoptin_review_remind_count', 0 );
30 -
31 - // Conditions:
32 - // - installed for at least 10 days
33 - // - at least 25 confirmed opt-ins
34 - //
35 - // The threshold used to be 3. Three confirmations is a site that has
36 - // barely started; asking for a public review at that point is asking
37 - // someone to vouch for something they have not seen work yet.
38 - if ( ( time() - $installed_at ) < DAY_IN_SECONDS * 10 ) {
39 - return;
40 - }
41 -
42 - if ( $confirmed_optins < 25 ) {
43 - return;
44 - }
45 -
46 - if ( $dismissed ) {
47 - return;
48 - }
49 -
50 - if ( $remind_later > 0 && ( time() < $remind_later ) ) {
51 - return;
52 - }
53 -
54 - // Max 2 reminders
55 - if ( $remind_count >= 2 ) {
56 - return;
57 - }
58 -
59 - // Claim this screen. The credit-link notice runs later on the same hook
60 - // and stands down when it sees this — asking a site owner for two
61 - // favours at once is how a plugin earns a one-star review, and the
62 - // review request is the more valuable of the two.
63 - $GLOBALS['f12_doi_review_notice_shown'] = true;
64 -
65 - ?>
66 - <div class="notice notice-info is-dismissible f12-cf7-doubleoptin-review-notice">
67 - <p>
68 - <?php printf(
69 - wp_kses(
70 - /* translators: %d: number of confirmed opt-ins. */
71 - __(
72 - '<strong>Double Opt-In for WordPress</strong> has already confirmed <strong>%d email subscriptions</strong>. Would you support us with a quick review?',
73 - 'double-opt-in'
74 - ),
75 - array( 'strong' => array() )
76 - ),
77 - (int) $confirmed_optins
78 - ); ?>
79 - </p>
80 - <p>
81 - <a href="https://wordpress.org/support/plugin/double-opt-in/reviews/#new-post"
82 - target="_blank"
83 - class="button button-primary">
84 - <?php _e( 'Leave a review now', 'double-opt-in' ); ?>
85 - </a>
86 - <?php
87 - // The only path out of this notice used to be a public review.
88 - // Someone who is unhappy has no other outlet, so the feedback
89 - // lands as a one-star rating that nobody can answer. This gives
90 - // them somewhere to say it to us instead.
91 - ?>
92 - <a href="<?php echo esc_url( get_feedback_url( 'review-notice' ) ); ?>"
93 - target="_blank"
94 - rel="noopener"
95 - class="button">
96 - <?php esc_html_e( 'Something not working? Tell us', 'double-opt-in' ); ?>
97 - </a>
98 - <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'f12_cf7_doubleoptin_review_remind', '1' ), 'doi_review_action' ) ); ?>"
99 - class="button">
100 - <?php _e( 'Remind me later', 'double-opt-in' ); ?>
101 - </a>
102 - <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'f12_cf7_doubleoptin_review_dismissed', '1' ), 'doi_review_action' ) ); ?>"
103 - class="button">
104 - <?php _e( "Don't ask again", 'double-opt-in' ); ?>
105 - </a>
106 - </p>
107 - </div>
108 - <?php
109 - }
110 -
111 - /**
112 - * Handle review notice actions (dismiss / remind later).
113 - */
114 - function f12_cf7_doubleoptin_handle_review_actions() {
115 - if ( ! current_user_can( 'manage_options' ) ) {
116 - return;
117 - }
118 -
119 - $is_dismiss = isset( $_GET['f12_cf7_doubleoptin_review_dismissed'] );
120 - $is_remind = isset( $_GET['f12_cf7_doubleoptin_review_remind'] );
121 -
122 - if ( ! $is_dismiss && ! $is_remind ) {
123 - return;
124 - }
125 -
126 - if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'doi_review_action' ) ) {
127 - return;
128 - }
129 -
130 - if ( $is_dismiss ) {
131 - update_option( 'f12_cf7_doubleoptin_review_dismissed', true );
132 - }
133 -
134 - if ( $is_remind ) {
135 - $remind_count = (int) get_option( 'f12_cf7_doubleoptin_review_remind_count', 0 );
136 - update_option( 'f12_cf7_doubleoptin_review_remind_later', time() + DAY_IN_SECONDS * 7 );
137 - update_option( 'f12_cf7_doubleoptin_review_remind_count', $remind_count + 1 );
138 - }
139 -
140 - // Redirect to remove query parameters from URL
141 - wp_safe_redirect( remove_query_arg( [ 'f12_cf7_doubleoptin_review_dismissed', 'f12_cf7_doubleoptin_review_remind', '_wpnonce' ] ) );
142 - exit;
143 - }
144 -}
1 +<?php
2 +
3 +namespace forge12\contactform7\CF7DoubleOptIn;
4 +
5 +if ( ! defined( 'ABSPATH' ) ) {
6 + exit;
7 +}
8 +
9 +// Prevent double-registration when Free + Pro are both active
10 +if ( ! function_exists( __NAMESPACE__ . '\\f12_cf7_doubleoptin_maybe_show_review_notice' ) ) {
11 +
12 + add_action( 'admin_notices', __NAMESPACE__ . '\\f12_cf7_doubleoptin_maybe_show_review_notice' );
13 + add_action( 'admin_init', __NAMESPACE__ . '\\f12_cf7_doubleoptin_handle_review_actions' );
14 +
15 + /**
16 + * Confirmed opt-ins a site needs before we ask for a review.
17 + *
18 + * History: 3 at first — a site that has barely started, asked to vouch for
19 + * something it has not seen work yet. Then 25, which small sites rarely
20 + * reach: nine ratings in four years, and the count is what wp.org ranks
21 + * and visitors weigh. 10 (5.7.1) is past the "does it work at all" stage
22 + * and still within reach of a small site's first weeks.
23 + */
24 + function f12_cf7_doubleoptin_review_threshold(): int {
25 + /**
26 + * Filter the number of confirmed opt-ins before the review request shows.
27 + *
28 + * @param int $threshold Default 10.
29 + *
30 + * @since 5.7.1
31 + */
32 + return max( 1, (int) apply_filters( 'f12_doi_review_min_confirmed', 10 ) );
33 + }
34 +
35 + /**
36 + * Whether the review request is due. Pure: every fact comes in.
37 + *
38 + * @param array{now:int, installedAt:int, confirmed:int, dismissed:bool, remindLater:int, remindCount:int, pagenow:string, page:string} $facts
39 + */
40 + function f12_cf7_doubleoptin_review_is_due( array $facts ): bool {
41 + // Only where someone looks at the plugin: the dashboard, the plugins
42 + // screen and the plugin's own pages — not on every admin screen.
43 + $onScreen = in_array( $facts['pagenow'], array( 'index.php', 'plugins.php' ), true )
44 + || ( $facts['pagenow'] === 'admin.php' && strpos( $facts['page'], 'f12-doi' ) === 0 );
45 + if ( ! $onScreen ) {
46 + return false;
47 + }
48 + if ( ( $facts['now'] - $facts['installedAt'] ) < DAY_IN_SECONDS * 10 ) {
49 + return false;
50 + }
51 + if ( $facts['confirmed'] < f12_cf7_doubleoptin_review_threshold() ) {
52 + return false;
53 + }
54 + if ( $facts['dismissed'] ) {
55 + return false;
56 + }
57 + if ( $facts['remindLater'] > 0 && $facts['now'] < $facts['remindLater'] ) {
58 + return false;
59 + }
60 + // Max 2 reminders.
61 + return $facts['remindCount'] < 2;
62 + }
63 +
64 + /**
65 + * Show review notice if conditions are met.
66 + */
67 + function f12_cf7_doubleoptin_maybe_show_review_notice() {
68 + if ( ! current_user_can( 'manage_options' ) ) {
69 + return;
70 + }
71 +
72 + global $pagenow;
73 + $optin_counters = get_option( 'f12_cf7_doubleoptin_telemetry_counters', [] );
74 + $confirmed_optins = isset( $optin_counters['confirmed_optins'] ) ? (int) $optin_counters['confirmed_optins'] : 0;
75 +
76 + $due = f12_cf7_doubleoptin_review_is_due(
77 + array(
78 + 'now' => time(),
79 + 'installedAt' => (int) get_option( 'f12_cf7_doubleoptin_installed_at', time() ),
80 + 'confirmed' => $confirmed_optins,
81 + 'dismissed' => (bool) get_option( 'f12_cf7_doubleoptin_review_dismissed', false ),
82 + 'remindLater' => (int) get_option( 'f12_cf7_doubleoptin_review_remind_later', 0 ),
83 + 'remindCount' => (int) get_option( 'f12_cf7_doubleoptin_review_remind_count', 0 ),
84 + 'pagenow' => isset( $pagenow ) ? (string) $pagenow : '',
85 + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only: which admin page is open.
86 + 'page' => isset( $_GET['page'] ) ? sanitize_key( wp_unslash( $_GET['page'] ) ) : '',
87 + )
88 + );
89 + if ( ! $due ) {
90 + return;
91 + }
92 +
93 + // Claim this screen. The credit-link notice runs later on the same hook
94 + // and stands down when it sees this — asking a site owner for two
95 + // favours at once is how a plugin earns a one-star review, and the
96 + // review request is the more valuable of the two.
97 + $GLOBALS['f12_doi_review_notice_shown'] = true;
98 +
99 + ?>
100 + <div class="notice notice-info is-dismissible f12-cf7-doubleoptin-review-notice">
101 + <p>
102 + <?php printf(
103 + wp_kses(
104 + /* translators: %d: number of confirmed opt-ins. */
105 + __(
106 + '<strong>Double Opt-In for WordPress</strong> has already confirmed <strong>%d email subscriptions</strong>. Would you support us with a quick review?',
107 + 'double-opt-in'
108 + ),
109 + array( 'strong' => array() )
110 + ),
111 + (int) $confirmed_optins
112 + ); ?>
113 + </p>
114 + <p>
115 + <a href="https://wordpress.org/support/plugin/double-opt-in/reviews/#new-post"
116 + target="_blank"
117 + class="button button-primary">
118 + <?php _e( 'Leave a review now', 'double-opt-in' ); ?>
119 + </a>
120 + <?php
121 + // The only path out of this notice used to be a public review.
122 + // Someone who is unhappy has no other outlet, so the feedback
123 + // lands as a one-star rating that nobody can answer. This gives
124 + // them somewhere to say it to us instead.
125 + ?>
126 + <a href="<?php echo esc_url( get_feedback_url( 'review-notice' ) ); ?>"
127 + target="_blank"
128 + rel="noopener"
129 + class="button">
130 + <?php esc_html_e( 'Something not working? Tell us', 'double-opt-in' ); ?>
131 + </a>
132 + <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'f12_cf7_doubleoptin_review_remind', '1' ), 'doi_review_action' ) ); ?>"
133 + class="button">
134 + <?php _e( 'Remind me later', 'double-opt-in' ); ?>
135 + </a>
136 + <a href="<?php echo esc_url( wp_nonce_url( add_query_arg( 'f12_cf7_doubleoptin_review_dismissed', '1' ), 'doi_review_action' ) ); ?>"
137 + class="button">
138 + <?php _e( "Don't ask again", 'double-opt-in' ); ?>
139 + </a>
140 + </p>
141 + </div>
142 + <?php
143 + }
144 +
145 + /**
146 + * Handle review notice actions (dismiss / remind later).
147 + */
148 + function f12_cf7_doubleoptin_handle_review_actions() {
149 + if ( ! current_user_can( 'manage_options' ) ) {
150 + return;
151 + }
152 +
153 + $is_dismiss = isset( $_GET['f12_cf7_doubleoptin_review_dismissed'] );
154 + $is_remind = isset( $_GET['f12_cf7_doubleoptin_review_remind'] );
155 +
156 + if ( ! $is_dismiss && ! $is_remind ) {
157 + return;
158 + }
159 +
160 + if ( ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( wp_unslash( $_GET['_wpnonce'] ), 'doi_review_action' ) ) {
161 + return;
162 + }
163 +
164 + if ( $is_dismiss ) {
165 + update_option( 'f12_cf7_doubleoptin_review_dismissed', true );
166 + }
167 +
168 + if ( $is_remind ) {
169 + $remind_count = (int) get_option( 'f12_cf7_doubleoptin_review_remind_count', 0 );
170 + update_option( 'f12_cf7_doubleoptin_review_remind_later', time() + DAY_IN_SECONDS * 7 );
171 + update_option( 'f12_cf7_doubleoptin_review_remind_count', $remind_count + 1 );
172 + }
173 +
174 + // Redirect to remove query parameters from URL
175 + wp_safe_redirect( remove_query_arg( [ 'f12_cf7_doubleoptin_review_dismissed', 'f12_cf7_doubleoptin_review_remind', '_wpnonce' ] ) );
176 + exit;
177 + }
178 +}