403Webshell
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 :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/wp-content/themes/matreshka/inc/shipping-method.php
<?php
/**
 * Кастомные методы доставки Matreshka
 *
 * Два метода:
 *  – Доставка (matreshka_delivery): 389 ₽ доставка + 49.99 ₽ упаковка
 *  – Самовывоз (matreshka_pickup):  49.99 ₽ упаковка, клиент выбирает магазин
 *
 * @package Matreshka
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/* ──────────────────────────────────────────────
 * 1. Регистрация методов доставки
 * ────────────────────────────────────────────── */

add_filter( 'woocommerce_shipping_methods', 'matreshka_register_shipping_methods' );
function matreshka_register_shipping_methods( $methods ) {
	$methods['matreshka_delivery'] = 'WC_Matreshka_Delivery';
	$methods['matreshka_pickup']   = 'WC_Matreshka_Pickup';
	return $methods;
}

/* ──────────────────────────────────────────────
 * 2. Классы методов доставки (init после WC)
 * ────────────────────────────────────────────── */

add_action( 'woocommerce_shipping_init', 'matreshka_shipping_init' );
function matreshka_shipping_init() {

	/* ── Доставка ─────────────────────────────── */
	class WC_Matreshka_Delivery extends WC_Shipping_Method {

		public function __construct( $instance_id = 0 ) {
			$this->id                   = 'matreshka_delivery';
			$this->instance_id          = absint( $instance_id );
			$this->method_title         = 'Доставка Matreshka';
			$this->method_description   = 'Курьерская доставка: 389 ₽ + 49.99 ₽ упаковка';
			$this->supports             = array( 'shipping-zones', 'instance-settings' );
			$this->enabled              = 'yes';
			$this->title                = 'Доставка';

			$this->init();
		}

		public function init() {
			$this->init_form_fields();
			$this->init_settings();
			add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
		}

		public function init_form_fields() {
			$this->instance_form_fields = array(
				'delivery_cost' => array(
					'title'   => 'Стоимость доставки (₽)',
					'type'    => 'number',
					'default' => 389,
				),
				'packaging_cost' => array(
					'title'   => 'Стоимость упаковки (₽)',
					'type'    => 'number',
					'default' => 49.99,
					'custom_attributes' => array( 'step' => '0.01' ),
				),
			);
		}

		public function calculate_shipping( $package = array() ) {
			$delivery  = floatval( $this->get_option( 'delivery_cost', 389 ) );
			$packaging = floatval( $this->get_option( 'packaging_cost', 49.99 ) );

			$this->add_rate( array(
				'id'    => $this->get_rate_id(),
				'label' => $this->title,
				'cost'  => $delivery + $packaging,
				'meta_data' => array(
					'delivery_cost'  => $delivery,
					'packaging_cost' => $packaging,
				),
			) );
		}
	}

	/* ── Самовывоз ────────────────────────────── */
	class WC_Matreshka_Pickup extends WC_Shipping_Method {

		public function __construct( $instance_id = 0 ) {
			$this->id                   = 'matreshka_pickup';
			$this->instance_id          = absint( $instance_id );
			$this->method_title         = 'Самовывоз Matreshka';
			$this->method_description   = 'Самовывоз: 49.99 ₽ упаковка, клиент выбирает магазин';
			$this->supports             = array( 'shipping-zones', 'instance-settings' );
			$this->enabled              = 'yes';
			$this->title                = 'Самовывоз';

			$this->init();
		}

		public function init() {
			$this->init_form_fields();
			$this->init_settings();
			add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
		}

		public function init_form_fields() {
			// Собираем все магазины из matreshka_stores для мультиселекта
			$all_stores  = matreshka_get_all_stores();
			$store_opts  = array();
			foreach ( $all_stores as $i => $store ) {
				$store_opts[ $i ] = ( $store['name'] ?? '—' ) . ' — ' . ( $store['address'] ?? '' );
			}

			$this->instance_form_fields = array(
				'packaging_cost' => array(
					'title'   => 'Стоимость упаковки (₽)',
					'type'    => 'number',
					'default' => 49.99,
					'custom_attributes' => array( 'step' => '0.01' ),
				),
				'pickup_stores' => array(
					'title'       => 'Доступные магазины для самовывоза',
					'type'        => 'multiselect',
					'class'       => 'wc-enhanced-select',
					'description' => 'Выберите магазины из списка (источник: метабокс «Адреса магазинов» на страницах).',
					'desc_tip'    => true,
					'options'     => $store_opts,
					'default'     => array_keys( $store_opts ), // по умолчанию все
				),
			);
		}

		/**
		 * Получить индексы выбранных магазинов.
		 */
		public function get_enabled_store_indices() {
			$saved = $this->get_option( 'pickup_stores', array() );
			if ( empty( $saved ) ) {
				// Если ничего не сохранено — все
				return array_keys( matreshka_get_all_stores() );
			}
			return array_map( 'intval', (array) $saved );
		}

		public function calculate_shipping( $package = array() ) {
			$packaging = floatval( $this->get_option( 'packaging_cost', 49.99 ) );

			$this->add_rate( array(
				'id'    => $this->get_rate_id(),
				'label' => $this->title,
				'cost'  => $packaging,
				'meta_data' => array(
					'packaging_cost' => $packaging,
				),
			) );
		}
	}
}

/* ──────────────────────────────────────────────
 * 3. Хелпер: получить все магазины из мета-полей страниц
 * ────────────────────────────────────────────── */

function matreshka_get_all_stores() {
	static $cache = null;
	if ( $cache !== null ) {
		return $cache;
	}

	$stores = array();
	$pages  = get_pages();
	foreach ( $pages as $page ) {
		$page_stores = get_post_meta( $page->ID, '_matreshka_stores', true );
		if ( is_array( $page_stores ) && ! empty( $page_stores ) ) {
			foreach ( $page_stores as $store ) {
				if ( ! empty( $store['name'] ) ) {
					$stores[] = $store;
				}
			}
		}
	}

	$cache = $stores;
	return $stores;
}

/**
 * Получить только те магазины, которые включены для самовывоза
 * в настройках метода Самовывоз Matreshka.
 */
function matreshka_get_pickup_stores() {
	static $cache = null;
	if ( $cache !== null ) {
		return $cache;
	}

	$all = matreshka_get_all_stores();
	if ( empty( $all ) ) {
		$cache = array();
		return $cache;
	}

	// Находим instance метода matreshka_pickup
	$enabled_indices = null;
	$zones = WC_Shipping_Zones::get_zones();
	foreach ( $zones as $zone_data ) {
		foreach ( $zone_data['shipping_methods'] as $m ) {
			if ( $m->id === 'matreshka_pickup' ) {
				$enabled_indices = $m->get_enabled_store_indices();
				break 2;
			}
		}
	}

	// Проверяем Rest of World (zone 0)
	if ( $enabled_indices === null ) {
		$rest = WC_Shipping_Zones::get_zone( 0 );
		foreach ( $rest->get_shipping_methods() as $m ) {
			if ( $m->id === 'matreshka_pickup' ) {
				$enabled_indices = $m->get_enabled_store_indices();
				break;
			}
		}
	}

	if ( $enabled_indices === null ) {
		$cache = $all;
		return $cache;
	}

	$filtered = array();
	foreach ( $enabled_indices as $idx ) {
		if ( isset( $all[ $idx ] ) ) {
			$filtered[ $idx ] = $all[ $idx ];
		}
	}
	$cache = $filtered;
	return $cache;
}

/* ──────────────────────────────────────────────
 * 3b. Хелпер: получить стоимости доставки из настроек
 * ────────────────────────────────────────────── */

function matreshka_get_shipping_costs() {
	static $cache = null;
	if ( $cache !== null ) {
		return $cache;
	}

	$costs = array( 'delivery' => 389.0, 'packaging' => 49.99 );

	$all_zones   = WC_Shipping_Zones::get_zones();
	$all_zones[] = array( 'shipping_methods' => WC_Shipping_Zones::get_zone( 0 )->get_shipping_methods() );

	foreach ( $all_zones as $zone_data ) {
		foreach ( $zone_data['shipping_methods'] as $m ) {
			if ( $m->id === 'matreshka_delivery' ) {
				$costs['delivery']  = floatval( $m->get_option( 'delivery_cost', 389 ) );
				$costs['packaging'] = floatval( $m->get_option( 'packaging_cost', 49.99 ) );
				break 2;
			}
		}
	}

	$cache = $costs;
	return $costs;
}

/* ──────────────────────────────────────────────
 * 4. AJAX: переключение метода доставки
 * ────────────────────────────────────────────── */

add_action( 'wp_ajax_matreshka_set_shipping', 'matreshka_ajax_set_shipping' );
add_action( 'wp_ajax_nopriv_matreshka_set_shipping', 'matreshka_ajax_set_shipping' );

function matreshka_ajax_set_shipping() {
	check_ajax_referer( 'matreshka_shipping_nonce', 'nonce' );

	$method = sanitize_text_field( $_POST['method'] ?? '' );
	if ( ! in_array( $method, array( 'delivery', 'pickup' ), true ) ) {
		wp_send_json_error( array( 'message' => 'Invalid method' ) );
	}

	// 1. Save shipping type to session
	WC()->session->set( 'matreshka_shipping_type', $method );

	// 2. Save pickup store index
	$store_index = 0;
	if ( $method === 'pickup' ) {
		$store_index = absint( $_POST['store_index'] ?? 0 );
		$stores       = array_values( matreshka_get_pickup_stores() );
		if ( ! isset( $stores[ $store_index ] ) ) {
			$store_index = 0;
		}
		WC()->session->set( 'matreshka_pickup_store', $store_index );
	}

	// 3. Persist to user meta (remember for future orders)
	if ( is_user_logged_in() ) {
		$uid = get_current_user_id();
		update_user_meta( $uid, '_matreshka_shipping_type', $method );
		if ( $method === 'pickup' ) {
			update_user_meta( $uid, '_matreshka_pickup_store', $store_index );
		}
	}

	// 4. Calculate shipping to populate available rates
	$chosen_prefix = $method === 'pickup' ? 'matreshka_pickup' : 'matreshka_delivery';
	WC()->cart->calculate_shipping();
	$packages = WC()->shipping()->get_packages();

	// 5. Find the actual rate id (e.g. matreshka_pickup:3)
	$rate_id = $chosen_prefix;
	foreach ( $packages as $package ) {
		if ( ! empty( $package['rates'] ) ) {
			foreach ( $package['rates'] as $rid => $rate ) {
				if ( strpos( $rid, $chosen_prefix ) === 0 ) {
					$rate_id = $rid;
					break 2;
				}
			}
		}
	}

	// 6. Set chosen method, then recalculate totals
	WC()->session->set( 'chosen_shipping_methods', array( $rate_id ) );
	WC()->cart->calculate_totals();

	wp_send_json_success( array(
		'method'     => $method,
		'rate_id'    => $rate_id,
		'total'      => WC()->cart->get_total( 'edit' ),
		'total_html' => WC()->cart->get_total(),
	) );
}

/* ──────────────────────────────────────────────
 * 5. Добавляем Зону доставки по умолчанию при активации
 *    (если методов ещё нет)
 * ────────────────────────────────────────────── */

add_action( 'admin_init', 'matreshka_maybe_add_default_shipping_zone', 20 );
function matreshka_maybe_add_default_shipping_zone() {
	if ( get_option( 'matreshka_shipping_zone_created' ) ) {
		return;
	}

	// Проверяем, есть ли уже зоны с нашими методами
	$zones = WC_Shipping_Zones::get_zones();
	foreach ( $zones as $zone_data ) {
		foreach ( $zone_data['shipping_methods'] as $m ) {
			if ( in_array( $m->id, array( 'matreshka_delivery', 'matreshka_pickup' ), true ) ) {
				update_option( 'matreshka_shipping_zone_created', 1 );
				return;
			}
		}
	}

	// Также проверяем Rest of World (zone 0)
	$rest = WC_Shipping_Zones::get_zone( 0 );
	foreach ( $rest->get_shipping_methods() as $m ) {
		if ( in_array( $m->id, array( 'matreshka_delivery', 'matreshka_pickup' ), true ) ) {
			update_option( 'matreshka_shipping_zone_created', 1 );
			return;
		}
	}

	// Создаём зону «Все регионы» и добавляем оба метода
	$zone = new WC_Shipping_Zone();
	$zone->set_zone_name( 'Все регионы' );
	$zone->save();
	$zone->add_shipping_method( 'matreshka_delivery' );
	$zone->add_shipping_method( 'matreshka_pickup' );

	update_option( 'matreshka_shipping_zone_created', 1 );
}

/* ──────────────────────────────────────────────
 * 6. Метод по умолчанию: Доставка
 * ────────────────────────────────────────────── */

add_filter( 'woocommerce_shipping_chosen_method', 'matreshka_default_shipping_method', 10, 3 );
function matreshka_default_shipping_method( $default, $rates, $chosen_method ) {
	// 1. Check session for user's current choice
	$session_type = WC()->session ? WC()->session->get( 'matreshka_shipping_type' ) : null;

	// 2. If no session — try user meta (persisted from previous orders)
	if ( ! $session_type && is_user_logged_in() ) {
		$saved = get_user_meta( get_current_user_id(), '_matreshka_shipping_type', true );
		if ( $saved ) {
			$session_type = $saved;
			WC()->session->set( 'matreshka_shipping_type', $saved );
			if ( $saved === 'pickup' ) {
				$store = get_user_meta( get_current_user_id(), '_matreshka_pickup_store', true );
				WC()->session->set( 'matreshka_pickup_store', absint( $store ) );
			}
		}
	}

	// 3. Return the rate matching user's choice
	if ( $session_type ) {
		$prefix = $session_type === 'pickup' ? 'matreshka_pickup' : 'matreshka_delivery';
		foreach ( $rates as $rate_id => $rate ) {
			if ( strpos( $rate_id, $prefix ) === 0 ) {
				return $rate_id;
			}
		}
	}

	// 4. Default — Доставка
	foreach ( $rates as $rate_id => $rate ) {
		if ( strpos( $rate_id, 'matreshka_delivery' ) === 0 ) {
			return $rate_id;
		}
	}
	return $default;
}

/* ──────────────────────────────────────────────
 * 7. Сохраняем данные самовывоза (магазин) в заказе
 * ────────────────────────────────────────────── */

add_action( 'woocommerce_checkout_create_order', 'matreshka_save_shipping_to_order', 20, 2 );
function matreshka_save_shipping_to_order( $order, $data ) {

	$type = WC()->session->get( 'matreshka_shipping_type', 'delivery' );
	$order->update_meta_data( '_matreshka_shipping_type', $type );

	if ( $type === 'pickup' ) {
		$store_index = WC()->session->get( 'matreshka_pickup_store', 0 );
		$stores = array_values( matreshka_get_pickup_stores() );

		if ( isset( $stores[ $store_index ] ) ) {
			$store = $stores[ $store_index ];
			$order->update_meta_data( '_matreshka_pickup_store_name',    $store['name'] ?? '' );
			$order->update_meta_data( '_matreshka_pickup_store_address', $store['address'] ?? '' );
			$order->update_meta_data( '_matreshka_pickup_store_phone',   $store['phone'] ?? '' );
			$order->update_meta_data( '_matreshka_pickup_store_hours',   $store['hours'] ?? '' );
		}
	}
}

/* ──────────────────────────────────────────────
 * 8. Показываем инфо о доставке в админке заказа
 * ────────────────────────────────────────────── */

/* Old shipping admin display removed — now in inc/admin-order-metaboxes.php */

/* Old pickup thankyou display removed — now in woocommerce/checkout/thankyou.php */

/* ──────────────────────────────────────────────
 * 10. Скрываем стандартный WC калькулятор доставки
 * ────────────────────────────────────────────── */

add_filter( 'woocommerce_shipping_show_shipping_calculator', '__return_false' );

/* ──────────────────────────────────────────────
 * 11. Подключаем скрипт и стили на корзину/чекаут
 * ────────────────────────────────────────────── */

add_action( 'wp_enqueue_scripts', 'matreshka_shipping_assets' );
function matreshka_shipping_assets() {
	if ( ! is_cart() && ! is_checkout() ) {
		return;
	}

	wp_enqueue_style(
		'matreshka-shipping',
		get_template_directory_uri() . '/assets/css/shipping.css',
		array(),
		filemtime( get_template_directory() . '/assets/css/shipping.css' )
	);

	wp_enqueue_script(
		'matreshka-shipping',
		get_template_directory_uri() . '/assets/js/shipping.js',
		array( 'jquery' ),
		filemtime( get_template_directory() . '/assets/js/shipping.js' ),
		true
	);

	$costs = function_exists( 'matreshka_get_shipping_costs' ) ? matreshka_get_shipping_costs() : array( 'delivery' => 389, 'packaging' => 49.99 );

	wp_localize_script( 'matreshka-shipping', 'matreshkaShipping', array(
		'ajaxurl'      => admin_url( 'admin-ajax.php' ),
		'nonce'        => wp_create_nonce( 'matreshka_shipping_nonce' ),
		'stores'       => array_values( matreshka_get_pickup_stores() ),
		'current'      => WC()->session ? WC()->session->get( 'matreshka_shipping_type', 'delivery' ) : 'delivery',
		'currentStore' => WC()->session ? WC()->session->get( 'matreshka_pickup_store', 0 ) : 0,
		'costs'        => $costs,
	) );
}

Youez - 2016 - github.com/yon3zu
LinuXploit