• uxtora

    (@uxtora)


    Привет. Данный плагин супер, но есть один минус в плане работы с WooCommerce и любыми языками кроме англ. Дело в том, что он автоматом таки переводит ВНУТРЕННИЕ атрибуты в товаре, ровно как и глобальные. Хотя не должен этого делать, ибо тогда ломается стандартный вывод вариантов товара в корзине. Т.е допустим я добавил внутренний(!) атрибут “Цвет”. По итогу он будет выводить его как tsvet. Хотя из коробки WooCommerce выводит так, как написали, ибо это не сущность.

    Почему is_wc_attribute() ВСЕГДА возвращает false для внутренних атрибутов:

    is_wc_attribute_taxonomy() → проверяет глобальные атрибуты WooCommerce
    Внутренний атрибут “цвет” → НЕ глобальный → false

    is_wc_product_not_converted_attribute() → сломанная логика:

    php
    protected function is_wc_product_not_converted_attribute( string $title ): bool {
    global $product; // ← ПРОБЛЕМА 1: часто NULL

    if ( ! is_a( $product, 'WC_Product' ) ) {
        return false; // ← Часто срабатывает здесь
    }
    
    $attributes = (array) get_post_meta( $product->get_id(), '_product_attributes', true );
    // ... проверяет уже сохранённые атрибуты

    }
    Почему global $product часто NULL:
    При сохранении товара из админки WooCommerce не всегда устанавливает эту глобальную переменную. При AJAX-обработке атрибутов она точно не установлена
    Метод вызывается из контекста sanitize_title(), а не из страницы товара

    Итог:
    is_wc_attribute_taxonomy(“цвет”) → false
    is_wc_product_not_converted_attribute(“цвет”) → false (потому что global $product = NULL)
    is_wc_attribute(“цвет”) → false
    transliterate(“цвет”) → “tsvet”

    Ошибка в коде: Метод is_wc_product_not_converted_attribute() пытается определить атрибут по уже сохранённым данным, но не учитывает, что:

    НОВЫЙ атрибут ещё не сохранён

    Глобальная переменная $product не установлена в нужном контексте

    Надо проверять не метаполя, а $_POST данные или контекст сохранения товара

Viewing 15 replies - 1 through 15 (of 15 total)
  • Plugin Author kaggdesign

    (@kaggdesign)

    Да, проблема известная. Спасибо за более подробное описание. Постараемся найти время и пофиксить.

    Plugin Author kaggdesign

    (@kaggdesign)

    Я поправил. Посмотрите 6.7.0-RC1 – решает вашу проблему? https://github.com/mihdan/cyr2lat/releases/download/v6.7.0-RC1/cyr2lat.6.7.0-RC1.zip

    Plugin Author kaggdesign

    (@kaggdesign)

    Похоже, что не решает… Вижу сам. Вернусь к этой теме позже.

    Thread Starter uxtora

    (@uxtora)

    Твой фикс ловит только woocommerce_save_attributes. Это AJAX-сохранение внутри карточки “сохранить атрибуты”, там вроде всё ок.

    Но основная проблема — при полном сохранении товара. Когда жмёшь «Опубликовать» или «Обновить», WooCommerce не вызывает этот экшн. Атрибуты приходят в $_POST['attribute_names'] и сохраняются напрямую в _product_attributes. + у массового редактирования…

    Расширить метод is_local_attribute()?

    protected function is_local_attribute( string $title ): bool {
    // 1. Глобальные атрибуты — не трогаем, это не локальные
    if ( 0 === strpos( $title, 'pa_' ) ) {
    return false;
    }

    // 2. Сохранение через карточку товара (редактирование атрибутов)
    $action = isset( $_POST['action'] )
    ? sanitize_text_field( wp_unslash( $_POST['action'] ) )
    : '';

    if ( 'woocommerce_save_attributes' === $action ) {
    $data = isset( $_POST['data'] )
    ? filter_input( INPUT_POST, 'data', FILTER_SANITIZE_URL )
    : '';
    wp_parse_str( urldecode( $data ), $attributes );
    $attribute_names = $attributes['attribute_names'] ?? [];
    return in_array( $title, $attribute_names, true );
    }

    // 3. Полное сохранение товара (кнопка «Обновить»)
    if ( doing_action( 'save_post' ) || doing_action( 'wp_insert_post' ) ) {
    if ( isset( $_POST['attribute_names'] ) && is_array( $_POST['attribute_names'] ) ) {
    return in_array( $title, $_POST['attribute_names'], true );
    }
    }

    return false;
    }

    Как считаешь, это решит проблему полностью? По-хорошему нужно вообще тотально вырезать работу с внутренними атрибутами и вообще их не трогать ровно как и глобальные. Это не в “политике” плагина.

    Thread Starter uxtora

    (@uxtora)

    ну или

    protected function is_local_attribute( string $title ): bool {
    // ВСЁ ЧТО НЕ pa_ — ЭТО ВНУТРЕННИЙ АТРИБУТ, НЕ ТРОГАЕМ
    if ( 0 !== strpos( $title, 'pa_' ) ) {
    return true;
    }

    return false;
    }

    ?



    Thread Starter uxtora

    (@uxtora)

    В настройках плагина есть флажок «Товары (product)», но он отключает только фоновую конвертацию существующих слагов.

    Живая транслитерация при сохранении товара и атрибутов всё равно работает, потому что висит на sanitize_title и не проверяет эту настройку.

    Предлагаю либо:

    1. Сделать, чтобы sanitize_title уважал настройку «Товары (product)», либо
    2. Добавить отдельную настройку «Не трогать атрибуты WooCommerce» (+ разделить какие именно не трогать).

    Я предлагаю вариант 2 — просто исключить всё с префиксом pa_ и всё без pa_ в контексте WooCommerce.

    Просто например при синхронизации товаров с моим складом ломается абсолютно всё, ибо все синхронизации заточены под ваниль, а не под переведённые

    Thread Starter uxtora

    (@uxtora)

    Или вовсе так:

    public function sanitize_title( $title, $raw_title = '', $context = '' ) {
    global $wpdb;

    // Не транслитерировать при создании глобальных WC атрибутов
    if ( function_exists( 'wc_sanitize_taxonomy_name' ) ) {
    $trace = debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS );

    foreach ( $trace as $call ) {
    if (
    isset( $call['function'] ) &&
    $call['function'] === 'wc_sanitize_taxonomy_name'
    ) {
    return $title;
    }
    }
    }

    if (
    ! $title ||
    'query' === $context ||
    ! $this->transliterate_on_pre_term_slug_filter( (string) $title )
    ) {
    return $title;
    }

    $title = urldecode( (string) $title );
    $pre = apply_filters( 'ctl_pre_sanitize_title', false, $title );

    if ( false !== $pre ) {
    return $pre;
    }

    if ( $this->is_term ) {
    $this->is_term = false;

    if ( $this->is_frontend && class_exists( SitePress::class ) ) {
    return $title;
    }

    $sql = $wpdb->prepare(
    "SELECT slug FROM $wpdb->terms t LEFT JOIN $wpdb->term_taxonomy tt
    ON t.term_id = tt.term_id
    WHERE t.slug = %s",
    rawurlencode( $title )
    );

    if ( $this->taxonomies ) {
    $sql .= ' AND tt.taxonomy IN (' . $this->prepare_in( $this->taxonomies ) . ')';
    }

    $term = $wpdb->get_var( $sql );

    if ( ! empty( $term ) ) {
    return $term;
    }
    }

    return $this->is_wc_attribute( $title ) ? $title : $this->transliterate( $title );
    }

    }

    • This reply was modified 2 months ago by uxtora.
    Thread Starter uxtora

    (@uxtora)

    Я сделал себе “личный cyr-to-lat. Он переводит всё кроме атрибутов. Если интересно – скажи, скину

    Plugin Author kaggdesign

    (@kaggdesign)

    Нет, спасибо.

    Если есть желание – можно сделать PR на GitHub, с тестами.

    Я сделаю позже фильтр на WC атрибуты, чтобы закрыть проблему. И более корректную обработку атрибутов. К слову, debug_backtrace – не решение. Это тормоз.

    Thread Starter uxtora

    (@uxtora)

    нене, я сделал вообще иначе, без debug_backtrace . Твой плагин не трогал. И всё что было в прошлых коммах тоже не использовал.
    Вот если интересно – https://github.com/uxtora/cyr-to-lat-wp-personal-.git
    Проверил, работает. Что думаешь?

    Если поможет в фиксе – буду рад.

    • This reply was modified 2 months ago by uxtora.
    • This reply was modified 2 months ago by uxtora.
    Thread Starter uxtora

    (@uxtora)

    Дополнил

    Thread Starter uxtora

    (@uxtora)

    Привет. Нашёл ещё одну очень сильную проблему. Возможно она появилась после обновлений – хз. Если сохранить страницу и потом поменять слаг напрямую – он возвращает старый после сохранения. Т,е допустим ты создал страницу “Главная”, он создал ей слаг “glavnaya”. Нажал сохранить. Страница сохранилась. Потом ты решил поменять слаг вручную на “home”. Идешь редачить, AJAX улетает, вроде всё окей, но при сохранении получаешь опять старый слаг. Т.е пост нейм у него почему-то пустой. Я проверил несколько плагинов и везде такая же проблема. + тестировал, просто делал ключи+санитайз = та же проблема. Я решил лишь при прямой перезаписи в БД, но это не совсем правильно т.к обходятся стандартные хуки и тд. Но вроде как при аяксе пофигу… Не знаю. Там есть дебаг файлы, попробуй убери $wpdb->update и поменяй на ванилу, тебе вернёт старый слаг. Короче вп..
    https://github.com/uxtora/cyr-to-lat-wp-personal-/blob/main/record%20to%20DB%20AJAX

    • This reply was modified 1 month, 4 weeks ago by uxtora.
    • This reply was modified 1 month, 4 weeks ago by uxtora.
    Plugin Author kaggdesign

    (@kaggdesign)

    Спасибо за детали.

    По основной теме — я вернусь к этому вопросу позже.

    Что касается предложенного решения через кастомный плагин: спасибо, что поделились, но я не могу разбирать и отлаживать сторонний/самописный код. Это выходит за рамки поддержки нашего плагина.

    Thread Starter uxtora

    (@uxtora)

    Привет. Поправили?

    Plugin Author kaggdesign

    (@kaggdesign)

    Мы выпустили новую версию 6.7.0. Посмотрите, решает ли она проблему.

Viewing 15 replies - 1 through 15 (of 15 total)

You must be logged in to reply to this topic.