'support-access',
'menu_label' => __( 'Support Access', $this->textdomain ),
'parent_slug' => 'users.php',
'textdomain' => 'support-access',
'defaults' => array(),
)
);
$this->menu_slug = $args['menu_slug'];
$this->menu_label = $args['menu_label'];
$this->parent_slug = $args['parent_slug'];
$this->textdomain = $args['textdomain'];
// Set default settings with fallbacks
$this->default_settings = wp_parse_args(
$args['defaults'],
array(
'duration' => 1,
'duration_unit' => 'weeks',
'usage_limit' => '',
'role' => 'administrator',
'locale' => '',
)
);
// Schedule cron job on plugin activation.
register_activation_hook( __FILE__, array( $this, 'schedule_access_expiration_check' ) );
// Clear the scheduled cron job on plugin deactivation.
register_deactivation_hook( __FILE__, array( $this, 'clear_access_expiration_check' ) );
// Schedule the cron event to check for expired admins.
add_action( 'check_access_expiration_event', array( $this, 'check_access_expiration' ) );
// Handle temp admin login by checking the URL parameters.
add_action( 'init', array( $this, 'check_access_login' ) );
// Add admin menu page.
add_action( 'admin_menu', array( $this, 'add_support_access_menu' ) );
// Handle form submission to create temp admin users.
add_action( 'admin_post_create_access_user', array( $this, 'handle_access_form_submission' ) );
// Handle deletion of temporary admins.
add_action( 'admin_post_delete_access_user', array( $this, 'handle_access_deletion' ) );
// Handle generating new access URLs.
add_action( 'admin_init', array( $this, 'handle_url_generation' ) );
}
/**
* Prevent cloning of the instance
*/
protected function __clone() {}
/**
* Prevent unserializing of the instance
*/
public function __wakeup() {
throw new \Exception( 'Cannot unserialize singleton' );
}
/**
* Schedule the cron job when the plugin is activated.
*/
public function schedule_access_expiration_check() {
if ( ! wp_next_scheduled( 'check_access_expiration_event' ) ) {
wp_schedule_event( time(), 'hourly', 'check_access_expiration_event' );
}
}
/**
* Clear the scheduled cron job on plugin deactivation.
*/
public function clear_access_expiration_check() {
$timestamp = wp_next_scheduled( 'check_access_expiration_event' );
if ( $timestamp ) {
wp_unschedule_event( $timestamp, 'check_access_expiration_event' );
}
}
/**
* Check for expired admins.
*/
public function check_access_expiration() {
$args = array(
'meta_key' => 'support_access_token',
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'support_access_expiration',
'compare' => 'EXISTS',
),
),
);
$user_query = new WP_User_Query( $args );
if ( ! empty( $user_query->results ) ) {
foreach ( $user_query->results as $user ) {
$expiration_time = get_user_meta( $user->ID, 'support_access_expiration', true );
if ( $expiration_time && time() > $expiration_time ) {
wp_delete_user( $user->ID );
}
}
}
}
/**
* Add a menu item to the specified parent menu (default: Users).
*/
public function add_support_access_menu() {
add_submenu_page(
$this->parent_slug, // Parent menu slug.
$this->menu_label, // Page title.
$this->menu_label, // Menu title.
'manage_options', // Capability.
$this->menu_slug, // Menu slug.
array( $this, 'support_access_page' ) // Callback function for the page content.
);
}
/**
* Admin page content for Support Access.
*/
public function support_access_page() {
?>
textdomain ); ?>
$user_id . '|' . $token,
),
home_url()
);
}
?>
%s
%s
%s
',
esc_html__( 'Support user access created successfully', $this->textdomain ),
$access_url ? sprintf(
'%s: %s
',
esc_html__( 'Access URL', $this->textdomain ),
esc_url( $access_url ),
esc_js( $access_url ),
esc_html__( 'Copy URL', $this->textdomain )
) : '',
esc_html__( 'Important: Copy this URL now. For security reasons it cannot be displayed again.', $this->textdomain )
);
}
?>
list_access_users(); ?>
create_access_user( $role );
// Store user metadata.
update_user_meta( $result['user_id'], 'support_access_login_count', 0 );
update_user_meta( $result['user_id'], 'support_access_expiration', $expiration_time );
update_user_meta( $result['user_id'], 'support_access_limit', $limit );
if ( ! empty( $locale ) ) {
update_user_meta( $result['user_id'], 'locale', $locale );
}
// Redirect with success message and access token.
wp_redirect(
add_query_arg(
array(
'page' => 'support-access',
'message' => 'success',
'user_id' => $result['user_id'],
'token' => $result['access_token'],
),
admin_url( 'users.php' )
)
);
exit;
}
/**
* Create a temporary admin user.
*
* @param string $role The role to assign to the user.
* @return array Array containing user ID and access token.
*/
private function create_access_user( $role = 'administrator' ) {
$username = 'support_user_' . uniqid();
$password = wp_generate_password();
$email = $username . '@example.com';
$user_id = wp_create_user( $username, $password, $email );
$user = new WP_User( $user_id );
$user->set_role( $role );
// Generate random token and store its hash for verification
$access_token = wp_generate_password( 32, false );
$token_hash = hash( 'sha256', $access_token );
update_user_meta( $user_id, 'support_access_token_hash', $token_hash );
return array(
'user_id' => $user_id,
'access_token' => $access_token,
);
}
/**
* Check if the access token is valid and log in the user.
*/
public function check_access_login() {
if ( ! isset( $_GET['support_access'] ) ) {
return;
}
$parts = explode( '|', sanitize_text_field( wp_unslash( $_GET['support_access'] ) ) );
if ( count( $parts ) !== 2 ) {
wp_safe_redirect( home_url() );
exit;
}
list( $user_id, $received_token ) = $parts;
$user_id = absint( $user_id );
// Get stored hash.
$stored_hash = get_user_meta( $user_id, 'support_access_token_hash', true );
if ( empty( $stored_hash ) ) {
wp_safe_redirect( home_url() );
exit;
}
// Verify token.
if ( ! hash_equals( $stored_hash, hash( 'sha256', $received_token ) ) ) {
wp_safe_redirect( home_url() );
exit;
}
// Check expiration and limits.
$expiration = get_user_meta( $user_id, 'support_access_expiration', true );
$limit = get_user_meta( $user_id, 'support_access_limit', true );
$login_count = get_user_meta( $user_id, 'support_access_login_count', true );
if ( time() > $expiration ) {
wp_delete_user( $user_id );
wp_safe_redirect( home_url() );
exit;
}
if ( $limit > 0 && $login_count >= $limit ) {
wp_safe_redirect( home_url() );
exit;
}
// Log the user in.
wp_set_current_user( $user_id );
wp_set_auth_cookie( $user_id );
update_user_meta( $user_id, 'support_access_login_count', intval( $login_count ) + 1 );
wp_safe_redirect( admin_url() );
exit;
}
/**
* List temporary admins with login count, expiration date, and delete option.
*/
private function list_access_users() {
$args = array(
'meta_query' => array(
'relation' => 'AND',
array(
'key' => 'support_access_token_hash',
'compare' => 'EXISTS',
),
array(
'key' => 'support_access_expiration',
'compare' => 'EXISTS',
),
),
);
$user_query = new WP_User_Query( $args );
if ( ! empty( $user_query->results ) ) {
echo '' . esc_html__( 'Temporary Users', $this->textdomain ) . '
';
echo '';
echo '';
echo '';
echo '' . esc_html__( 'Username', $this->textdomain ) . ' | ';
echo '' . esc_html__( 'Role', $this->textdomain ) . ' | ';
echo '' . esc_html__( 'Login Count', $this->textdomain ) . ' | ';
echo '' . esc_html__( 'Expiration Date', $this->textdomain ) . ' | ';
echo '' . esc_html__( 'Access URL', $this->textdomain ) . ' | ';
echo '' . esc_html__( 'Actions', $this->textdomain ) . ' | ';
echo '
';
echo '';
echo '';
foreach ( $user_query->results as $user ) {
$login_count = get_user_meta( $user->ID, 'support_access_login_count', true );
$user_profile_url = get_edit_user_link( $user->ID );
$expiration_time = get_user_meta( $user->ID, 'support_access_expiration', true );
$expiration_date = $expiration_time ?
wp_date( get_option( 'date_format' ) . ' ' . get_option( 'time_format' ), $expiration_time ) : '';
$limit = get_user_meta( $user->ID, 'support_access_limit', true );
$login_info = ( empty( $limit ) || '0' === $limit ) ? $login_count . ' / ∞' : $login_count . ' / ' . $limit;
// Get user's role
$user_roles = array_map(
function( $role ) {
return translate_user_role( wp_roles()->get_names()[ $role ] );
},
$user->roles
);
?>
user_login ); ?> |
|
|
|
textdomain ); ?>
|
|
';
echo '
';
}
}
/**
* Handle temporary admin deletion.
*/
public function handle_access_deletion() {
if ( isset( $_POST['delete_access_user_id'] ) && current_user_can( 'manage_options' ) ) {
$user_id = absint( $_POST['delete_access_user_id'] );
if ( wp_verify_nonce( $_POST['_wpnonce'], 'delete_access_user_' . $user_id ) ) {
wp_delete_user( $user_id );
// Store deletion message in transient.
set_transient(
'support_access_message_' . get_current_user_id(),
array(
'type' => 'success',
'message' => __( 'Support access user deleted successfully.', $this->textdomain ),
),
30
);
wp_redirect( admin_url( 'users.php?page=support-access' ) );
exit;
}
}
}
/**
* Handle generating new access URL.
*/
public function handle_url_generation() {
if ( ! isset( $_GET['action'], $_GET['user_id'] ) || 'generate_access_url' !== $_GET['action'] ) {
return;
}
if ( ! current_user_can( 'manage_options' ) ) {
return;
}
$user_id = absint( $_GET['user_id'] );
if ( ! wp_verify_nonce( $_GET['_wpnonce'], 'generate_access_url_' . $user_id ) ) {
wp_die( 'Invalid nonce' );
}
// Generate new token and hash
$access_token = wp_generate_password( 32, false );
$token_hash = hash( 'sha256', $access_token );
update_user_meta( $user_id, 'support_access_token_hash', $token_hash );
// Redirect with success message and access token
wp_redirect(
add_query_arg(
array(
'page' => 'support-access',
'message' => 'success',
'user_id' => $user_id,
'token' => $access_token,
),
admin_url( 'users.php' )
)
);
exit;
}
}
}