| Server IP : 104.171.130.249 / Your IP : 216.73.216.146 Web Server : nginx/1.25.5 System : Linux 0dac65491b7e 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : root ( 0) PHP Version : 8.4.23 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : OFF | Perl : ON | Python : OFF | Sudo : OFF | Pkexec : OFF Directory : /var/www/html/wp-content/themes/matreshka/inc/ |
Upload File : |
<?php
/**
* Checkout session preferences, order metadata, and phone validation.
*/
/* ── Payment method (cart modal) ───────────────────────────── */
/**
* AJAX: Save chosen payment method to WC session.
*/
add_action( 'wp_ajax_matreshka_set_payment_method', 'matreshka_set_payment_method' );
add_action( 'wp_ajax_nopriv_matreshka_set_payment_method', 'matreshka_set_payment_method' );
function matreshka_set_payment_method() {
check_ajax_referer( 'matreshka_add_to_cart_nonce', 'security' );
$method = sanitize_text_field( $_POST['payment_method'] ?? '' );
if ( $method && WC()->session ) {
WC()->session->set( 'chosen_payment_method', $method );
}
wp_send_json_success();
}
/* ── Substitution preferences (cart modal) ─────────────────── */
/**
* AJAX: Save substitution preferences to WC session.
*/
add_action( 'wp_ajax_matreshka_save_substitution', 'matreshka_save_substitution_prefs' );
add_action( 'wp_ajax_nopriv_matreshka_save_substitution', 'matreshka_save_substitution_prefs' );
function matreshka_save_substitution_prefs() {
check_ajax_referer( 'matreshka_add_to_cart_nonce', 'security' );
$prefs = [
'substitution' => sanitize_text_field( $_POST['substitution'] ?? 'call_replace' ),
'comment' => sanitize_textarea_field( $_POST['comment'] ?? '' ),
'less_bags' => ! empty( $_POST['less_bags'] ),
'vegs_in_bags' => ! empty( $_POST['vegs_in_bags'] ),
];
WC()->session->set( 'matreshka_substitution_prefs', $prefs );
wp_send_json_success();
}
/**
* Save substitution preferences as order meta when order is placed.
*/
add_action( 'woocommerce_checkout_order_processed', 'matreshka_save_substitution_to_order', 10, 3 );
function matreshka_save_substitution_to_order( $order_id, $posted_data, $order ) {
$prefs = WC()->session->get( 'matreshka_substitution_prefs' );
$user_id = $order->get_customer_id();
// Fallback: if session is empty, load from user meta (returning customer)
if ( empty( $prefs ) && $user_id ) {
$prefs = [
'substitution' => get_user_meta( $user_id, '_matreshka_substitution_type', true ) ?: 'call_replace',
'comment' => get_user_meta( $user_id, '_matreshka_packer_comment', true ) ?: '',
'less_bags' => get_user_meta( $user_id, '_matreshka_less_bags', true ) === 'yes',
'vegs_in_bags' => get_user_meta( $user_id, '_matreshka_vegs_in_bags', true ) === 'yes',
];
}
// Final fallback: default to call_replace
if ( empty( $prefs ) ) {
$prefs = [
'substitution' => 'call_replace',
'comment' => '',
'less_bags' => false,
'vegs_in_bags' => false,
];
}
$labels = [
'call_replace' => 'Позвонить и заменить',
'no_replace' => 'Не заменять',
'auto_replace' => 'Не спрашивать и заменить',
];
$order->update_meta_data( '_matreshka_substitution_type', $prefs['substitution'] );
$order->update_meta_data( '_matreshka_substitution_label', $labels[ $prefs['substitution'] ] ?? $prefs['substitution'] );
$order->update_meta_data( '_matreshka_packer_comment', $prefs['comment'] );
$order->update_meta_data( '_matreshka_less_bags', $prefs['less_bags'] ? 'yes' : 'no' );
$order->update_meta_data( '_matreshka_vegs_in_bags', $prefs['vegs_in_bags'] ? 'yes' : 'no' );
// leave_at_door — from checkout form
$leave_at_door = ! empty( $posted_data['leave_at_door'] ) || ! empty( $_POST['leave_at_door'] );
$order->update_meta_data( '_matreshka_leave_at_door', $leave_at_door ? 'yes' : 'no' );
$order->save();
// Save substitution prefs to user meta for future orders
if ( $user_id ) {
update_user_meta( $user_id, '_matreshka_substitution_type', $prefs['substitution'] );
update_user_meta( $user_id, '_matreshka_packer_comment', $prefs['comment'] );
update_user_meta( $user_id, '_matreshka_less_bags', $prefs['less_bags'] ? 'yes' : 'no' );
update_user_meta( $user_id, '_matreshka_vegs_in_bags', $prefs['vegs_in_bags'] ? 'yes' : 'no' );
}
// Clear session after saving
WC()->session->set( 'matreshka_substitution_prefs', null );
}
/**
* Save custom checkout address fields to order meta + update user meta.
*/
add_action( 'woocommerce_checkout_order_processed', 'matreshka_save_checkout_custom_fields', 20, 3 );
function matreshka_save_checkout_custom_fields( $order_id, $posted_data, $order ) {
$is_pickup = WC()->session && 'pickup' === WC()->session->get( 'matreshka_shipping_type', 'delivery' );
$fields_map = [
'billing_entrance' => '_matreshka_entrance',
'billing_intercom' => '_matreshka_intercom',
'billing_floor' => '_matreshka_floor',
'billing_apartment' => '_matreshka_apartment',
];
// Комментарий курьеру (order_comments → customer_note + order meta)
$courier_comment = sanitize_text_field( $_POST['order_comments'] ?? '' );
if ( $courier_comment ) {
$order->update_meta_data( '_matreshka_courier_comment', $courier_comment );
}
$user_id = $order->get_customer_id();
foreach ( $fields_map as $post_key => $meta_key ) {
$val = sanitize_text_field( $_POST[ $post_key ] ?? '' );
$order->update_meta_data( $meta_key, $val );
// Also update user meta so it persists for next delivery orders.
if ( $user_id && ! $is_pickup ) {
update_user_meta( $user_id, $meta_key, $val );
}
}
// Sync billing_address_1 → shipping_address_1 on user meta for delivery only.
if ( $user_id && ! $is_pickup && ! empty( $_POST['billing_address_1'] ) ) {
$address = sanitize_text_field( $_POST['billing_address_1'] );
update_user_meta( $user_id, 'shipping_address_1', $address );
}
$order->save();
}
/**
* Keep the saved delivery address intact when checkout is submitted as pickup.
*
* The pickup checkout UI does not render billing_address_1, so WooCommerce can
* receive an empty value and persist it back to the customer profile.
*/
function matreshka_preserve_profile_address_for_pickup_checkout( $posted_data ) {
if ( ! is_user_logged_in() || ! WC()->session || 'pickup' !== WC()->session->get( 'matreshka_shipping_type', 'delivery' ) ) {
return $posted_data;
}
$user_id = get_current_user_id();
$address = trim( (string) get_user_meta( $user_id, 'billing_address_1', true ) );
if ( '' === $address ) {
$address = trim( (string) get_user_meta( $user_id, 'shipping_address_1', true ) );
}
if ( '' === $address ) {
return $posted_data;
}
$posted_data['billing_address_1'] = $address;
$posted_data['shipping_address_1'] = $address;
return $posted_data;
}
add_filter( 'woocommerce_checkout_posted_data', 'matreshka_preserve_profile_address_for_pickup_checkout', 15 );
/**
* Validate and format customer phone numbers consistently for every order.
*
* The accepted input must start with +7 and contain exactly 10 subscriber
* digits. Valid numbers are stored in the presentation format used by checkout.
*
* @param string $phone Phone number from checkout or REST API.
* @return string Empty string when the phone number is invalid.
*/
function matreshka_normalize_order_phone( $phone ) {
$phone = trim( (string) $phone );
if ( ! preg_match( '/^\+7(?:[\s()-]*\d){10}$/u', $phone ) ) {
return '';
}
$digits = preg_replace( '/\D+/', '', $phone );
if ( 11 !== strlen( $digits ) || '7' !== $digits[0] ) {
return '';
}
return sprintf(
'+7 %s %s %s %s',
substr( $digits, 1, 3 ),
substr( $digits, 4, 3 ),
substr( $digits, 7, 2 ),
substr( $digits, 9, 2 )
);
}
/**
* Normalize a valid phone number before WooCommerce creates the order.
*
* @param array $posted_data Checkout data.
* @return array
*/
function matreshka_normalize_checkout_phone( $posted_data ) {
if ( isset( $posted_data['billing_phone'] ) ) {
$phone = matreshka_normalize_order_phone( $posted_data['billing_phone'] );
if ( $phone ) {
$posted_data['billing_phone'] = $phone;
}
}
return $posted_data;
}
add_filter( 'woocommerce_checkout_posted_data', 'matreshka_normalize_checkout_phone', 20 );
/**
* Require the phone number even when checkout is submitted without JavaScript.
*
* @param array $data Validated checkout data.
* @param WP_Error $errors Checkout validation errors.
*/
function matreshka_validate_checkout_phone( $data, $errors ) {
if ( ! matreshka_normalize_order_phone( $data['billing_phone'] ?? '' ) ) {
$errors->add( 'billing_phone_invalid', 'Введите номер телефона в формате +7 XXX XXX XX XX.' );
}
}
add_action( 'woocommerce_after_checkout_validation', 'matreshka_validate_checkout_phone', 10, 2 );
/**
* Apply the same phone requirement to orders created through the WooCommerce REST API.
*
* @param WC_Order $order Order being created or updated.
* @param WP_REST_Request $request REST request.
* @param bool $creating Whether this is a new order.
* @return WC_Order|WP_Error
*/
function matreshka_validate_rest_order_phone( $order, $request, $creating ) {
$billing = $request->get_param( 'billing' );
$has_phone = is_array( $billing ) && array_key_exists( 'phone', $billing );
if ( ! $creating && ! $has_phone ) {
return $order;
}
$phone = matreshka_normalize_order_phone( $order->get_billing_phone() );
if ( ! $phone ) {
return new WP_Error(
'matreshka_invalid_billing_phone',
'Введите номер телефона в формате +7 XXX XXX XX XX.',
array( 'status' => 400 )
);
}
$order->set_billing_phone( $phone );
return $order;
}
add_filter( 'woocommerce_rest_pre_insert_shop_order_object', 'matreshka_validate_rest_order_phone', 10, 3 );
/* Old substitution admin display removed — now in inc/admin-order-metaboxes.php */