Скрипт массового удаления товаров на 1С-Битрикс и пошаговая инструкция как им пользоваться
Ниже скрипт массового удаления товаров, с настройкой шага и прогресс-баром1) Создайте файл delete.php в корне сайте (это где папка bitrix)
2) Добавьте в него следующий код или скачайте файл по ссылке. Не забудьте в строке $IBLOCK_ID = 123; заменить ID инфоблока на свой (тот из которого нужно удалить элементы)
3) Запустите скприт https://ВашДомен/delete.php
Нужна помощь с настройкой?
Если для вас это покажется слишком сложным или нет времени — просто оставьте заявку. Мы подключимся и настроим всё за вас. Пишите на info@prav-site.ru или оставить заявку и мы поможем.
Скопируйте этот код
<?php
define("NO_KEEP_STATISTIC", true);
define("NOT_CHECK_PERMISSIONS", false);
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/prolog_before.php");
global $USER, $APPLICATION, $CACHE_MANAGER;
$IBLOCK_ID = 123;
$SESSION_KEY = "PS_DELETE_IBLOCK_" . $IBLOCK_ID;
if (!$USER || !$USER->IsAdmin()) {
http_response_code(403);
die("Доступ запрещен");
}
if (!CModule::IncludeModule("iblock")) {
die("Модуль iblock не подключен");
}
@set_time_limit(0);
ignore_user_abort(true);
function psDeleteJson($data)
{
global $APPLICATION;
if (method_exists($APPLICATION, "RestartBuffer")) {
$APPLICATION->RestartBuffer();
}
header("Content-Type: application/json; charset=UTF-8");
echo json_encode($data, JSON_UNESCAPED_UNICODE);
require($_SERVER["DOCUMENT_ROOT"] . "/bitrix/modules/main/include/epilog_after.php");
exit;
}
function psGetElementsCount($iblockId)
{
return (int)CIBlockElement::GetList(
[],
[
"IBLOCK_ID" => $iblockId,
"CHECK_PERMISSIONS" => "N",
],
[]
);
}
function psGetBatchIds($iblockId, $limit, $excludeIds = [])
{
$filter = [
"IBLOCK_ID" => $iblockId,
"CHECK_PERMISSIONS" => "N",
];
if (!empty($excludeIds)) {
$filter["!ID"] = array_values($excludeIds);
}
$ids = [];
$res = CIBlockElement::GetList(
["ID" => "ASC"],
$filter,
false,
["nTopCount" => $limit],
["ID"]
);
while ($row = $res->Fetch()) {
$ids[] = (int)$row["ID"];
}
return $ids;
}
if (
isset($_REQUEST["ajax"])
&& $_REQUEST["ajax"] === "Y"
) {
if (!check_bitrix_sessid()) {
psDeleteJson([
"success" => false,
"message" => "Ошибка сессии. Обновите страницу и попробуйте снова.",
]);
}
$action = isset($_REQUEST["action"]) ? (string)$_REQUEST["action"] : "";
if ($action === "init") {
$total = psGetElementsCount($IBLOCK_ID);
$_SESSION[$SESSION_KEY] = [
"total" => $total,
"processed" => 0,
"deleted" => 0,
"failed" => [],
"started_at" => time(),
];
psDeleteJson([
"success" => true,
"total" => $total,
"processed" => 0,
"deleted" => 0,
"failed" => 0,
"percent" => $total > 0 ? 0 : 100,
"done" => $total <= 0,
"message" => $total > 0
? "Найдено элементов: " . $total
: "В инфоблоке нет элементов для удаления",
]);
}
if ($action === "delete") {
if (empty($_SESSION[$SESSION_KEY])) {
psDeleteJson([
"success" => false,
"message" => "Сессия удаления не найдена. Запустите удаление заново.",
]);
}
$step = isset($_REQUEST["step"]) ? (int)$_REQUEST["step"] : 50;
if ($step < 1) {
$step = 1;
}
if ($step > 1000) {
$step = 1000;
}
$session = &$_SESSION[$SESSION_KEY];
$total = (int)$session["total"];
$failedIds = !empty($session["failed"]) ? array_keys($session["failed"]) : [];
$ids = psGetBatchIds($IBLOCK_ID, $step, $failedIds);
if (empty($ids)) {
if (is_object($CACHE_MANAGER)) {
$CACHE_MANAGER->ClearByTag("iblock_id_" . $IBLOCK_ID);
}
psDeleteJson([
"success" => true,
"total" => $total,
"processed" => (int)$session["processed"],
"deleted" => (int)$session["deleted"],
"failed" => count($session["failed"]),
"percent" => 100,
"done" => true,
"message" => "Удаление завершено",
]);
}
$deletedInStep = 0;
$failedInStep = 0;
$errors = [];
foreach ($ids as $elementId) {
$deleteResult = CIBlockElement::Delete($elementId);
$session["processed"]++;
if ($deleteResult) {
$session["deleted"]++;
$deletedInStep++;
} else {
$failedInStep++;
$errorText = "Неизвестная ошибка";
if (is_object($GLOBALS["APPLICATION"])) {
$exception = $GLOBALS["APPLICATION"]->GetException();
if ($exception) {
$errorText = $exception->GetString();
}
}
$session["failed"][$elementId] = $errorText;
$errors[] = [
"id" => $elementId,
"error" => $errorText,
];
}
}
$processed = (int)$session["processed"];
$deleted = (int)$session["deleted"];
$failed = count($session["failed"]);
$percent = $total > 0 ? round(($processed / $total) * 100, 2) : 100;
if ($percent > 100) {
$percent = 100;
}
$done = $processed >= $total || count($ids) < $step;
if ($done && is_object($CACHE_MANAGER)) {
$CACHE_MANAGER->ClearByTag("iblock_id_" . $IBLOCK_ID);
}
psDeleteJson([
"success" => true,
"total" => $total,
"processed" => $processed,
"deleted" => $deleted,
"failed" => $failed,
"deleted_in_step" => $deletedInStep,
"failed_in_step" => $failedInStep,
"percent" => $percent,
"done" => $done,
"errors" => $errors,
"message" => $done ? "Удаление завершено" : "Удаление продолжается",
]);
}
psDeleteJson([
"success" => false,
"message" => "Неизвестное действие",
]);
}
?>
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8">
<title>Массовое удаление элементов инфоблока <?=htmlspecialcharsbx($IBLOCK_ID)?></title>
<style>
body {
margin: 0;
padding: 40px;
font-family: Arial, sans-serif;
background: #f4f6f8;
color: #222;
}
.delete-page {
max-width: 900px;
margin: 0 auto;
background: #fff;
border-radius: 16px;
padding: 32px;
box-shadow: 0 10px 35px rgba(0, 0, 0, 0.08);
}
.delete-page h1 {
margin: 0 0 12px;
font-size: 28px;
line-height: 1.25;
}
.delete-warning {
margin: 20px 0;
padding: 16px 18px;
border-radius: 12px;
background: #fff3cd;
border: 1px solid #ffe08a;
color: #7a5200;
line-height: 1.5;
}
.delete-settings {
display: flex;
flex-wrap: wrap;
gap: 16px;
align-items: flex-end;
margin: 24px 0;
}
.delete-field {
display: flex;
flex-direction: column;
gap: 8px;
}
.delete-field label {
font-size: 14px;
color: #555;
}
.delete-field input {
width: 160px;
height: 44px;
border: 1px solid #d8dde6;
border-radius: 10px;
padding: 0 12px;
font-size: 16px;
}
.delete-btn {
height: 44px;
border: none;
border-radius: 10px;
padding: 0 20px;
font-size: 15px;
cursor: pointer;
transition: 0.2s;
}
.delete-btn--start {
background: #d93025;
color: #fff;
}
.delete-btn--start:hover {
background: #b9271f;
}
.delete-btn--stop {
background: #e9edf3;
color: #222;
}
.delete-btn:disabled {
opacity: 0.55;
cursor: not-allowed;
}
.delete-progress {
margin-top: 28px;
}
.delete-progress__bar {
width: 100%;
height: 24px;
background: #e9edf3;
border-radius: 999px;
overflow: hidden;
}
.delete-progress__fill {
width: 0;
height: 100%;
background: linear-gradient(90deg, #d93025, #ff7a59);
border-radius: 999px;
transition: width 0.25s ease;
}
.delete-progress__info {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 12px;
margin-top: 18px;
}
.delete-stat {
padding: 14px;
border-radius: 12px;
background: #f6f8fb;
}
.delete-stat__label {
font-size: 13px;
color: #677082;
margin-bottom: 6px;
}
.delete-stat__value {
font-size: 22px;
font-weight: 700;
}
.delete-log {
margin-top: 24px;
height: 220px;
overflow: auto;
background: #111827;
color: #e5e7eb;
border-radius: 12px;
padding: 16px;
font-family: Consolas, monospace;
font-size: 13px;
line-height: 1.45;
}
.delete-log div {
margin-bottom: 4px;
}
@media (max-width: 700px) {
body {
padding: 16px;
}
.delete-page {
padding: 20px;
}
.delete-progress__info {
grid-template-columns: 1fr 1fr;
}
}
</style>
</head>
<body>
<div class="delete-page">
<h1>Массовое удаление элементов инфоблока <?=$IBLOCK_ID?></h1>
<div class="delete-warning">
Внимание: скрипт удаляет элементы инфоблока физически. Перед запуском сделайте резервную копию базы данных.
После завершения работы удалите этот файл с сайта.
</div>
<div class="delete-settings">
<div class="delete-field">
<label for="deleteStep">Шаг удаления за один запрос</label>
<input type="number" id="deleteStep" value="50" min="1" max="1000">
</div>
<button type="button" class="delete-btn delete-btn--start" id="startDelete">
Начать удаление
</button>
<button type="button" class="delete-btn delete-btn--stop" id="stopDelete" disabled>
Остановить
</button>
</div>
<div class="delete-progress">
<div class="delete-progress__bar">
<div class="delete-progress__fill" id="progressFill"></div>
</div>
<div class="delete-progress__info">
<div class="delete-stat">
<div class="delete-stat__label">Всего</div>
<div class="delete-stat__value" id="totalCount">0</div>
</div>
<div class="delete-stat">
<div class="delete-stat__label">Обработано</div>
<div class="delete-stat__value" id="processedCount">0</div>
</div>
<div class="delete-stat">
<div class="delete-stat__label">Удалено</div>
<div class="delete-stat__value" id="deletedCount">0</div>
</div>
<div class="delete-stat">
<div class="delete-stat__label">Ошибок</div>
<div class="delete-stat__value" id="failedCount">0</div>
</div>
</div>
</div>
<div class="delete-log" id="deleteLog"></div>
</div>
<script>
const ajaxUrl = window.location.pathname;
const sessid = '<?=CUtil::JSEscape(bitrix_sessid())?>';
const startBtn = document.getElementById('startDelete');
const stopBtn = document.getElementById('stopDelete');
const stepInput = document.getElementById('deleteStep');
const progressFill = document.getElementById('progressFill');
const totalCount = document.getElementById('totalCount');
const processedCount = document.getElementById('processedCount');
const deletedCount = document.getElementById('deletedCount');
const failedCount = document.getElementById('failedCount');
const deleteLog = document.getElementById('deleteLog');
let stopped = false;
function logMessage(text) {
const item = document.createElement('div');
item.textContent = '[' + new Date().toLocaleTimeString() + '] ' + text;
deleteLog.appendChild(item);
deleteLog.scrollTop = deleteLog.scrollHeight;
}
function updateProgress(data) {
totalCount.textContent = data.total || 0;
processedCount.textContent = data.processed || 0;
deletedCount.textContent = data.deleted || 0;
failedCount.textContent = data.failed || 0;
const percent = data.percent || 0;
progressFill.style.width = percent + '%';
}
function sendRequest(params) {
params.ajax = 'Y';
params.sessid = sessid;
return fetch(ajaxUrl, {
method: 'POST',
credentials: 'same-origin',
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
},
body: new URLSearchParams(params)
}).then(response => response.json());
}
function runDeleteStep() {
if (stopped) {
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
logMessage('Удаление остановлено пользователем');
return;
}
let step = parseInt(stepInput.value, 10);
if (!step || step < 1) {
step = 1;
}
if (step > 1000) {
step = 1000;
}
sendRequest({
action: 'delete',
step: step
}).then(data => {
if (!data.success) {
logMessage(data.message || 'Ошибка удаления');
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
return;
}
updateProgress(data);
logMessage(
'Шаг выполнен. Удалено за шаг: ' +
(data.deleted_in_step || 0) +
', ошибок за шаг: ' +
(data.failed_in_step || 0) +
', прогресс: ' +
(data.percent || 0) +
'%'
);
if (data.errors && data.errors.length) {
data.errors.forEach(errorItem => {
logMessage('Ошибка элемента ID ' + errorItem.id + ': ' + errorItem.error);
});
}
if (data.done) {
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
logMessage(data.message || 'Удаление завершено');
return;
}
setTimeout(runDeleteStep, 250);
}).catch(error => {
logMessage('Ошибка запроса: ' + error.message);
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
});
}
startBtn.addEventListener('click', function () {
const confirmText = 'Вы точно хотите удалить все элементы инфоблока <?=CUtil::JSEscape($IBLOCK_ID)?>? Действие необратимо.';
if (!confirm(confirmText)) {
return;
}
stopped = false;
startBtn.disabled = true;
stopBtn.disabled = false;
stepInput.disabled = true;
deleteLog.innerHTML = '';
updateProgress({
total: 0,
processed: 0,
deleted: 0,
failed: 0,
percent: 0
});
logMessage('Инициализация удаления');
sendRequest({
action: 'init'
}).then(data => {
if (!data.success) {
logMessage(data.message || 'Ошибка инициализации');
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
return;
}
updateProgress(data);
logMessage(data.message);
if (data.done) {
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
return;
}
runDeleteStep();
}).catch(error => {
logMessage('Ошибка запроса: ' + error.message);
startBtn.disabled = false;
stopBtn.disabled = true;
stepInput.disabled = false;
});
});
stopBtn.addEventListener('click', function () {
stopped = true;
stopBtn.disabled = true;
});
</script>
</body>
</html>
Поделитесь с друзьями
