2026年8月8日

2026年8月8日

WordPressのユーザープロフィールにカスタムフィールドを追加する方法

はじめに

WordPressのユーザープロフィールは標準フィールドだけでは不十分なことが多く、プロフィール写真のURL、SNSアカウント、所属部署などの情報を追加したいケースが頻繁にあります。show_user_profileedit_user_profileアクションを使えば、管理画面のプロフィールページに独自フィールドを安全に追加・保存できます。

症状・原因

  • ユーザープロフィールに所属・肩書きなどの独自情報を追加できない
  • SNSのプロフィールリンクをデフォルトの「ウェブサイト」欄以外に追加したい
  • フロントエンドのプロフィールページでカスタム情報を表示したい
  • ユーザーごとに独自のアバター画像URLを設定させたい
  • user_contactmethodsが何なのか分からずSNSリンクの追加方法が不明

解決手順

ステップ1:show_user_profile/edit_user_profileでフィールドを追加

<?php
/**
 * 管理画面のプロフィールページにカスタムフィールドを追加
 *
 * show_user_profile:自分のプロフィール編集時
 * edit_user_profile:管理者が他ユーザーを編集する時
 * 両方にフックすることで全ケースに対応
 */
function add_custom_user_profile_fields( $user ) {
    // カスタムフィールドの値を取得
    $company    = get_user_meta( $user->ID, 'company', true );
    $department = get_user_meta( $user->ID, 'department', true );
    $position   = get_user_meta( $user->ID, 'position', true );
    $phone      = get_user_meta( $user->ID, 'phone', true );
    $bio_short  = get_user_meta( $user->ID, 'bio_short', true );
    ?>

    <!-- nonceフィールドでセキュリティ確保 -->
    <?php wp_nonce_field( 'save_custom_user_profile', 'custom_profile_nonce' ); ?>

    <h2>追加プロフィール情報</h2>

    <table class="form-table" role="presentation">

        <tr>
            <th scope="row">
                <label for="company">会社・組織名</label>
            </th>
            <td>
                <input type="text" name="company" id="company"
                    value="<?php echo esc_attr( $company ); ?>"
                    class="regular-text" />
            </td>
        </tr>

        <tr>
            <th scope="row">
                <label for="department">部署名</label>
            </th>
            <td>
                <input type="text" name="department" id="department"
                    value="<?php echo esc_attr( $department ); ?>"
                    class="regular-text" />
            </td>
        </tr>

        <tr>
            <th scope="row">
                <label for="position">役職・肩書き</label>
            </th>
            <td>
                <input type="text" name="position" id="position"
                    value="<?php echo esc_attr( $position ); ?>"
                    class="regular-text" />
            </td>
        </tr>

        <tr>
            <th scope="row">
                <label for="phone">電話番号</label>
            </th>
            <td>
                <input type="tel" name="phone" id="phone"
                    value="<?php echo esc_attr( $phone ); ?>"
                    class="regular-text" />
                <p class="description">公開されません。管理者のみ閲覧可能です。</p>
            </td>
        </tr>

        <tr>
            <th scope="row">
                <label for="bio_short">一言自己紹介</label>
            </th>
            <td>
                <textarea name="bio_short" id="bio_short" rows="3"
                    class="large-text"><?php echo esc_textarea( $bio_short ); ?></textarea>
                <p class="description">120文字以内で入力してください。</p>
            </td>
        </tr>

    </table>
    <?php
}
// 自分のプロフィール + 他ユーザーのプロフィール両方にフック
add_action( 'show_user_profile', 'add_custom_user_profile_fields' );
add_action( 'edit_user_profile', 'add_custom_user_profile_fields' );
?>

ステップ2:personal_options_update/edit_user_profile_updateで保存処理

<?php
/**
 * カスタムプロフィールフィールドの保存処理
 *
 * personal_options_update:自分のプロフィール更新時
 * edit_user_profile_update:管理者が他ユーザーを更新する時
 */
function save_custom_user_profile_fields( $user_id ) {
    // nonceの検証(セキュリティチェック)
    if ( ! isset( $_POST['custom_profile_nonce'] ) ||
         ! wp_verify_nonce( $_POST['custom_profile_nonce'], 'save_custom_user_profile' ) ) {
        return;
    }

    // 権限チェック:自分のプロフィールか管理者のみ保存可能
    if ( ! current_user_can( 'edit_user', $user_id ) ) {
        return;
    }

    // 保存するフィールドのリスト(サニタイズ方法も定義)
    $fields_to_save = array(
        'company'    => 'sanitize_text_field',
        'department' => 'sanitize_text_field',
        'position'   => 'sanitize_text_field',
        'phone'      => 'sanitize_text_field',
        'bio_short'  => 'sanitize_textarea_field',
    );

    foreach ( $fields_to_save as $field_key => $sanitize_function ) {
        if ( isset( $_POST[ $field_key ] ) ) {
            // サニタイズしてからuser_metaに保存
            $value = call_user_func( $sanitize_function, $_POST[ $field_key ] );

            // bio_shortは文字数制限
            if ( 'bio_short' === $field_key && mb_strlen( $value ) > 120 ) {
                $value = mb_substr( $value, 0, 120 );
            }

            update_user_meta( $user_id, $field_key, $value );
        }
    }

    // 保存成功の管理画面通知
    add_filter( 'user_profile_update_errors', function( $errors ) {
        // エラーがない場合のみ成功メッセージを追加
        if ( ! $errors->get_error_codes() ) {
            // 成功通知はWordPressがデフォルトで表示する
        }
    } );
}
add_action( 'personal_options_update',    'save_custom_user_profile_fields' );
add_action( 'edit_user_profile_update',   'save_custom_user_profile_fields' );
?>

ステップ3:フロントエンドテンプレートでuser_metaを表示

<?php
/**
 * フロントエンドのプロフィールページでカスタムフィールドを表示
 * author.php や page-profile.php で使用
 */
function render_user_profile( $user_id = null ) {
    // user_idが指定されない場合は現在のアーカイブユーザーを使用
    if ( null === $user_id ) {
        $user = get_queried_object();
        $user_id = $user->ID ?? 0;
    }

    if ( ! $user_id ) return;

    // ユーザー情報を取得
    $user       = get_userdata( $user_id );
    $company    = get_user_meta( $user_id, 'company',    true );
    $department = get_user_meta( $user_id, 'department', true );
    $position   = get_user_meta( $user_id, 'position',  true );
    $bio_short  = get_user_meta( $user_id, 'bio_short',  true );

    // SNSリンク(ステップ5で追加したフィールド)
    $twitter   = get_user_meta( $user_id, 'twitter',   true );
    $linkedin  = get_user_meta( $user_id, 'linkedin',  true );

    ?>
    <div class="author-profile">

        <!-- アバター(カスタムURLまたはGravatar) -->
        <div class="author-avatar">
            <?php echo get_avatar( $user_id, 120, '', '', array( 'class' => 'author-photo' ) ); ?>
        </div>

        <!-- 著者情報 -->
        <div class="author-info">
            <h1 class="author-name"><?php echo esc_html( $user->display_name ); ?></h1>

            <?php if ( $position || $company ) : ?>
                <p class="author-title">
                    <?php echo esc_html( $position ); ?>
                    <?php if ( $position && $company ) echo ' / '; ?>
                    <?php echo esc_html( $company ); ?>
                    <?php if ( $department ) echo ' ' . esc_html( $department ); ?>
                </p>
            <?php endif; ?>

            <?php if ( $bio_short ) : ?>
                <p class="author-bio-short"><?php echo esc_html( $bio_short ); ?></p>
            <?php endif; ?>

            <?php if ( $user->user_description ) : ?>
                <div class="author-bio"><?php echo wpautop( esc_html( $user->user_description ) ); ?></div>
            <?php endif; ?>

            <!-- SNSリンク -->
            <div class="author-social">
                <?php if ( $twitter ) : ?>
                    <a href="https://twitter.com/<?php echo esc_attr( ltrim( $twitter, '@' ) ); ?>"
                        class="social-link twitter" target="_blank" rel="noopener noreferrer">
                        Twitter
                    </a>
                <?php endif; ?>
                <?php if ( $linkedin ) : ?>
                    <a href="<?php echo esc_url( $linkedin ); ?>"
                        class="social-link linkedin" target="_blank" rel="noopener noreferrer">
                        LinkedIn
                    </a>
                <?php endif; ?>
            </div>
        </div>

    </div>
    <?php
}
?>

ステップ4:get_avatar_urlフィルターでカスタムアバターURLを設定

<?php
/**
 * カスタムアバターURL機能の実装
 * ユーザーが自分のアバター画像URLを設定できるようにする
 */

// --- プロフィール画面にアバターURLフィールドを追加 ---
function add_avatar_url_field( $user ) {
    $avatar_url = get_user_meta( $user->ID, 'custom_avatar_url', true );
    ?>
    <h2>カスタムアバター</h2>
    <table class="form-table">
        <tr>
            <th><label for="custom_avatar_url">アバター画像URL</label></th>
            <td>
                <input type="url" name="custom_avatar_url" id="custom_avatar_url"
                    value="<?php echo esc_url( $avatar_url ); ?>"
                    class="regular-text" />
                <p class="description">
                    GravatarのかわりにカスタムURLの画像をアバターとして使用します。<br>
                    推奨サイズ:200×200px以上の正方形画像
                </p>
                <?php if ( $avatar_url ) : ?>
                    <div class="avatar-preview">
                        <img src="<?php echo esc_url( $avatar_url ); ?>"
                            alt="アバタープレビュー" width="80" height="80"
                            style="border-radius:50%;margin-top:8px;" />
                    </div>
                <?php endif; ?>
            </td>
        </tr>
    </table>
    <?php
}
add_action( 'show_user_profile', 'add_avatar_url_field' );
add_action( 'edit_user_profile', 'add_avatar_url_field' );

// --- アバターURL保存処理 ---
function save_avatar_url( $user_id ) {
    if ( ! current_user_can( 'edit_user', $user_id ) ) return;

    if ( isset( $_POST['custom_avatar_url'] ) ) {
        $url = esc_url_raw( $_POST['custom_avatar_url'] );
        // URLが画像ファイルかどうかを簡易チェック
        if ( empty( $url ) || preg_match( '/\.(jpg|jpeg|png|gif|webp)(\?.*)?$/i', $url ) ) {
            update_user_meta( $user_id, 'custom_avatar_url', $url );
        }
    }
}
add_action( 'personal_options_update',  'save_avatar_url' );
add_action( 'edit_user_profile_update', 'save_avatar_url' );

// --- get_avatar_urlフィルターでカスタムURLを優先使用 ---
function use_custom_avatar_url( $url, $id_or_email, $args ) {
    $user_id = 0;

    // $id_or_email からユーザーIDを取得
    if ( is_numeric( $id_or_email ) ) {
        $user_id = (int) $id_or_email;
    } elseif ( is_string( $id_or_email ) ) {
        $user = get_user_by( 'email', $id_or_email );
        if ( $user ) $user_id = $user->ID;
    } elseif ( $id_or_email instanceof WP_User ) {
        $user_id = $id_or_email->ID;
    }

    if ( $user_id > 0 ) {
        $custom_url = get_user_meta( $user_id, 'custom_avatar_url', true );
        if ( ! empty( $custom_url ) ) {
            return $custom_url; // カスタムURLをGravatarの代わりに使用
        }
    }

    return $url; // カスタムURLがなければデフォルトのGravatarを使用
}
add_filter( 'get_avatar_url', 'use_custom_avatar_url', 10, 3 );
?>

ステップ5:user_contactmethodsフィルターでSNSリンクを追加

<?php
/**
 * ユーザープロフィールのコンタクト方法にSNSリンクを追加
 * user_contactmethods フィルターで管理
 *
 * デフォルトではWordPressはコンタクトフィールドを持たない(旧バージョンはMySpaceなど)
 */
function add_social_media_contacts( $methods ) {
    // 不要なデフォルトフィールドを削除(任意)
    unset( $methods['aim'] );     // 旧AOL Instant Messenger
    unset( $methods['jabber'] );  // 旧Jabber
    unset( $methods['yim'] );     // 旧Yahoo Messenger

    // SNSリンクを追加
    $methods['twitter']   = 'Twitter / X ユーザー名(@なし)';
    $methods['facebook']  = 'Facebook プロフィールURL';
    $methods['instagram'] = 'Instagram ユーザー名';
    $methods['linkedin']  = 'LinkedIn プロフィールURL';
    $methods['youtube']   = 'YouTube チャンネルURL';
    $methods['github']    = 'GitHub ユーザー名';

    return $methods;
}
add_filter( 'user_contactmethods', 'add_social_media_contacts' );

/**
 * フロントエンドでSNSリンクを表示するヘルパー関数
 * author.php から呼び出し
 */
function get_user_social_links( $user_id ) {
    $social_links = array();

    // user_contactmethods で登録したキーでメタを取得
    $twitter   = get_the_author_meta( 'twitter',   $user_id );
    $facebook  = get_the_author_meta( 'facebook',  $user_id );
    $instagram = get_the_author_meta( 'instagram', $user_id );
    $linkedin  = get_the_author_meta( 'linkedin',  $user_id );
    $github    = get_the_author_meta( 'github',    $user_id );

    // URLを整形
    if ( $twitter )   $social_links['twitter']   = 'https://twitter.com/' . ltrim( $twitter, '@' );
    if ( $facebook )  $social_links['facebook']  = esc_url( $facebook );
    if ( $instagram ) $social_links['instagram'] = 'https://instagram.com/' . ltrim( $instagram, '@' );
    if ( $linkedin )  $social_links['linkedin']  = esc_url( $linkedin );
    if ( $github )    $social_links['github']    = 'https://github.com/' . ltrim( $github, '@' );

    return $social_links;
}
?>

注意事項

  • nonce検証: プロフィールフィールドの保存にはwp_nonce_field()wp_verify_nonce()を必ず組み合わせてCSRF攻撃を防止してください
  • 権限チェック: current_user_can( 'edit_user', $user_id )で権限を確認してから保存処理を実行してください
  • サニタイズ: テキストフィールドはsanitize_text_field()、URLはesc_url_raw()、テキストエリアはsanitize_textarea_field()でそれぞれサニタイズしてください
  • get_the_author_meta: user_contactmethodsで追加したフィールドはget_the_author_meta()でも取得できます

まとめ

show_user_profile/edit_user_profileでフィールドを表示、personal_options_update/edit_user_profile_updateで保存、get_avatar_urlフィルターでカスタムアバター、user_contactmethodsでSNSリンクを追加することで、WordPressのユーザープロフィールを大幅に拡張できます。関連記事:WordPressのユーザー登録フォームをカスタマイズしてセキュリティを強化する方法

お気軽にご相談ください

お見積りへ お問い合わせへ