Skip to content

Commit

Permalink
Switch to three-state approach (#31)
Browse files Browse the repository at this point in the history
* #

* Switch to three-state approach

* Update readme.txt

* Use wp_parse_url

* Update test-user-meta.php
  • Loading branch information
obenland authored Jul 9, 2024
1 parent 7696427 commit 767384f
Show file tree
Hide file tree
Showing 6 changed files with 123 additions and 46 deletions.
115 changes: 84 additions & 31 deletions class-obenland-wp-approve-user.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ class Obenland_Wp_Approve_User extends Obenland_Wp_Plugins_V5 {
*/
protected $options;

/**
* Users flagged as pending.
*
* @since 12
*
* @var int
*/
protected $pending_count = 0;

/**
* Users flagged as unapproved.
*
Expand All @@ -43,6 +52,15 @@ class Obenland_Wp_Approve_User extends Obenland_Wp_Plugins_V5 {
*/
protected $unapproved_users = array();

/**
* Number of unapproved users.
*
* @since 12
*
* @var int
*/
protected $unapproved_count = 0;

/**
* Constructor
*
Expand All @@ -66,16 +84,22 @@ public function __construct() {
);

if ( is_admin() ) {
/**
* Get all users where wp-approve-user meta value is false or doesn't exist.
*/
$args = array(
'fields' => 'ID',
'meta_key' => 'wp-approve-user', //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
'meta_value' => false, //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
'meta_value' => 'pending', //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
);

if ( is_multisite() ) {
$args['blog_id'] = is_network_admin() ? 0 : get_current_blog_id();
}
$this->pending_count = count( get_users( $args ) );

$this->unapproved_users = get_users( $args );
$args['meta_value'] = 'unapproved'; //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
$this->unapproved_count = count( get_users( $args ) );
}

load_plugin_textdomain( 'wp-approve-user', false, 'wp-approve-user/lang' );
Expand Down Expand Up @@ -201,18 +225,29 @@ public function admin_print_styles_settings_page_wp_approve_user() {
* @return array
*/
public function views_users( $views ) {
if ( $this->unapproved_users ) {
// phpcs:ignore WordPress.Security.NonceVerification
$site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
$url = 'site-users-network' === get_current_screen()->id ? add_query_arg( array( 'id' => $site_id ), 'site-users.php' ) : 'users.php';
// phpcs:ignore WordPress.Security.NonceVerification
$site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
$url = 'site-users-network' === get_current_screen()->id ? add_query_arg( array( 'id' => $site_id ), 'site-users.php' ) : 'users.php';

if ( $this->pending_count ) {
$views['pending'] = sprintf(
'<a href="%1$s" class="%2$s">%3$s <span class="count">(%4$s)</span></a>',
esc_url( add_query_arg( array( 'role' => 'wpau_pending' ), $url ) ),
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
'wpau_pending' === $this->get_role() ? 'current' : '',
esc_html__( 'Pending', 'wp-approve-users' ),
$this->pending_count
);
}

if ( $this->unapproved_count ) {
$views['unapproved'] = sprintf(
'<a href="%1$s" class="%2$s">%3$s <span class="count">(%4$s)</span></a>',
esc_url( add_query_arg( array( 'role' => 'wpau_unapproved' ), $url ) ),
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
'wpau_unapproved' === $this->get_role() ? 'current' : '',
esc_html__( 'Unapproved', 'wp-approve-users' ),
count( $this->unapproved_users )
$this->unapproved_count
);
}

Expand All @@ -232,11 +267,21 @@ public function pre_user_query( $query ) {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput
$role = empty( $query->query_vars['role'] ) && isset( $_REQUEST['role'] ) ? $_REQUEST['role'] : $query->query_vars['role'];

if ( 'wpau_pending' === $role ) {
unset( $query->query_vars['meta_query'] );
$query->query_vars['role'] = '';
$query->query_vars['meta_key'] = 'wp-approve-user'; //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
$query->query_vars['meta_value'] = 'pending'; //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value

remove_filter( 'pre_user_query', array( $this, 'pre_user_query' ) );
$query->prepare_query();
}

if ( 'wpau_unapproved' === $role ) {
unset( $query->query_vars['meta_query'] );
$query->query_vars['role'] = '';
$query->query_vars['meta_key'] = 'wp-approve-user'; //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_key
$query->query_vars['meta_value'] = false; //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value
$query->query_vars['meta_value'] = 'unapproved'; //phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_value

remove_filter( 'pre_user_query', array( $this, 'pre_user_query' ) );
$query->prepare_query();
Expand All @@ -260,34 +305,38 @@ public function user_row_actions( $actions, $user_object ) {
$site_id = isset( $_REQUEST['id'] ) ? intval( $_REQUEST['id'] ) : 0;
$url = 'site-users-network' === get_current_screen()->id ? add_query_arg( array( 'id' => $site_id ), 'site-users.php' ) : 'users.php';

if ( get_user_meta( $user_object->ID, 'wp-approve-user', true ) ) {
$url = wp_nonce_url(
$status = get_user_meta( $user_object->ID, 'wp-approve-user', true );

if ( 'approved' !== $status ) {
$unapprove_url = wp_nonce_url(
add_query_arg(
array(
'action' => 'wpau_unapprove',
'action' => 'wpau_approve',
'user' => $user_object->ID,
'role' => $this->get_role(),
),
$url
),
'wpau-unapprove-users'
'wpau-approve-users'
);

$actions['wpau-unapprove'] = sprintf( '<a class="submitunapprove" href="%1$s">%2$s</a>', esc_url( $url ), esc_html__( 'Unapprove', 'wp-approve-user' ) );
$actions['wpau-approve'] = sprintf( '<a class="submitapprove" href="%1$s">%2$s</a>', esc_url( $unapprove_url ), esc_html__( 'Approve', 'wp-approve-user' ) );
}

} else {
$url = wp_nonce_url(
if ( 'unapproved' !== $status ) {
$approve_url = wp_nonce_url(
add_query_arg(
array(
'action' => 'wpau_approve',
'action' => 'wpau_unapprove',
'user' => $user_object->ID,
'role' => $this->get_role(),
),
$url
),
'wpau-approve-users'
'wpau-unapprove-users'
);

$actions['wpau-approve'] = sprintf( '<a class="submitapprove" href="%1$s">%2$s</a>', esc_url( $url ), esc_html__( 'Approve', 'wp-approve-user' ) );
$actions['wpau-unapprove'] = sprintf( '<a class="submitunapprove" href="%1$s">%2$s</a>', esc_url( $approve_url ), esc_html__( 'Unapprove', 'wp-approve-user' ) );
}
}

Expand Down Expand Up @@ -317,7 +366,7 @@ public function wp_authenticate_user( $userdata ) {
return $userdata;
}

if ( get_user_meta( $userdata->ID, 'wp-approve-user', true ) ) {
if ( 'approved' === get_user_meta( $userdata->ID, 'wp-approve-user', true ) ) {
return $userdata;
}

Expand All @@ -337,21 +386,26 @@ public function wp_authenticate_user( $userdata ) {
* @param int $id User ID.
*/
public function user_register( $id ) {
update_user_meta( $id, 'wp-approve-user', current_user_can( 'create_users' ) );
$status = current_user_can( 'create_users' ) ? 'approved' : 'pending';

update_user_meta( $id, 'wp-approve-user', $status );
update_user_meta( $id, 'wp-approve-user-new-registration', true );
}

/**
* Fires after a new user registration has been recorded.
*
* Prevents WordPress to send the new user notification email, if the user has to be approved first.
* Still notifies the admin about the new user registration.
*
* @author Konstantin Obenland
* @since 6 - 04.03.2019
* @access public
*
* @param int $user_id ID of the newly registered user.
*/
public function register_new_user( $user_id ) {
if ( ! get_user_meta( $user_id, 'wp-approve-user', true ) ) {
if ( 'pending' === get_user_meta( $user_id, 'wp-approve-user', true ) ) {
remove_action( 'register_new_user', 'wp_send_new_user_notifications' );
add_action( 'register_new_user', 'wp_new_user_notification' );
}
Expand All @@ -372,6 +426,8 @@ public function map_action2() {
}

// phpcs:enable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput

wp_add_inline_style( 'list-tables', '.wp-list-table.users tbody th, .wp-list-table.users tbody td { box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.1); } #the-list .submitapprove { color:#007017; } #the-list .submitunapprove { color:#996800; }' );
}

/**
Expand Down Expand Up @@ -524,12 +580,8 @@ public function admin_menu() {

foreach ( $menu as $key => $menu_item ) {
if ( array_search( 'users.php', $menu_item, true ) ) {

// No need for number formatting, count() always returns an integer.
$awaiting_mod = count( $this->unapproved_users );

// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$menu[ $key ][0] .= " <span class='update-plugins count-{$awaiting_mod}'><span class='plugin-count'>{$awaiting_mod}</span></span>";
$menu[ $key ][0] .= " <span class='update-plugins count-{$this->unapproved_count}'><span class='plugin-count'>{$this->unapproved_count}</span></span>";

break; // Bail on success.
}
Expand Down Expand Up @@ -774,9 +826,9 @@ public function wpau_approve( $user_id ) {
*/
public function delete_user( $user_id ) {
$is_new_registration = get_user_meta( $user_id, 'wp-approve-user-new-registration', true );
$is_approved = get_user_meta( $user_id, 'wp-approve-user', true );
$is_unapproved = 'unapproved' === get_user_meta( $user_id, 'wp-approve-user', true );

if ( $is_new_registration && ! $is_approved && $this->options['wpau-send-unapprove-email'] ) {
if ( $is_new_registration && $is_unapproved && $this->options['wpau-send-unapprove-email'] ) {
$user = new WP_User( $user_id );
$blogname = wp_specialchars_decode( get_option( 'blogname' ), ENT_QUOTES );

Expand Down Expand Up @@ -826,7 +878,7 @@ protected function approve() {
);
}

update_user_meta( $id, 'wp-approve-user', true );
update_user_meta( $id, 'wp-approve-user', 'approved' );

/**
* Fires after a user has been approved.
Expand Down Expand Up @@ -875,7 +927,7 @@ protected function unapprove() {
);
}

update_user_meta( $id, 'wp-approve-user', false );
update_user_meta( $id, 'wp-approve-user', 'unapproved' );
WP_Session_Tokens::get_instance( $id )->destroy_all();

/**
Expand Down Expand Up @@ -1036,7 +1088,7 @@ protected function set_up_role_context() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput

if ( empty( $_REQUEST['role'] ) && ! empty( $_REQUEST['_wp_http_referer'] ) ) {
$referrer = parse_url( $_REQUEST['_wp_http_referer'] ); // phpcs:ignore WordPress.WP.AlternativeFunctions.parse_url_parse_url
$referrer = wp_parse_url( $_REQUEST['_wp_http_referer'] );

if ( ! empty( $referrer['query'] ) ) {
$args = wp_parse_args( $referrer['query'] );
Expand Down Expand Up @@ -1064,6 +1116,7 @@ protected function set_up_role_context() {
protected function get_role() {
$roles = array_keys( get_editable_roles() );
$roles[] = 'wpau_unapproved';
$roles[] = 'wpau_pending';
$role = false;

if ( isset( $_REQUEST['role'] ) && in_array( $_REQUEST['role'], $roles, true ) ) {
Expand Down
1 change: 0 additions & 1 deletion css/settings-page.css
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,3 @@ label.image-radio-option input {
float: none !important;
}
}

38 changes: 31 additions & 7 deletions js/wp-approve-user.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,31 @@
jQuery(function($){
$('tr:has(.submitapprove)').css('background-color', '#FFFFE0');
$('.actions select[name^="action"]').append(
'<option value="wpau_bulk_approve">' + wp_approve_user.approve + '</option>' +
'<option value="wpau_bulk_unapprove">' + wp_approve_user.unapprove + '</option>'
);
});
document.addEventListener('DOMContentLoaded', function() {
// Select all table rows
document.querySelectorAll('tr').forEach(function(row) {
// Check if the row has an element with class 'submitapprove'
let hasSubmitApprove = row.querySelector('.submitapprove') !== null;
// Check if the row has an element with class 'submitunapprove'
let hasSubmitUnapprove = row.querySelector('.submitunapprove') !== null;

// If the row has both 'submitapprove' and 'submitunapprove' elements, change background color to '#FFFFE0'
if (hasSubmitApprove && hasSubmitUnapprove) {
row.style.backgroundColor = '#FFFFE0';
}
// If the row has only 'submitapprove' element, change background color to '#FAAFAA'
else if (hasSubmitApprove) {
row.style.backgroundColor = '#FAAFAA';
}
});

// Append options to the select elements with name starting with 'action' inside elements with class 'actions'
document.querySelectorAll('.actions select[name^="action"]').forEach(function(select) {
var optionApprove = document.createElement('option');
optionApprove.value = 'wpau_bulk_approve';
optionApprove.textContent = wp_approve_user.approve;
select.appendChild(optionApprove);

var optionUnapprove = document.createElement('option');
optionUnapprove.value = 'wpau_bulk_unapprove';
optionUnapprove.textContent = wp_approve_user.unapprove;
select.appendChild(optionUnapprove);
});
});
2 changes: 1 addition & 1 deletion js/wp-approve-user.min.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions readme.txt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ Yes! Under Settings > Approve User, you can choose when to send an email and cus

= 12 =
* Bumped minimum required WordPress version to 4.7.
* Switches to a three-state approval system: approved, unapproved, and pending.
* When a user is unapproved, they now get immediately logged out from all active sessions.
* Uses a cron job to auto-approve more than 100 users asynchronously after plugin activation.

Expand Down
12 changes: 6 additions & 6 deletions tests/test-user-meta.php
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public function test_user_register_admin_single_site() {

$class->user_register( $user_id );

$this->assertSame( '1', get_user_meta( $user_id, 'wp-approve-user', true ) );
$this->assertSame( 'approved', get_user_meta( $user_id, 'wp-approve-user', true ) );
$this->assertSame( '1', get_user_meta( $user_id, 'wp-approve-user-new-registration', true ) );
}

Expand All @@ -80,7 +80,7 @@ public function test_user_register_admin_multisite() {

$class->user_register( $user_id );

$this->assertEmpty( get_user_meta( $user_id, 'wp-approve-user', true ) );
$this->assertSame( 'pending', get_user_meta( $user_id, 'wp-approve-user', true ) );
$this->assertSame( '1', get_user_meta( $user_id, 'wp-approve-user-new-registration', true ) );
}

Expand All @@ -97,7 +97,7 @@ public function test_user_register_subscriber() {

$class->user_register( $user->ID );

$this->assertEmpty( get_user_meta( $user->ID, 'wp-approve-user', true ) );
$this->assertSame( 'pending', get_user_meta( $user->ID, 'wp-approve-user', true ) );
$this->assertSame( '1', get_user_meta( $user->ID, 'wp-approve-user-new-registration', true ) );
}

Expand Down Expand Up @@ -132,7 +132,7 @@ public function test_wp_authenticate_user_simple_site() {
$class = new Obenland_Wp_Approve_User();

// Returns WP_User for admins, even if they're unapproved.
update_user_meta( static::$admin->ID, 'wp-approve-user', false );
update_user_meta( static::$admin->ID, 'wp-approve-user', 'unapproved' );
$result = $class->wp_authenticate_user( static::$admin );
$this->assertSame( static::$admin, $result );
}
Expand All @@ -147,15 +147,15 @@ public function test_wp_authenticate_user_multisite() {
$class = new Obenland_Wp_Approve_User();

// Returns WP_Error for admins when they're unapproved.
update_user_meta( static::$admin->ID, 'wp-approve-user', false );
update_user_meta( static::$admin->ID, 'wp-approve-user', 'unapproved' );
$result = $class->wp_authenticate_user( static::$admin );
$this->assertWPError( $result );
$this->assertSame( 'wpau_confirmation_error', $result->get_error_code() );

// Returns WP_User for super admins, even if they're unapproved.
$user = static::factory()->user->create_and_get( array( 'role' => 'subscriber' ) );
grant_super_admin( $user->ID );
update_user_meta( $user->ID, 'wp-approve-user', false );
update_user_meta( $user->ID, 'wp-approve-user', 'unapproved' );

$result = $class->wp_authenticate_user( $user );
$this->assertSame( $user, $result );
Expand Down

0 comments on commit 767384f

Please sign in to comment.