
在 WordPress 中,您可以註冊多個作者,每個作者都有自己的 URL。問題是這個作者 URL 會顯示作者的使用者名稱,這就給您的 WordPress 網站帶來了安全風險。由於作者使用者名稱暴露在外,攻擊者可以利用它來嘗試登入或強行進入您的網站。
為了解決這個問題,我們可以用 UUID 這樣的隨機 ID 遮蔽作者 URL。這樣,作者 URL 就不會暴露作者的使用者名稱,而且會更加安全。
我們將研究兩種方法:硬辦法,我們自己編寫程式碼;簡易法,我們使用外掛。
話不多說,讓我們來看看它是如何工作的。
硬辦法(寫程式碼)
首先,在 /wp-content/plugin
目錄或 /wp-content/mu-plugins/
目錄下建立一個新的 PHP 檔案,例如 uuid-slug.php
,將其作為必須使用的外掛載入。該檔案將包含外掛標頭檔案…
* This file is read by WordPress to display the plugin's information in the admin area.
* Plugin Name: Author UUID Slug
* Plugin URI: https://github.com/hongkiat/wp-author-uuid-slug
* Description: Use UUID for the author URL.
* Author URI: https://github.com/tfirdaus
/**
* Plugin bootstrap file.
*
* This file is read by WordPress to display the plugin's information in the admin area.
*
* @wordpress-plugin
* Plugin Name: Author UUID Slug
* Plugin URI: https://github.com/hongkiat/wp-author-uuid-slug
* Description: Use UUID for the author URL.
* Version: 1.0.0
* Requires at least: 6.0
* Requires PHP: 7.4
* Author: Thoriq Firdaus
* Author URI: https://github.com/tfirdaus
*/
/**
* Plugin bootstrap file.
*
* This file is read by WordPress to display the plugin's information in the admin area.
*
* @wordpress-plugin
* Plugin Name: Author UUID Slug
* Plugin URI: https://github.com/hongkiat/wp-author-uuid-slug
* Description: Use UUID for the author URL.
* Version: 1.0.0
* Requires at least: 6.0
* Requires PHP: 7.4
* Author: Thoriq Firdaus
* Author URI: https://github.com/tfirdaus
*/
…以及實現基於 UUID 的作者 URL 所需的邏輯。在這種情況下,我們將在使用者配置檔案編輯器中提供一個簡單的輸入來新增 UUID。
add_action('show_user_profile', 'add_uuid_field_to_profile');
add_action('edit_user_profile', 'add_uuid_field_to_profile');
function add_uuid_field_to_profile($user)
$uuid = get_user_meta($user->ID, '_uuid', true);
<table class="form-table">
<th><label for="user_uuid"><?php esc_html_e('UUID', 'hongkiat'); ?></label></th>
value="<?php echo esc_attr($uuid); ?>"
<?php echo !current_user_can('manage_options') ? 'readonly' : ''; ?>
if (current_user_can('manage_options')) {
esc_html_e('Enter or update the UUID for this user.', 'hongkiat');
esc_html_e('This UUID is read-only for non-administrators.', 'hongkiat');
add_action('personal_options_update', 'save_uuid_field');
add_action('edit_user_profile_update', 'save_uuid_field');
function save_uuid_field($user_id)
if (!current_user_can('manage_options', $user_id)) {
$new_uuid = isset($_POST['user_uuid']) ? sanitize_text_field($_POST['user_uuid']) : '';
if (!empty($new_uuid) && is_uuid($new_uuid)) {
update_user_meta($user_id, '_uuid', $new_uuid);
delete_user_meta($user_id, '_uuid');
$pattern = '/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i'; // UUID pattern.
return (bool) preg_match($pattern, $value);
add_action('show_user_profile', 'add_uuid_field_to_profile');
add_action('edit_user_profile', 'add_uuid_field_to_profile');
function add_uuid_field_to_profile($user)
{
$uuid = get_user_meta($user->ID, '_uuid', true);
?>
<table class="form-table">
<tr>
<th><label for="user_uuid"><?php esc_html_e('UUID', 'hongkiat'); ?></label></th>
<td>
<input
type="text"
name="user_uuid"
id="user_uuid"
value="<?php echo esc_attr($uuid); ?>"
class="regular-text"
<?php echo !current_user_can('manage_options') ? 'readonly' : ''; ?>
/>
<p class="description">
<?php
if (current_user_can('manage_options')) {
esc_html_e('Enter or update the UUID for this user.', 'hongkiat');
} else {
esc_html_e('This UUID is read-only for non-administrators.', 'hongkiat');
}
?>
</p>
</td>
</tr>
</table>
<?php
}
add_action('personal_options_update', 'save_uuid_field');
add_action('edit_user_profile_update', 'save_uuid_field');
function save_uuid_field($user_id)
{
if (!current_user_can('manage_options', $user_id)) {
return false;
}
$new_uuid = isset($_POST['user_uuid']) ? sanitize_text_field($_POST['user_uuid']) : '';
if (!empty($new_uuid) && is_uuid($new_uuid)) {
update_user_meta($user_id, '_uuid', $new_uuid);
} else {
delete_user_meta($user_id, '_uuid');
}
}
function is_uuid($value)
{
$pattern = '/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i'; // UUID pattern.
return (bool) preg_match($pattern, $value);
}
add_action('show_user_profile', 'add_uuid_field_to_profile');
add_action('edit_user_profile', 'add_uuid_field_to_profile');
function add_uuid_field_to_profile($user)
{
$uuid = get_user_meta($user->ID, '_uuid', true);
?>
<table class="form-table">
<tr>
<th><label for="user_uuid"><?php esc_html_e('UUID', 'hongkiat'); ?></label></th>
<td>
<input
type="text"
name="user_uuid"
id="user_uuid"
value="<?php echo esc_attr($uuid); ?>"
class="regular-text"
<?php echo !current_user_can('manage_options') ? 'readonly' : ''; ?>
/>
<p class="description">
<?php
if (current_user_can('manage_options')) {
esc_html_e('Enter or update the UUID for this user.', 'hongkiat');
} else {
esc_html_e('This UUID is read-only for non-administrators.', 'hongkiat');
}
?>
</p>
</td>
</tr>
</table>
<?php
}
add_action('personal_options_update', 'save_uuid_field');
add_action('edit_user_profile_update', 'save_uuid_field');
function save_uuid_field($user_id)
{
if (!current_user_can('manage_options', $user_id)) {
return false;
}
$new_uuid = isset($_POST['user_uuid']) ? sanitize_text_field($_POST['user_uuid']) : '';
if (!empty($new_uuid) && is_uuid($new_uuid)) {
update_user_meta($user_id, '_uuid', $new_uuid);
} else {
delete_user_meta($user_id, '_uuid');
}
}
function is_uuid($value)
{
$pattern = '/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i'; // UUID pattern.
return (bool) preg_match($pattern, $value);
}
出於安全考慮,只有擁有 manage_options
許可權的使用者才能啟用和編輯此輸入,因此只有管理員才能為使用者新增或更新 UUID。沒有適當許可權的使用者只能看到只讀輸入。
更改作者頁面URL
接下來,我們需要修改作者頁面URL,使用 UUID 代替作者的使用者名稱。如下所示,我們可以透過執行 author_link
過濾器來實現這一點:
add_filter('author_link', 'change_author_url', 10, 3);
function change_author_url($link, $author_id, $author_nicename)
$uuid = get_user_meta($author_id, '_uuid', true);
return str_replace('/' . $authorSlug, '/' . $uuid, $link);
add_filter('author_link', 'change_author_url', 10, 3);
function change_author_url($link, $author_id, $author_nicename)
{
$uuid = get_user_meta($author_id, '_uuid', true);
if (is_string($uuid)) {
return str_replace('/' . $authorSlug, '/' . $uuid, $link);
}
return $link;
}
add_filter('author_link', 'change_author_url', 10, 3);
function change_author_url($link, $author_id, $author_nicename)
{
$uuid = get_user_meta($author_id, '_uuid', true);
if (is_string($uuid)) {
return str_replace('/' . $authorSlug, '/' . $uuid, $link);
}
return $link;
}
該功能將更新為作者生成的 URL,同時影響前端主題和管理介面。

處理作者歸檔的查詢
由於我們修改了作者歸檔 URL 的 URL 結構,因此還需要處理相應的查詢。如果不這樣做,WordPress 就會返回 404 Not Found錯誤,因為它無法識別如何透過作者的 _uuid
後設資料來查詢作者。
為了實現這一功能,我們可以使用 pre_get_posts
鉤子,如下所示:
add_action('pre_get_posts', 'author_uuid_query');
function author_uuid_query($query) {
* If the permalink structure is set to plain, the author should be queried
if ((bool) get_option('permalink_structure') === false) {
$author_name = $query->query_vars['author_name'] ?? '';
if (! is_string($author_name) || ! is_uuid($author_name)) {
$query->is_author = false;
$query->is_archive = false;
'meta_value' => $author_name,
if (count($users) <= 0) {
$query->is_author = false;
$query->is_archive = false;
if (! $user instanceof WP_User) {
$query->is_author = false;
$query->is_archive = false;
$query->set('author_name', $user->user_nicename);
add_action('pre_get_posts', 'author_uuid_query');
function author_uuid_query($query) {
/**
* If the permalink structure is set to plain, the author should be queried
* by the user ID.
*/
if ((bool) get_option('permalink_structure') === false) {
return;
}
$author_name = $query->query_vars['author_name'] ?? '';
if (! is_string($author_name) || ! is_uuid($author_name)) {
$query->is_404 = true;
$query->is_author = false;
$query->is_archive = false;
return;
}
$users = get_users([
'meta_key' => '_uuid',
'meta_value' => $author_name,
]);
if (count($users) <= 0) {
$query->is_404 = true;
$query->is_author = false;
$query->is_archive = false;
return;
}
$user = $users[0];
if (! $user instanceof WP_User) {
$query->is_404 = true;
$query->is_author = false;
$query->is_archive = false;
return;
}
$query->set('author_name', $user->user_nicename);
}
add_action('pre_get_posts', 'author_uuid_query');
function author_uuid_query($query) {
/**
* If the permalink structure is set to plain, the author should be queried
* by the user ID.
*/
if ((bool) get_option('permalink_structure') === false) {
return;
}
$author_name = $query->query_vars['author_name'] ?? '';
if (! is_string($author_name) || ! is_uuid($author_name)) {
$query->is_404 = true;
$query->is_author = false;
$query->is_archive = false;
return;
}
$users = get_users([
'meta_key' => '_uuid',
'meta_value' => $author_name,
]);
if (count($users) <= 0) {
$query->is_404 = true;
$query->is_author = false;
$query->is_archive = false;
return;
}
$user = $users[0];
if (! $user instanceof WP_User) {
$query->is_404 = true;
$query->is_author = false;
$query->is_archive = false;
return;
}
$query->set('author_name', $user->user_nicename);
}
上面的程式碼會驗證固定連結結構是否設定為預設的“Plain”設定以外的其他設定。我們不處理“Plain”連結結構的查詢,因為在這種情況下,WordPress 使用的是作者 ID ( ?author=<id>
) 而不是 author_name
。
在REST API中更改作者標籤
使用者的使用者名稱也在 /wp-json/wp/v2/users
REST API 端點中公開。為提高安全性,我們將用 UUID 替換使用者名稱,從而對其進行修改。如下所示,我們可以透過實施 rest_prepare_user
鉤子來實現這一點:
add_filter('rest_prepare_user', 'change_user_slug_in_rest_api', 10, 2);
function change_user_slug_in_rest_api($response, $user)
$data = $response->get_data();
$uuid = get_user_meta($author_id, '_uuid', true);
$response->set_data($data);
add_filter('rest_prepare_user', 'change_user_slug_in_rest_api', 10, 2);
function change_user_slug_in_rest_api($response, $user)
{
$data = $response->get_data();
if (is_array($data)) {
$uuid = get_user_meta($author_id, '_uuid', true);
if (is_string($uuid)) {
$data['slug'] = $uuid;
}
}
$response->set_data($data);
return $response;
}
add_filter('rest_prepare_user', 'change_user_slug_in_rest_api', 10, 2);
function change_user_slug_in_rest_api($response, $user)
{
$data = $response->get_data();
if (is_array($data)) {
$uuid = get_user_meta($author_id, '_uuid', true);
if (is_string($uuid)) {
$data['slug'] = $uuid;
}
}
$response->set_data($data);
return $response;
}
有了這種實現方式,作者 URL 現在將使用 UUID 而不是使用者名稱。任何使用原始使用者名稱訪問作者 URL 的嘗試都會導致 404 未找到錯誤。
雖然這種解決方案對小型網站或使用者數量有限的網站很有效,但在處理大量使用者時,管理起來就會變得很麻煩。在這種情況下,為每個使用者手動設定 UUID 既費時又不切實際。
因此,讓我們來探討一種可提供更精簡解決方案的替代方法。
簡易法(安裝外掛)
為了獲得更簡單的解決方案,我們將使用一個名為 Feature Flipper 的外掛。該外掛提供多種安全功能,包括使用 UUID 混淆使用者名稱。
你可以直接從 WordPress 儀表板的外掛部分安裝該外掛。安裝並啟用後,導航至 “設定”>“Feature”>“Security”,然後啟用“Obfuscate Usernames”選項。

儲存設定後,外掛將自動為網站上的所有現有使用者生成 UUID。此外,它還會在新使用者註冊時為其分配 UUID。
小結
為作者頁面 URL 實施 UUID 是一種有效的安全措施,可以透過隱藏作者使用者名稱來保護 WordPress 網站。這種方法大大降低了暴力攻擊和未經授權訪問嘗試的風險。
在本教程中,我們探討了兩種實施方法。對於喜歡自定義解決方案的使用者,可以檢視本次教程涉及的完整的原始碼(GitHub 程式碼庫) 。另外,Feature Flipper 外掛為尋求現成解決方案的使用者提供了一種更直接的方法。
評論留言