You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WooCommerce账户自定义DOB字段仅允许客户编辑一次求助

解决WooCommerce用户仅能编辑出生日期一次的问题

我帮你调整了代码,实现了前端客户只能设置一次出生日期,管理员后台可随意编辑的需求,同时修复了日期格式设置和生日折扣的逻辑漏洞(原代码不管用户是否生日都会给折扣)。

核心思路

  • 前端账户详情页:检查用户是否已保存过生日日期,若已存在则将字段设为只读状态(用户能看到但无法修改);若未设置则显示可编辑字段。
  • 后台管理员:保持原功能不受限制,可随时修改用户出生日期。
  • 修正日期格式为YYYY-MM-DD,并完善生日折扣判断逻辑(仅在用户生日当天发放折扣)。

完整修改后的代码

// 前端账户详情页显示出生日期字段(限制仅能编辑一次)
add_action( 'woocommerce_edit_account_form', 'dob_on_myaccount_form' );
function dob_on_myaccount_form() {
    $user_id = get_current_user_id();
    $existing_dob = get_user_meta( $user_id, 'birthday_field', true );
    
    $field_args = array(
        'type' => 'date',
        'label' => __('出生日期', 'woocommerce' ),
        'required' => false,
        'input_attrs' => array(
            'placeholder' => 'YYYY-MM-DD',
            'pattern' => '\d{4}-\d{2}-\d{2}', // 强制日期格式为年-月-日
        )
    );

    // 如果已存在生日数据,添加只读属性
    if ( !empty($existing_dob) ) {
        $field_args['input_attrs']['readonly'] = 'readonly';
        $field_args['input_attrs']['disabled'] = 'disabled'; // 增强禁用效果
    }

    woocommerce_form_field( 'birthday_field', $field_args, $existing_dob );
}

// 前端保存账户详情时的错误处理
add_action( 'woocommerce_save_account_details_errors', 'dob_on_myaccount_form_error', 10, 1 );
function dob_on_myaccount_form_error( $args ) {
    $user_id = get_current_user_id();
    $existing_dob = get_user_meta( $user_id, 'birthday_field', true );
    
    // 仅当用户未设置过生日时,才校验是否填写
    if ( empty($existing_dob) && isset( $_POST['birthday_field'] ) && empty( $_POST['birthday_field'] ) ) {
        $args->add('error', __( '请填写出生日期', 'woocommerce' ) );
    }
}

// 前端保存账户详情(仅允许首次设置)
add_action( 'woocommerce_save_account_details', 'dob_on_myaccount_form_save', 10, 1 );
function dob_on_myaccount_form_save( $user_id ) {
    $existing_dob = get_user_meta( $user_id, 'birthday_field', true );
    
    // 仅当用户未设置过生日时,才允许保存
    if ( empty($existing_dob) && isset( $_POST['birthday_field'] ) && !empty( $_POST['birthday_field'] ) ) {
        update_user_meta( $user_id, 'birthday_field', sanitize_text_field( $_POST['birthday_field'] ) );
    }
}

// 生日折扣逻辑(仅在用户生日当天发放10%折扣)
add_action( 'woocommerce_cart_calculate_fees', 'give_birthday_discount', 10, 1 );
function give_birthday_discount( $cart ) {
    if ( is_admin() && !defined('DOING_AJAX') ) return;
    
    $user_id = get_current_user_id();
    if ( !$user_id ) return; // 未登录用户不享受折扣
    
    $user_dob = get_user_meta( $user_id, 'birthday_field', true );
    if ( empty($user_dob) ) return; // 未设置生日的用户不享受
    
    // 提取生日的月和日,与当前日期对比
    $current_date = date('m-d');
    $birthday_month_day = date('m-d', strtotime($user_dob));
    
    if ( $current_date === $birthday_month_day ) {
        $discount_percentage = 10;
        $discount_amount = -( $cart->subtotal * $discount_percentage / 100 );
        $cart->add_fee( __( '生日折扣', 'woocommerce' ), $discount_amount );
    }
}

// 后台用户资料页显示出生日期字段
add_action( 'show_user_profile', 'dob_on_admin_profile', 10, 1 );
add_action( 'edit_user_profile', 'dob_on_admin_profile', 10, 1 );
function dob_on_admin_profile( $user ) {
?>
<h3><?php _e('生日','woocommerce'); ?></h3>
<table class="form-table">
    <tr>
        <th><label for="birthday_field"><?php _e('出生日期', 'woocommerce'); ?></label></th>
        <td><input type="date" name="birthday_field" value="<?php echo esc_attr(get_the_author_meta('birthday_field', $user->ID)); ?>" class="regular-text" /></td>
    </tr>
</table>
<br />
<?php
}

// 后台保存用户出生日期(管理员无限制)
add_action( 'personal_options_update', 'dob_on_admin_profile_save', 10, 1 );
add_action( 'edit_user_profile_update', 'dob_on_admin_profile_save', 10, 1 );
function dob_on_admin_profile_save( $user_id ) {
    if ( ! empty( $_POST['birthday_field'] ) ) {
        update_user_meta( $user_id, 'birthday_field', sanitize_text_field( $_POST['birthday_field'] ) );
    }
}

关键修改说明

  1. 前端字段限制:在dob_on_myaccount_form中,通过检查用户是否已存在birthday_field元数据,为已设置的字段添加readonly和disabled属性,阻止用户修改。
  2. 保存逻辑限制:在dob_on_myaccount_form_save中,仅当用户未设置过生日时才允许保存新的日期,彻底防止重复修改。
  3. 日期格式设置:通过input_attrs添加pattern属性,强制用户输入YYYY-MM-DD格式的日期,同时设置占位符提示。
  4. 折扣逻辑修复:原代码会无条件给折扣,现在修改为仅当用户生日的月日与当前日期匹配时,才发放10%的折扣,并且排除了后台和未登录用户的情况。

内容的提问来源于stack exchange,提问作者user14906105

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:40:14