EventManager::getInstance()->registerEventHandler(
'iblock',
'OnIBlockPropertyBuildList',
'main',
StructureCustomProperty::class,
'GetUserTypeDescription'
);
Далее создаем класс
class StructureCustomProperty
{
/**
* Метод возвращает массив описания собственного типа свойств.
*
* @return array
*/
public static function GetUserTypeDescription(): array
{
return [
'USER_TYPE' => 'BLOCKS',
'DESCRIPTION' => 'Блоки',
'PROPERTY_TYPE' => PropertyTable::TYPE_STRING,
'GetPropertyFieldHtml' => [__CLASS__, 'getPropertyFieldHtml'],
'ConvertToDB' => [__CLASS__, 'convertToDB'],
];
}
/**
* Метод возвращает html.Другими словами, визуал вашего свойства в админке.
*
* @return string
*/
public static function getPropertyFieldHtml(array $arProperty, array $value, array $strHTMLControlName): string
{
global $APPLICATION;
ob_start();
// Тут может быть ваш html. Я вынес его в собственный компонент.Так более правильно
$APPLICATION->IncludeComponent(
'custom:custom-property',
'.default',
[
'ARRAY_VALUES' => $value,
'ARRAY_PROPERTY' => $arProperty,
'STR_HTML_CONTROL_NAME' => $strHTMLControlName,
]
);
return ob_get_clean();
}
/**
* @param $arProperty
* @param $value
* @return int|null
*/
public static function convertToDB($arProperty, $value): ?int
{
/** Удаление */
if (!empty($value['VALUE']['REMOVED'])) {
CIBlockElement::Delete($value['VALUE']['REMOVED']);
return null;
}
/** Пропуск пустого шаблона */
if (empty($value['VALUE']['NAME'])) {
return null;
}
/** Создание или обновление */
$linkIblockId = (int)$arProperty['LINK_IBLOCK_ID'];
$linkElementId = (int)$value['VALUE']['ELEMENT_ID'];
if (!$linkElementId) {
$linkElementId = self::addLinkElement($linkIblockId, $value['VALUE'] ?: []);
} else {
self::updateLinkElement($linkIblockId, $linkElementId, $value['VALUE'] ?: []);
}
return $linkElementId;
}
/**
* @param int $linkIblockId
* @param array $value
* @return int|null
*/
private static function addLinkElement(int $linkIblockId, array $value): ?int
{
$newElement = new CIBlockElement();
$properties = self::preparePropertyValues($value);
$id = $newElement->Add(
[
'IBLOCK_ID' => $linkIblockId,
'NAME' => $value['NAME'],
'ACTIVE' => $value['ACTIVE'],
'SORT' => $value['SORT'],
'PROPERTY_VALUES' => $properties,
]
);
return $id ?: null;
}
/**
* @param int $linkIblockId
* @param int $linkElementId
* @param array $value
* @return bool
*/
private static function updateLinkElement(int $linkIblockId, int $linkElementId, array $value): bool
{
$properties = self::preparePropertyValues($value);
$element = new CIBlockElement();
$fields = [
'NAME' => $value['NAME'],
'ACTIVE' => $value['ACTIVE'] ?? 'N',
'SORT' => $value['SORT'],
'TIMESTAMP_X' => new DateTime(),
];
$element->Update($linkElementId, $fields);
CIBlockElement::SetPropertyValuesEx($linkElementId, $linkIblockId, $properties);
return true;
}
/**
* @param array $value
* @return array
*/
private static function preparePropertyValues(array $value): array
{
$propertyValuesPrepared = [];
foreach ($value['PROPERTIES'] ?? [] as $propertyCode => $propertyValue) {
if (is_array($propertyValue)) {
foreach ($propertyValue as $propertyInnerValue) {
$propertyValuesPrepared[$propertyCode][]['VALUE'] = $propertyInnerValue;
}
} else {
$propertyValuesPrepared [$propertyCode] = ['VALUE' => $propertyValue];
}
}
return $propertyValuesPrepared;
}
}
Как результат, в админке у вас появится возможность создать свойство с вашим типом
Как пример, я использовал редактор json полей, а клиенту сделал удобный интерфейс