Проблема пагинации в самописном фильтре для товаров minishop2

У меня есть сниппет который генерирует пользовательские фильтры добалвенные через tv — тут кроме генерации строк ничего нет.
Получаю такую форму
<form id="filter-form">
        {set $tvValues = $_modx->runSnippet('getTVValuesFromDB')}
        {if $tvValues}
            {set $filters = json_decode($tvValues, true)}
             <div class="filter-section">
                <div class="filter-title">
                    [[%mmix.composition? &namespace=`innova`]] <span class="arrow"><img src="files/img/items/expand.png" alt=""></span>
                </div>
                <div class="filter-content open">
                    {if $filters.ice_properties_uk}
                        {foreach $filters.ice_properties_uk as $value}
                            <li>
                                <label class='label-checkbox'>
                                    <input type="checkbox" class="filter-checkbox checkbox-input" name="properties[]" value="{$value}"><span>{$value}</span>
                                </label>
                            </li>
                        {/foreach}
                    {/if}
                </div>
            </div>
                                        
            <div class="filter-section">
                <div class="filter-title">
                    [[%mmix.packaging? &namespace=`innova`]] <span class="arrow"><img src="files/img/items/expand.png" alt=""></span>
                </div>
                <div class="filter-content open">
                    {if $filters.weight}
                        {foreach $filters.weight as $value}
                            <li>
                                <label class='label-checkbox'>
                                    <input type="checkbox" class="filter-checkbox checkbox-input" name="weight[]" value="{$value}"><span>{$value}г</span>
                                </label>
                            </li>
                        {/foreach}
                    {/if}
                    <input type="hidden" name="idResource" value="[[*id]]">
                </div>
            </div>
        {else}
            <li>Фильтры не заданы</li>
        {/if}
</form>
В общем в нем все ок.
Дальше идет js, который отправляет данные на файл обработчик. Дело в том, что этот js пока что не работает с пагинацией и файл обработчик отлично с ним работает и возвращает товары переданные в фильтр
<script>
    $(document).ready(function () {
    $('.filter-checkbox').on('change', function () {
        updateProducts();
    });

    function updateProducts() {
        let filterData = $('#filter-form').serialize();
        let parentId = [[*id]]; // ID категории

        $.ajax({
            url: '/assets/components/filter.php',
            type: 'GET',
            data: filterData + '&parent=' + parentId,
            beforeSend: function () {
                $('#products-container').html('<p>Загрузка...</p>');
            },
            success: function (data) {
                $('#products-container').html(data);
            }
        });
    }
});
</script>
Вот так выглядит сам файл обработчик
<?php
define('MODX_API_MODE', true);
require_once dirname(dirname(dirname(__FILE__))) . '/index.php';

$modx->getService('error', 'error.modError', '', '');
$modx->setLogLevel(modX::LOG_LEVEL_ERROR);
$modx->setLogTarget('FILE');

if ($modx->getOption('idShop') == $_GET['idResource']) {
    $id = isset($_GET['parent']) ? (int)$_GET['parent'] : 0;
    if ($id === 0) {
        echo json_encode(['error' => 'Ошибка: отсутствует ID категории']);
        exit;
    }
//    print_r($_GET);

    $query = $modx->newQuery('modResource');
    $query->select('id');
    $query->where(['parent' => $id]);
    $query->prepare();
    $query->stmt->execute();
    $childCategories = $query->stmt->fetchAll(PDO::FETCH_COLUMN);

    $parentIds = !empty($childCategories) ? $childCategories : [$id];

} else {
    $id = isset($_GET['parent']) ? (int)$_GET['parent'] : 0;
    if ($id === 0) {
        echo json_encode(['error' => 'Ошибка: отсутствует ID категории']);
        exit;
    }
    $parentIds = [$id];
}

$properties = isset($_GET['properties']) ? array_filter($_GET['properties']) : [];
$weight = isset($_GET['weight']) ? (array)$_GET['weight'] : [];

$where = [];

$propertyWhere = [];
if (!empty($properties)) {
    foreach ($properties as $property) {
        $propertyWhere[] = "tv.value LIKE '%" . trim($property) . "%'";
    }
    if (!empty($propertyWhere)) {
        $where[] = '(' . implode(' OR ', $propertyWhere) . ')';
    }
}

if (!empty($weight)) {
    $where[] = "tv_weight.value IN ('" . implode("','", array_map('trim', $weight)) . "')";
}

$query = $modx->newQuery('modResource');
$query->distinct();
$query->leftJoin('modTemplateVarResource', 'tv', 'tv.contentid = modResource.id AND tv.tmplvarid = ' . $modx->getObject('modTemplateVar', ['name' => 'ice_properties_uk'])->get('id'));
$query->leftJoin('modTemplateVarResource', 'tv_weight', 'tv_weight.contentid = modResource.id AND tv_weight.tmplvarid = ' . $modx->getObject('modTemplateVar', ['name' => 'weight'])->get('id'));

$query->select('modResource.id');
$query->where(['modResource.parent:IN' => $parentIds]);

if (!empty($where)) {
    $query->where(implode(' AND ', $where));
}

$query->prepare();
$query->stmt->execute();
$productIds = $query->stmt->fetchAll(PDO::FETCH_COLUMN);

if (empty($productIds)) {
    echo '<p>Товары не найдены</p>';
    exit;
}

$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
//print_r($productIds);
$output = $modx->runSnippet('pdoPage', [
    'class' => 'msProduct',
    'resources' => implode(',', $productIds),
    'tpl' => 'tpl.msProducts.row',
    'includeTVs' => 'back-img,product-img,ice_properties_uk,weight',
    'limit' => 2,
    'showHidden' => 0,
    'pageVarKey' => 'page',
    'page' => $page,
    'loadModels' => 'ms2',
    'leftJoin' => json_encode([
        "msProductData" => [
            "class" => "msProductData",
            "on" => "msProduct.id = msProductData.id"
        ]
    ]),
    'select' => json_encode([
        "msProduct" => "id, pagetitle",
        "msProductData" => "price",
        "modx_ms2_products" => "opisanie_produkta,weight"
    ])
]);

echo '<pre>';
print_r($output);
echo '</pre>';
exit;
в нем незаконченный код пагинации, но суть в другом. Проблема заключается в том, что когда я пишу скрипт, который описывает пагинацию, то $output ничего не возвращает.

вот сам скрипт с пагинацией
<script>
    $(document).ready(function () {
        $('.filter-checkbox').on('change', function () {
            updateProducts();
        });

        $('#products-container').on('click', '.pagination a', function(e) {
            e.preventDefault();
            let pageUrl = $(this).attr('href');
            let urlParams = new URLSearchParams(pageUrl.split('?')[1]);
            let pageParam = urlParams.get('page') || 1;
            updateProducts(pageParam);
        });

        function updateProducts(page = 1) {
        console.log('Page:', page);

    let filterData = $('#filter-form').serialize();
    let parentId = [[*id]];
    $.ajax({
        url: '/assets/components/filter.php',
        type: 'GET',
        data: filterData + '&parent=' + parentId + '&page=' + page,
        beforeSend: function () {
            $('#products-container').html('<p>Загрузка...</p>'); 
        },
        success: function (data) {
            console.log('Response:', data);
            $('#products-container').html(data); 
        }
    });
}
    });
</script>
в переменную $productIds достаются айдишники товаров, что в первом, что во втором случае.
Как вы думаете, в чем может быть проблема? Я подозреваю то, что проблема в том что со js скриптом пагинации этот код просто некорректно работает
$output = $modx->runSnippet('pdoPage', [
    'class' => 'msProduct',
    'resources' => implode(',', $productIds),
    'tpl' => 'tpl.msProducts.row',
    'includeTVs' => 'back-img,product-img,ice_properties_uk,weight',
    'limit' => 2,
    'showHidden' => 0,
    'pageVarKey' => 'page',
    'page' => $page,
    'loadModels' => 'ms2',
    'leftJoin' => json_encode([
        "msProductData" => [
            "class" => "msProductData",
            "on" => "msProduct.id = msProductData.id"
        ]
    ]),
    'select' => json_encode([
        "msProduct" => "id, pagetitle",
        "msProductData" => "price",
        "modx_ms2_products" => "opisanie_produkta,weight"
    ])
]);
Alex
22 февраля 2025, 18:16
modx.pro
1
195
0

Комментарии: 4

Артур Шевченко
22 февраля 2025, 19:06
+1
Если решил делать пагинацию сам, то зачем используешь pdoPage? pdoPage твой js не понимает, больше скажу, pdoPage не умеет работать с динамическими параметрами, т.е. какие при вызове задал по таким выборку он и сделает и потом ничего пересчитывать не будет.
В твоём случае надо использовать вот это
    Alex
    23 февраля 2025, 03:16
    0
    Спасибо вам за то, что подсказали правильное направление — все получилось)
      Артур Шевченко
      23 февраля 2025, 11:42
      +1
      Ты первый у кого с SendIt всё получилось с первого раза)))
        Alex
        23 февраля 2025, 14:39
        0
        Возможно вариант неидеальный и неокончательный, но уже рабочий)
        В шаблоне внес правки в скрипт
        <script>
        $(document).ready(function () {
            let parentId = [[*id]];
        
            updateProducts(1, true);
        
            $('.filter-checkbox').on('change', function () {
                updateProducts(1, true);
            });
        
            $('#products-container').on('click', '.pagination a', function(e) {
                e.preventDefault();
                let pageUrl = $(this).attr('href');
                let urlParams = new URLSearchParams(pageUrl.split('?')[1]);
                let pageParam = urlParams.get('page') || 1;
                updateProducts(pageParam, true);
            });
        
            function updateProducts(page = 1, replaceContent = true) {
                console.log('Page:', page);
        
                let filterData = $('#filter-form').serialize();
        
                $.ajax({
                    url: '/assets/components/filter.php',
                    type: 'GET',
                    data: filterData + '&parent=' + parentId + '&page=' + page,
                    beforeSend: function () {
                        if (replaceContent) {
                            $('#products-container').html('<p>Загрузка...</p>');
                        }
                    },
                    success: function (data) {
                        console.log('Response:', data);
                        if (replaceContent) {
                            $('#products-container').html(data);
                        } else {
                            $('#products-container').append(data);
                        }
                    },
                    error: function(xhr, status, error) {
                        console.log('Error:', status, error);
                    }
                });
            }
        });
        </script>
        И в файле обработчике поменял вызов на

        $page = isset($_GET['page']) ? max((int)$_GET['page'], 1) : 1;
        $limit = 1;
        $offset = ($page - 1) * $limit;
        $total = count($productIds);
        $pages = ceil($total / $limit);
        $productIds = array_slice($productIds, $offset, $limit);
        
        $output = $modx->runSnippet('Pagination', [
            'class' => 'msProduct',
            'render' => '!pdoResources',
            'resources' => implode(',', $productIds),
            'tpl' => 'tpl.msProducts.row',
            'includeTVs' => 'back-img,product-img,ice_properties_uk,weight',
            'tplEmpty' => '',
            'limit' => $limit,
            'loadModels' => 'ms2',
            'includeContent' => 1,
            'page' => $page,
            'maxPageListItems' => 5,
            'pagination' => 'one',
            'leftJoin' => json_encode([
                "msProductData" => [
                    "class" => "msProductData",
                    "on" => "msProduct.id = msProductData.id"
                ]
            ]),
            'select' => json_encode([
                "msProduct" => "id, pagetitle",
                "msProductData" => "price",
                "modx_ms2_products" => "opisanie_produkta,weight"
            ])
        ]);
        
        $output .= '<div class="pagination">';
        if ($page > 1) {
            $output .= '<a href="?page=' . ($page - 1) . '">« Предыдущая</a>';
        }
        for ($i = 1; $i <= $pages; $i++) {
            $output .= '<a href="?page=' . $i . '"' . ($i === $page ? ' class="active"' : '') . '>' . $i . '</a>';
        }
        if ($page < $pages) {
            $output .= '<a href="?page=' . ($page + 1) . '">Следующая »</a>';
        }
        $output .= '</div>';
        
        echo $output;
        exit;
    Авторизуйтесь или зарегистрируйтесь, чтобы оставлять комментарии.
    4