Делаем ЧПУ картинок у Bitrix

Автор:Alex Posted Май 16, 2019

Делаем ЧПУ картинок у Bitrix

Я не знал что в настройках главного модуля есть такая опция »
Сохранять исходные имена загружаемых файлов», и врезультате все картинки на нашем сайте имеют вот такие некрасивые адреса:

/upload/iblock/00d/00d7e1282969b7830d06e7917ea9103b.jpg

Сам PHP код не сложный, но будет выполняться довольно продолжительное время, если изображений у вас много. Обратите внимание на значения $iblock_ids, $ob[‘IBLOCK_ID’]==2, $ob[‘IBLOCK_ID’]==28, ‘MORE_PICT’, ‘MORE_PICT_TORG ‘, их нужно заменить на свои значения.

В результате у вас получится что-то вроде

/upload/iblock/00d/name_element.jpg

CModule::IncludeModule("iblock");
$arSelect = Array("ID", "IBLOCK_ID", "NAME", "CODE", "PREVIEW_PICTURE", "DETAIL_PICTURE");
$iblock_ids = array(2,28); // ID инфоблоков, у которых будем менять имена картинок
// Получаем имена элементов инфоблока, именно их и будет использовать для наших картинок
$arFilter = Array("IBLOCK_ID"=>$iblock_ids,   "INCLUDE_SUBSECTIONS"=>"Y");
$res = CIBlockElement::GetList(Array("ID"=>"ASC"), $arFilter, false, false, $arSelect);
global $DB;
while($ob = $res->GetNext()){
$new_code = CUtil::translit($ob['NAME'], "ru", array()); // транслитерация имени файла
 
// Для картинки анонса 
if(!empty($ob['PREVIEW_PICTURE'])) {
	$first_pic_orig = CFile::GetPath($ob['PREVIEW_PICTURE']);
	$path_file = explode('/',$first_pic_orig);
	$first_pic = explode('.',$path_file[4]);
	$file_name = $first_pic[0];	// имя файла
	$file_exe = $first_pic[1];	// расширение файла
 
	$NEW_NAME_FILE = $path_file[0].'/'.$path_file[1].'/'.$path_file[2].'/'.$path_file[3].'/'.$new_code.'.'.$file_exe;	// новое имя с полным путем
 
	if($first_pic_orig != $NEW_NAME_FILE){
		// переименовываем файл
			rename($_SERVER['DOCUMENT_ROOT'].$first_pic_orig, $_SERVER['DOCUMENT_ROOT'].$NEW_NAME_FILE);
		// Исправляем значение в базе
			if(!empty($ob['PREVIEW_PICTURE'])) 
				$DB->Query('UPDATE b_file SET FILE_NAME="'.$new_code.'.'.$file_exe.'",ORIGINAL_NAME="'.$new_code.'.'.$file_exe.'" WHERE ID='.$ob['PREVIEW_PICTURE']);
	}
}
 
// Для детальной картинки
if(!empty($ob['DETAIL_PICTURE'])) {
	$first_pic_orig = CFile::GetPath($ob['DETAIL_PICTURE']);
	$path_file = explode('/',$first_pic_orig);
	$first_pic = explode('.',$path_file[4]);
	$file_name = $first_pic[0];	// имя файла
	$file_exe = $first_pic[1];	// расширение файла
 
	$NEW_NAME_FILE = $path_file[0].'/'.$path_file[1].'/'.$path_file[2].'/'.$path_file[3].'/'.$new_code.'.'.$file_exe;	
 
	if($first_pic_orig != $NEW_NAME_FILE){
		// переименовываем файл
			rename($_SERVER['DOCUMENT_ROOT'].$first_pic_orig, $_SERVER['DOCUMENT_ROOT'].$NEW_NAME_FILE);
		// Исправляем значение в базе
			if(!empty($ob['DETAIL_PICTURE'])) 
				$DB->Query('UPDATE b_file SET FILE_NAME="'.$new_code.'.'.$file_exe.'",ORIGINAL_NAME="'.$new_code.'.'.$file_exe.'" WHERE ID='.$ob['DETAIL_PICTURE']);
	}
}
 
	// Для дополнительных фото в свойстве элемента
	$arFilter_prop = Array("IBLOCK_ID"=>$iblock_ids, "ID"=>$ob['ID']);
	$res_prop = CIBlockElement::GetList(Array(), $arFilter_prop);
	$MORE_PICT_VALUE = array();
	if ($ob_prop = $res_prop->GetNextElement()){
		$arFields = $ob_prop->GetFields(); // поля элемента
		$arProps = $ob_prop->GetProperties(); // свойства элемента
		if($ob['IBLOCK_ID']==2) $MORE_PICT_VALUE = $arProps['MORE_PICT']['VALUE'];		// 'MORE_PICT' - свойство, ['VALUE'] - значение для IBLOCK_ID = 2
		if($ob['IBLOCK_ID']==28) $MORE_PICT_VALUE = $arProps['MORE_PICT_TORG']['VALUE']; // 'MORE_PICT_TORG' для IBLOCK_ID = 28
 
		$more_pic = array();
		if(!empty($MORE_PICT_VALUE) && count($MORE_PICT_VALUE)>0){
			for($i=0;$i<count($MORE_PICT_VALUE);$i++){
				$more_pic_orig[$i] = CFile::GetPath($MORE_PICT_VALUE[$i]);
 
				$path = explode('/',$more_pic_orig[$i]);
				$more_pic[$i] = explode('.',$path[4]);
				$file_name = $more_pic[$i][0];	// имя файла
				$file_exe = $more_pic[$i][1];	// расширение файла
				$NEW_NAME_FILE_MORE = $path[0].'/'.$path[1].'/'.$path[2].'/'.$path[3].'/'.$new_code.'_'.($i+1).'.'.$file_exe; // ($i+1) - порядковый номер картинки
 
				if($NEW_NAME_FILE_MORE!=$more_pic_orig[$i]){
					rename($_SERVER['DOCUMENT_ROOT'].$more_pic_orig[$i], $_SERVER['DOCUMENT_ROOT'].$NEW_NAME_FILE_MORE);	// переименуем файл
					// Исправляем значение в базе для IBLOCK_ID = 2
					if($ob['IBLOCK_ID']==2) 
						$DB->Query('UPDATE b_file SET FILE_NAME="'.$new_code.'_'.($i+1).'.'.$file_exe.'",ORIGINAL_NAME="'.$new_code.'_'.($i+1).'.'.$file_exe.'" WHERE ID='.$arProps['MORE_PICT']['VALUE'][$i]);
					// Исправляем значение в базе для IBLOCK_ID = 28
					if($ob['IBLOCK_ID']==28) 
						$DB->Query('UPDATE b_file SET FILE_NAME="'.$new_code.'_'.($i+1).'.'.$file_exe.'",ORIGINAL_NAME="'.$new_code.'_'.($i+1).'.'.$file_exe.'" WHERE ID='.$arProps['MORE_PICT_TORG']['VALUE'][$i]);
				}
			}
		}
	}
}

Автор:Alex Posted Май 16, 2019

Массовое изменение цены товаров по артикулу Bitrix

У пары товаров не сложно у вручную изменить цену, а если товаров несколько сотен, да еще и раскиданных по десяткам разделов, тут на помощь придёт простая форма для выгрузки из Excel, CSV.

Сама выгрузка предельно простая. 2 столбца: Артикул и Цена

Сохранить файл выгрузки нужно как CSV (MS-DOS)

Форма загрузки на сайт, с краткой памяткой:

<form enctype="multipart/form-data" action="" method="POST" class="form_csv">
    <input type="hidden" name="MAX_FILE_SIZE" value="30000">
	Если через Excel, то должны быть только 2 столбца: <u>Артикул</u> и <u>Цена</u>.<br>
	Файл должен быть сохранен как <b>CSV (MS-DOS):</b><br><br>
	ID инфоблока, где лежат товары: 
	<input name="find_section_section" type="text" value="">
	<br>
	<input name="userfile" type="file" accept=".csv">
    <input type="submit" value="Изменить цены">
</form>
<br>
Скорость обработки: ~ 30 цен за 1 секунду

Сам PHP код:

if($_FILES['userfile']){
	if ($_FILES['userfile']['tmp_name']){
		echo "ID - ARTIKUL - PRICE - RESULT<br>";
		$row = 1;
		$prop_artic = 275; // ID свойства товара, отвечающего за артикул, у вас будет другое число, см. в настройках инфоблока
			if (($handle = fopen($_FILES['userfile']['tmp_name'], "r")) !== FALSE){
				while(($data = fgetcsv($handle, 4000, ";")) !== FALSE){
 
					$num = count($data);
					$row++;
					$artikul = trim($data[0]);				// артикул из файла
					$price = trim($data[1]);
					$price = str_replace(" ", "", $price);
					$price = str_replace(",", ".", $price);	// цена из файла, убираем пробелы, а копейки отделяем через точку
 
					$iblock_id = $_POST['find_section_section'];
 
					$res_hl = $DB-&gt;Query("SELECT * FROM b_iblock_element_property WHERE IBLOCK_PROPERTY_ID=".$prop_artic." AND VALUE='".$artikul."'");	// для декорико
 
					$result_db = $res_hl-&gt;result-&gt;num_rows;
 
					if($result_db&gt;0){
						while ($this_val = $res_hl-&gt;Fetch())
						{
							$ELEMENT_ID = $this_val["IBLOCK_ELEMENT_ID"];
						}
 
						// Ищем цены в базе
						$res_chek = $DB-&gt;Query("SELECT * FROM b_catalog_price WHERE PRODUCT_ID=".$ELEMENT_ID);
						if($res_chek-&gt;result-&gt;num_rows == 0){
							// Добавляем если нет в базе
							$arFields = Array(
								"PRODUCT_ID" =&gt; $ELEMENT_ID,
								"CATALOG_GROUP_ID" =&gt; 1,
								"PRICE" =&gt; $price,
								"CURRENCY" =&gt; "RUB"
							);
							CPrice::Add($arFields);
						} else {
							if($res_chek-&gt;result-&gt;num_rows == 2 || $res_chek-&gt;result-&gt;num_rows == 3 || $res_chek-&gt;result-&gt;num_rows == 4){
							// если цены задвоились, то их сначала удаляем старые данные, потом добавляем/обновляем цены
								$res_del = $DB-&gt;Query("SELECT MIN(ID) FROM b_catalog_price WHERE PRODUCT_ID=".$ELEMENT_ID."");
								while ($pr = $res_del -&gt;Fetch())
								{
									$min_id = (int)$pr["MIN(ID)"];
									$DB-&gt;Query("DELETE FROM b_catalog_price WHERE ID=".$min_id."");
								}
							}
							// Изменяем цены, если есть в базе
							$DB-&gt;Query("UPDATE b_catalog_price SET PRICE='".$price."',PRICE_SCALE='".$price."' WHERE PRODUCT_ID=".$ELEMENT_ID);
						}
 
						// ДАЛЕЕ РАБОТАЕТ С ТОРГОВЫМИ ПРЕДЛОЖЕНИЯМИ
						$arSKU = 0;
						$arSKU = CCatalogSKU::getOffersList($ELEMENT_ID, $iblock_id, array('ACTIVE' =&gt; 'Y'), array(), array());	// получаем торговые предложения товара, для нашего инфоблока $iblock_id по ID товара $ELEMENT_ID
						if(count($arSKU)&gt;0)
						{	// если есть торг. предложения
							foreach($arSKU as $item_s){
								foreach($item_s as $item_sku)
								{
									$ar_res = CCatalogProduct::GetByID($item_sku['ID']);	// получаем свойства торг. предложения
 
									// получаем цену и id цены
									$db_res = CPrice::GetList(array(),array("PRODUCT_ID" =&gt; $item_sku["ID"],"CATALOG_GROUP_ID" =&gt; "1"));
									if($ar_res_sku = $db_res-&gt;Fetch()){
										$ar_res_sku["PRICE"];
									}
 
 
									// делаем новую цену
 
									$res_chek = $DB-&gt;Query("SELECT * FROM b_catalog_price WHERE PRODUCT_ID=".$item_sku["ID"]);
									if($res_chek-&gt;result-&gt;num_rows == 0){
										// Добавляем, если нет
										$arFields = Array(
											"PRODUCT_ID" =&gt; $item_sku["ID"],
											"CATALOG_GROUP_ID" =&gt; 1,
											"PRICE" =&gt; $price,
											"CURRENCY" =&gt; "RUB"
										);
										CPrice::Add($arFields);
									} else {
										if($res_chek-&gt;result-&gt;num_rows == 2 || $res_chek-&gt;result-&gt;num_rows == 3 || $res_chek-&gt;result-&gt;num_rows == 4){
											$res_del = $DB-&gt;Query("SELECT MIN(ID) FROM b_catalog_price WHERE PRODUCT_ID=".$item_sku["ID"]."");
											while ($pr = $res_del -&gt;Fetch())
											{
												$min_id = (int)$pr["MIN(ID)"];
												$DB-&gt;Query("DELETE FROM b_catalog_price WHERE ID=".$min_id."");
											}
										}
										// Изменяем, если есть
										$DB-&gt;Query("UPDATE b_catalog_price SET PRICE='".$price."',PRICE_SCALE='".$price."' WHERE PRODUCT_ID=".$item_sku["ID"]);
									}
								}
							}
						}
 
						echo $ELEMENT_ID." - ".$artikul." - новая цена: ".$price." <br>";
					}
				}
				fclose($handle);
			}
		//echo "Файл корректен и был успешно загружен.\n";
	} else {
		echo "Файл не выбран !\n";
	}
}
Автор:Alex Posted Май 16, 2019

Параметры (длина, ширина, количество и др) товара Bitrix из Excel

Сегодня покажу как сделать форму для массовой выгрузки параметров товара Bitrix: длина, ширина, высота, вес, доступное количество из Excel (CSV) на сайт.

Изначально подготовим в Excel выгрузку, которая должна содержать 6 столбцов по порядку: Артикул, Длина, Ширина, Высота, Вес, Количество.

После заполнения сохраняем в формате csv (MS-DOS)

Создаем страницу и добавляем туда:

<h2>Выгрузка параметров Длина, Ширина, Высота, ВЕС через CSV: </h2>
<form enctype="multipart/form-data" action="?file=csv" method="POST" class="form_csv">
	<input type="hidden" name="file" value="csv">
	<input type="hidden" name="lang" value="ru">
	<input type="hidden" name="MAX_FILE_SIZE" value="30000">
	<input name="userfile" type="file" accept=".csv">
	<input type="submit" value="Загрузить">
</form>

PHP код:

global $DB;
if($_FILES['userfile'] &amp;&amp; $_GET['file']=='csv'){
if ($_FILES['userfile']['tmp_name']){
	$row = 1;
	$prop_artic = 275; // ID свойства товара, отвечающего за артикул, у вас будет другое число, смотрите в настройках инфоблока /bitrix/admin/iblock_admin.php?type=catalog&amp;lang=ru
	if (($handle = fopen($_FILES['userfile']['tmp_name'], "r"))!==FALSE ){
		while(($data = fgetcsv($handle, 4000, ";")) !== FALSE){
			$num = count($data);
			$row++;			
			if(mb_detect_encoding($data[0])!="UTF-8"){
			// проверяем кодировку, лучше чтобы она была UTF-8
				$artikul = trim(iconv(mb_detect_encoding($data[0]), "utf-8", $data[0]));
			} else 
				$artikul = trim($data[0]);
 
			// Наши параметры:
			$dlina = trim($data[1]);
			$shirina = trim($data[2]);
			$visota = trim($data[3]);
			$ves = trim($data[4]);
			$dostupno = trim($data[5]);
 
			$val_ar = $DB-&gt;Query('SELECT * FROM b_iblock_element_property WHERE IBLOCK_PROPERTY_ID='.$prop_artic.' AND VALUE="'.$artikul.'"');	// находи ID товара по артикулу
			while ($arr_id_el = $val_ar-&gt;Fetch())
			{
				if(!empty($arr_id_el['IBLOCK_ELEMENT_ID'])){	// если ID найден - устанавливаем параметры
					$DB-&gt;Query('UPDATE b_catalog_product SET WEIGHT='.$ves.', LENGTH='.$dlina.', WIDTH='.$shirina.', HEIGHT='.$visota.' QUANTITY='.$dostupno.' WHERE ID='.$arr_id_el['IBLOCK_ELEMENT_ID']);
					echo $artikul." - успешно <br>";
				}
			}
		}
	}
}
}

Автор:Alex Posted Сен 24, 2018

AJAX запрос средствами Битрикс

Мало кто знает, что в Битриксе есть стандартные средства для отправки AJAX запросов, без использования jQuery или чистого JS.

BX.ajax({   
	url: '/include/page.php',
	data: {
	},
	method: 'GET',
	timeout: 0,
	async: true,
	processData: true,
	scriptsRunFirst: true,
	emulateOnload: true,
	start: true,
	cache: true,
	onsuccess: function(data){
	   // выполняем в случае успеха
	},
	onfailure: function(){
	   // в случае ошибки
	}
});
Автор:Alex Posted Сен 24, 2018

Создание диалоговых (модальных) окон в Битрикс

В Битриксе есть стандартная js библиотека для создания таких окон, но почему-то она плохо задокументировано.
А ведь там все просто:
Подключаем JS библиотеку через php на странице:

CJSCore::Init(array('window'));

Воздать окно с вызовом /include/page.php в нем:

var popup = new BX.CDialog({
'title':'Выбрать товары', 
'content_url':'/include/page.php', 
'width':'550', 
'height':'350'
});

где content_url — ссылка на страницу, которая будет показана, вместо этого параметра можно использовать content — который выведет произвольное содержимое, width и height размеры окна

Показать окно:

popup.Show();

Закрыть окно:

popup.Close();

Изменить на лету содержимое окна:

popup.SetContent("html внутри окна")

Изменять CSS стили окна можно как душе угодно.

Автор:Alex Posted Сен 24, 2018

Обновить или добавить значение свойства элемента Битрикс

Тут все просто, в документации функция CIBlockElement::SetPropertyValuesEx добавляет/обновляет свойство.
Есть момент, для свойств «список», нужно указывать id значения свойства,
а для свойств типа «справочник» нужно указывать символьный код значения.
Пример использования:

CIBlockElement::SetPropertyValuesEx($ID, false, array('SVOYSTVO' => 228));

где $ID — ид элемента, SVOYSTVO — символьный код свойства, 228 — значение свойства (т.к. у меня свойство список, указывает id нужного значения)

Автор:Alex Posted Сен 24, 2018

Поиск и замена значения в базе данных MySQL

Команда замены в MySQL очень простая REPLACE.
Предположим, нам нужно найти во всех записях wp_posts слово «staroe» и заменить его на «novoe»

UPDATE `wp_posts` SET `post_content` = REPLACE(`post_content`, 'staroe', 'novoe') WHERE post_content LIKE "%staroe%";

где post_content — имя столбца (в нашем случае тело записи)

Автор:Alex Posted Сен 24, 2018

Возвращение минимальной цены товара по торговому предложению Битрикс

Функцию можно добавить в init.php и получить минимальную цену любого товара.

CModule::IncludeModule('catalog');
function GetOfferMinPrice($IBLOCK_ID,$item_id){
	// получаем все торг. предложения
	$arSKU = CCatalogSKU::getOffersList($item_id, $IBLOCK_ID, array('ACTIVE' => 'Y'), array(), array());	
	// Если у товара есть торговые предложения
	if(count($arSKU)>0){
		$arr_price = array();
		foreach($arSKU as $item_s)
		{
		  foreach($item_s as $item_sku)
		  {
			// получаем цену, где 1 - тип цены
			$ret_sku = GetCatalogProductPrice($item_sku['ID'], 1);
			  if ($ret_sku['PRICE']){
				$arr_price[] = ceil($ret_sku['PRICE']);
			  }		
		  }
		}
	$itog_price_sku = min($arr_price);
	} else {
		$ret_sku = GetCatalogProductPrice($item_id, 1);
		if ($ret_sku['PRICE']){
			$itog_price_sku = ceil($ret_sku['PRICE']);
		}
	}
 
	return $itog_price_sku;
}

где, $IBLOCK_ID — ид инфоблока ,$item_id — ид товара с торговыми предложениями, если тп нет — вернет цену товара.
Пример вызова:

GetOfferMinPrice(2,10);
Автор:Alex Posted Сен 24, 2018

Добавить пункт в меню админки Битрикс

Для добавления своего пункта меню в административный раздел Битрикс, нужно в init.php
добавить функцию:

AddEventHandler("main", "OnBuildGlobalMenu", "ChangeIblockMenu");
function ChangeIblockMenu(&$adminMenu, &$moduleMenu){
	$moduleMenu[] = array(
		"parent_menu"	=> "global_menu_services", // поместим в раздел "Сервис"
		"section"	=> "change_iblock_elements",
		"sort"        => 10,                    // сортировка пункта меню
		"url"         => "change_iblock_elements.php?lang=".LANG,  // ссылка на пункте меню
		"text"        => 'Изменить категорию',       // текст пункта меню
		"title"       => 'Изменить категорию', // текст всплывающей подсказки
		"icon"        => "fileman_menu_icon", // малая иконка
		"page_icon"   => "fileman_page_icon", // большая иконка
		"items_id"    => "change_iblock_elements",  // идентификатор ветви
		"items"       => array()          // остальные уровни меню сформируем ниже.
	);
}

где global_menu_services — параметр ID одного из глобальных разделов (в нашем случае Сервис), узнать можно через инспектор кода в dom html нужного раздела id=»***»;
change_iblock_elements — название нашего пункта меню в виде символьного кода;
«change_iblock_elements.php?lang=».LANG — путь к файлу php, все они должны храниться в /bitrix/admin/ ;
fileman_menu_icon — название класса css иконки рядом с пунктом меню, можно добавить свою или использовать с другого пункта меню (в нашем случае взяли в пункта «Структура сайта»)

Автор:Alex Posted Сен 24, 2018

По ID торгового предложения получить остальные предложения в Битрикс

Предположим у нас уже есть Ид торгового, сначало нужно получить Ид основного товара, а потом по нем все его торговые предложения.
Получаем ID основного товара:

$MainElenemt = CCatalogSku::GetProductInfo( $ID_SKU );

где $ID_SKU — id торгового предложения, а $MainElenemt[‘ID’] — id товара
Получаем все остальные предложения в виде массива:

$arSKU = CCatalogSKU::getOffersList($MainElenemt['ID'], $IBLOCK_ID, array('ACTIVE' => 'Y'), array(), array());
foreach($arSKU as $item_s)
 {
   foreach($item_s as $item_sku)
   {
     var_dump($item_sku);
   }
}

где $MainElenemt[‘ID’] — ид основного товара, $IBLOCK_ID — ид инфоблока, $item_sku — массив торговых предложений