Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.53% covered (warning)
85.53%
65 / 76
66.67% covered (warning)
66.67%
2 / 3
CRAP
n/a
0 / 0
wpcomsh_ajax_anyone_can_register_handle_dismissal
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
5
wpcomsh_users_can_register_option_change
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
wpcomsh_anyone_register_warning
88.06% covered (warning)
88.06%
59 / 67
0.00% covered (danger)
0.00%
0 / 1
12.25
1<?php
2/**
3 * Active Anyone can register option notice file.
4 *
5 * @package wpcomsh
6 */
7
8/**
9 * Adds a dismissible admin notice to warn about the risks when users_can_register option is active.
10 * The purpose is to reduce unnecessary activation of this option and to reduce chances that malicious admins can register to the site.
11 */
12const WPCOMSH_ACR_DISMISSED_METADATA = 'wpcomsh_anyone_can_register_dismissed_notice';
13
14/** Handle AJAX request to dismiss notice **/
15function wpcomsh_ajax_anyone_can_register_handle_dismissal() {
16    if ( isset( $_SERVER['REQUEST_METHOD'] ) && isset( $_POST['action'] ) ) {
17        if ( 'anyone_can_register_dismiss_notice' === $_POST['action'] && check_ajax_referer( 'anyone_can_register_ajax_nonce', '_ajax_nonce', false ) ) {
18            update_user_meta( get_current_user_id(), WPCOMSH_ACR_DISMISSED_METADATA, '1' );
19        }
20    }
21}
22add_action( 'wp_ajax_anyone_can_register_dismiss_notice', 'wpcomsh_ajax_anyone_can_register_handle_dismissal' );
23
24/**
25 * Clear metadata when option disabled.
26 *
27 * @param int $old_value of users_can_register option.
28 * @param int $new_value of users_can_register option.
29 */
30function wpcomsh_users_can_register_option_change( $old_value, $new_value ) {
31    if ( ! $new_value ) {
32        delete_metadata( 'user', 0, WPCOMSH_ACR_DISMISSED_METADATA, 1, true );
33        return;
34    }
35}
36add_action( 'update_option_users_can_register', 'wpcomsh_users_can_register_option_change', 10, 2 );
37
38/**
39 * Adds a dismissible notice to wp-admin pages for all administrators if users_can_register option is active.
40 * Default roles of Admin and Shop Manager warn red while all other roles warn orange.
41 * Dismissal metadata is cleared for all admins when option is disabled.
42 *
43 * @global WP_Roles $wp_roles Available roles.
44 * @global string $pagenow Current page being viewed.
45 */
46function wpcomsh_anyone_register_warning() {
47    global $wp_roles;
48    global $pagenow;
49
50    if ( ! current_user_can( 'manage_options' ) ) {
51        return;
52    }
53
54    if ( ! get_option( 'users_can_register' ) ) {
55        return;
56    }
57
58    $dismissed = get_user_meta( get_current_user_id(), WPCOMSH_ACR_DISMISSED_METADATA, true );
59
60    if ( $dismissed ) {
61        return;
62    }
63
64    $default_role = get_option( 'default_role' );
65
66    // only show notice for roles with higher permissions - requested in regards to Sensei p6rkRX-6NA-p2#comment-6691
67    if ( ! in_array( $default_role, array( 'administrator', 'shop_manager', 'editor', 'author' ), true ) ) {
68        return;
69    }
70
71    $warning_text_main = ( $pagenow !== 'options-general.php' ) ?
72    /* translators: %1$s default role, %2$s support doc URL, %3$s site options URL, %4$s string highlighting risks*/
73    __(
74        'The <a href="%2$s">"Anyone can register" option</a> is currently active. The current default role is %1$s. %4$s <a href="%3$s"><strong>Please consider disabling this option if open registration is not needed.</strong></a>.',
75        'wpcomsh'
76    ) :
77    /* translators: %1$s default role, %2$s support doc URL, %3$s site options URL, %4$s string highlighting risks*/
78    __(
79        'The <a href="%2$s">"Anyone can register" option</a> is currently active. The current default role is %1$s. %4$s <strong>Please consider disabling this option if open registration is not needed.<strong>',
80        'wpcomsh'
81    );
82
83    $warning_text_role = '';
84    // using switch instead of array to account for custom $default_role
85    switch ( $default_role ) {
86        case 'administrator':
87            $warning_text_role = __(
88                'It allows a user full control over your site and its contents.',
89                'wpcomsh'
90            );
91            break;
92        case 'shop_manager':
93            $warning_text_role = __(
94                'It allows a user control over your orders and products.',
95                'wpcomsh'
96            );
97            break;
98        case 'editor':
99            $warning_text_role = __(
100                'It allows a user to post/modify/delete all content.',
101                'wpcomsh'
102            );
103            break;
104        case 'author':
105            $warning_text_role = __(
106                'It allows a user to post content.',
107                'wpcomsh'
108            );
109            break;
110        default:
111            $warning_text_role = __(
112                'This may pose a security risk to your site.',
113                'wpcomsh'
114            );
115    }
116
117    $message = sprintf(
118        $warning_text_main,
119        esc_html( $wp_roles->roles[ $default_role ]['name'] ),
120        esc_url( 'https://wordpress.com/support/security/#anyone-can-register' ),
121        esc_url( admin_url( 'options-general.php' ) ),
122        $warning_text_role
123    );
124
125    $notice_style = in_array( $default_role, array( 'administrator', 'shop_manager' ), true ) ? 'notice__icon-wrapper-red' : 'notice__icon-wrapper-orange';
126    printf(
127        '<div class="notice wpcomsh-notice is-dismissible anyone-can-register-notice">
128            <span class="notice__icon-wrapper %1$s">
129                <span class="dashicons dashicons-info"></span>
130            </span>
131            <span class="notice__content">
132                <span class="notice__text">%2$s</span>
133            </span>
134        </div>',
135        esc_attr( $notice_style ),
136        wp_kses_post( $message )
137    );
138
139    $nonce = wp_create_nonce( 'anyone_can_register_ajax_nonce' );
140
141    // admin-ajax call to add metadata for persistent dismissal
142    echo '<script id="anyone-can-register-notice" type="text/javascript">
143        jQuery( function( $ ) {
144            $( document ).ready( function() {
145                $( ".anyone-can-register-notice .notice-dismiss" ).on( "click", function() {
146                    $.ajax( {
147                        url: ' . wp_json_encode( esc_url_raw( admin_url( 'admin-ajax.php' ) ), JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . ',
148                        type: "POST",
149                        data: {
150                            action: "anyone_can_register_dismiss_notice",
151                            _ajax_nonce: ' . wp_json_encode( $nonce, JSON_UNESCAPED_SLASHES | JSON_HEX_TAG | JSON_HEX_AMP ) . '
152                        },
153                        error: function( xhr, status, error ) {
154                            alert( error );
155                        }
156                    });
157                });
158            });
159        });
160    </script>';
161}
162
163add_action( 'admin_notices', 'wpcomsh_anyone_register_warning' );