如何通过 WooCommerce 管理端的变更单设置支付网关

How to set Payment Gateway by change order from admin side in WooCommerce

请帮忙!我正在尝试通过更改管理员的订单详细信息来定义支付网关。

作为默认选项,我想使用 'bacs' 支付网关。客户下订单,然后我想更改订单并将付款方式转为自定义 'payment2' 网关。

为此,我制作了带有复选框的 metabox,它应该变成 on/off 'payment2' 方法并取消设置默认值 'bacs'。复选框工作正常。

但是,我无法让它工作。首先,我无法获得带有复选框值的 post 元数据。请检查以下代码:

function show_payment2_payment_gateway( $available_gateways ) { 

    $use_payment2 = get_post_meta( $post->ID, 'use_payment2', true );    

    if($use_payment2 == "yes") {

    unset( $available_gateways['bacs'] );
    }  
    else {
        unset( $available_gateways['payment2'] );
    }

    return $available_gateways; 
}

add_filter( 'woocommerce_available_payment_gateways',    'show_payment2_payment_gateway', 10, 1 ); 

UPD

这是我的后端复选框代码。正如我所说,它运行良好并将元值保存为 'yes'

//
//Adding Meta container admin shop_order pages
//
add_action( 'add_meta_boxes', 'mv_add_meta_boxes' );
if ( ! function_exists( 'mv_add_meta_boxes' ) )
{
    function mv_add_meta_boxes()
    {
        global $woocommerce, $order, $post;

        add_meta_box( 'mv_other_fields', __('PAYMENT2','woocommerce'),   'mv_add_other_fields_for_packaging', 'shop_order', 'side', 'core' );
    }
}


//
//adding Meta field in the meta container admin shop_order pages
//
if ( ! function_exists( 'mv_save_wc_order_other_fields' ) )
{
    function mv_add_other_fields_for_packaging()
    {
        global $woocommerce, $order, $post;

        $meta_field_data = get_post_meta( $post->ID, 'use_payment2', true );
        $meta_field_data_checked = $meta_field_data["use_payment2"][0];         

        if($meta_field_data == "yes") $meta_field_data_checked =  'checked="checked"';         

        echo '
        <label for="use_epay">TURN PAYMENT2 ON?</label>
        <input type="hidden" name="mv_other_meta_field_nonce" value="' .  wp_create_nonce() . '">
        <input type="checkbox" name="use_payment2" value="yes"  '.$meta_field_data_checked.'>';

    }
}

//
//Save the data of the Meta field
//
add_action( 'save_post', 'mv_save_wc_order_other_fields', 10, 1 );
if ( ! function_exists( 'mv_save_wc_order_other_fields' ) )
{

    function mv_save_wc_order_other_fields( $post_id ) {

        // We need to verify this with the proper authorization (security  stuff).

        // Check if our nonce is set.
        if ( ! isset( $_POST[ 'mv_other_meta_field_nonce' ] ) ) {
            return $post_id;
        }
        $nonce = $_REQUEST[ 'mv_other_meta_field_nonce' ];

        //Verify that the nonce is valid.
        if ( ! wp_verify_nonce( $nonce ) ) {
            return $post_id;
        }

        // If this is an autosave, our form has not been submitted, so we don't  want to do anything.
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
            return $post_id;
        }

        // Check the user's permissions.
        if ( 'page' == $_POST[ 'post_type' ] ) {

            if ( ! current_user_can( 'edit_page', $post_id ) ) {
                return $post_id;
            }
        } else {

            if ( ! current_user_can( 'edit_post', $post_id ) ) {
                return $post_id;
            }
        }
        // --- Its safe for us to save the data ! --- //

        // Sanitize user input  and update the meta field in the database.
        update_post_meta( $post_id, 'use_payment2', $_POST[ 'use_payment2' ] );
    }
}

UPD

这是后端的工作代码(自定义复选框元数据框)。它保存复选框值并更改订单详细信息中的付款方式:

//
//Adding Meta container admin shop_order pages
//
add_action( 'add_meta_boxes', 'mv_add_meta_boxes' );
if ( ! function_exists( 'mv_add_meta_boxes' ) )
{
function mv_add_meta_boxes()
{
    global $woocommerce, $order, $post;

    add_meta_box( 'mv_other_fields', __('PAYMENT2','woocommerce'),   'mv_add_other_fields_for_packaging', 'shop_order', 'side', 'core' );
}
}



//
//adding Meta field in the meta container admin shop_order pages
//
if ( ! function_exists( 'mv_save_wc_order_other_fields' ) )
{
function mv_add_other_fields_for_packaging()
 {
    global $woocommerce, $order, $post;

    $meta_field_data = get_post_meta( $post->ID, 'use_payment2', true );    

    echo '<label for="use_payment2">USE PAYMENT2?</label>
          <input type="hidden" name="mv_other_meta_field_nonce" value="' .  wp_create_nonce() . '">';

    if($meta_field_data == "yes") {
        $meta_field_data_checked =  'checked="checked"';

    echo'<input type="checkbox" name="use_payment2" value="yes"  '.$meta_field_data_checked.'>';
}
    else {
    echo'<input type="checkbox" name="use_payment2" value="yes">';    
    }
 }
}

//Save the data of the Meta field
add_action( 'save_post', 'mv_save_wc_order_other_fields', 10, 1 );
if ( ! function_exists( 'mv_save_wc_order_other_fields' ) )
{

function mv_save_wc_order_other_fields( $post_id ) {

    // We need to verify this with the proper authorization (security  stuff).

    // Check if our nonce is set.
    if ( ! isset( $_POST[ 'mv_other_meta_field_nonce' ] ) ) {
        return $post_id;
    }
    $nonce = $_REQUEST[ 'mv_other_meta_field_nonce' ];

    //Verify that the nonce is valid.
    if ( ! wp_verify_nonce( $nonce ) ) {
        return $post_id;
    }

    // If this is an autosave, our form has not been submitted, so we don't  want to do anything.
    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return $post_id;
    }

    // Check the user's permissions.
    if ( 'page' == $_POST[ 'post_type' ] ) {

        if ( ! current_user_can( 'edit_page', $post_id ) ) {
            return $post_id;
        }
    } else {

        if ( ! current_user_can( 'edit_post', $post_id ) ) {
            return $post_id;
        }
    }
    // --- Its safe for us to save the data ! --- //

    // Sanitize user input  and update the meta field in the database.
    $use_payment2 = sanitize_text_field($_POST[ 'use_payment2' ]);
    update_post_meta( $post_id, 'use_payment2', $use_payment2 );

    if($_POST[ 'use_payment2' ] == 'yes') {            
            update_post_meta( $post_id, '_payment_method', 'payment2' );
        }
        elseif (get_post_meta( $post_id, '_payment_method', true ) != 'bacs') {
                update_post_meta( $post_id, '_payment_method', 'bacs' );    
    }

  }
}

但是,如何在前端使用复选框状态?我仍然无法使用此代码获取复选框值:

function show_payment2_payment_gateway( $available_gateways ) { 

global $woocommerce, $order, $post;

$payment_method = get_post_meta( $post_id, 'use_payment2', true );

if(isset($payment_method) == 'yes') {

unset( $available_gateways['bacs'] );

}
 else {

unset( $available_gateways['payment2'] );

}

return $available_gateways; 
}         

add_filter( 'woocommerce_available_payment_gateways', 'show_payment2_payment_gateway', 10, 1 );

现在,它总是显示 Payment2 选项,即使复选框被选中或未被选中。

在 WooCommerce 中列出默认支付网关的函数是 core_gateways()。此函数挂钩到名为 woocommerce_payment_gateways 的过滤器。因此,第一步是删除该过滤器并添加我们自己的过滤器。我将只在主题文件夹中的 functions.php 文件中工作(记住?永远不要修改核心文件)。为此,我们将使用 remove_filter() 和 add_filter() 函数:

remove_filter( 'woocommerce_payment_gateways', 'core_gateways' );
add_filter( 'woocommerce_payment_gateways', 'my_core_gateways' );

现在我们已经删除了过滤器,您可以看到在 add_filter() 函数中我们有一个名为 my_core_gateways 的回调。此回调是将替换默认 core_gateways() 函数的函数的名称。此功能是列出 WooCommerce 默认支付网关的功能。我将更改该函数的内容并替换对 WC_Gateway_BACS class 的调用。这个class是银行转账默认class。这是该新功能的代码:

/**
 * core_gateways function modified.
 *
 * @access public
 * @param mixed $methods
 * @return void
 */
function my_core_gateways( $methods ) {
    $methods[] = 'WC_Gateway_BACS_custom';
    $methods[] = 'WC_Gateway_Cheque';
    $methods[] = 'WC_Gateway_COD';
    $methods[] = 'WC_Gateway_Mijireh';
    $methods[] = 'WC_Gateway_Paypal';
    return $methods;
}

如您所见,我所做的唯一更改是将 WC_Gateway_BACS 替换为 WC_Gateway_BACS_custom。

你还在我身边吗?好吧,总而言之,我需要删除调用默认支付网关的过滤器,并使用自定义函数。在这个自定义函数中,我替换了对 BACS class 的调用,现在我需要创建这个新的 BACS class。为此,请使用该代码:

class WC_Gateway_BACS_custom extends WC_Gateway_BACS {

    /**
     * Process the payment and return the result
     *
     * @access public
     * @param int $order_id
     * @return array
     */
    function process_payment( $order_id ) {
        global $woocommerce;

        $order = new WC_Order( $order_id );

        // Mark as processing (that's what we want to change!)
        $order->update_status('processing', __( 'Awaiting BACS payment', 'woocommerce' ));

        // Reduce stock levels
        $order->reduce_order_stock();

        // Remove cart
        $woocommerce->cart->empty_cart();

        // Return thankyou redirect
        return array(
            'result'    => 'success',
            'redirect'  => add_query_arg('key', $order->order_key, add_query_arg('order', $order->id, get_permalink(woocommerce_get_page_id('thanks'))))
        );
    }

}

在这段代码中,我只将默认状态从“暂停”更改为“处理中”……。砰的一声,魔法出现了!现在,使用 BACS 支付网关支付的每个订单都将被标记为处理中,而不是暂停。

Update 2 related to your comments (and your question update)

您使用的钩子是前端钩子(不是管理员),所以它不会起作用。

为了实现目标,您需要替换函数中的一些代码,当您在后端(管理员)编辑订单页面更新订单时,这些代码将保存您的自定义复选框值。

因此您的代码现在将如下所示:

add_action( 'save_post', 'mv_save_wc_order_other_fields', 10, 1 );
if ( ! function_exists( 'mv_save_wc_order_other_fields' ) )
{

    function mv_save_wc_order_other_fields( $post_id ) {

        // We need to verify this with the proper authorization (security stuff).

        // Check if our nonce is set.
        if ( ! isset( $_POST[ 'mv_other_meta_field_nonce' ] ) )
            return $post_id;

        // Passing the value to a variable
        $nonce = $_REQUEST[ 'mv_other_meta_field_nonce' ];

        // If this is an autosave, our form has not been submitted, so we don't want to do anything.
        if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
            return $post_id;

        // Check the user's permissions.
        if ( 'page' == $_POST[ 'post_type' ] ) {
            if ( ! current_user_can( 'edit_page', $post_id ) )
                return $post_id;

        } else {
            if ( ! current_user_can( 'edit_post', $post_id ) )
                return $post_id;
        }

        // --- Its safe for us to save the data ! --- //

        // Sanitize user input and update the meta field in the database.
        $use_payment2 = sanitize_text_field($_POST[ 'use_payment2' ]);
        update_post_meta( $post_id, 'use_payment2', $use_payment2 );

        // Updating securely the data with your conditions
        if($use_payment2 == 'yes')
            update_post_meta( $post_id, '_payment_method', 'payment2' );
        else
            update_post_meta( $post_id, '_payment_method', 'bacs' );    
    }
}

现在应该可以正常工作了……

代码进入您的活动子主题(或主题)的 function.php 文件。或者在任何插件 php 文件中。

由于此代码来自 之一,您不必保留与 "mv_"问题的用户名。您可以将其更改为 "dan_" 例如...


参考:

经过几天的头痛之后,我找到了一种简单的方法,即仅当我向客户发送 link 时才显示定义的支付网关。

现在客户可以使用默认的'bacs'方式下单,管理员可以在付款前查看。然后管理员将订单状态更改为等待付款并 link 发送给客户。当客户打开 link 时,我的自定义支付网关将激活。

我决定使用 woocommerce 端点来检查它是否 'order-pay' 页面。我使用了以下代码:

function show_payment2_payment_gateway( $available_gateways ) { 

global $woocommerce, $order, $post;

if (is_wc_endpoint_url( 'order-pay' )) {

unset( $available_gateways['bacs'] );

}
 else {

unset( $available_gateways['payment2'] );

}

return $available_gateways; 
}         

add_filter( 'woocommerce_available_payment_gateways', 'show_payment2_payment_gateway', 10, 1 );

现在一切如我所愿。我希望这会有用。感谢@LoicTheAztec 的帮助!