【问题标题】:WooCommerce: Dynamic Custom Checkout Fields in adminWooCommerce:管理员中的动态自定义结帐字段
【发布时间】:2023-03-27 03:26:01
【问题描述】:

我在向订单管理员添加自定义结帐字段时遇到问题(可能还有电子邮件,我还没有)。除了编码问题,我主要关注https://www.kathyisawesome.com/woocommerce-customize-checkout-fields/ - 这是我目前的代码:

http://pastebin.com/y8LDcDxS

假设购物车中有一件产品,我会根据产品数量添加“x”数量的 $fields['extra_fields']。我正在为 kia_display_order_data_in_admin() 苦苦挣扎 - 无论我做什么,我都会被 get_country() 咬住。我在 pastebin 中有非动态变化(基于购物车中有两种产品) - 我试图让这部分动态化的所有其他东西都不起作用。

我看到一些选项可以在管理员中加载这些动态字段,但我无法到达那里:

  1. 再次获取产品数量并将 $i 附加到标准字段名称的末尾

  2. 以某种方式获取所有字段的数组,以便我可以提取 $fields['extra_fields']

  3. 通过 order_id 获取 extra_fields 帖子元

  4. 还有别的吗?

编辑:在 Kia 的帮助下,我稍微修改了代码,现在它会动态添加自定义结帐字段。这一直有效到管理员订单屏幕,但在管理员kia_save_extra_details()尝试更新订单详细信息时不起作用@

编辑 2:请参阅下面接受的答案,因为这适用于我的问题

【问题讨论】:

  • 感谢您访问我的网站。 :) 我已经回答了如何在结账时设置显示。希望你能从那里拿走它。
  • 你有机会尝试这个吗?
  • 我确实在下面尝试了您的代码,但无法解决/让它工作。感谢您在构建初始字段数组时的提醒 - 摆脱了一些代码重复。新pastebin.com/PnvGCGRG。在管理员中编辑详细信息后尝试更新时,它一直有效到管理员订单屏幕。还没有尝试过电子邮件,但我认为这些将与产品相关(很像这些结帐字段应该如何),我可能会尝试SkyVerge tutorials 之一
  • 您不需要使用pastebin,您可以将代码粘贴到您的问题中。
  • 见@helgatheviking接受的答案下面的解决方案

标签: php wordpress woocommerce checkout custom-fields


【解决方案1】:

您确定产品附加组件可能不适合这个吗?如果没有,我认为您需要的是自定义输入类型。这应该可以帮助您入门。

/* Add a new checkout field 
 * 
 * These is our base field group, later on, depending on product quanitiy, $key = 'passenger_title_1' for example
 * 
 */

function supreme_filter_checkout_fields($fields){
    $fields['extra_fields'] = array(
    'passenger_details' => array(
        'type' => 'passenger_details',
        'required'      => false,
        'label' => __( 'Passenger Details' )
        ),
    );

    return $fields;

}
add_filter( 'woocommerce_checkout_fields', 'supreme_filter_checkout_fields' );

“passenger_details”输入到底是什么?好吧,我们要定义它,因为woocommerce_form_field() 有一个全部捕获,以防类型与 WooCommerce 的任何默认值都不匹配。见'woocommerce_form_field_' . $args['type']

我们将在此处列出您希望为每位乘客提供的字段组。

function supreme_filter_checkout_field_group( $field, $key, $args, $value ){
    $op_cart_count = WC()->cart->get_cart_contents_count();

    $html = '';

    for ( $i = 1; $i <= $op_cart_count; $i++) {

        $html .= woocommerce_form_field( "passenger_details[$i][title]", array( 
            "type" => "select",
            "return" => true,
            "value" => "",
            "options" => array( "mr" => __( "Mr" ), "mrs" => __( "Mrs" ), "miss" => __( "Miss" ) ),
            "required"      => false,
            "label" => __( "Title" )
            )
        );
        $html .= woocommerce_form_field( "passenger_details[$i][first_name]", array(
            "type" => "text",
            "return" => true,
            "value" => "",
            "required"      => false,
            "label" => __( "First Name" )
            )
        );
        $html .= woocommerce_form_field( "passenger_details[$i][middle_name]", array(
            "type" => "text",
            "return" => true,
            "value" => "",
            "required"      => false,
            "label" => __( "Middle Name" )
            )
        );
        $html .= woocommerce_form_field( "passenger_details[$i][last_name]", array(
            "type" => "text",
            "return" => true,
            "value" => "",
            "required"      => false,
            "label" => __( "Last Name" )
            )
        );
        $html .= woocommerce_form_field( "passenger_details[$i][date_of_birth]", array(
            "type"          => "text",
            "return" => true,
            "value" => "",
            "class"         => array("date-of-birth form-row-wide"),
            "required"      => false,
            "label"         => __("Date of Birth"),
            "placeholder"       => __("Select Date"),
            "options"     =>   array("" => __("Date of Birth", "woocommerce" ))
            )
        );
        $html .= woocommerce_form_field( "passenger_details[$i][dietary_required]", array(
            "type" => "select",
            "return" => true,
            "value" => "",
            "class"         => array("dietary-required form-row-wide"),
            "options" => array( "" => __( "Please Select" ), "y" => __( "Yes" ), "n" => __( "No" ) ),
            "required"      => false,
            "label" => __( "Dietary Requirements?" )
            )
        );
        $html .= woocommerce_form_field( "passenger_details[$i][dietary_preference]", array(
            "type" => "select",
            "return" => true,
            "value" => "",
            "class"         => array("dietary-requirements form-row-wide"),
            "options" => array( "v" => __( "Vegetarian" ), "GF" => __( "Gluten Free" ) ),
            "required"      => false,
            "label" => __( "Meal Preferences" )
            )
        );

    }
    return $html;
}
add_filter( 'woocommerce_form_field_passenger_details', 'supreme_filter_checkout_field_group', 10, 4 );



// display the extra field on the checkout form
function supreme_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;


}
add_action( 'woocommerce_checkout_after_customer_details' ,'supreme_extra_checkout_fields' );

EDIT 处理数据的清理和保存。请注意,我更改了上面的 supreme_filter_checkout_field_group 函数并删除了 ID 参数。

~~使用id 参数我们可以动态设置输入名称。生成的标记应该是这样的:~~

<input type="text" class="input-text " name="last_name" id="passenger_details[2]last_name" placeholder="" value="">

这是错误的。 name 参数需要是一个数组!并且名称是从woocommerce_form_field() 的第一个参数中提取的。 ID 与我们的需求无关,尽管它确实需要是唯一的以保持正确的标记。这是我们需要的结果,现在应该通过上述修改得到:

<input type="text" class="input-text " name="passenger_details[2][last_name]" id="passenger_details[2][last_name]" placeholder="" value="">

现在提交时,$_POST['passenger_data'] 应该是数组(乘客详细信息)的数组(乘客)。经过我的编辑,它就是!

现在,为了处理这些数据并清理乘客数据中的各个字段,我们创建了一个函数来清理我们的自定义字段类型:

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

    $clean = array();

    foreach( $posted as $passenger ){
        $details = supreme_custom_checkout_clean_passenger_details( $passenger );

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

    return $clean;
}
add_filter( 'woocommerce_process_checkout_passenger_details_field', 'supreme_custom_process_checkout_field_passenger_details' );


function supreme_custom_checkout_clean_passenger_details( $passenger = array() ){
    $details = array();
    if( isset( $passenger["title"] ) ){
        $details['title'] = sanitize_text_field( $passenger["title"] );
    }
    if( isset( $passenger["first_name"] ) ){
        $details['first_name'] = sanitize_text_field( $passenger["first_name"] );
    }
    if( isset( $passenger["middle_name"] ) ){
        $details['middle_name'] = sanitize_text_field( $passenger["middle_name"] );
    }
    if( isset( $passenger["last_name"] ) ){
        $details['last_name'] = sanitize_text_field( $passenger["last_name"] );
    }
    if( isset( $passenger["date_of_birth"] ) ){
        $details['date_of_birth'] = $date = preg_replace("([^0-9/])", "", $passenger["date_of_birth"] );
    }
    if( isset( $passenger["dietary_required"] ) ){
        $details['dietary_required'] = $passenger["dietary_required"] == "y" ? "y": "n";
    }
    if( isset( $passenger["dietary_preference"] ) && isset( $passenger["dietary_required"] ) && $passenger["dietary_required"] == "y" ){
        $details['dietary_preference'] = $passenger["dietary_preference"] == "GF" ? "GF": "v";
    }
    return $details;
}

现在它已经过清理,更新只是保存帖子元数据的问题:

/**
 * update_post_meta
 * 
 */
function supreme_custom_checkout_field_update_order_meta( $order_id, $posted ){

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

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

现在,我们肯定已经将所有字段保存在 _passenger_details 后元键中,我们可以在需要显示它的任何时候循环遍历该数组。例如,这里是管理订单页面:

// display the extra data in the order admin panel
function kia_display_order_data_in_admin( $order ){  

    $passenger_details = get_post_meta( $order->id, "_passenger_details", true ); 

    if( ! empty( $passenger_details ) ) { 

        $passenger_defaults = array(
                "title" => "",
                "first_name" => "",
                "middle_name" => "",
                "last_name" => "",
                "date_of_birth" => "",
                "dietary_required" => "",
                "dietary_preference" => ""
            );

    ?>
    <div class="passenger_data">
        <h4><?php _e( "Passenger Details", "your-slug" ); ?></h4>
        <?php 
            $i = 1;

            foreach( $passenger_details as $passenger ){

                $passenger = wp_parse_args( $passenger, $passenger_defaults );

                echo "<p><strong>" . sprintf( __( "Passenger #%s", "your-slug" ), $i  ) . "</strong>" . "<br/>";
                echo __( "Title", "your-slug" ) . ' : ' . $passenger["title"] . "<br/>";
                echo __( "First Name", "your-slug" ) . ' : ' . $passenger["first_name"] . "<br/>";
                echo __( "Middle Name", "your-slug" ) . ' : ' . $passenger["middle_name"] . "<br/>";
                echo __( "Last Name", "your-slug" ) . ' : ' . $passenger["last_name"] . "<br/>";
                echo __( "Date of Birth", "your-slug" ) . ' : ' . $passenger["date_of_birth"] . "<br/>";
                echo __( "Dietary Required", "your-slug" ) . ' : ' . $passenger["dietary_required"] . "<br/>";
                echo __( "Dietary Preference", "your-slug" ) . ' : ' . $passenger["dietary_preference"] . "<br/>";

                echo "</p>";

                $i++;

            }

         ?>
    </div>
<?php }
}
add_action( "woocommerce_admin_order_data_after_order_details", "kia_display_order_data_in_admin" );

现在仍然留下感谢页面和电子邮件,但数据在那里。

【讨论】:

  • @tringwebdesign 你从中得到了什么结果? (它没用总是含糊不清)哪一部分没用?有时间我可以再看看。
  • 它不会动态添加额外的结帐字段。 TBH 我知道距离您的输入仅 6 天,但我不记得使用上面代码的结果,它显然不能作为纯复制和粘贴 sn-p 因此我对原始问题的修改编辑.如果你愿意,我可以回去重新测试?
  • 再看一遍,虽然输入显示它们没有所需的“名称”属性。请查看修改后的答案。我已经测试过了,它确实保存了数据。
  • 谢谢@helgatheviking 它确实有效,一些玛格丽塔爱送你了!现在要做的就是让管理员订单编辑工作。从那以后我和我的客户谈过,他将使用 Zapier 管理给供应商的订单电子邮件等。
猜你喜欢
  • 1970-01-01
  • 2023-03-05
  • 2023-04-10
  • 2018-07-21
  • 2021-04-17
  • 2017-06-19
  • 1970-01-01
  • 2017-03-21
相关资源
最近更新 更多