PDO::ERRMODE_EXCEPTION]); } catch (Exception $e) { die("Ошибка БД: " . $e->getMessage()); } if (isset($_GET['ajax']) && $_GET['ajax'] === 'target' && isset($_GET['q'])) { $q = '%' . trim($_GET['q']) . '%'; $stmt = $pdo->prepare("SELECT id, code, name FROM shop_feature WHERE name LIKE ? OR code LIKE ? ORDER BY name LIMIT 30"); $stmt->execute([$q, $q]); $results = $stmt->fetchAll(PDO::FETCH_ASSOC); header('Content-Type: application/json; charset=utf-8'); echo json_encode($results); exit; } $message = $norm_message = $units_message = ''; $tab = $_GET['tab'] ?? 'merge'; if ($tab === 'merge' && isset($_POST['action']) && $_POST['action'] === 'merge' && !empty($_POST['source_ids']) && !empty($_POST['target_id'])) { $source_ids = array_map('intval', $_POST['source_ids']); $target_id = (int)$_POST['target_id']; if (in_array($target_id, $source_ids)) { $message = '
Ошибка: целевая характеристика не может быть в списке удаляемых!
'; } else { $pdo->beginTransaction(); $added = $moved = 0; function get_merge_norm($value, $target_id) { $v = trim($value); if ($v === '') return false; $area_ids = [94, 144, 61, 204, 403, 593, 697, 834, 835, 890, 901, 918]; if (in_array($target_id, $area_ids)) { $v_lower = mb_strtolower($v, 'UTF-8'); $v_clean = preg_replace('/\s*(до|для|эффективен|рекомендуемая|обслуживаемая|м²|м2|кв\.?\s*м\.?|м\.?кв\.?|кв|м|м\.)\s*/iu', ' ', $v_lower); if (preg_match('/(\d+(?:[.,]\d+)?)/', $v_clean, $m)) { $num = str_replace(',', '.', $m[1]); return (string)round((float)$num); } return false; } return $v; } foreach ($source_ids as $fid) { $stmt = $pdo->prepare("SELECT id, value FROM shop_feature_values_varchar WHERE feature_id = ?"); $stmt->execute([$fid]); foreach ($stmt->fetchAll() as $row) { $norm = get_merge_norm($row['value'], $target_id); if ($norm === false || $norm === '') continue; $check = $pdo->prepare("SELECT id FROM shop_feature_values_varchar WHERE feature_id = ? AND value = ?"); $check->execute([$target_id, $norm]); $tid = $check->fetchColumn(); if (!$tid) { $pdo->prepare("INSERT INTO shop_feature_values_varchar (feature_id, sort, value) VALUES (?, 0, ?)") ->execute([$target_id, $norm]); $tid = $pdo->lastInsertId(); $added++; } $ins = $pdo->prepare("INSERT IGNORE INTO shop_product_features (product_id, sku_id, feature_id, feature_value_id) SELECT product_id, sku_id, ?, ? FROM shop_product_features WHERE feature_id = ? AND feature_value_id = ?"); $ins->execute([$target_id, $tid, $fid, $row['id']]); $moved += $ins->rowCount(); } $pdo->exec("DELETE FROM shop_product_features WHERE feature_id = $fid"); $pdo->exec("DELETE FROM shop_feature_values_varchar WHERE feature_id = $fid"); } $del = $pdo->prepare("DELETE FROM shop_feature WHERE id = ?"); foreach ($source_ids as $fid) $del->execute([$fid]); $pdo->commit(); $message = "

Объединение завершено!

Целевая: ID $target_id

Удалено характеристик: " . count($source_ids) . "

Добавлено значений: $added | Перенесено товаров: $moved

Новый поиск

"; } } $norm_search = trim($_GET['norm_q'] ?? ''); $norm_fid = (int)($_GET['norm_fid'] ?? 0); $norm_feature = null; $norm_values = []; if ($norm_fid > 0) { $stmt = $pdo->prepare("SELECT id, code, name FROM shop_feature WHERE id = ?"); $stmt->execute([$norm_fid]); $norm_feature = $stmt->fetch(PDO::FETCH_ASSOC); if ($norm_feature) { $stmt = $pdo->prepare("SELECT id, value FROM shop_feature_values_varchar WHERE feature_id = ? ORDER BY value"); $stmt->execute([$norm_fid]); $norm_values = $stmt->fetchAll(PDO::FETCH_ASSOC); } } if ($tab === 'normalize' && isset($_POST['action']) && $_POST['action'] === 'normalize' && $norm_fid > 0) { $pdo->beginTransaction(); $created = 0; foreach ($norm_values as $row) { $original = trim($row['value']); if (!preg_match('/\d+(?:[.,]\d+)?/', $original, $m)) { continue; } $num_str = $m[0]; $num = str_replace(',', '.', $num_str); $normalized = (string) round((float)$num); $check = $pdo->prepare(" SELECT id FROM shop_feature_values_varchar WHERE feature_id = ? AND value = ?"); $check->execute([$norm_fid, $normalized]); $new_id = $check->fetchColumn(); if (!$new_id) { $pdo->prepare(" INSERT INTO shop_feature_values_varchar (feature_id, sort, value) VALUES (?, 0, ?) ")->execute([$norm_fid, $normalized]); $new_id = $pdo->lastInsertId(); $created++; } if ($row['id'] != $new_id) { $pdo->prepare(" UPDATE shop_product_features SET feature_value_id = ? WHERE feature_id = ? AND feature_value_id = ? ")->execute([$new_id, $norm_fid, $row['id']]); } } $pdo->exec("DELETE v FROM shop_feature_values_varchar v LEFT JOIN shop_product_features pf ON pf.feature_value_id = v.id WHERE v.feature_id = $norm_fid AND pf.id IS NULL"); $pdo->commit(); $norm_message = "

Преобразование завершено!

Создано новых чистых значений: $created

Обновить страницу

"; } $units_search = trim($_GET['units_q'] ?? ''); $units_fid = (int)($_GET['units_fid'] ?? 0); $units_feature = null; $units_values = []; $available_units = [ '' => '— без единицы —', ' кв. м.' => ' кв. м.', ' м²' => ' м²', ' кг' => ' кг', ' г' => ' г', ' кВт' => ' кВт', ' Вт' => ' Вт', ' л' => ' л', ' мм' => ' мм', ' см' => ' см', ' м' => ' м', ' шт.' => ' шт.', ' В' => ' В', ' А' => ' А', ' дБ' => ' дБ', ' л/ч' => ' л/ч', ' м³/ч' => ' м³/ч', ]; if ($units_fid > 0) { $stmt = $pdo->prepare("SELECT id, code, name FROM shop_feature WHERE id = ?"); $stmt->execute([$units_fid]); $units_feature = $stmt->fetch(PDO::FETCH_ASSOC); if ($units_feature) { $stmt = $pdo->prepare("SELECT id, value FROM shop_feature_values_varchar WHERE feature_id = ? ORDER BY value"); $stmt->execute([$units_fid]); $units_values = $stmt->fetchAll(PDO::FETCH_ASSOC); } } if ($tab === 'units' && isset($_POST['action']) && $_POST['action'] === 'add_units' && $units_fid > 0 && isset($_POST['unit'])) { $unit = $_POST['unit']; if ($unit === '') { $units_message = '
Выберите единицу измерения!
'; } else { $pdo->beginTransaction(); $updated = 0; foreach ($units_values as $row) { $old_value = $row['value']; $new_value = $old_value . $unit; $check = $pdo->prepare("SELECT id FROM shop_feature_values_varchar WHERE feature_id = ? AND value = ?"); $check->execute([$units_fid, $new_value]); $new_id = $check->fetchColumn(); if (!$new_id) { $pdo->prepare("INSERT INTO shop_feature_values_varchar (feature_id, sort, value) VALUES (?, 0, ?)") ->execute([$units_fid, $new_value]); $new_id = $pdo->lastInsertId(); $updated++; } if ($row['id'] != $new_id) { $pdo->prepare("UPDATE shop_product_features SET feature_value_id = ? WHERE feature_id = ? AND feature_value_id = ?") ->execute([$new_id, $units_fid, $row['id']]); } } $pdo->exec("DELETE v FROM shop_feature_values_varchar v LEFT JOIN shop_product_features pf ON pf.feature_value_id = v.id WHERE v.feature_id = $units_fid AND pf.id IS NULL"); $pdo->commit(); $units_message = "

Единица \"$unit\" добавлена ко всем значениям!

Создано/обновлено значений: $updated

Обновить и посмотреть

"; } } $search = trim($_GET['q'] ?? ''); $mv_search = trim($_GET['mv_q'] ?? ''); $mv_fid = (int)($_GET['mv_fid'] ?? 0); $mv_feature = null; $mv_values = []; if ($mv_fid > 0) { $stmt = $pdo->prepare("SELECT id, code, name FROM shop_feature WHERE id = ?"); $stmt->execute([$mv_fid]); $mv_feature = $stmt->fetch(PDO::FETCH_ASSOC); if ($mv_feature) { $stmt = $pdo->prepare("SELECT id, value FROM shop_feature_values_varchar WHERE feature_id = ? ORDER BY value"); $stmt->execute([$mv_fid]); $mv_values = $stmt->fetchAll(PDO::FETCH_ASSOC); } } if ($tab === 'merge_values' && isset($_POST['action']) && $_POST['action'] === 'merge_values' && $mv_fid > 0 && !empty($_POST['map'])) { $map = $_POST['map']; $pdo->beginTransaction(); $merged = 0; try { foreach ($map as $old_id => $new_id) { $old_id = (int)$old_id; $new_id = (int)$new_id; if ($old_id === $new_id) continue; $stmt = $pdo->prepare("UPDATE shop_product_features SET feature_value_id = ? WHERE feature_id = ? AND feature_value_id = ?"); $stmt->execute([$new_id, $mv_fid, $old_id]); $merged += $stmt->rowCount(); } $stmt = $pdo->prepare(" DELETE v FROM shop_feature_values_varchar v LEFT JOIN shop_product_features pf ON pf.feature_value_id = v.id WHERE v.feature_id = ? AND pf.id IS NULL "); $stmt->execute([$mv_fid]); $pdo->commit(); $merge_values_message = "

Дубли значений успешно объединены!

Перенесено товаров: $merged

Обновить и посмотреть результат

"; } catch (Exception $e) { $pdo->rollBack(); $merge_values_message = "
Ошибка при объединении: " . htmlspecialchars($e->getMessage()) . "
"; } } $group_sort_message = ''; if ( $tab === 'group_sort' && isset($_POST['action']) && $_POST['action'] === 'move_to_group' ) { $type_id = (int)($_POST['type_id'] ?? 0); $target_group_id = (int)($_POST['group_id'] ?? 0); $feature_ids = array_values(array_unique(array_map('intval', $_POST['feature_ids'] ?? []))); if ($type_id <= 0 || $target_group_id <= 0 || empty($feature_ids)) { $group_sort_message = '
Неверные данные формы
'; return; } try { $pdo->beginTransaction(); $stmt = $pdo->prepare(" SELECT MAX(sort) FROM shop_type_features WHERE type_id = ? "); $stmt->execute([$type_id]); $max_sort = (int)$stmt->fetchColumn(); $tmp_sort = $max_sort + 100; $stmt = $pdo->prepare(" UPDATE shop_type_features SET sort = ? WHERE type_id = ? AND feature_id = ? "); foreach ($feature_ids as $fid) { $stmt->execute([$tmp_sort++, $type_id, $fid]); } $stmt = $pdo->prepare(" SELECT tf.sort FROM shop_type_features tf JOIN shop_feature f ON f.id = tf.feature_id WHERE tf.type_id = ? AND tf.feature_id = ? AND f.type = 'divider' "); $stmt->execute([$type_id, $target_group_id]); $group_sort = (int)$stmt->fetchColumn(); if ($group_sort <= 0) { throw new Exception('Группа не найдена в этом типе товаров'); } $stmt = $pdo->prepare(" SELECT MIN(tf.sort) FROM shop_type_features tf JOIN shop_feature f ON f.id = tf.feature_id WHERE tf.type_id = ? AND f.type = 'divider' AND tf.sort > ? "); $stmt->execute([$type_id, $group_sort]); $next_divider_sort = $stmt->fetchColumn(); $next_divider_sort = $next_divider_sort ? (int)$next_divider_sort : PHP_INT_MAX; $sort = $group_sort + 1; $stmt = $pdo->prepare(" UPDATE shop_type_features SET sort = ? WHERE type_id = ? AND feature_id = ? "); foreach ($feature_ids as $fid) { $stmt->execute([$sort++, $type_id, $fid]); } $stmt = $pdo->prepare(" SELECT feature_id FROM shop_type_features WHERE type_id = ? ORDER BY sort "); $stmt->execute([$type_id]); $all = $stmt->fetchAll(PDO::FETCH_COLUMN); $sort = 1; $stmt = $pdo->prepare(" UPDATE shop_type_features SET sort = ? WHERE type_id = ? AND feature_id = ? "); foreach ($all as $fid) { $stmt->execute([$sort++, $type_id, $fid]); } $pdo->commit(); $group_sort_message = '

Готово

Характеристика перемещена в выбранную группу.

Обновить

'; } catch (Exception $e) { $pdo->rollBack(); $group_sort_message = '
Ошибка: ' . htmlspecialchars($e->getMessage()) . '
'; } } ?> Инструмент для характеристик — Shop-Script
1. Объединение характеристик
2. Преобразование значений характеристик
3. Единицы измерения для характеристик
4. Объединение дублей значений характеристик
5. Дубли товаров
6. Meta title/description
7. Сортировка значений характеристик
8. Сортировка характеристик в группах
⚠️ ВАЖНОЕ ПРЕДУПРЕЖДЕНИЕ

Используйте инструмент осознанно и только если понимаете, что делаете.

1. Объединение нескольких характеристик в одну

Сбросить
prepare("SELECT id, code, name, type FROM shop_feature WHERE name LIKE ? OR code LIKE ? ORDER BY name"); $stmt->execute(['%' . $search . '%', '%' . $search . '%']); $features = $stmt->fetchAll(); if (!empty($features)): ?>
query("SELECT COUNT(DISTINCT product_id) FROM shop_product_features WHERE feature_id = {$f['id']}")->fetchColumn(); $vals_stmt = $pdo->prepare(" SELECT DISTINCT value FROM shop_feature_values_varchar WHERE feature_id = ? ORDER BY value ASC LIMIT 30 "); $vals_stmt->execute([$f['id']]); $vals = $vals_stmt->fetchAll(PDO::FETCH_COLUMN); if (empty($vals)) { $vals_str = 'нет значений'; } else { $total_stmt = $pdo->prepare("SELECT COUNT(DISTINCT value) FROM shop_feature_values_varchar WHERE feature_id = ?"); $total_stmt->execute([$f['id']]); $total = $total_stmt->fetchColumn(); $display_vals = array_map('htmlspecialchars', $vals); $vals_str = implode(', ', $display_vals); if ($total > 30) { $vals_str .= ' (и ещё ' . ($total - 30) . ' значений...)'; } } ?>
ID Code Название Товаров Значения (примеры)

Выберите целевую характеристику:

Выбрана: — не выбрана —

2. Преобразование значений внутри одной характеристики

Приводит значения характеристик к целому числу "до 10", "10 м2", "10.5" → "10"

Сбросить
prepare("SELECT id, code, name FROM shop_feature WHERE name LIKE ? OR code LIKE ? OR id = ? ORDER BY name LIMIT 20"); $stmt->execute(["%$norm_search%", "%$norm_search%", $norm_search]); $norm_features = $stmt->fetchAll(PDO::FETCH_ASSOC); ?>

Выберите характеристику:

Ничего не найдено

ID —

Уникальных значений:

ID значенияЗначение

3. Массовое добавление единиц измерения

Добавляет выбранную единицу ко всем значениям (например, "10" → "10 кв. м.")

Сбросить
prepare("SELECT id, code, name FROM shop_feature WHERE name LIKE ? OR code LIKE ? OR id = ? ORDER BY name LIMIT 20"); $stmt->execute(["%$units_search%", "%$units_search%", $units_search]); $found = $stmt->fetchAll(PDO::FETCH_ASSOC); ?>

Выберите характеристику:

Ничего не найдено

ID —

Значений:

IDТекущее значение


4. Объединение дублей значений внутри характеристики

Ручное слияние похожих значений (например, "да" и "да, опция" → "опция")

Сбросить
prepare("SELECT id, code, name FROM shop_feature WHERE name LIKE ? OR code LIKE ? OR id = ? ORDER BY name LIMIT 20"); $stmt->execute(["%$mv_search%", "%$mv_search%", $mv_search]); $found = $stmt->fetchAll(PDO::FETCH_ASSOC); ?>

Выберите характеристику:

ID —

Уникальных значений:

Текущее значение → Слить в
(ID )

5. Удаление дубликатов товаров

Находит товары с одинаковым названием в выбранной категории и всех её подкатегориях

query("SELECT id, name, depth, left_key, right_key FROM shop_category WHERE status = 1 ORDER BY left_key")->fetchAll(PDO::FETCH_ASSOC); $selected_cat = (int)($_GET['cat_id'] ?? 0); $dup_message = ''; $duplicates = []; if ($selected_cat > 0 && isset($_GET['search'])) { $cat_stmt = $pdo->prepare("SELECT left_key, right_key FROM shop_category WHERE id = ?"); $cat_stmt->execute([$selected_cat]); $cat = $cat_stmt->fetch(PDO::FETCH_ASSOC); if ($cat) { $stmt = $pdo->prepare(" SELECT p.id, p.name, p.price, p.create_datetime FROM shop_product p JOIN shop_category_products cp ON cp.product_id = p.id JOIN shop_category c ON c.id = cp.category_id WHERE c.left_key >= ? AND c.right_key <= ? AND p.status = 1 ORDER BY p.name, p.price ASC, p.create_datetime ASC "); $stmt->execute([$cat['left_key'], $cat['right_key']]); $all_products = $stmt->fetchAll(PDO::FETCH_ASSOC); $groups = []; foreach ($all_products as $prod) { $groups[$prod['name']][] = $prod; } foreach ($groups as $name => $prods) { if (count($prods) > 1) { $duplicates = array_merge($duplicates, $prods); } } } } if (isset($_POST['action']) && $_POST['action'] === 'delete_duplicates' && !empty($_POST['delete_ids'])) { $delete_ids = array_map('intval', $_POST['delete_ids']); $placeholders = str_repeat('?,', count($delete_ids) - 1) . '?'; $pdo->beginTransaction(); try { $pdo->prepare("DELETE FROM shop_product_features WHERE product_id IN ($placeholders)")->execute($delete_ids); $pdo->prepare("DELETE FROM shop_product_images WHERE product_id IN ($placeholders)")->execute($delete_ids); $pdo->prepare("DELETE FROM shop_product_skus WHERE product_id IN ($placeholders)")->execute($delete_ids); $pdo->prepare("DELETE FROM shop_product_pages WHERE product_id IN ($placeholders)")->execute($delete_ids); $pdo->prepare("DELETE FROM shop_product_reviews WHERE product_id IN ($placeholders)")->execute($delete_ids); $pdo->prepare("DELETE FROM shop_product_related WHERE product_id IN ($placeholders) OR related_product_id IN ($placeholders)")->execute(array_merge($delete_ids, $delete_ids)); $pdo->prepare("DELETE FROM shop_category_products WHERE product_id IN ($placeholders)")->execute($delete_ids); $pdo->prepare("DELETE FROM shop_product WHERE id IN ($placeholders)")->execute($delete_ids); $pdo->commit(); $dup_message = "

Полностью удалено " . count($delete_ids) . " дубликатов товаров!

Все связанные данные (характеристики, изображения, SKU, отзывы и т.д.) также удалены.

Обновить список

"; } catch (Exception $e) { $pdo->rollBack(); $dup_message = "
Ошибка при удалении: " . htmlspecialchars($e->getMessage()) . "
"; } } ?>
0 || isset($_GET['search'])): ?> Сбросить
0 && isset($_GET['search'])): ?>

Дубликатов по названию не найдено в этой категории и подкатегориях.

$prod): if ($prod['name'] !== $current_name) { $current_name = $prod['name']; $group_index++; echo ""; } ?>
Удалить ID товара Название Цена Дата создания
Группа дубликатов #$group_index: " . htmlspecialchars($current_name) . "
₽

6. Массовое добавление или изменение Meta (title и description) в категориях и товарах.

Поддерживаемые переменные:
Для категорий: {category_name}
Для товаров: {product_name}

prepare("SELECT id, name FROM shop_category WHERE id IN ($placeholders)"); $stmt->execute($cat_ids); $cats = $stmt->fetchAll(PDO::FETCH_ASSOC); $pdo->beginTransaction(); foreach ($cats as $cat) { $title = str_replace('{category_name}', $cat['name'], $title_template); $description = str_replace('{category_name}', $cat['name'], $description_template); $upd = $pdo->prepare("UPDATE shop_category SET meta_title = ?, meta_description = ? WHERE id = ?"); $upd->execute([$title, $description, $cat['id']]); } $pdo->commit(); $meta_message = "
Meta обновлены для " . count($cats) . " категорий!
"; } if ($meta_type === 'products') { $prod_ids = array_map('intval', $_POST['prod_ids'] ?? []); $apply_to_all = empty($prod_ids); if ($apply_to_all) { $stmt = $pdo->prepare("SELECT id, name FROM shop_product"); $stmt->execute(); $prods = $stmt->fetchAll(PDO::FETCH_ASSOC); } else { $placeholders = str_repeat('?,', count($prod_ids) - 1) . '?'; $stmt = $pdo->prepare("SELECT id, name FROM shop_product WHERE id IN ($placeholders)"); $stmt->execute($prod_ids); $prods = $stmt->fetchAll(PDO::FETCH_ASSOC); } $pdo->beginTransaction(); foreach ($prods as $prod) { $title = str_replace('{product_name}', $prod['name'], $title_template); $description = str_replace('{product_name}', $prod['name'], $description_template); $upd = $pdo->prepare("UPDATE shop_product SET meta_title = ?, meta_description = ? WHERE id = ?"); $upd->execute([$title, $description, $prod['id']]); } $pdo->commit(); $count = count($prods); $meta_message = "
Meta обновлены для $count товаров!
"; } } $categories = $pdo->query("SELECT id, name, depth FROM shop_category WHERE status = 1 ORDER BY left_key")->fetchAll(PDO::FETCH_ASSOC); $prod_search_cat = (int)($_GET['prod_search_cat'] ?? 0); $prod_search_name = trim($_GET['prod_search_name'] ?? ''); $products = []; if ($meta_type === 'products') { $sql = "SELECT p.id, p.name, p.price FROM shop_product p"; $params = []; $where = []; if ($prod_search_cat > 0) { $cat_stmt = $pdo->prepare("SELECT left_key, right_key FROM shop_category WHERE id = ?"); $cat_stmt->execute([$prod_search_cat]); $cat = $cat_stmt->fetch(); if ($cat) { $where[] = "EXISTS (SELECT 1 FROM shop_category_products cp JOIN shop_category c ON c.id = cp.category_id WHERE cp.product_id = p.id AND c.left_key >= ? AND c.right_key <= ?)"; $params[] = $cat['left_key']; $params[] = $cat['right_key']; } } if ($prod_search_name !== '') { $where[] = "p.name LIKE ?"; $params[] = '%' . $prod_search_name . '%'; } if (!empty($where)) { $sql .= " WHERE " . implode(' AND ', $where); } $sql .= " ORDER BY p.name LIMIT 500"; $stmt = $pdo->prepare($sql); $stmt->execute($params); $products = $stmt->fetchAll(PDO::FETCH_ASSOC); } ?>
Категории Товары

Meta для категорий

ВыбратьIDНазвание

Meta для товаров

или по названию:
0 || $prod_search_name !== ''): ?> Сбросить
query("SELECT COUNT(*) FROM shop_product"); $total_products = $total_stmt->fetchColumn(); $apply_to_all = ($prod_search_cat == 0 && $prod_search_name === ''); if ($apply_to_all) { } else { $page = max(1, (int)($_GET['page'] ?? 1)); $per_page = 300; $offset = ($page - 1) * $per_page; $sql = "SELECT p.id, p.name, p.price FROM shop_product p"; $params = []; $where = []; if ($prod_search_cat > 0) { $cat_stmt = $pdo->prepare("SELECT left_key, right_key FROM shop_category WHERE id = ?"); $cat_stmt->execute([$prod_search_cat]); $cat = $cat_stmt->fetch(); if ($cat) { $where[] = "EXISTS (SELECT 1 FROM shop_category_products cp JOIN shop_category c ON c.id = cp.category_id WHERE cp.product_id = p.id AND c.left_key >= ? AND c.right_key <= ?)"; $params[] = $cat['left_key']; $params[] = $cat['right_key']; } } if ($prod_search_name !== '') { $where[] = "p.name LIKE ?"; $params[] = '%' . $prod_search_name . '%'; } $where_sql = !empty($where) ? " WHERE " . implode(' AND ', $where) : ''; $count_stmt = $pdo->prepare("SELECT COUNT(*) FROM shop_product p" . $where_sql); $count_stmt->execute($params); $found_count = $count_stmt->fetchColumn(); $stmt = $pdo->prepare($sql . $where_sql . " ORDER BY p.name LIMIT $per_page OFFSET $offset"); $stmt->execute($params); $products = $stmt->fetchAll(PDO::FETCH_ASSOC); $total_pages = ceil($found_count / $per_page); } ?>

Внимание: Meta будут применены ко всем товарам в магазине.

Это может занять 1–2 минуты.

1): ?>
Страница из
ВыбратьIDНазваниеЦена
₽

7. Сортировка значений характеристик

Изменение порядка отображения значений в фильтрах (поле sort)

0) { $stmt = $pdo->prepare("SELECT id, code, name FROM shop_feature WHERE id = ?"); $stmt->execute([$sort_fid]); $sort_feature = $stmt->fetch(PDO::FETCH_ASSOC); if ($sort_feature) { $stmt = $pdo->prepare("SELECT id, value, sort FROM shop_feature_values_varchar WHERE feature_id = ? ORDER BY sort ASC, value ASC"); $stmt->execute([$sort_fid]); $sort_values = $stmt->fetchAll(PDO::FETCH_ASSOC); } } if (isset($_POST['action']) && $_POST['action'] === 'save_sort' && $sort_fid > 0 && !empty($_POST['sort_order'])) { $sort_order = $_POST['sort_order']; $pdo->beginTransaction(); $stmt = $pdo->prepare("UPDATE shop_feature_values_varchar SET sort = ? WHERE id = ?"); foreach ($sort_order as $value_id => $new_sort) { $value_id = (int)$value_id; $new_sort = max(0, (int)$new_sort); $stmt->execute([$new_sort, $value_id]); } $pdo->commit(); $sort_message = "

Порядок сохранён в базе!

Обновить страницу

"; $stmt = $pdo->prepare("SELECT id, value, sort FROM shop_feature_values_varchar WHERE feature_id = ? ORDER BY sort ASC, value ASC"); $stmt->execute([$sort_fid]); $sort_values = $stmt->fetchAll(PDO::FETCH_ASSOC); } ?>
Сбросить
prepare("SELECT id, code, name FROM shop_feature WHERE name LIKE ? OR code LIKE ? OR id = ? ORDER BY name LIMIT 30"); $stmt->execute(["%$sort_search%", "%$sort_search%", $sort_search]); $found_features = $stmt->fetchAll(PDO::FETCH_ASSOC); ?>

Выберите атрибут:

Ничего не найдено

Сортировка: ID —

Значений: . Нажмите кнопку — поля заполнятся автоматически. Подправьте при необходимости и сохраните.

$v): ?>
Значение Порядок (sort)

8. Перемещение характеристик в группы

Группы — это характеристики с type = 'divider'.
Группа определяется положением divider в списке внутри выбранного типа товаров, как в админке Shop-Script.

Если у вас нет групп, то их необходимо создать в админке сайта Настройки -> Типы и характеристики товаров -> Заголовок группы характеристик.

query(" SELECT id, name FROM shop_type ORDER BY name "); $types = $stmt->fetchAll(PDO::FETCH_ASSOC); $current_type_id = isset($_GET['type_id']) ? (int)$_GET['type_id'] : ($types[0]['id'] ?? 0); $stmt = $pdo->query(" SELECT id, name FROM shop_feature WHERE type = 'divider' ORDER BY name "); $groups = $stmt->fetchAll(PDO::FETCH_ASSOC); $group_map = []; foreach ($groups as $g) { $group_map[$g['id']] = $g['name'] . ' (ID ' . $g['id'] . ')'; } $features = []; if ($current_type_id) { $stmt = $pdo->prepare(" SELECT tf.sort, f.id, f.name, f.code, f.type FROM shop_type_features tf JOIN shop_feature f ON f.id = tf.feature_id WHERE tf.type_id = :type_id ORDER BY tf.sort ASC "); $stmt->execute(['type_id' => $current_type_id]); $rows = $stmt->fetchAll(PDO::FETCH_ASSOC); $current_group_id = 0; foreach ($rows as $row) { if ($row['type'] === 'divider') { $current_group_id = $row['id']; $features[] = [ 'id' => $row['id'], 'name' => $row['name'], 'code' => $row['code'], 'type' => $row['type'], 'group_id' => 0 ]; } else { $features[] = [ 'id' => $row['id'], 'name' => $row['name'], 'code' => $row['code'], 'type' => $row['type'], 'group_id' => $current_group_id ]; } } } ?>
>
Выбрать ID Название Код Тип Текущая группа
>