有没有办法将自定义代码添加到公共静态函数中? (woocommerce update_order_review)
Posted
技术标签:
【中文标题】有没有办法将自定义代码添加到公共静态函数中? (woocommerce update_order_review)【英文标题】:Is there a way to add custom code into a public static function? (woocommerce update_order_review) 【发布时间】:2021-10-26 23:25:16 【问题描述】:我已在我的 woocommerce 结帐页面中添加了购物车部分。现在我想用 ajax 更新购物车。 (如果有人改变了他的国家......)
到目前为止,我已经尝试在“update_checkout”上创建一个 ajax 调用,但我遇到的问题是我无法从 ajax 获取新数据。
唯一有效的方法是在我编辑核心 woocommerce public static function update_order_review()
时。有什么办法可以用我的插件连接到它以将我的代码添加到这个函数中?我需要补充:
// Get cart fragment. CUSTOM
ob_start();
woocommerce_order_cart();
$woocommerce_order_cart = ob_get_clean();
然后将此片段放入 wp_send_json() 函数中:
wp_send_json(
array(
'result' => empty( $messages ) ? 'success' : 'failure',
'messages' => $messages,
'reload' => $reload_checkout,
'fragments' => apply_filters(
'woocommerce_update_order_review_fragments',
array(
'.woocommerce-cart-form__contents' => $woocommerce_order_cart,/* CUSTOM */
'.woocommerce-checkout-review-order-table' => $woocommerce_order_review,
'.woocommerce-checkout-payment' => $woocommerce_checkout_payment,
)
),
)
);
这是整个函数:
/**
* AJAX update order review on checkout.
*/
public static function update_order_review()
check_ajax_referer( 'update-order-review', 'security' );
wc_maybe_define_constant( 'WOOCOMMERCE_CHECKOUT', true );
if ( WC()->cart->is_empty() && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_update_order_review_expired', true ) )
self::update_order_review_expired();
do_action( 'woocommerce_checkout_update_order_review', isset( $_POST['post_data'] ) ? wp_unslash( $_POST['post_data'] ) : '' ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' );
$posted_shipping_methods = isset( $_POST['shipping_method'] ) ? wc_clean( wp_unslash( $_POST['shipping_method'] ) ) : array();
if ( is_array( $posted_shipping_methods ) )
foreach ( $posted_shipping_methods as $i => $value )
$chosen_shipping_methods[ $i ] = $value;
WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods );
WC()->session->set( 'chosen_payment_method', empty( $_POST['payment_method'] ) ? '' : wc_clean( wp_unslash( $_POST['payment_method'] ) ) );
WC()->customer->set_props(
array(
'billing_country' => isset( $_POST['country'] ) ? wc_clean( wp_unslash( $_POST['country'] ) ) : null,
'billing_state' => isset( $_POST['state'] ) ? wc_clean( wp_unslash( $_POST['state'] ) ) : null,
'billing_postcode' => isset( $_POST['postcode'] ) ? wc_clean( wp_unslash( $_POST['postcode'] ) ) : null,
'billing_city' => isset( $_POST['city'] ) ? wc_clean( wp_unslash( $_POST['city'] ) ) : null,
'billing_address_1' => isset( $_POST['address'] ) ? wc_clean( wp_unslash( $_POST['address'] ) ) : null,
'billing_address_2' => isset( $_POST['address_2'] ) ? wc_clean( wp_unslash( $_POST['address_2'] ) ) : null,
)
);
if ( wc_ship_to_billing_address_only() )
WC()->customer->set_props(
array(
'shipping_country' => isset( $_POST['country'] ) ? wc_clean( wp_unslash( $_POST['country'] ) ) : null,
'shipping_state' => isset( $_POST['state'] ) ? wc_clean( wp_unslash( $_POST['state'] ) ) : null,
'shipping_postcode' => isset( $_POST['postcode'] ) ? wc_clean( wp_unslash( $_POST['postcode'] ) ) : null,
'shipping_city' => isset( $_POST['city'] ) ? wc_clean( wp_unslash( $_POST['city'] ) ) : null,
'shipping_address_1' => isset( $_POST['address'] ) ? wc_clean( wp_unslash( $_POST['address'] ) ) : null,
'shipping_address_2' => isset( $_POST['address_2'] ) ? wc_clean( wp_unslash( $_POST['address_2'] ) ) : null,
)
);
else
WC()->customer->set_props(
array(
'shipping_country' => isset( $_POST['s_country'] ) ? wc_clean( wp_unslash( $_POST['s_country'] ) ) : null,
'shipping_state' => isset( $_POST['s_state'] ) ? wc_clean( wp_unslash( $_POST['s_state'] ) ) : null,
'shipping_postcode' => isset( $_POST['s_postcode'] ) ? wc_clean( wp_unslash( $_POST['s_postcode'] ) ) : null,
'shipping_city' => isset( $_POST['s_city'] ) ? wc_clean( wp_unslash( $_POST['s_city'] ) ) : null,
'shipping_address_1' => isset( $_POST['s_address'] ) ? wc_clean( wp_unslash( $_POST['s_address'] ) ) : null,
'shipping_address_2' => isset( $_POST['s_address_2'] ) ? wc_clean( wp_unslash( $_POST['s_address_2'] ) ) : null,
)
);
if ( isset( $_POST['has_full_address'] ) && wc_string_to_bool( wc_clean( wp_unslash( $_POST['has_full_address'] ) ) ) )
WC()->customer->set_calculated_shipping( true );
else
WC()->customer->set_calculated_shipping( false );
WC()->customer->save();
// Calculate shipping before totals. This will ensure any shipping methods that affect things like taxes are chosen prior to final totals being calculated. Ref: #22708.
WC()->cart->calculate_shipping();
WC()->cart->calculate_totals();
// Get order review fragment.
ob_start();
woocommerce_order_review();
$woocommerce_order_review = ob_get_clean();
// Get cart fragment. CUSTOM
ob_start();
woocommerce_order_cart();
$woocommerce_order_cart = ob_get_clean();
// Get checkout payment fragment.
ob_start();
woocommerce_checkout_payment();
$woocommerce_checkout_payment = ob_get_clean();
// Get messages if reload checkout is not true.
$reload_checkout = isset( WC()->session->reload_checkout );
if ( ! $reload_checkout )
$messages = wc_print_notices( true );
else
$messages = '';
unset( WC()->session->refresh_totals, WC()->session->reload_checkout );
wp_send_json(
array(
'result' => empty( $messages ) ? 'success' : 'failure',
'messages' => $messages,
'reload' => $reload_checkout,
'fragments' => apply_filters(
'woocommerce_update_order_review_fragments',
array(
'.woocommerce-cart-form__contents' => $woocommerce_order_cart,/* CUSTOM */
'.woocommerce-checkout-review-order-table' => $woocommerce_order_review,
'.woocommerce-checkout-payment' => $woocommerce_checkout_payment,
)
),
)
);
【问题讨论】:
如果这个地方没有do_action是不可能的。 您也许可以尝试在woocommerce_update_order_review_fragments
过滤器中执行此操作,该过滤器将在wp_send_json
调用的最后应用。在未修改的版本中,它获取一个仅传入两个键的数组 - 但您可以在其中添加第三个自定义键。 woocommerce_order_cart()
在没有任何参数的情况下被调用,所以我希望它也可以在不同的上下文中调用。
【参考方案1】:
好了,终于搞定了。
首先我创建了一个函数来调用我的购物车模板(它与订单审查模板的方式基本相同)
if ( ! function_exists( 'woocommerce_order_cart' ) )
/**
* Output the Cart table for the checkout.
*
* @param bool $deprecated Deprecated param.
*/
function bb_order_cart( $deprecated = false )
include(plugin_dir_path( __FILE__ ).'assets/templates/woocommerce/cart/bb-cart-summary-ajax.php');
;
;
之后,我将购物车部分复制到该文件中。
<?php
/**
* BB Cart Summary
*
*
* @see https://docs.woocommerce.com/document/template-structure/
* @package WooCommerce\Templates
* @version 5.2.0
*/
defined( 'ABSPATH' ) || exit;
?>
<table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents" cellspacing="0">
<tbody>
<?php do_action( 'woocommerce_before_cart_contents' );
$i = 0;
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-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.
;?>
<div class="item_quantity_container">
<?php echo $cart_item['quantity'];?>
</div>
</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 ) . ' ' );
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 ) );
$item_meta_bb = get_field( "wc_bb_prd_cart_input", $product_id );
?> <div class="prd_cart_item_meta"><?php
echo $item_meta_bb;
?></div><?php
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-subtotal" data-title="<?php esc_attr_e( 'Subtotal', '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
$i++;
?>
<?php if ($i > '2')?>
<style type="text/css">.cart_table width: 102%;</style><?php ;?>
<?php do_action( 'woocommerce_cart_contents' ); ?>
<?php do_action( 'woocommerce_after_cart_contents' ); ?>
</tbody>
</table>
好的。现在我可以运行以在我的结帐中获取购物车模板。现在我们进入更难的部分,ajax 处理程序。
我创建了一个名为“refresh_cart.js”的新文件并对其进行了初始化。
function changeCart()
if ( is_checkout() )
wp_enqueue_script( 'wc-update-checkout-cart', plugins_url( '/js/refresh_cart.js', __FILE__ ), array('jquery'), '', true);
wp_localize_script( 'wc-update-checkout-cart', 'refresh_cart',
array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
) );
add_action( 'wp_footer', 'changeCart', 10 );
我已将 wc js 中的重要部分复制到该文件中。
/* global wc_checkout_params */
jQuery( function( $ )
// wc_checkout_params is required to continue, ensure the object exists
if ( typeof wc_checkout_params === 'undefined' )
return false;
$.blockUI.defaults.overlayCSS.cursor = 'default';
var wc_checkout_form =
updateTimer: false,
dirtyInput: false,
selectedPaymentMethod: false,
xhr: false,
$order_review: $( '#order_review' ),
$checkout_form: $( 'form.checkout' ),
init: function()
$( document.body ).on( 'update_checkout', this.update_checkout );
$( document.body ).on( 'init_checkout', this.init_checkout );
// Update on page load
if ( wc_checkout_params.is_checkout === '1' )
$( document.body ).trigger( 'init_checkout' );
if ( wc_checkout_params.option_guest_checkout === 'yes' )
$( 'input#createaccount' ).on( 'change', this.toggle_create_account ).trigger( 'change' );
,
reset_update_checkout_timer: function()
clearTimeout( wc_checkout_form.updateTimer );
,
update_checkout: function( event, args )
// Small timeout to prevent multiple requests when several fields update at the same time
wc_checkout_form.reset_update_checkout_timer();
wc_checkout_form.updateTimer = setTimeout( wc_checkout_form.update_checkout_action, '5', args );
,
update_checkout_action: function( args )
if ( wc_checkout_form.xhr )
wc_checkout_form.xhr.abort();
if ( $( 'form.checkout' ).length === 0 )
return;
args = typeof args !== 'undefined' ? args :
update_shipping_method: true
;
var data =
post_data : $( 'form.checkout' ).serialize()
;
$( '.woocommerce-checkout-payment, .woocommerce-checkout-review-order-table, .woocommerce-cart-form__contents' ).block(
message: null,
overlayCSS:
background: '#fff',
opacity: 0.6
);
var country = $( '#billing_country' ).val(),
state = $( '#billing_state' ).val(),
postcode = $( ':input#billing_postcode' ).val(),
city = $( '#billing_city' ).val(),
address = $( ':input#billing_address_1' ).val(),
address_2 = $( ':input#billing_address_2' ).val(),
s_country = country,
s_state = state,
s_postcode = postcode,
s_city = city,
s_address = address,
s_address_2 = address_2,
$required_inputs = $( wc_checkout_form.$checkout_form ).find( '.address-field.validate-required:visible' ),
has_full_address = true;
if ( $required_inputs.length )
$required_inputs.each( function()
if ( $( this ).find( ':input' ).val() === '' )
has_full_address = false;
);
if ( $( '#ship-to-different-address' ).find( 'input' ).is( ':checked' ) )
s_country = $( '#shipping_country' ).val();
s_state = $( '#shipping_state' ).val();
s_postcode = $( ':input#shipping_postcode' ).val();
s_city = $( '#shipping_city' ).val();
s_address = $( ':input#shipping_address_1' ).val();
s_address_2 = $( ':input#shipping_address_2' ).val();
var data =
action: 'bb_update_order_review',
security: wc_checkout_params.update_order_review_nonce,
country : country,
state : state,
postcode : postcode,
city : city,
address : address,
address_2 : address_2,
s_country : s_country,
s_state : s_state,
s_postcode : s_postcode,
s_city : s_city,
s_address : s_address,
s_address_2 : s_address_2,
has_full_address: has_full_address,
post_data : $( 'form.checkout' ).serialize()
;
wc_checkout_form.xhr = $.ajax(
type: "POST",
url: wc_checkout_params.ajax_url,
data: data,
success: function( data )
console.log(data);
// Always update the fragments
if ( data && data.fragments )
$.each( data.fragments, function ( key, value )
if ( ! wc_checkout_form.fragments || wc_checkout_form.fragments[ key ] !== value )
$( key ).replaceWith( value );
$( key ).unblock();
);
wc_checkout_form.fragments = data.fragments;
// Fire updated_checkout event.
$( document.body ).trigger( 'updated_checkout', [ data ] );
);
,
;
wc_checkout_form.init();
);
现在我们需要为我们在 refresh_cart.js 文件中调用的函数添加 ajax 操作。
add_action( 'wp_ajax_bb_update_order_review', 'bb_update_order_review' );
add_action( 'wp_ajax_nopriv_bb_update_order_review', 'bb_update_order_review' );
现在我们只需要重新创建 public static function update_order_review()
函数即可使其正常工作:
function bb_update_order_review()
WC()->customer->set_props(
array(
'billing_country' => isset( $_POST['country'] ) ? wc_clean( wp_unslash( $_POST['country'] ) ) : null,
)
);
if ( wc_ship_to_billing_address_only() )
WC()->customer->set_props(
array(
'shipping_country' => isset( $_POST['country'] ) ? wc_clean( wp_unslash( $_POST['country'] ) ) : null,
)
);
else
WC()->customer->set_props(
array(
'shipping_country' => isset( $_POST['s_country'] ) ? wc_clean( wp_unslash( $_POST['s_country'] ) ) : null,
)
);
WC()->customer->save();
// Calculate shipping before totals. This will ensure any shipping methods that affect things like taxes are chosen prior to final totals being calculated. Ref: #22708.
WC()->cart->calculate_shipping();
WC()->cart->calculate_totals();
// Get cart fragment. BEERBALLER
ob_start();
bb_order_cart();
$bb_order_cart = ob_get_clean();
/* $reload_checkout = isset( WC()->session->reload_checkout );
WC()->session->reload_checkout;
unset( WC()->session->refresh_totals, WC()->session->reload_checkout );
*/
wp_send_json(
array(
'result' => empty( $messages ) ? 'success' : 'failure',
'messages' => $messages,
'reload' => $reload_checkout,
'fragments' => apply_filters(
'woocommerce_update_order_review_fragments',
array(
'.woocommerce-cart-form__contents' => $bb_order_cart,/* BEERBALLER */
)
),
)
);
就是这样!
【讨论】:
以上是关于有没有办法将自定义代码添加到公共静态函数中? (woocommerce update_order_review)的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法将自定义 QGroupBox 添加到任何小部件/布局?
将自定义中间件添加到 Laravel Passport 端点