Skip to content

Производительность: extend_cart_data() кладёт весь список ПВЗ в каждый ответ Store API /cart (блочный чекаут) #148

Description

@dzvtr

Проблема

На блочном чекауте (WooCommerce Checkout block / Store API) метод CheckoutMapBlock::extend_cart_data() (src/Blocks/CheckoutMapBlock.php) регистрируется через woocommerce_store_api_register_endpoint_data() на схему корзины (CartSchema) и возвращает поле points = весь JSON-список ПВЗ выбранного города ($api->officeListRaw($city)).

Это поле попадает в каждый ответ GET /wp-json/wc/store/v1/cart. Блочный чекаут перезапрашивает /cart многократно (при загрузке страницы и при любом update — десятки запросов за сессию оформления), поэтому один и тот же большой payload со списком ПВЗ передаётся по сети снова и снова.

Замеры

После ввода города ответ /cart раздувается с ~13 КБ до ~1 МБ (для крупного города — весь список пунктов выдачи; у нас фиксировали ~1.14 МБ). На пустой корзине / без города — норма (points: "[]").

Влияние

  • заметное замедление и подтормаживание страницы оформления, особенно на мобильных и медленных соединениях;
  • многократный лишний трафик (одни и те же ~1 МБ в каждом опросе /cart);
  • если officeListRaw() не кэшируется — ещё и повторные обращения к api.cdek.ru на каждый запрос.

Вероятно, это же является корнем #131 (много запросов / долгая загрузка), но там симптом описан на странице каталога — здесь конкретно про размер payload Store API /cart на чекауте.

Код (5.0.0)

public static function extend_cart_data(): array
{
    $cityInput     = CheckoutHelper::getCurrentValue('city');
    $postcodeInput = CheckoutHelper::getCurrentValue('postcode');

    if (empty($cityInput)) {
        return ['points' => '[]'];
    }

    $api = new CdekApi;
    try {
        $city   = $api->cityCodeGet($cityInput, $postcodeInput);
        $points = $city !== null ? $api->officeListRaw($city) : '[]';
    } catch (ExceptionContract $e) {
        $city   = null;
        $points = '[]';
    }

    return [
        'inputs' => ['city' => $cityInput, 'postcode' => $postcodeInput],
        'city'   => $city,
        'points' => $points, // весь список ПВЗ города — в каждом ответе /cart
    ];
}

Окружение

  • CDEKDelivery 5.0.0
  • WooCommerce 10.9.1, WordPress 7.0, PHP 8.3.31
  • Чекаут — блочный (Store API /wp-json/wc/store/v1/cart)

Как воспроизвести

  1. Блочный чекаут, товар в корзине.
  2. Ввести город доставки.
  3. В DevTools → Network посмотреть ответы GET /wp-json/wc/store/v1/cart: в extensions.official_cdek.points — весь список ПВЗ (~1 МБ), и он повторяется в каждом из множества запросов /cart.

Ожидаемое поведение / предложение по исправлению

Не вкладывать полный список ПВЗ в расширение CartSchema, отдаваемое на каждый /cart. Варианты:

  1. вынести список ПВЗ в отдельный on-demand REST-эндпоинт, который фронтенд запрашивает один раз при открытии карты выбора пункта выдачи;
  2. либо отдавать points только при фактической смене города, а не в каждом ответе;
  3. как минимум — серверное кэширование списка ПВЗ и/или отдача компактного набора полей.

Готовы предоставить HAR и тайминги при необходимости. Спасибо!

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions