From 855b355eac85bc1bfc0241023cbfc407f16eac04 Mon Sep 17 00:00:00 2001 From: Andrei-10 Date: Thu, 15 May 2025 13:50:40 +0000 Subject: [PATCH] Feat | Add cart and checkout Co-authored-by: gp_dev Reviewed-on: https://git.good-production.xyz/Good-Production/cosmopet-architecture/pulls/14 --- wp-content/themes/cosmopet/functions.php | 2 +- .../global-functions/multilang-functions.php | 44 +++ .../modules/layout/module-controller.php | 1 + .../shop/components/cart/assets/js/cart.js | 7 +- .../modules/shop/module-ajax-controller.php | 143 ++++++++ .../modules/shop/module-controller.php | 325 +++++++++++++++++- .../themes/cosmopet/templates/layout.twig | 28 ++ 7 files changed, 546 insertions(+), 4 deletions(-) diff --git a/wp-content/themes/cosmopet/functions.php b/wp-content/themes/cosmopet/functions.php index f1347d6..9210656 100644 --- a/wp-content/themes/cosmopet/functions.php +++ b/wp-content/themes/cosmopet/functions.php @@ -425,6 +425,7 @@ require_once('modules/blog/module-ajax-controller.php'); require_once('modules/forms/module-ajax-controller.php'); require_once('modules/shop/module-ajax-controller.php'); + add_action('wp', 'my_custom_checkout_code'); function my_custom_checkout_code() { if (function_exists('is_checkout') && is_checkout() && !is_order_received_page()) { @@ -434,7 +435,6 @@ function my_custom_checkout_code() { require_once('modules/author/module-ajax-controller.php'); - include_module('forms'); include_module('layout'); diff --git a/wp-content/themes/cosmopet/global-functions/multilang-functions.php b/wp-content/themes/cosmopet/global-functions/multilang-functions.php index e69de29..161d7a7 100644 --- a/wp-content/themes/cosmopet/global-functions/multilang-functions.php +++ b/wp-content/themes/cosmopet/global-functions/multilang-functions.php @@ -0,0 +1,44 @@ + +скидку!', 'Узнайте о нас больше и получите скидку!'); + pll_register_string ('Это миф!', 'Это миф!'); + pll_register_string ('Это правда!', 'Это правда!'); + pll_register_string ('Правда', 'Правда'); + pll_register_string ('Миф', 'Миф'); + pll_register_string ('Далее', 'Далее'); + pll_register_string ('ваш результат', 'ваш результат'); + pll_register_string ('Скопировать', 'Скопировать'); + pll_register_string ('Скопировано', 'Скопировано'); + pll_register_string ('В магазин', 'В магазин'); + pll_register_string ('Наш блог', 'Наш блог'); + pll_register_string ('Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных', 'Новости рынка кормов и экологии, полезные статьи о здоровье домашних животных'); + pll_register_string ('ЭТАПЫ ПРОИЗВОД­СТВА', 'ЭТАПЫ ПРОИЗВОД­СТВА'); + pll_register_string ('Этапы производс­тва корма', 'Этапы производс­тва корма'); + pll_register_string ('Все статьи', 'Все статьи'); + pll_register_string ('Узнать больше', 'Узнать больше'); +}); + diff --git a/wp-content/themes/cosmopet/modules/layout/module-controller.php b/wp-content/themes/cosmopet/modules/layout/module-controller.php index e3a0b36..08e4f89 100644 --- a/wp-content/themes/cosmopet/modules/layout/module-controller.php +++ b/wp-content/themes/cosmopet/modules/layout/module-controller.php @@ -3,4 +3,5 @@ include_module('header'); include_component('shop', 'cart'); +include_module('shop'); include_module('footer'); diff --git a/wp-content/themes/cosmopet/modules/shop/components/cart/assets/js/cart.js b/wp-content/themes/cosmopet/modules/shop/components/cart/assets/js/cart.js index bcef82e..bb96745 100644 --- a/wp-content/themes/cosmopet/modules/shop/components/cart/assets/js/cart.js +++ b/wp-content/themes/cosmopet/modules/shop/components/cart/assets/js/cart.js @@ -18,7 +18,9 @@ jQuery(document).ready(function($) { }); // Увеличение количества - $(document).on('click', '.counter__button.plus', function(e) { + + $(document).on('click', '.modal__basket .counter__button.plus', function(e) { + e.preventDefault(); const key = $(this).data('key'); const input = $(this).siblings('.counter__input'); @@ -27,7 +29,8 @@ jQuery(document).ready(function($) { }); // Уменьшение количества - $(document).on('click', '.counter__button.minus', function(e) { + + $(document).on('click', '.modal__basket .counter__button.minus', function(e) { e.preventDefault(); const key = $(this).data('key'); const input = $(this).siblings('.counter__input'); diff --git a/wp-content/themes/cosmopet/modules/shop/module-ajax-controller.php b/wp-content/themes/cosmopet/modules/shop/module-ajax-controller.php index e69de29..7b8eb35 100644 --- a/wp-content/themes/cosmopet/modules/shop/module-ajax-controller.php +++ b/wp-content/themes/cosmopet/modules/shop/module-ajax-controller.php @@ -0,0 +1,143 @@ + 'Код купона не указан.' ) ); + } + + // Применение купона + $applied = WC()->cart->apply_coupon( $coupon_code ); + + if ( $applied ) { + wp_send_json_success(); + } else { + wp_send_json_error( array( 'message' => 'Купон не применён. Проверьте код.' ) ); + } +} + + +/** + * Обработчик AJAX для обновления количества товара в корзине + */ +add_action('wp_ajax_update_cart_quantity', 'update_cart_quantity_handler'); +add_action('wp_ajax_nopriv_update_cart_quantity', 'update_cart_quantity_handler'); + +function update_cart_quantity_handler() { + if (!isset($_POST['cart_item_key']) || !isset($_POST['quantity'])) { + wp_send_json_error('Недостаточно данных'); + return; + } + + $cart_item_key = sanitize_text_field($_POST['cart_item_key']); + $quantity = intval($_POST['quantity']); + + if ($quantity <= 0) { + wp_send_json_error('Некорректное количество'); + return; + } + + $cart = WC()->cart; + $cart_item = $cart->get_cart_item($cart_item_key); + + if (!$cart_item) { + wp_send_json_error('Товар не найден в корзине'); + return; + } + + $updated = $cart->set_quantity($cart_item_key, $quantity); + + if ($updated) { + wp_send_json_success(); + } else { + wp_send_json_error('Не удалось обновить количество'); + } +} + +/** + * Обработчик AJAX для восстановления товара в корзине + */ +add_action('wp_ajax_restore_cart_item', 'restore_cart_item_handler'); +add_action('wp_ajax_nopriv_restore_cart_item', 'restore_cart_item_handler'); + +function restore_cart_item_handler() { + if (!isset($_POST['product_id']) || !isset($_POST['quantity'])) { + wp_send_json_error('Недостаточно данных'); + return; + } + + $product_id = intval($_POST['product_id']); + $variation_id = isset($_POST['variation_id']) ? intval($_POST['variation_id']) : 0; + $quantity = intval($_POST['quantity']); + + if ($quantity <= 0) { + wp_send_json_error('Некорректное количество'); + return; + } + + $cart = WC()->cart; + $cart_item_key = $cart->add_to_cart($product_id, $quantity, $variation_id); + + if ($cart_item_key) { + wp_send_json_success(); + } else { + wp_send_json_error('Не удалось восстановить товар'); + } +} + +/** + * Обработчик AJAX для получения фрагментов корзины + */ +add_action('wp_ajax_get_cart_fragment', 'get_cart_fragment_handler'); +add_action('wp_ajax_nopriv_get_cart_fragment', 'get_cart_fragment_handler'); + +function get_cart_fragment_handler() { + ob_start(); + Timber::render('shop/cart-contents.twig', Timber::context()); + $contents = ob_get_clean(); + + $response = array( + 'contents' => $contents, + 'total' => WC()->cart->get_cart_total(), + 'count' => WC()->cart->get_cart_contents_count() + ); + + wp_send_json_success($response); +} + + +/** + * Инициализация WooCommerce AJAX + */ +add_action('wp_enqueue_scripts', 'enqueue_woocommerce_ajax_scripts'); +function enqueue_woocommerce_ajax_scripts() { + wp_localize_script('jquery', 'woocommerce_params', array( + 'ajax_url' => admin_url('admin-ajax.php'), + 'currency_symbol' => get_woocommerce_currency_symbol(), + 'currency_format' => str_replace(array('%1$s', '%2$s'), array('%s', '%v'), get_woocommerce_price_format()), + 'i18n_restore_item' => pll_e('Восстановить', 'woocommerce') + )); +} + +add_action('wp_ajax_remove_cart_item', 'handle_remove_cart_item'); +add_action('wp_ajax_nopriv_remove_cart_item', 'handle_remove_cart_item'); + +function handle_remove_cart_item() { + if (!isset($_POST['cart_item_key'])) { + wp_send_json_error('Не указан ключ элемента корзины'); + return; + } + + $cart_item_key = sanitize_text_field($_POST['cart_item_key']); + $cart = WC()->cart; + + if ($cart->remove_cart_item($cart_item_key)) { + wp_send_json_success(); + } else { + wp_send_json_error('Не удалось удалить товар из корзины'); + } +} \ No newline at end of file diff --git a/wp-content/themes/cosmopet/modules/shop/module-controller.php b/wp-content/themes/cosmopet/modules/shop/module-controller.php index 9c541f6..5fb6a26 100644 --- a/wp-content/themes/cosmopet/modules/shop/module-controller.php +++ b/wp-content/themes/cosmopet/modules/shop/module-controller.php @@ -1,5 +1,327 @@ 'text', + 'label' => __('Имя', 'woocommerce'), + 'placeholder' => __('Ваше имя', 'woocommerce'), + 'required' => true, + 'class' => array('form-row-wide'), + 'priority' => 10, + ); + $fields['billing']['billing_last_name'] = array( + 'type' => 'text', + 'label' => __('Фамилия', 'woocommerce'), + 'placeholder' => __('Ваша фамилия', 'woocommerce'), + 'required' => true, + 'class' => array('form-row-wide'), + 'priority' => 10, + ); + $fields['billing']['billing_email'] = array( + 'type' => 'email', + 'label' => __('E-mail', 'woocommerce'), + 'placeholder' => __('Начните вводить ваш email', 'woocommerce'), + 'required' => true, + 'class' => array('form-row-wide'), + 'priority' => 20, + ); + $fields['billing']['billing_phone'] = array( + 'type' => 'tel', + 'label' => __('Телефон', 'woocommerce'), + 'placeholder' => __('+7 ___ ___ ____', 'woocommerce'), + 'required' => true, + 'class' => array('form-row-wide'), + 'priority' => 30, + ); + $fields['billing']['billing_city'] = array( + 'type' => 'text', + 'label' => __('Населенный пункт', 'woocommerce'), + 'placeholder' => __('Ваш город', 'woocommerce'), + 'required' => true, + 'class' => array('form-row-wide'), + 'priority' => 40, + ); + + $fields['billing']['billing_address_1'] = array( + 'type' => 'text', + 'label' => __('Адрес', 'woocommerce'), + 'placeholder' => __('Адрес', 'woocommerce'), + 'required' => false, + 'class' => array('visually-hidden'), + 'priority' => 40, + ); + $fields['billing']['billing_address_2'] = array( + 'type' => 'text', + 'label' => __('Адрес 2', 'woocommerce'), + 'placeholder' => __('Адрес 2', 'woocommerce'), + 'required' => false, + 'class' => array('visually-hidden'), + 'priority' => 40, + ); + + return $fields; +} +// remove_action( 'woocommerce_review_order_before_payment', 'woocommerce_review_order_shipping' ); + +add_action( 'init', function() { + update_option( 'woocommerce_enable_coupons', 'yes' ); // Включение купонов +} ); + +add_filter( 'woocommerce_available_payment_gateways', 'set_default_payment_gateway' ); + +function set_default_payment_gateway( $available_gateways ) { + if ( is_cart() || is_checkout() ) { + // Устанавливаем способ оплаты по умолчанию + $default_payment_gateway = 'tbank'; // ID способа оплаты, например 'cod' для "наличными при доставке" + + // Проверяем, доступен ли этот способ оплаты + if ( isset( $available_gateways[ $default_payment_gateway ] ) ) { + foreach ( $available_gateways as $gateway_id => $gateway ) { + // Оставляем только выбранный способ оплаты + if ( $gateway_id !== $default_payment_gateway ) { + unset( $available_gateways[ $gateway_id ] ); + } + } + } + } + + return $available_gateways; +} + +add_filter( 'woocommerce_checkout_terms_and_conditions_checkbox_enabled', '__return_false' ); +add_filter( 'woocommerce_checkout_terms_is_required', '__return_false' ); +remove_action( 'woocommerce_checkout_before_terms_and_conditions', 'wc_checkout_privacy_policy_text', 20 ); +remove_action( 'woocommerce_checkout_terms_and_conditions', 'wc_terms_and_conditions_page_content', 30 ); +remove_action( 'woocommerce_checkout_after_terms_and_conditions', 'wc_privacy_policy_text', 20 ); + +add_action( 'woocommerce_checkout_process', 'remove_terms_validation' ); + +function remove_terms_validation() { + remove_action( 'woocommerce_checkout_process', 'woocommerce_checkout_terms_and_conditions' ); +} + +add_filter( 'woocommerce_order_button_html', 'custom_checkout_button_classes' ); + +function custom_checkout_button_classes( $button ) { + // Заменяем стандартные классы + $button = '
+ +
'; + return $button; + + + +} + +add_filter( 'woocommerce_checkout_fields', 'customize_checkout_registration_fields' ); + +function customize_checkout_registration_fields( $fields ) { + // Убираем поле ввода пароля + unset( $fields['account']['account_password'] ); + + return $fields; +} + +// Автоматическая генерация пароля +add_filter( 'woocommerce_checkout_posted_data', 'generate_password_for_registration' ); + +function generate_password_for_registration( $data ) { + + + $billing_first_name = isset( $_POST['billing_first_name'] ) ? sanitize_text_field( $_POST['billing_first_name'] ) : ''; + $billing_last_name = isset( $_POST['billing_last_name'] ) ? sanitize_text_field( $_POST['billing_last_name'] ) : ''; + $billing_address_1 = isset( $_POST['billing_address_1'] ) ? sanitize_text_field( $_POST['billing_address_1'] ) : ''; + $billing_address_2 = isset( $_POST['billing_address_2'] ) ? sanitize_text_field( $_POST['billing_address_2'] ) : ''; + $billing_city = isset( $_POST['billing_city'] ) ? sanitize_text_field( $_POST['billing_city'] ) : ''; + $billing_postcode = isset( $_POST['billing_postcode'] ) ? sanitize_text_field( $_POST['billing_postcode'] ) : ''; + $billing_country = isset( $_POST['billing_country'] ) ? sanitize_text_field( $_POST['billing_country'] ) : ''; + $billing_state = isset( $_POST['billing_state'] ) ? sanitize_text_field( $_POST['billing_state'] ) : ''; + $billing_phone = isset( $_POST['billing_phone'] ) ? sanitize_text_field( $_POST['billing_phone'] ) : ''; + $billing_email = isset( $_POST['billing_email'] ) ? sanitize_email( $_POST['billing_email'] ) : ''; + + + $data['shipping_first_name'] = $data['billing_first_name']; + $data['shipping_last_name'] = $data['billing_last_name']; + $data['shipping_address_1'] = $data['billing_address_1'] . $data['billing_address_2']; + $data['shipping_city'] = $data['billing_city']; + $data['shipping_postcode'] = $data['billing_postcode']; + $data['shipping_country'] = $data['billing_country']; + $data['shipping_state'] = $data['billing_state']; + + + + return $data; +} + + +function handle_user_registration_on_checkout() { + // Получаем данные из POST-запроса + if ( isset( $_POST['billing_email'] ) && isset( $_POST['reg'] )) { + if ($_POST['reg'] == '1'){ + + + $email = sanitize_email( $_POST['billing_email'] ); + $pass = sanitize_text_field( $_POST['pass'] ); + + // Регистрация пользователя + $user_id = custom_register_user_from_post( $email, $pass ); + + if ( is_wp_error( $user_id ) ) { + // Если email уже существует, выводим ошибку + wc_add_notice( $user_id->get_error_message(), 'error' ); + } else { + + wp_set_current_user( $user_id ); // Устанавливаем текущего пользователя + wp_set_auth_cookie( $user_id ); // Устанавливаем куки для авторизации + do_action( 'wp_login', $email, $user ); // Событие входа в систему + + }} + + } +} +add_action( 'woocommerce_checkout_process', 'handle_user_registration_on_checkout' ); + + +function custom_register_user_from_post( $email, $pass ) { + // Проверяем, есть ли уже пользователь с таким email + if ( email_exists( $email ) ) { + return new WP_Error( 'email_exists', 'Этот email уже зарегистрирован.' ); + } + + // Создаем пользователя в WordPress + $user_id = wp_create_user( $email, $pass, $email ); + if ( is_wp_error( $user_id ) ) { + return $user_id; // Возвращаем ошибку, если не удалось создать пользователя + } + + update_user_meta( $user_id, 'billing_email', $email ); // Устанавливаем email + update_user_meta( $user_id, 'user_email', $email ); // Устанавливаем email для входа + + // Устанавливаем роль пользователя как 'customer' для WooCommerce + $user = new WP_User( $user_id ); + $user->set_role( 'customer' ); + return $user_id; +} + + +add_filter( 'woocommerce_form_field', 'add_error_containers_to_checkout_fields', 10, 4 ); + +function add_error_containers_to_checkout_fields( $field, $key, $args, $value ) { + if ( is_checkout() ) { + // Добавляем контейнер для ошибок под полем + $error_container = '
'; + $field .= $error_container; + } + return $field; +} + +add_filter( 'woocommerce_add_error', 'remove_payments_word_from_errors_multilang' ); + +function remove_payments_word_from_errors_multilang( $error ) { + // Слова для удаления в разных языках + $translations = array( + 'Платежи', // Русский + 'Billing', // Английский + ); + + foreach ( $translations as $word ) { + $error = str_replace( $word, '', $error ); + } + + return trim( $error ); +} + + +add_action( 'woocommerce_checkout_process', 'validate_phone_field_with_li_data_id' ); + +function validate_phone_field_with_li_data_id() { + // Получаем значение телефона из формы + $phone = isset( $_POST['billing_phone'] ) ? sanitize_text_field( $_POST['billing_phone'] ) : ''; + + // Проверяем формат телефона + if ( ! preg_match( '/^\+?[0-9\s\-\(\)]+$/', $phone ) ) { + wc_add_notice( 'phone_err', 'error', 'billing_phone' ); + } +} + +add_action( 'woocommerce_checkout_process', 'make_address_required_for_specific_shipping' ); + +function make_address_required_for_specific_shipping() { + // Получаем выбранный метод доставки + $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); + $chosen_shipping = isset( $chosen_shipping_methods[0] ) ? $chosen_shipping_methods[0] : ''; + + // Проверяем, выбран ли метод доставки "official_cdek:137" + if ( $chosen_shipping === 'official_cdek:137' ) { + // Проверяем, заполнен ли адрес + if ( empty( $_POST['billing_address_1'] ) ) { + wc_add_notice('adress_error', 'error' ); + } + } +} + +function auto_fill_shipping_fields_from_billing( $order_id ) { + // Получаем объект заказа + $order = wc_get_order( $order_id ); + + if ( ! $order ) { + return; // Если заказ недоступен, выходим + } + + // Получаем значения полей billing из глобального $_POST + $billing_first_name = isset( $_POST['billing_first_name'] ) ? sanitize_text_field( $_POST['billing_first_name'] ) : ''; + $billing_last_name = isset( $_POST['billing_last_name'] ) ? sanitize_text_field( $_POST['billing_last_name'] ) : ''; + $billing_address_1 = isset( $_POST['billing_address_1'] ) ? sanitize_text_field( $_POST['billing_address_1'] ) : ''; + $billing_address_2 = isset( $_POST['billing_address_2'] ) ? sanitize_text_field( $_POST['billing_address_2'] ) : ''; + $billing_city = isset( $_POST['billing_city'] ) ? sanitize_text_field( $_POST['billing_city'] ) : ''; + $billing_postcode = isset( $_POST['billing_postcode'] ) ? sanitize_text_field( $_POST['billing_postcode'] ) : ''; + $billing_country = isset( $_POST['billing_country'] ) ? sanitize_text_field( $_POST['billing_country'] ) : ''; + $billing_state = isset( $_POST['billing_state'] ) ? sanitize_text_field( $_POST['billing_state'] ) : ''; + $billing_phone = isset( $_POST['billing_phone'] ) ? sanitize_text_field( $_POST['billing_phone'] ) : ''; + $billing_email = isset( $_POST['billing_email'] ) ? sanitize_email( $_POST['billing_email'] ) : ''; + + // Копируем данные в поля доставки + $order->set_shipping_first_name( $billing_first_name ); + $order->set_shipping_last_name( $billing_last_name ); + $order->set_shipping_address_1( $billing_address_1 ); + $order->set_shipping_address_2( $billing_address_2 ); + $order->set_shipping_city( $billing_city ); + $order->set_shipping_postcode( $billing_postcode ); + $order->set_shipping_country( $billing_country ); + $order->set_shipping_state( $billing_state ); + + // Сохраняем изменения в заказе + $order->save(); +} + add_filter('timber/context', function($context) { if (function_exists('is_product') && is_product()) { $product_id = get_the_ID(); @@ -53,4 +375,5 @@ } return $context; - }); \ No newline at end of file + }); + diff --git a/wp-content/themes/cosmopet/templates/layout.twig b/wp-content/themes/cosmopet/templates/layout.twig index e69de29..1c8eabc 100644 --- a/wp-content/themes/cosmopet/templates/layout.twig +++ b/wp-content/themes/cosmopet/templates/layout.twig @@ -0,0 +1,28 @@ + + + + + {{ function('wp_head') }} + {{ function('wp_title') }} + + + + + + + + + {% include 'header.twig' %} + +
+ {% block content %} + {% endblock %} + {% include 'modal.twig' %} +
+ + {% include 'footer.twig' %} + + {{ function('wp_footer') }} + + +