Woocommerce 预订中每人和每件商品的动态结账自定义字段

2024-05-10

对于预订网站,我正在尝试创建一个功能,可以根据人数添加与会者列表。感谢 LoicTheAztec,我已经获得了单次预订的代码。那部分工作正常。

我还需要相同的功能来进行多次预订。我怎样才能实现这个目标?

这是代码:

//* Add a new checkout field
add_filter( 'woocommerce_checkout_fields', 'ppp_filter_checkout_fields' );
function ppp_filter_checkout_fields($fields){
    $fields['extra_fields'] = array(
    'participant_details' => array(
        'type' => 'participant_details',
        'required'      => false,
        'label' => __( 'Participant Details' )
        ),
    );

    // Add a "persons" hidden input field
    foreach( WC()->cart->get_cart() as $cart_item ) {
        $persons = $cart_item['booking']['_persons'][0];
    }
    echo '<input type="hidden" name="persons" value="' . $persons . '">';

    return $fields;
}

//* Add the field to the checkout
add_filter( 'woocommerce_form_field_participant_details', 'ppp_filter_checkout_field_group', 10, 4 );
function ppp_filter_checkout_field_group( $field, $key, $args, $value ){
    $op_cart_count = WC()->cart->get_cart_contents_count();

    $items = WC()->cart->get_cart();

    foreach($items as $item) {
        $person = $item['booking']['_persons'][0];
    }

    if ($person > 1) {

        $html = '';

        $html .= "<h3>Deelnemers</h3>";

        for ( $i = 1; $i < $person; $i++) {
            $counter = $i + 1;

            $html .= "Deelnemer ". $counter . "<br>";

            $html .= woocommerce_form_field( "participant_details[$i][full_name]", array(
                "type" => "text",
                "return" => true,
                "value" => "",
                "required"      => true,
                "label" => __( "Naam" )
                )
            );
            $html .= woocommerce_form_field( "participant_details[$i][email_address]", array(
                "type" => "email",
                "return" => true,
                "value" => "",
                "required"      => true,
                "label" => __( "Emailadres" )
                )
            );

        }
        return $html;
    }
}

//* display the extra field on the checkout form
add_action( 'woocommerce_checkout_after_customer_details' ,'ppp_extra_checkout_fields' );
function ppp_extra_checkout_fields(){

    $checkout = WC()->checkout();

    foreach ( $checkout->checkout_fields['extra_fields'] as $key => $field ) :

        woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );

    endforeach;
}

//* Validate custom checkout fields
add_action( 'woocommerce_after_checkout_validation', 'ppp_checkout_field_participant_details_validation', 20, 2 );
function ppp_checkout_field_participant_details_validation( $data, $errors ){
    if ( isset( $_POST['persons'] ) && $_POST['persons'] > 1 ){

        for ( $i = 1, $j = 2; $i < esc_attr( $_POST['persons'] ); $i++, $j++ ) {
            if ( empty( $_POST['participant_details'][$i]['full_name'] ) )
                $errors->add( 'participant_'.$i.'_full_name',  __( "Please fill in the participant $j full name" ), 'error' );

            if ( empty( $_POST['participant_details'][$i]['email_address'] ) )
                $errors->add( 'participant_'.$i.'_email_address',  __( "Please fill in the participant $j email address" ), 'error' );
        }
    }
}


//* Sanitize our custom field
function ppp_custom_process_checkout_field_participant_details( $posted ){

    $clean = array();

    foreach( $posted as $participant ){
        $details = ppp_custom_checkout_clean_participant_details( $participant );

        if( ! empty( $details ) ){
            $clean[] = $details;
        }
    }

    return $clean;
}
add_filter( 'woocommerce_process_checkout_participant_details_field', 'ppp_custom_process_checkout_field_participant_details' );

//*
function ppp_custom_checkout_clean_participant_details( $participant = array() ){
    $details = array();
    if( isset( $participant["full_name"] ) ){
        $details['full_name'] = sanitize_text_field( $participant["full_name"] );
    }
    if( isset( $participant["email_address"] ) ){
        $details['email_address'] = sanitize_text_field( $participant["email_address"] );
    }
    return $details;
}


//* Update_post_meta
add_action( 'woocommerce_checkout_update_order_meta', 'ppp_custom_checkout_field_update_order_meta', 10, 2 );
function ppp_custom_checkout_field_update_order_meta( $order_id, $posted ){

    if( ! empty( $posted["participant_details"] ) ){
        update_post_meta( $order_id, "_participant_details", $posted["participant_details"] );
    } else {
        delete_post_meta( $order_id, "_participant_details" );
    }

}
add_action( 'woocommerce_checkout_update_order_meta', 'ppp_custom_checkout_field_update_order_meta', 10, 2 );

您错过了一个额外的循环(购物车项目循环)……我已经完全重新审视了您的代码,使其适用于多个项目(不同的项目)。

因此,这些字段现在由项目和每个项目上的人员动态生成:

// Conditional function: Check if at least there is more than one person in cart items
function ppp_check_persons(){
    $enabled    = array();

    foreach( WC()->cart->get_cart() as $cart_item) {
        if( isset($cart_item['booking']['_persons'][0])
        && $cart_item['booking']['_persons'][0] > 1 )
        {
            $enabled = true;
            break;
        }
    }
    return $enabled;
}

// Add a new checkout field
add_filter( 'woocommerce_checkout_fields', 'ppp_filter_checkout_fields' );
function ppp_filter_checkout_fields($fields){

    $fields['extra_fields'] = array( 'participant' => array(
        'type' => 'participant',
        'required'      => false,
        'label' => __( 'Participant Details' )
    ) );

    $cart_items = WC()->cart->get_cart();
    $count      = 1;

    echo '<input type="hidden" name="items_count" value="' . sizeof($cart_items) . '">';

    if( ! ppp_check_persons() ) return $fields; // Exit (not enough persons)

    // Add "persons" hidden input fields for each cart_item
    foreach( WC()->cart->get_cart() as $cart_item ) {
        $persons = $cart_item['booking']['_persons'][0];
        echo '<input type="hidden" name="persons_'.$count.'" value="' . $persons . '">';
        $count++;
    }

    return $fields;
}

// Add the field to the checkout
add_filter( 'woocommerce_form_field_participant', 'ppp_filter_checkout_field_group', 10, 4 );
function ppp_filter_checkout_field_group( $field, $key, $args, $value ){
    if( ! ppp_check_persons() ) return $fields; // Exit (not enough persons)

    ob_start();

    echo "<h3>Deelnemers</h3>";

    $cart_items = WC()->cart->get_cart();
    $nb_items   = sizeof($cart_items);
    $count      = 1;

    // Loop through cart items;
    foreach( $cart_items as $cart_item) {
        $persons = $cart_item['booking']['_persons'][0];

        if ( $persons > 1  && $persons != 1 ) {
            echo '<h4 style="font-size:135%;">Item'.$count.'</h4>';

            for ( $i = 1, $j = 2; $i < $persons; $i++, $j++)
            {
                echo '<span style="margin-bottom:12px;display:inline-block;font-size:112%;">' . __("Deelnemer") . ' ' . $j . '</span>';

                echo woocommerce_form_field( "participant[$count][$j][fname]", array(
                    "type" => "text",
                    "return" => true,
                    "value" => "",
                    "required"      => true,
                    "label" => __( "Naam" )
                ) );

                echo woocommerce_form_field( "participant[$count][$j][email]", array(
                    "type" => "email",
                    "return" => true,
                    "value" => "",
                    "required"      => true,
                    "label" => __( "Emailadres" )
                ) );

            }
            echo '<br>';
        }
        $count++;
    }
    return ob_get_clean();
}

// display the extra field on the checkout form
add_action( 'woocommerce_checkout_after_customer_details' ,'ppp_extra_checkout_fields' );
function ppp_extra_checkout_fields(){
    $checkout = WC()->checkout();

    foreach ( $checkout->checkout_fields['extra_fields'] as $key => $field )
    {
        woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
    }
}

// Validate custom checkout fields
add_action( 'woocommerce_after_checkout_validation', 'ppp_checkout_field_participant_details_validation', 20, 2 );
function ppp_checkout_field_participant_details_validation( $data, $errors ){
    if ( !( isset($_POST['items_count']) && ! empty($_POST['items_count']) ) ) return; // Exit

    for ( $h = 1; $h <= esc_attr( $_POST['items_count'] ); $h++ )
    {
        if ( isset( $_POST['persons_'.$h] ) && $_POST['persons_'.$h] > 1 )
        {
            for ( $i = 1, $j = 2; $i < esc_attr( $_POST['persons_'.$h] ); $i++, $j++ )
            {
                if ( isset( $data['participant'][$h][$j]['fname'] ) && empty( $data['participant'][$h][$j]['fname'] ) )
                    $errors->add( 'participant_'.$h.'_'.$j.'_fname',  __( "Please fill in the participant $j full name (Item $h)" ), 'error' );

                if ( isset( $data['participant'][$h][$j]['email'] ) && empty( $data['participant'][$h][$j]['email'] ) )
                    $errors->add( 'participant_'.$h.'_'.$j.'_email',  __( "Please fill in the participant $j email address (Item $h)" ), 'error' );
            }
        }
    }
}


// Save custom fields values in the order as meta data
add_action( 'woocommerce_checkout_create_order', 'ppp_custom_fields_checkout_create_order', 20, 2 );
function ppp_custom_fields_checkout_create_order( $order, $data ){
    if ( !( isset($_POST['items_count']) && ! empty($_POST['items_count']) ) ) return; // Exit

    // Save number of different items in cart
    $order->update_meta_data( '_items_count', esc_attr( $_POST['items_count'] ) );

    for ( $h = 1; $h <= esc_attr( $_POST['items_count'] ); $h++ )
    {
        if ( isset( $_POST['persons_'.$h] ) && $_POST['persons_'.$h] > 1 )
        {
            // Save number of persons for each item in cart
            $order->update_meta_data( '_item_'.$h.'_persons', esc_attr( $_POST['persons_'.$h] ) );

            for ( $i = 1, $j = 2; $i < esc_attr( $_POST['persons_'.$h] ); $i++, $j++ )
            {
                // Save number of persons for each item in cart
                if ( isset( $data['participant'][$h][$j]['fname'] ) ){
                    $full_name = sanitize_text_field( $data['participant'][$h][$j]['fname'] );
                    $order->update_meta_data( '_participant_'.$h.'_'.$j.'_fname', $full_name );
                }

                if ( isset( $data['participant'][$h][$j]['email'] ) ){
                    $email_address = sanitize_text_field( $data['participant'][$h][$j]['email'] );
                    $order->update_meta_data( '_participant_'.$h.'_'.$j.'_email', $email_address );
                }
            }
        }
    }
}

代码位于活动子主题(或活动主题)的 function.php 文件中。经过测试并有效。

在订单前端和后端和/或电子邮件通知中显示数据对于处理其他所有内容的这个答案来说太宽泛了。要在管理订单编辑页面中的客户详细信息下方显示这些数据,这不是一个好主意,应该在自定义元框中完成。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Woocommerce 预订中每人和每件商品的动态结账自定义字段 的相关文章

随机推荐

  • Java 的 QP 求解器 [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • Angular flex-layout - fxLayoutGap 导致包裹行末尾出现恼人的间隙

    使用fxLayoutGap 和wrap 在被换行的每一行的末尾留下令人讨厌的边距 有没有办法来解决这个问题 https stackblitz com edit angular fxlayoutgap calc mralnz file app
  • 在 Spring 中设置 WS https 调用超时 (HttpsUrlConnectionMessageSender)

    我正在尝试为 WS 调用设置超时 我延长了WebServiceGatewaySupport并尝试将发送者超时设置为如下 public Object marshalSendAndReceive Object requestPayload We
  • 颤动附近的连接

    当我尝试在设备上做广告或发现时 我收到此错误 但是前一天在环路上效果很好 PlatformException Failure 17 API Nearby CONNECTIONS API is not available on this de
  • 在 Django Rest Framework 中过滤多个值

    我有一个模型想要过滤多个值 我的模型 class Product models Model ean models CharField max length 13 unique True product id models CharField
  • 不支持函数调用。考虑用对导出函数的引用替换函数或 lambda

    我在我的应用程序中使用 APP INITIALIZER 并在 app module ts 中将其设置如下 并进行必要的导入 NgModule providers ContextService provide APP INITIALIZER
  • F# 对于 OO 或命令式来说缺少什么? [关闭]

    就目前情况而言 这个问题不太适合我们的问答形式 我们希望答案得到事实 参考资料或专业知识的支持 但这个问题可能会引发辩论 争论 民意调查或扩展讨论 如果您觉得这个问题可以改进并可能重新开放 访问帮助中心 help reopen questi
  • 基本 C++ 文本对齐

    我正在尝试编写一个程序 该程序从文件中获取输入行并使其恰好为 80 个字符 假设输入行始终小于 80 然后打印该行 这是通过在以下标点符号后添加最多两个空格来完成的 如果一行少于 41 个字符 则不加修改地打印 如果该行仍然不是 80 个字
  • 将本机 swift Set 转换为数组[重复]

    这个问题在这里已经有答案了 我需要将 Set 转换为 AnyObject 或 String 的数组 这可能吗 我知道使用 NSSet 我可以使用 allObjects 但对于本机集似乎没有任何函数 只需直接强制转换为数组即可 let arr
  • History.pushState和页面刷新

    我开始研究 HTML5 新历史 API 不过 我有一个问题 如何处理页面刷新 例如 用户单击一个链接 该链接由 js 函数处理 该函数 异步加载页面内容 使用history pushState 更改URL 用户刷新页面 但是服务器上当然不存
  • 如何自定义 ckeditor 4.2 内置插件(如链接)?

    如果我想向链接插件添加选项卡 最佳实践方法是什么 我不想更改发布代码 只需用带有我的自定义的版本覆盖它即可 因此 很容易更新新版本 CKEDITOR 4 2 有这方面的操作方法吗 我正在使用新的内联样式工具栏 如果我获得源代码 我可以在没有
  • Windows、Emacs、Git Bash 和 shell 命令

    Windows 7 Emacs 24 3 1 git 1 8 1 msysgit 1 我的等效 emacs 文件中有以下内容 if equal system type windows nt progn setq explicit shell
  • Tesseract 是否会忽略扫描文档中的任何非文本区域?

    我正在使用 Tesseract 但我不知道它是否忽略任何非文本区域并仅针对文本 我是否必须删除任何非文本区域作为预处理步骤以获得更好的输出 Tesseract 有一个非常好的算法来检测文本 但它最终会给出误报匹配 理想情况下 您应该在将图像
  • 使用javascript向url添加哈希而不滚动页面?

    在不滚动页面的情况下向 url 添加哈希 使用 JavaScript 我打开页面 我向下滚动 我单击添加哈希的链接 可能带有值 test 示例 http www example com test http www example com t
  • 如何在 Material UI 的 webpack 构建中包含 Roboto 字体?

    For a 进步网络应用程序基于材质用户界面 http www material ui com 反应 并构建Webpack 我如何正确包含 Roboto 字体 以便该应用程序不依赖于 Google 服务器并且字体也可以工作offline T
  • 如何让 BottomNavigationBar 粘在键盘颤动的顶部

    我正在尝试制作一个简单的聊天应用程序 所以我创建了一个脚手架和我的身体 将是消息和我的bottomNavigationBar将是我的打字字段和发送图标 我添加了一个文本字段 但键入时导航栏被键盘隐藏 这是我的代码BottomNavigati
  • 对打开文件的脚本进行单元测试

    我编写了一个脚本 它打开一个文件 读取内容并进行一些操作和计算 并将它们存储在集合和字典中 我该如何为这样的事情编写单元测试 我的问题具体是 我会测试文件是否打开 文件很大 这是unix字典文件 我如何对计算进行单元测试 我真的必须手动计算
  • 如何使用材料用户界面和样式组件定位按钮基础

    使用ToggleButton and ToggleButtonGroup组件来自material ui从材料 ui 开始盖茨比模板 https github com mui org material ui tree master examp
  • 如何在“python setup.py test”中运行 py.test 和 linter

    我有一个项目setup py文件 我用pytest作为测试框架 我还在我的代码上运行各种 linter pep8 pylint pydocstyle pyflakes ETC 我用tox在多个 Python 版本中运行它们 并使用以下命令构
  • Woocommerce 预订中每人和每件商品的动态结账自定义字段

    对于预订网站 我正在尝试创建一个功能 可以根据人数添加与会者列表 感谢 LoicTheAztec 我已经获得了单次预订的代码 那部分工作正常 我还需要相同的功能来进行多次预订 我怎样才能实现这个目标 这是代码 Add a new check