Добавим кнопку удалить аккаунт в личном кабинете пользователя

add_shortcode('delete_account_button', function() {
if (!is_user_logged_in()) {
return '';
}
$user_id = get_current_user_id();
$deletion_attempts_key = 'deletion_attempts_' . $user_id;
$deletion_attempts = get_transient($deletion_attempts_key);
$error_msg = '';
if ($deletion_attempts && $deletion_attempts >= 3) {
$error_msg = 'Превышен лимит попыток удаления аккаунта. Пожалуйста, подождите 15 минут.';
}
if (isset($_POST['delete_my_account']) && !$error_msg) {
if (!isset($_POST['delete_my_account_nonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_POST['delete_my_account_nonce'])), 'delete_my_account_action')) {
set_transient($deletion_attempts_key, ($deletion_attempts ? $deletion_attempts + 1 : 1), 15 * MINUTE_IN_SECONDS);
wp_die('Ошибка безопасности. Пожалуйста, попробуйте еще раз.', 'Ошибка безопасности', [
'response' => 403,
'back_link' => true,
]);
}
if (!isset($_POST['current_password'])) {
$error_msg = 'Необходимо ввести текущий пароль для подтверждения удаления аккаунта.';
} else {
$user = get_user_by('id', $user_id);
if (!$user || !wp_check_password(sanitize_text_field($_POST['current_password']), $user->data->user_pass, $user_id)) {
set_transient($deletion_attempts_key, ($deletion_attempts ? $deletion_attempts + 1 : 1), 15 * MINUTE_IN_SECONDS);
$error_msg = 'Неверный пароль';
} elseif ((int)$user_id !== get_current_user_id()) {
// Пользователь может удалять только себя
$error_msg = 'У вас нет прав для удаления этого аккаунта';
} else {
error_log('User ID ' . $user_id . ' requested account deletion from IP: ' . $_SERVER['REMOTE_ADDR']);
do_action('before_delete_user_account', $user_id);
require_once(ABSPATH.'wp-admin/includes/user.php');
$deleted = wp_delete_user($user_id);
if ($deleted) {
wp_clear_auth_cookie();
wp_set_current_user(0);
wp_safe_redirect(home_url());
exit;
} else {
$error_msg = 'Произошла ошибка при удалении аккаунта. Пожалуйста, обратитесь к администратору.';
}
}
}
}
ob_start();
?>
<div class="delete-account-container">
<form method="post" onsubmit="return confirm('Вы действительно хотите удалить свой аккаунт?');">
<?php wp_nonce_field('delete_my_account_action', 'delete_my_account_nonce'); ?>
<input type="hidden" name="action" value="delete_account">
<div class="form-field">
<label for="current_password">Текущий пароль:</label>
<input type="password" name="current_password" id="current_password" required>
</div>
<?php wp_referer_field(); ?>
<button type="submit" name="delete_my_account" class="delete-account-btn">
Удалить аккаунт
</button>
</form>
<?php if (!empty($error_msg)): ?>
<div class="errors-message"><?php echo esc_html($error_msg); ?></div>
<?php endif; ?>
</div>
<?php
return ob_get_clean();
});
add_action('template_redirect', function() {
if (!is_user_logged_in()) {
return;
}
global $post;
if (!$post || !has_shortcode($post->post_content, 'delete_account_button')) {
return;
}
$ip = $_SERVER['REMOTE_ADDR'];
$visit_key = 'delete_page_visits_' . md5($ip);
$visits = get_transient($visit_key);
if (!$visits) {
set_transient($visit_key, 1, HOUR_IN_SECONDS);
} else if ($visits > 10) {
wp_die('Доступ временно ограничен из соображений безопасности. Пожалуйста, повторите попытку позже.', 'Доступ ограничен', [
'response' => 429,
'back_link' => true,
]);
} else {
set_transient($visit_key, $visits + 1, HOUR_IN_SECONDS);
}
});Если у вас пользователи могут загружать аватары, то удалим и картинку аватара из медиатеки WordPress. Поменяйте метаполе аватара (user_avatar) на своё!
add_action('before_delete_user_account', function($user_id) {
$avatar_id = get_user_meta($user_id, 'user_avatar', true);
if ($avatar_id && is_numeric($avatar_id)) {
wp_delete_attachment(absint($avatar_id), true);
delete_user_meta($user_id, 'user_avatar');
}
$sessions = WP_Session_Tokens::get_instance($user_id);
$sessions->destroy_all();
error_log('User account deleted: User ID ' . $user_id . ', Date: ' . current_time('mysql') . ', IP: ' . $_SERVER['REMOTE_ADDR']);
});Добавьте шорткод в личный кабинет пользователя [delete_account_button]
Немного стилизуем:
selector .delete-account-btn{background:transparent;color:#e4939f;text-decoration:underline;padding:4px 4px;font-size:13px;}
selector .form-field label{margin-bottom:10px; color:#F6F3EF;font-weight:bold;font-size:14px;}
#current_password{border-radius:10px;border:2px solid #d1d1d1;width:210px;background:#4d4d4d;}
.errors-message {color:#f5b4b5;margin-top:10px;font-size:14px;}