Я написал плагин WooCommerce для добавления точек обслуживания SF Express на страницу блокировки оформления заказа. Раскрывающийся список отображается правильно, но выбранная опция не передается в PHP, поэтому примечания к заказу не отражают выбранную точку обслуживания. Ниже приведены соответствующие фрагменты моего кода PHP и JS. Я попытался зарегистрировать данные POST, и кажется, что выбранный параметр неправильно передается функции PHP. Любые идеи или предложения о том, что может быть не так?
PHP-код:
<?php
if (!defined('ABSPATH')) {
exit;
}
if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
function sf_express_shipping_method_init() {
if (!class_exists('WC_Shipping_SF_Express')) {
class WC_Shipping_SF_Express extends WC_Shipping_Method {
public function __construct() {
$this->id = 'sf_express';
$this->method_title = __('SF Express Service Points', 'sf_express');
$this->method_description = __('Allows customers to pick up parcels from SF Express Service Points.', 'sf_express');
$this->init();
}
function init() {
$this->init_form_fields();
$this->init_settings();
$this->enabled = $this->get_option('enabled');
$this->title = $this->get_option('title');
add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
}
function init_form_fields() {
$this->form_fields = array(
'enabled' => array(
'title' => __('Enable/Disable', 'sf_express'),
'type' => 'checkbox',
'label' => __('Enable SF Express Service Points', 'sf_express'),
'default' => 'yes'
),
'title' => array(
'title' => __('Title', 'sf_express'),
'type' => 'text',
'description' => __('This controls the title which the user sees during checkout.', 'sf_express'),
'default' => __('SF Express Service Points', 'sf_express'),
'desc_tip' => true,
),
'service_points_csv' => array(
'title' => __('Service Points CSV', 'sf_express'),
'type' => 'textarea',
'description' => __('Paste the contents of your service points CSV file here.', 'sf_express'),
'default' => '',
),
);
}
public function calculate_shipping($package = array()) {
$rate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => '0',
'calc_tax' => 'per_order'
);
$this->add_rate($rate);
}
}
}
}
add_action('woocommerce_shipping_init', 'sf_express_shipping_method_init');
add_filter('woocommerce_shipping_methods', function($methods) {
$methods['sf_express'] = 'WC_Shipping_SF_Express';
return $methods;
});
add_action('wp_enqueue_scripts', function() {
wp_enqueue_script('sf_express', plugins_url('/sf-express.js', __FILE__), array('jquery'), '1.0', true);
wp_localize_script('sf_express', 'sf_express_params', array(
'ajax_url' => admin_url('admin-ajax.php')
));
});
// AJAX Handler for fetching service points
add_action('wp_ajax_fetch_sf_express_service_points', 'fetch_sf_express_service_points');
add_action('wp_ajax_nopriv_fetch_sf_express_service_points', 'fetch_sf_express_service_points');
function fetch_sf_express_service_points() {
$options = get_option('woocommerce_sf_express_settings');
$csv_data = $options['service_points_csv'];
$lines = explode("\n", $csv_data);
$html = '';
foreach ($lines as $line) {
$parts = explode(',', trim($line));
if (count($parts) >= 2) {
$html .= '<option value = "' . esc_attr(trim($parts[0])) . '">' . esc_html(trim($parts[1])) . '</option>';
}
}
echo $html;
wp_die();
}
add_action('woocommerce_checkout_create_order', function($order, $data) {
// Log the posted service point value
error_log('Selected SF Express Service Point: ' . print_r($_POST['sf_express_service_point'], true));
if (!empty($_POST['sf_express_service_point'])) {
$service_point = sanitize_text_field($_POST['sf_express_service_point']);
$order->update_meta_data('sf_express_service_point', $service_point);
$note = 'SF Express Service Point: ' . $service_point;
$order->add_order_note($note);
}
}, 10, 2);
function debugging( $order_id ) {
$order = wc_get_order( $order_id );
// Log the POST data for debugging
error_log('POST Data: ' . print_r($_POST, true));
if (isset($_POST['sf_express_service_point']) && !empty($_POST['sf_express_service_point'])) {
$service_point = sanitize_text_field($_POST['sf_express_service_point']);
error_log('Service Point: ' . $service_point); // Debug logging
$order->update_meta_data('sf_express_service_point', $service_point);
$note = 'Testing: ' . $service_point;
$order->add_order_note($note);
$order->save();
} else {
$note = 'Testing: Service point not set';
$order->add_order_note($note);
$order->save();
}
}
add_action('woocommerce_thankyou', 'debugging', 10, 1);
add_action('woocommerce_checkout_process', function() {
if (empty($_POST['sf_express_service_point']) && isset($_POST['shipping_method'][0]) && $_POST['shipping_method'][0] === 'sf_express') {
wc_add_notice(__('Please select an SF Express Service Point.', 'sf_express'), 'error');
}
});
add_action('woocommerce_admin_order_data_after_billing_address', function($order) {
$service_point = $order->get_meta('sf_express_service_point');
if ($service_point) {
echo '<p><strong>' . __('SF Express Service Point', 'sf_express') . ':</strong> ' . esc_html($service_point) . '</p>';
}
});
add_filter('woocommerce_email_order_meta_fields', function($fields, $sent_to_admin, $order) {
$service_point = $order->get_meta('sf_express_service_point');
if ($service_point) {
$fields['sf_express_service_point'] = array(
'label' => __('SF Express Service Point', 'sf_express'),
'value' => esc_html($service_point),
);
}
return $fields;
}, 10, 3);
add_action('woocommerce_order_details_after_order_table', function($order) {
$service_point = $order->get_meta('sf_express_service_point');
if ($service_point) {
echo '<p><strong>' . __('SF Express Service Point', 'sf_express') . ':</strong> ' . esc_html($service_point) . '</p>';
}
});
}
JS-код:
jQuery(document).ready(function($) {
console.info('SF Express script loaded');
function addServicePointField() {
console.info('Checking if service point field needs to be added');
if ($('#sf_express_service_point').length === 0) {
console.info('Adding service point field');
var servicePointFieldHtml = '<div class = "form-row form-row-wide">' +
'<label for = "sf_express_service_point">' +
'SF Express Service Point' +
'</label>' +
'<select id = "sf_express_service_point" name = "sf_express_service_point" class = "select">' +
'<option value = "">Select a service point</option>' +
'</select>' +
'</div>';
// Append to the shipping method container
$('.wc-block-components-shipping-rates-control__package').append(servicePointFieldHtml);
updateServicePointField(); // Fetch and update the dropdown
}
}
function removeServicePointField() {
console.info('Removing service point field if it exists');
$('#sf_express_service_point').parent().remove();
}
function updateServicePointField() {
console.info('Fetching updated service points');
$.ajax({
url: sf_express_params.ajax_url,
type: 'POST',
data: {
action: 'fetch_sf_express_service_points'
},
success: function(response) {
console.info('Service points fetched successfully');
$('#sf_express_service_point').html(response);
}
});
}
// Initial call with a delay to ensure all dynamic elements are rendered
setTimeout(addServicePointField, 1000);
// Re-add the service point field when the shipping method changes
$(document).on('change', 'input[name = "shipping_method[0]"]', function() {
var shippingMethod = $(this).val();
if (shippingMethod === 'sf_express') {
addServicePointField();
} else {
removeServicePointField();
}
});
// Ensure the field is included in the form submission
$('form.checkout').on('checkout_place_order', function() {
var servicePoint = $('#sf_express_service_point').val();
console.info('Selected service point: ' + servicePoint); // Debugging
if (servicePoint) {
$('<input>').attr({
type: 'hidden',
name: 'sf_express_service_point',
value: servicePoint
}).appendTo('form.checkout');
} else {
console.info('No service point selected');
}
});
// Trigger the addServicePointField function when the page loads and shipping method is already selected
if ($('input[name = "shipping_method[0]"]:checked').val() === 'sf_express') {
addServicePointField();
}
});
Селектор точек обслуживания отображается, но выбранная опция не сохраняется вместе с заказом. Я попытался зарегистрировать данные POST, и кажется, что выбранная опция не передается функции PHP правильно. Любые идеи или предложения о том, что может быть не так?






Во-первых, поскольку вы используете блок WooCommerce Checkout, обратите внимание, что он допускает очень мало настроек.
Вы не сможете получить выбранную «Точку обслуживания», чтобы сохранить ее как метаданные заказа, а также не сможете проверить поле, если значение не выбрано.
Кроме того, в вашем коде есть несколько ошибок.
Решение: использование переменных WC_Session.
Вместо этого вы можете сохранить выбранную «точку обслуживания» в переменной сеанса.
Поскольку вы не можете проверить это настраиваемое поле, единственный способ — удалить пустую опцию, чтобы у вас всегда было значение.
Кроме того, вместо отображения параметров через Ajax вы можете отобразить полное поле выбора, при этом все параметры с самого начала будут скрыты. Затем показываем или скрываем поле в зависимости от выбранного способа доставки.
Если клиент выбрал «SF Express» в качестве способа доставки, мы сохраняем выбранную «Точку обслуживания» через Ajax в переменной WC_Session.
Затем при отправке данных, если выбран метод доставки «SF Express», мы можем получить выбранную «Точку обслуживания» из переменной WC_Session.
Обратите внимание, что следующие перехватчики, похоже, не работают с блоками Checkout:
woocommerce_checkout_create_order,woocommerce_checkout_update_order_meta,woocommerce_checkout_order_created.Но хук woocommerce_checkout_create_order_shipping_item работает, поэтому мы его используем, чтобы сохранить выбранную «Точку обслуживания».
Код вашего метода class WC_Shipping_SF_Express останется неизменным. Мы меняем все остальное.
Обратите внимание, что следующий код следует использовать только с блоком проверки WooCommerce:
// Helper function: Get service points in a clean formatted array
function get_formatted_service_points_array() {
$sf_express_settings = get_option('woocommerce_sf_express_settings');
$service_points_csv = isset($sf_express_settings['service_points_csv']) ? $sf_express_settings['service_points_csv'] : null;
if ( ! $service_points_csv ) {
return false;
}
$service_points = (array) explode("\n", $service_points_csv);
if ( ! $service_points ) {
return false;
}
$service_point_array = array(); // Initializing
foreach( $service_points as $service_point ) {
$option = (array) explode(',', trim($service_point));
if ( isset($option[0], $option[1]) && !empty($option[0]) && !empty($option[1]) ) {
$service_point_array[esc_attr($option[0])] = esc_html($option[1]);
}
}
return $service_point_array;
}
// JQuery: Display Service Point field, show/hide the field and Send Ajax request
add_action('woocommerce_checkout_init', 'sf_express_checkout_init_js');
function sf_express_checkout_init_js() {
$service_points = get_formatted_service_points_array();
if ( ! $service_points ) return; // exit
$chosen_point = WC()->session->get('chosen_service_point');
$field_html = '<div class = "form-row form-row-wide" id = "sf_express_service_point_field" style = "margin-top:12px; display:none">' .
'<label for = "sf_express_service_point">' . __('Select a Service Point') . '</label>
<select id = "sf_express_service_point" name = "sf_express_service_point" class = "wc-select">';
foreach( $service_points as $option => $label ) {
$selected = $option === $chosen_point ? ' selected' : '';
$field_html .= sprintf('<option value = "%s" %s>%s</option>', $option, $selected, $label);
}
$field_html .= '</select></div>';
wc_enqueue_js( "var chosenShipping;
const shippingOpSel = '.wc-block-checkout__shipping-option input';
function saveChosenServicePointViaAjax( value ) {
const blockWhite = {message: null, overlayCSS: {background: '#fff', opacity: 0.6}};
formSel = 'form.wc-block-checkout__form';
$(formSel).block(blockWhite);
$.ajax({
url: '" . admin_url('/admin-ajax.php') . "',
type: 'POST',
data: {
'action': 'chosen_sf_express_service_point',
'service_point': value
},
success: function(response) {
$(formSel).unblock();
console.info('Chosen Service Point saved: '+response); // To be removed (for testing)
}
});
}
// On start (lightly delayed):
setTimeout(function(){
// Append the service points select field (hidden)
$('.wc-block-components-shipping-rates-control__package').append('{$field_html}');
chosenShipping = $(shippingOpSel+':checked').val();
// show service points if the chosen shipping method is 'sf_express'
if ( $(shippingOpSel+':checked').val() === 'sf_express' ) {
$('#sf_express_service_point_field').show();
saveChosenServicePointViaAjax( $('#sf_express_service_point').val() );
}
console.info('Chosen shipping (start): '+$(shippingOpSel+':checked').val()); // To be removed (for testing)
}, 100);
// On change: show or hide service points based on the chosen shipping method
$(document.body).on('change', '.wc-block-checkout__shipping-option input', function() {
chosenShipping = $(this).val();
if (chosenShipping === 'sf_express') {
$('#sf_express_service_point_field').show();
saveChosenServicePointViaAjax( $('#sf_express_service_point').val() );
} else {
$('#sf_express_service_point_field').hide();
}
console.info('Chosen shipping (change): '+chosenShipping); // To be removed (for testing)
});
// On change: When choosing a service point
$(document.body).on('change', '#sf_express_service_point', function() {
console.info('Chosen point (change): '+$(this).val()); // To be removed (for testing)
saveChosenServicePointViaAjax( $(this).val() );
});");
}
// AJAX Handler for fetching service points
add_action('wp_ajax_chosen_sf_express_service_point', 'save_chosen_service_point_in_session');
add_action('wp_ajax_nopriv_chosen_sf_express_service_point', 'save_chosen_service_point_in_session');
function save_chosen_service_point_in_session() {
if ( isset($_POST['service_point']) ) {
$service_point = esc_attr($_POST['service_point']);
WC()->session->set('chosen_service_point', $service_point); // Set value in a session variable
}
wp_die(isset($service_point) ? $service_point : 'Error: no service point.');
}
// Save the chosen service point as order "shipping" item metadata (displayed on admin order shipping item)
add_action('woocommerce_checkout_create_order_shipping_item', 'save_chosen_service_point_as_order_shipping_meta', 10, 4);
function save_chosen_service_point_as_order_shipping_meta( $item, $package_key, $package, $order ) {
if ( 'sf_express' !== WC()->session->get( 'chosen_shipping_methods' )[$package_key] ) {
return;
}
if ( $chosen_point = WC()->session->get('chosen_service_point') ) {
$item->update_meta_data('Service point', $chosen_point );
}
}
// Save the chosen service point as order meta
add_action( 'woocommerce_order_status_changed', 'save_chosen_service_point_as_order_meta', 10, 4 );
function save_chosen_service_point_as_order_meta( $order_id, $status_from, $status_to, $order ) {
// If "Service point order metadata exists we exit
if ( $order->get_meta('sfe_service_point') ) return; // Exit
foreach ($order->get_items('shipping') as $item ) {
if ( $item->get_method_id() !== 'sf_express' ) {
continue;
}
if ( $service_point = $item->get_meta('Service point') ) {
$all_points = get_formatted_service_points_array();
$order->update_meta_data('sfe_service_point', $all_points[$service_point] );
$order->add_order_note('SF Express Service Point: ' . $all_points[$service_point]);
$order->save();
break;
}
}
}
// Remove the session variable if exists
add_action( 'woocommerce_thankyou', 'remove_sfe_service_point_session_variable', 10, 1 );
function remove_sfe_service_point_session_variable( $order_id ) {
if ( WC()->session->__isset('sfe_service_point') ) {
WC()->session->__unset('sfe_service_point');
}
}
// Display on admin orders after shipping address
add_action('woocommerce_admin_order_data_after_shipping_address', 'admin_order_sfe_service_point_display' );
function admin_order_sfe_service_point_display($order) {
if ( $service_point = $order->get_meta('sfe_service_point') ) {
printf( '<div><h3>%s:</h3> <span>%s</span></div>',
__('SF Express Service Point', 'sf_express'),
esc_html($service_point)
);
}
}
// Display on customer orders (thankyou, order pay, view order)
add_action( 'woocommerce_order_details_after_order_table', 'customer_order_sfe_service_point_display' );
function customer_order_sfe_service_point_display( $order ) {
if ( $service_point = $order->get_meta('sfe_service_point') ) {
printf('<h2 class = "woocommerce-order-service_point__title">%s</h2>
<table class = "woocommerce-table"><tbody><tr><th>%s</th></tr><tbody></table>',
esc_html__( 'SF Express Service Point', 'woocommerce' ), $service_point );
}
}
// Display custom fields data on email notifications
add_action( 'woocommerce_email_order_details', 'email_notifications_sfe_service_point_display', 20, 4 );
function email_notifications_sfe_service_point_display( $order, $sent_to_admin, $plain_text, $email ) {
if ( $service_point = $order->get_meta('sfe_service_point') ) {
echo '<style>
.service-point table{width: 100%; font-family: \'Helvetica Neue\', Helvetica, Roboto, Arial, sans-serif;
color: #737373; border: 1px solid #e4e4e4; margin-bottom:8px;}
.service-point table th, .message table td{text-align: left; border-top-width: 4px;
color: #737373; border: 1px solid #e4e4e4; padding: 12px; width:58%;}
.service-point table td{text-align: left; border-top-width: 4px; color: #737373; border: 1px solid #e4e4e4; padding: 12px;}
</style>';
printf( '<div class = "service-point"><h2>%s</h2>
<table cellspacing = "0" cellpadding = "6"><tbody>
<tr><td>%s</td></tr>
</tbody></table></div><br>',
esc_html__( 'SF Express Service Point', 'woocommerce' ), $service_point );
}
}
Код находится в файле function.php вашей дочерней темы (или в плагине). Протестировано и работает.
По заказам клиентов:
В уведомлениях по электронной почте:
По заказу администратора:
моя вина...обновлено