【问题标题】:WooCommerce order again and custom item data for price calculationWooCommerce 再次订购和用于价格计算的自定义商品数据
【发布时间】:2020-11-13 19:47:47
【问题描述】:

我在重新订购时尝试添加/获取自定义商品数据时遇到了一些问题。

首先让我解释一下:我主要使用 WooCommerce 作为发票制造商,所以我必须进行的自定义更改之一是在每个产品中添加自定义百分比折扣字段(您也可以在购物车页面中编辑),所以我的问题是当重新订购时,购物车物品在那里,但百分比折扣不再影响价格,如果我尝试更改百分比值,所有价格均为 0(产品价格和产品总价) .

这是我正在使用的代码:

// Add a custom field before single add to cart
add_action('woocommerce_before_add_to_cart_button', 'custom_product_price_field', 5);
function custom_product_price_field()
{
    echo '<div class="custom-text text">
    <p>Descuento %:</p>
    <input type="text" id="custom_price" name="custom_price" value="" placeholder="e.g. 10" title="Custom Text" class="custom_price text_custom text">
    </div>';
}

// Get custom field value, calculate new item price, save it as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_field_data', 20, 3);
function add_custom_field_data($cart_item_data, $product_id, $variation_id)
{
    $product_id = $variation_id > 0 ? $variation_id : $product_id;

    if (!isset($_POST['custom_price'])) {
        return $cart_item_data;
    }

    $custom_price = (float) sanitize_text_field($_POST['custom_price']);


    if ($custom_price > 40) {
        wc_add_notice(__('El descuento debe ser menor a 40%'), 'error');
        return $cart_item_data;

    }

    $product = wc_get_product($product_id); // The WC_Product Object

    $price = (float) $product->get_price();

    $cart_item_data['base_price'] = $price;
    $cart_item_data['new_price'] = $price * (100 - $custom_price) / 100;
    if($custom_price > 0 || !empty($custom_price))
        $cart_item_data['percentage'] = $custom_price . "%";



    return $cart_item_data;
}

// Set the new calculated cart item price
add_action('woocommerce_before_calculate_totals', 'extra_price_add_custom_price', 20, 1);
function extra_price_add_custom_price($cart)
{
    if (is_admin() && !defined('DOING_AJAX')) {
        return;
    }

    if (did_action('woocommerce_before_calculate_totals') >= 2) {
        return;
    }

    foreach ($cart->get_cart() as $cart_item) {

        if (isset($cart_item['new_price'])) {
            $cart_item['data']->set_price((float) $cart_item['new_price']);
        }
    }
}

// Display cart item custom price details
add_filter('woocommerce_cart_item_price', 'display_cart_items_custom_price_details', 20, 3);
function display_cart_items_custom_price_details($product_price, $cart_item, $cart_item_key)
{


    if (isset($cart_item['base_price'])) {
        $product = $cart_item['data'];
        $product_price = wc_price(wc_get_price_to_display($product, array('price' => $cart_item['base_price'])));
    }

    return $product_price;
}

// Add order item meta.
add_action('woocommerce_add_order_item_meta', 'add_order_item_meta', 10, 3);
function add_order_item_meta($item_id, $cart_item, $cart_item_key)
{
    if (isset($cart_item['percentage'])) {
        wc_add_order_item_meta($item_id, 'percentage', $cart_item['percentage']);
    }
}

此部分用于编辑购物车页面中的百分比折扣:

//Custom Script Register
function discount_update_cart_scripts()
{
    wp_register_script('discount-cart-script', get_stylesheet_directory_uri() . '/js/discount-cart.js', array('jquery'), time(), true);
    wp_localize_script('discount-cart-script', 'discount_vars', array('ajaxurl' => admin_url('admin-ajax.php')));
    wp_enqueue_script('discount-cart-script');
}
add_action('wp_enqueue_scripts', 'discount_update_cart_scripts');

//Update Discount percentage in cart item 
function discount_update_cart_item()
{
    if (!isset($_POST['wpnonce']) || !wp_verify_nonce($_POST['wpnonce'], 'woocommerce-cart')) {
        wp_send_json(array('status' => 'error', 'message' => 'wp nonce error'));
        exit;
    }

    $cart = WC()->cart->cart_contents;
    $cart_id = $_POST['cart_id'];
    $percentage = $_POST['percentage'];

    if ($percentage > 40) {
        wc_add_notice(__('El descuento debe ser menor a 40%'), 'notice');
        wp_send_json(array('status' => 'error', 'message' => 'percentage error'));
        exit;
    }

    wc_clear_notices();

    $cart_item = $cart[$cart_id];
    $cart_item['new_price'] = $cart_item['base_price'] * (100 - $percentage) / 100;
    $cart_item['percentage'] = $percentage . "%";

    WC()->cart->cart_contents[$cart_id] = $cart_item;
    WC()->cart->set_session();
    wp_send_json(array('status' => 'success'));
    exit;
}
add_action('wp_ajax_discount_update_cart_item', 'discount_update_cart_item');

这是javascript代码:

(function ($) {
    function updateDiscountMeta(cart_id) {
        $.ajax({
            type: 'POST',
            url: discount_vars.ajaxurl,
            data: {
                action: 'discount_update_cart_item',
                wpnonce: $('#woocommerce-cart-nonce').val(),
                percentage: $('#discount_cart_' + cart_id).val(),
                cart_id: cart_id
            },
            success: function (response) {}
        })
    } 
    $('.discount-cart-item').on('change keyup paste', function () {
        var cart_id = $(this).data('cart-id');
        updateDiscountMeta(cart_id);
    });

    $( document.body ).on( 'updated_cart_totals', function(){
        $('.discount-cart-item').on('change keyup paste', function () {
            var cart_id = $(this).data('cart-id');
            updateDiscountMeta(cart_id);
        });
    });
})(jQuery);

这是用于重新订购的部分(我被卡住的地方):

add_filter( 'woocommerce_order_again_cart_item_data', 'order_again_custom', 10, 3 );

function order_again_custom($cart_item_meta, $product, $order){
    //Create an array of all the missing custom field keys that needs to be added in cart item.
    $customfields = [
                    'Titulo1', 
        'percentage',
        'custom_price',
        'price',
        'new_price',
                    ];
    global $woocommerce;
    remove_all_filters( 'woocommerce_add_to_cart_validation' );
    if ( ! array_key_exists( 'item_meta', $cart_item_meta ) || ! is_array( $cart_item_meta['item_meta'] ) )
    foreach ( $customfields as $key ){
        if(!empty($product[$key])){
            $cart_item_meta[$key] = $product[$key];
        }
    }
    return $cart_item_meta;
}
function cs_add_order_again_to_my_orders_actions( $actions, $order ) {
    if ( $order->has_status( 'completed' ) ) {
        $actions['order-again'] = array(
            'url'  => wp_nonce_url( add_query_arg( 'order_again', $order->get_id() ) , 'woocommerce-order_again' ),
            'name' => __( 'Order Again', 'woocommerce' )
        );
    }

    return $actions;
}

add_filter( 'woocommerce_my_account_my_orders_actions', 'cs_add_order_again_to_my_orders_actions', 50, 2 );

购物车页面代码

<?php
/**
 * Cart Page
 *
 * This template can be overridden by copying it to yourtheme/woocommerce/cart/cart.php.
 *
 * HOWEVER, on occasion WooCommerce will need to update template files and you
 * (the theme developer) will need to copy the new files to your theme to
 * maintain compatibility. We try to do this as little as possible, but it does
 * happen. When this occurs the version of the template file will be bumped and
 * the readme will list any important changes.
 *
 * @see     https://docs.woocommerce.com/document/template-structure/
 * @package WooCommerce/Templates
 * @version 3.8.0
 */
defined( 'ABSPATH' ) || exit;
do_action( 'woocommerce_before_cart' ); ?>

<form class="woocommerce-cart-form" action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post">
    <?php do_action( 'woocommerce_before_cart_table' ); ?>

    <table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents" cellspacing="0">
        <thead>
            <tr>
                <th class="product-remove">&nbsp;</th>
                <th class="product-thumbnail">&nbsp;</th>
                <th class="product-name"><?php esc_html_e( 'Product', 'woocommerce' ); ?></th>
                <th class="product-price"><?php esc_html_e( 'Price', 'woocommerce' ); ?></th>
                <th class="product-quantity"><?php esc_html_e( 'Quantity', 'woocommerce' ); ?></th>
                <th class="product-quantity"><?php esc_html_e( 'Descuento', 'woocommerce' ); ?></th>
                <th class="product-subtotal"><?php esc_html_e( 'Total', 'woocommerce' ); ?></th>
            </tr>
        </thead>
        <tbody>
            <?php do_action( 'woocommerce_before_cart_contents' ); ?>

            <?php
            foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
                $_product   = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
                $product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
                if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
                    $product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
                    ?>
                    <tr class="woocommerce-cart-form__cart-item <?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">

                        <td class="product-remove">
                            <?php
                                echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
                                    'woocommerce_cart_item_remove_link',
                                    sprintf(
                                        '<a href="%s" class="remove" aria-label="%s" data-product_id="%s" data-product_sku="%s">&times;</a>',
                                        esc_url( wc_get_cart_remove_url( $cart_item_key ) ),
                                        esc_html__( 'Remove this item', 'woocommerce' ),
                                        esc_attr( $product_id ),
                                        esc_attr( $_product->get_sku() )
                                    ),
                                    $cart_item_key
                                );
                            ?>
                        </td>

                        <td class="product-thumbnail">
                        <?php
                        $thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
                        if ( ! $product_permalink ) {
                            echo $thumbnail; // PHPCS: XSS ok.
                        } else {
                            printf( '<a href="%s">%s</a>', esc_url( $product_permalink ), $thumbnail ); // PHPCS: XSS ok.
                        }
                        ?>
                        </td>

                        <td class="product-name" data-title="<?php esc_attr_e( 'Product', 'woocommerce' ); ?>">
                        <?php
                        if ( ! $product_permalink ) {
                            echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . '&nbsp;' );
                        } else {
                            echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '<a href="%s">%s</a>', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
                        }
                        do_action( 'woocommerce_after_cart_item_name', $cart_item, $cart_item_key );
                        // Meta data.
                        echo wc_get_formatted_cart_item_data( $cart_item ); // PHPCS: XSS ok.
                        // Backorder notification.
                        if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $cart_item['quantity'] ) ) {
                            echo wp_kses_post( apply_filters( 'woocommerce_cart_item_backorder_notification', '<p class="backorder_notification">' . esc_html__( 'Available on backorder', 'woocommerce' ) . '</p>', $product_id ) );
                        }
                        ?>
                        </td>

                        <td class="product-price" data-title="<?php esc_attr_e( 'Price', 'woocommerce' ); ?>">
                            <?php
                                echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
                            ?>
                        </td>

                        <td class="product-quantity" data-title="<?php esc_attr_e( 'Quantity', 'woocommerce' ); ?>">
                        <?php
                        if ( $_product->is_sold_individually() ) {
                            $product_quantity = sprintf( '1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
                        } else {
                            $product_quantity = woocommerce_quantity_input(
                                array(
                                    'input_name'   => "cart[{$cart_item_key}][qty]",
                                    'input_value'  => $cart_item['quantity'],
                                    'max_value'    => $_product->get_max_purchase_quantity(),
                                    'min_value'    => '0',
                                    'product_name' => $_product->get_name(),
                                ),
                                $_product,
                                false
                            );
                        }
                        echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item ); // PHPCS: XSS ok.
                        ?>
                        </td>
                        <td class="product-quantity" data-title="<?php esc_attr_e( 'Discount', 'woocommerce' ); ?>">
                            <!--label for="discount"><?php esc_html_e( 'Discount:', 'woocommerce' ); ?></label> <input type="text" name="discount" class="input-text" id="discount_code" value="" placeholder="<?php esc_attr_e( 'dscto', 'woocommerce' ); ?>" /-->
                                <span>Dscto %:</span>
                                <input class="discount-cart-item" type="text" id="discount_cart_<?php echo $cart_item_key; ?>" class="input-text text" data-cart-id="<?php echo $cart_item_key; ?>" value="<?php echo ( isset( $cart_item[ 'percentage' ] ) ) ? substr($cart_item['percentage'], 0, -1) : ''; ?>" title="<?php esc_attr_e( 'Descuento', 'woocommerce' ); ?>" size="4" placeholder="e.g. 10">
                        </td>

                        <td class="product-subtotal" data-title="<?php esc_attr_e( 'Total', 'woocommerce' ); ?>">
                            <?php
                                echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
                            ?>
                        </td>
                    </tr>
                    <?php
                }
            }
            ?>

            <?php do_action( 'woocommerce_cart_contents' ); ?>

            <tr>
                <td colspan="6" class="actions">

                    <?php if ( wc_coupons_enabled() ) { ?>
                        <div class="coupon">
                            <label for="coupon_code"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>" /> <button type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?></button>
                            <?php do_action( 'woocommerce_cart_coupon' ); ?>
                        </div>
                    <?php } ?>

                    <button type="submit" class="button" name="update_cart" value="<?php esc_attr_e( 'Update cart', 'woocommerce' ); ?>"><?php esc_html_e( 'Update cart', 'woocommerce' ); ?></button>

                    <?php do_action( 'woocommerce_cart_actions' ); ?>

                    <?php wp_nonce_field( 'woocommerce-cart', 'woocommerce-cart-nonce' ); ?>
                </td>
            </tr>

            <?php do_action( 'woocommerce_after_cart_contents' ); ?>
        </tbody>
    </table>
    <?php do_action( 'woocommerce_after_cart_table' ); ?>
</form>

<?php do_action( 'woocommerce_before_cart_collaterals' ); ?>

<div class="cart-collaterals">
    <?php
        /**
         * Cart collaterals hook.
         *
         * @hooked woocommerce_cross_sell_display
         * @hooked woocommerce_cart_totals - 10
         */
        do_action( 'woocommerce_cart_collaterals' );
    ?>
</div>

<?php do_action( 'woocommerce_after_cart' ); ?>

我做错了什么?有什么想法吗?

【问题讨论】:

    标签: php jquery ajax woocommerce cart


    【解决方案1】:

    您没有将所有必需的购物车商品数据保存为自定义订单商品元数据,因此在使用“再次订购”时,一些自定义购物车商品数据会丢失,并且您的价格计算不会被应用。

    还有woocommerce_add_order_item_meta钩子是deprecated since WooCommerce 3

    注意:使用您提供的代码,我无法更改购物车页面中的百分比,因此可能缺少某些内容。

    您需要在代码中删除/替换以下函数:

    // Add order item meta.
    add_action('woocommerce_add_order_item_meta', 'add_order_item_meta', 10, 3);
    function add_order_item_meta($item_id, $cart_item, $cart_item_key)
    {
        if (isset($cart_item['percentage'])) {
            wc_add_order_item_meta($item_id, 'percentage', $cart_item['percentage']);
        }
    }
    

    还有这个:

    add_filter( 'woocommerce_order_again_cart_item_data', 'order_again_custom', 10, 3 );
    
    function order_again_custom($cart_item_meta, $product, $order){
        //Create an array of all the missing custom field keys that needs to be added in cart item.
        $customfields = [
                        'Titulo1', 
            'percentage',
            'custom_price',
            'price',
            'new_price',
                        ];
        global $woocommerce;
        remove_all_filters( 'woocommerce_add_to_cart_validation' );
        if ( ! array_key_exists( 'item_meta', $cart_item_meta ) || ! is_array( $cart_item_meta['item_meta'] ) )
        foreach ( $customfields as $key ){
            if(!empty($product[$key])){
                $cart_item_meta[$key] = $product[$key];
            }
        }
        return $cart_item_meta;
    }
    

    通过以下的:

    // Save custom cart item data as custom order item meta data
    add_action( 'woocommerce_checkout_create_order_line_item', 'add_order_item_meta', 10, 4 );
    function add_order_item_meta( $item, $cart_item_key, $values, $order ) {
        
        // Save and display the "Percentage" (optional - if needed)
        if (isset($values['percentage'])) {
            $item->update_meta_data( 'Percentage', $values['percentage'] ); 
        }
    
        // Save All custom cart item data as a hidden data array (important)
        if (isset($values['percentage']) && isset($values['base_price']) && isset($values['new_price']) ) {
            $custom_data = array(
                'percentage' => $values['percentage'],
                'base_price' => $values['base_price'],
                'new_price'  => $values['new_price'],
            );
            $item->update_meta_data( '_custom_data', $custom_data ); // save
        }
    }
    
    // Add custom order item meta as custom cart item meta
    add_filter( 'woocommerce_order_again_cart_item_data', 'custom_cart_item_data_for_order_again', 10, 3 );
    function custom_cart_item_data_for_order_again( $cart_item_meta, $item, $order ) {
        // Get the hidden order item data
        $custom_data = (array) $item->get_meta( '_custom_data' );
    
        if( ! empty($custom_data) ) {
            $cart_item_meta = array_merge( $cart_item_meta, $custom_data );
        }
        return $cart_item_meta;
    }
    

    代码进入您的活动子主题(或活动主题)的 function.php 文件中。经过测试并且可以工作。

    【讨论】:

    • 谢谢你是救命稻草,一切正常!!是的,我忘了添加购物车页面的代码(我已经添加它以防万一有人想使用它)
    猜你喜欢
    • 1970-01-01
    • 2019-02-01
    • 2019-02-02
    • 2018-10-31
    • 1970-01-01
    • 2019-12-21
    • 2017-04-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多