Skip Navigation

This is the technical support forum for WPML - the multilingual WordPress plugin.

Everyone can read, but only WPML clients can post here. WPML team is replying on the forum 6 days per week, 22 hours per day.

Sun Mon Tue Wed Thu Fri Sat
- 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 8:00 – 12:00 -
- 12:00 – 16:00 12:00 – 16:00 12:00 – 16:00 12:00 – 16:00 12:00 – 16:00 -

Supporter timezone: Europe/Zagreb (GMT+01:00)

Tagged: 

This topic contains 5 replies, has 1 voice.

Last updated by Dražen 7 hours, 28 minutes ago.

Assisted by: Dražen.

Author Posts
January 17, 2025 at 4:57 pm #16607607

aleksandrsC

Background of the issue:
I wrote a script to update the stock and prices of products using the WooCommerce API. The script modifies only the main language via requests by product ID, expecting the other languages to synchronize automatically for stock and price. When I perform the same process manually through the admin panel, everything works as expected, and the translations are not reset. Link to a page where the issue can be seen:


from googleapiclient.discovery import build
import requests
from concurrent.futures import ThreadPoolExecutor, as_completed
from datetime import datetime  # Для работы со временем
 
# Настройки Google Sheets API
SPREADSHEET_ID = '-------------------'  # ID вашей таблицы
SHEET_NAME = 'Hook'  # Имя листа в таблице
 
# Настройки WooCommerce API
WC_API_URL = '<em><u>hidden link</u></em>'
CONSUMER_KEY = '--------'
CONSUMER_SECRET = '--------------'
 
# Фиксация времени начала
start_time = datetime.now()
print(f"Время начала: {start_time.strftime('%Y-%m-%d %H:%M:%S')}")
 
# Подключение к Google Sheets
service = build('sheets', 'v4', developerKey='--------------------')
sheet = service.spreadsheets()
 
# Считывание данных
range_name = f'{SHEET_NAME}!A:E'  # Диапазон данных (например, A и E колонки)
result = sheet.values().get(spreadsheetId=SPREADSHEET_ID, range=range_name).execute()
rows = result.get('values', [])
 
# Проверка: есть ли данные
if not rows:
    print("Нет данных для обработки.")
    exit()
 
# Формируем список продуктов для обновления
products_to_update = []
 
print("Данные из таблицы Google Sheets:")
for row in rows:
    if len(row) >= 5:  # Убедимся, что нужные колонки существуют
        product_id = row[1]  # ID продукта
        in_stock = row[3]  # Статус наличия
        price = row[4]  # Цена
 
        stock_status = "instock" if in_stock == '1' else "outofstock"
         
        # Добавляем продукт в список для batch-обновления
        products_to_update.append({
            "id": int(product_id),
            "stock_status": stock_status,
            "regular_price": price
        })
        print(f"ID продукта: {product_id}, В наличии: {stock_status}, Цена: {price}")
 
# Если нечего обновлять, завершаем выполнение
if not products_to_update:
    print("Нет товаров для обновления.")
    exit()
 
# Максимальное количество товаров в одном запросе
BATCH_SIZE = 50
MAX_WORKERS = 3  # Количество потоков для асинхронной обработки
 
# Функция для отправки batch-запроса
def send_batch_update(batch, start_index):
    payload = {"update": batch}
    try:
        response = requests.post(WC_API_URL, auth=(CONSUMER_KEY, CONSUMER_SECRET), json=payload)
        if response.status_code == 200:
            print(f"Успешно обновлены товары (с {start_index + 1} по {start_index + len(batch)}):")
            for updated_product in response.json().get("update", []):
                print(f"- Product ID {updated_product['id']}: {updated_product['stock_status']}, Цена: {updated_product.get('regular_price', 'N/A')}")
        else:
            print(f"Ошибка при обновлении батча с {start_index + 1} по {start_index + len(batch)}: {response.text}")
    except Exception as e:
        print(f"Ошибка в запросе с {start_index + 1} по {start_index + len(batch)}: {e}")
 
# Функция разделения на батчи и асинхронной отправки
def update_products_bulk_async(products):
    with ThreadPoolExecutor(max_workers=MAX_WORKERS) as executor:
        futures = []
        for i in range(0, len(products), BATCH_SIZE):
            batch = products[i:i + BATCH_SIZE]
            futures.append(executor.submit(send_batch_update, batch, i))
         
        # Обработка завершенных задач
        for future in as_completed(futures):
            try:
                future.result()  # Проверяем результат выполнения
            except Exception as e:
                print(f"Ошибка выполнения задачи: {e}")
 
# Основной код
print("Начало массового обновления товаров...")
try:
    update_products_bulk_async(products_to_update)
except Exception as e:
    print(f"Ошибка при выполнении batch-обновления: {e}")
print("Обновление завершено.")
 
# Фиксация времени окончания
end_time = datetime.now()
print(f"Время окончания: {end_time.strftime('%Y-%m-%d %H:%M:%S')}")
 
# Вывод длительности выполнения
duration = end_time - start_time
print(f"Общее время выполнения: {duration}")
print("Обновление завершено.")

Symptoms:
After each use of the script, the translations for all the products involved in the process are reset and end up matching the main language.

Questions:
Why do translations reset after using the script?
How can I prevent translations from being overwritten?

January 21, 2025 at 9:33 am #16617297

Alejandro
Supporter

Languages: English (English ) Spanish (Español ) Italian (Italiano )

Timezone: Europe/Rome (GMT+01:00)

Hello,

I'll help you get started while a supporter takes your case.

1) Please know that we do not support custom coding so we can't really help much here. However, when you do things manually and save a post, you're actually executing a series of hooks that are not being executed here. try to find and use the "save_post" hook and see if by calling it after you finish making changes to it, the content gets updated.

2) Did this code ever work before? if so do you know when did it stop working?

Regards,

January 21, 2025 at 11:11 pm #16620705

aleksandrsC

Hello,

I understand that custom coding is not supported, but anyway maybe I can receive some suggestions.
The script perfectly does its job. It sends only id, stock_status, and regular_price fields to the API to ensure minimal changes.
While the updates for stock and prices are correctly reflected on all languages, the translations (such as product names and descriptions) for the affected products are reset to match the main language.

Here are my questions:

Why does updating products via WooCommerce REST API reset translations?
How can I prevent translations from being overwritten when updating stock and prices through the API?

Thank you,
Aleksandrs.

January 22, 2025 at 7:11 am #16621247

Dražen
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello Aleksandrs,

update of stock and price should not reset translations, but could be that you added this translation manually but have not disabled WPML editor. Then any save in default language will reset manual added translations. Can you please check?

- https://wpml.org/documentation/translating-your-contents/using-different-translation-editors-for-different-pages/

Regards,
Drazen

step-1-arrow-wp-editor-1.jpg
January 22, 2025 at 10:27 am #16622172

aleksandrsC

Hello Drazen,

Thanks for your reply. Actually I'm using same design for every language.

When I add new products to the website, I duplicate every product to all languages via WPML "Translation Management" tab to get new ID for every language. After that I update every new duplicated product by ID via WordPress product import CSV (every language separately).

Should I disable WPML editor in this case?
And there is a option how to disable WPML editor for all products at once?

Best regards,
Aleksandrs.

January 22, 2025 at 12:12 pm #16622729

Dražen
Supporter

Languages: English (English )

Timezone: Europe/Zagreb (GMT+01:00)

Hello Aleksandrs,

since you duplicated them, maybe they are still left as duplicates so it sync /duplicates content on save., I would advise checking post meta table for icl_duplicate_of and delete if any.

If not, when you switch to WP editor there will be a popup asking you if you wish to switch for that post, all posts or website.

Regards,
Drazen