diff --git a/CHANGELOG.md b/CHANGELOG.md index 5869cffd..74b9019c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -78,6 +78,7 @@ - **Некорректные URL в ЛК заказов клиента (#141):** кнопка «Сбросить» фильтра и ссылки пагинации вели на корень сайта (`/?`) из-за `` в шаблоне MODX — URL формируются server-side через `makeUrl()` + `http_build_query()`, пагинация сохраняет фильтр по статусу. Добавлены недостающие SVG-иконки в спрайт (`icon-arrow-left`, `icon-truck`, `icon-credit-card`, `icon-message`), исправлен `fill` → `stroke` для Feather-иконок в деталях заказа - **Некорректные URL и хардкод английских сообщений в ЛК адресов (#142):** кнопки «Добавить адрес», «Редактировать», «Отмена» вели на корень сайта — URL формируются server-side через `makeUrl()` + `http_build_query()`. API-контроллер `CustomerAddressController` содержал хардкод английских строк вместо лексиконов — все сообщения заменены на `$this->modx->lexicon()`, добавлено 7 ключей в ru/en лексиконы - **Отсутствие ключа `desc` в свойствах сниппетов и источников при сборке пакета (#127):** добавлена инициализация `desc` пустой строкой если ключ отсутствует в определении свойства — устраняет warning/ошибку в `resolver_04_sources` и `resolver_08_snippet_properties` +- **Ссылка на товар в таблице категории открывалась в новой вкладке:** у шаблона колонки `pagetitle` убран `target="_blank"` в дефолтном конфиге Vue, в сидере грида и миграцией для уже сохранённых записей `ms3_grid_fields` #### ⚠️ Breaking changes diff --git a/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php b/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php index 6cce055d..3ae3c2f8 100644 --- a/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php +++ b/core/components/minishop3/migrations/20251231140000_seed_category_products_grid_config.php @@ -60,7 +60,7 @@ public function up() 'min_width' => '200px', 'config' => json_encode([ 'type' => 'template', - 'template' => '({id}) {pagetitle}' + 'template' => '({id}) {pagetitle}' ], JSON_UNESCAPED_UNICODE), 'is_system' => 0, 'is_default' => 1, diff --git a/core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php b/core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php new file mode 100644 index 00000000..ac1b8c05 --- /dev/null +++ b/core/components/minishop3/migrations/20260328120000_category_products_pagetitle_link_same_tab.php @@ -0,0 +1,102 @@ +gridFieldsTable(); + $stmt = $this->getAdapter()->getConnection()->prepare( + "UPDATE `{$table}` SET config = ? WHERE id = ?" + ); + + foreach ($this->fetchPagetitleFieldRows() as $row) { + $config = json_decode($row['config'], true); + if (!is_array($config) || empty($config['template']) || !is_string($config['template'])) { + continue; + } + $template = $config['template']; + if (!$this->templateHasBlankTarget($template)) { + continue; + } + $config['template'] = $this->stripBlankTargetFromTemplate($template); + $stmt->execute([json_encode($config, JSON_UNESCAPED_UNICODE), (int) $row['id']]); + } + } + + public function down(): void + { + $table = $this->gridFieldsTable(); + $stmt = $this->getAdapter()->getConnection()->prepare( + "UPDATE `{$table}` SET config = ? WHERE id = ?" + ); + + foreach ($this->fetchPagetitleFieldRows() as $row) { + $config = json_decode($row['config'], true); + if (!is_array($config) || empty($config['template']) || !is_string($config['template'])) { + continue; + } + $template = $config['template']; + if ($this->templateHasBlankTarget($template)) { + continue; + } + $restored = $this->restoreBlankTargetBeforeProductLinkClass($template); + if ($restored === null) { + continue; + } + $config['template'] = $restored; + $stmt->execute([json_encode($config, JSON_UNESCAPED_UNICODE), (int) $row['id']]); + } + } + + private function gridFieldsTable(): string + { + $prefix = $this->getAdapter()->getOption('table_prefix'); + + return $prefix . 'ms3_grid_fields'; + } + + /** + * @return list + */ + private function fetchPagetitleFieldRows(): array + { + $table = $this->gridFieldsTable(); + + return $this->fetchAll( + "SELECT id, config FROM `{$table}` WHERE grid_key = 'category-products' AND field_name = 'pagetitle'" + ); + } + + private function templateHasBlankTarget(string $template): bool + { + return str_contains($template, 'target="_blank"') + || str_contains($template, "target='_blank'"); + } + + private function stripBlankTargetFromTemplate(string $template): string + { + return str_replace([' target="_blank"', " target='_blank'"], '', $template); + } + + /** + * Re-inserts target="_blank" only for templates that use class product-link (stock layout). + */ + private function restoreBlankTargetBeforeProductLinkClass(string $template): ?string + { + if (str_contains($template, 'class="product-link"')) { + return str_replace(' class="product-link"', ' target="_blank" class="product-link"', $template); + } + if (str_contains($template, "class='product-link'")) { + return str_replace(" class='product-link'", " target='_blank' class='product-link'", $template); + } + + return null; + } +} diff --git a/vueManager/src/components/CategoryProductsGrid.vue b/vueManager/src/components/CategoryProductsGrid.vue index 2e2b213c..e765408c 100644 --- a/vueManager/src/components/CategoryProductsGrid.vue +++ b/vueManager/src/components/CategoryProductsGrid.vue @@ -540,7 +540,7 @@ function getDefaultColumns() { minWidth: '12.5rem', type: 'template', template: - '({id}) {pagetitle}', + '({id}) {pagetitle}', }, { name: 'article',