Написал пользовательское поле для главного модуля. Позволяет создавать хранить в одном поле много блоков с заголовком и текстом.

Так выглядит на странице редактирование раздела инфоблока:

Конечно поддерживается при выводе значения свойства в списке элементов в режиме редактирования:

Долго не буду рассказывать зачем оно нужно. Просто держите код обработчика:

<?php
/**
 * Created by olegpro.ru
 * User: Oleg Maksimenko <ya@olegpro.ru>
 * Date: 23.10.2015. Time: 10:52
 */
 
/**
 * Binding
 * \Bitrix\Main\EventManager::getInstance()->addEventHandler('main', 'OnUserTypeBuildList',
 *      array('\Olegpro\Classes\Handlers\UserType\MultiStringBlock', 'getUserTypeDescription')
 * );
 *
 */
 
namespace Olegpro\Classes\Handlers\UserType;
 
 
class MultiStringBlock extends \CUserTypeString
{
 
    /**
     * @return array
     */
    public function getUserTypeDescription()
    {
        return array(
            'USER_TYPE_ID' => 'multi_string_block',
            'CLASS_NAME' => __CLASS__,
            'DESCRIPTION' => 'Multi string block [Artmix]',
            'BASE_TYPE' => 'string',
        );
    }
 
    /**
     * @param array $arUserField
     * @param array $arHtmlControl
     * @return mixed
     */
    public function GetEditFormHTML($arUserField, $arHtmlControl)
    {
        return self::getEditRowHtml($arUserField, $arHtmlControl);
    }
 
    /**
     * @param $arUserField
     * @param $arHtmlControl
     * @return mixed
     */
    public function getEditRowHtml($arUserField, $arHtmlControl)
    {
 
        if (
            $arUserField['VALUE'] === false
            && isset($arUserField['SETTINGS']['DEFAULT_VALUE'])
            && strlen($arUserField['SETTINGS']['DEFAULT_VALUE']) > 0
        ) {
            $arHtmlControl['VALUE'] = json_decode(
                array(
                    'HEADER' => '',
                    'TEXT' => htmlspecialcharsbx($arUserField['SETTINGS']['DEFAULT_VALUE']),
                )
            );
        }
 
        if (!(
            strlen(trim($arHtmlControl['VALUE'])) > 0
            && ($arValue = @unserialize(htmlspecialcharsback($arHtmlControl['VALUE'])))
            && is_array($arValue)
            && isset($arValue['HEADER'], $arValue['TEXT'])
        )
        ) {
 
            $arValue = array(
                'HEADER' => '',
                'TEXT' => '',
            );
 
        }
 
        $tpl = str_replace(
            '#INPUT_HTML#',
            ($arUserField['SETTINGS']['ROWS'] > 1
                ? '<textarea name="#INPUT_NAME#[TEXT]" cols="#SETTING_TEXT_SIZE#" rows="#SETTING_TEXT_ROWS#" placeholder="Text block *" #INPUT_TEXT_ATTRIBUTES#>#VALUE_TEXT#</textarea>'
                : '<input type="text" name="#INPUT_NAME#[TEXT]" value="#VALUE_TEXT#" placeholder="Text block *" #INPUT_TEXT_ATTRIBUTES# />'
            ),
            self::getEditRowHtmlWrapper()
        );
 
        $result = str_replace(
            array(
                '#INPUT_NAME#',
                '#VALUE_HEADER#',
                '#VALUE_TEXT#',
                '#SETTING_TEXT_SIZE#',
                '#SETTING_TEXT_ROWS#',
                '#INPUT_TEXT_ATTRIBUTES#',
            ),
            array(
                $arHtmlControl['NAME'],
                $arValue['HEADER'],
                $arValue['TEXT'],
                $arUserField['SETTINGS']['SIZE'],
                $arUserField['SETTINGS']['ROWS'],
                implode(' ',
                    array_filter(
                        array(
                            $arUserField['SETTINGS']['MAX_LENGTH'] > 0
                                ? sprintf('maxlength="%s"', $arUserField['SETTINGS']['MAX_LENGTH'])
                                : '',
                            $arUserField['EDIT_IN_LIST'] != 'Y'
                                ? sprintf('disabled="disabled"')
                                : '',
                        )
                    )
                )
            ),
            $tpl
        );
 
 
        return $result;
 
    }
 
    /**
     * @return string
     */
    protected function getEditRowHtmlWrapper()
    {
        return sprintf(
            '<div
                style="margin-bottom: 15px;
                border: 1px solid #d0d7d8;
                background: #fafcfc;
                padding: 12px 10px 12px 10px;
                width: 100%%">
                    <input name="#INPUT_NAME#[HEADER]" type="text" placeholder="Header block" size="60" value="#VALUE_HEADER#" /><br><br>
                    #INPUT_HTML#
            </div>'
        );
    }
 
    /**
     * @param array|bool $arUserField
     * @param array $arHtmlControl
     * @param $bVarsFromForm
     * @return string
     */
    public function GetSettingsHTML($arUserField, $arHtmlControl, $bVarsFromForm)
    {
        return parent::GetSettingsHTML($arUserField, $arHtmlControl, $bVarsFromForm);
    }
 
    /**
     * @param array $arUserField
     * @param array $arHtmlControl
     * @return string
     */
    public function GetAdminListViewHTML($arUserField, $arHtmlControl)
    {
        if (
            strlen(trim($arHtmlControl['VALUE'])) > 0
            && ($arValue = @unserialize(htmlspecialcharsback($arHtmlControl['VALUE'])))
            && is_array($arValue)
            && isset($arValue['HEADER'], $arValue['TEXT'])
        ) {
            return sprintf('<strong>%s</strong>%s', $arValue['HEADER'], $arValue['TEXT']);
        } else {
            return '&nbsp;';
        }
    }
 
    /**
     * @param array $arUserField
     * @param array $arHtmlControl
     * @return mixed|string
     */
    public function GetAdminListEditHTML($arUserField, $arHtmlControl)
    {
        return self::getEditRowHtml($arUserField, $arHtmlControl);
    }
 
    /**
     * @param array $arUserField
     * @return string
     */
    public function OnSearchIndex($arUserField)
    {
        if (is_array($arUserField['VALUE'])) {
            return implode("\r\n/",
                (is_array($arUserField['VALUE'])
                    ? implode("\r\n", $arUserField['VALUE'])
                    : $arUserField['VALUE']
                )
            );
        } else {
            return $arUserField['VALUE'];
        }
    }
 
    /**
     * @param $arUserField
     * @param $value
     * @return string
     */
    public function OnBeforeSave($arUserField, $value)
    {
        if (
            is_array($value)
            && isset($value['HEADER'], $value['TEXT'])
            && strlen(trim($value['TEXT'])) > 0
        ) {
            return serialize($value);
        } else {
            return '';
        }
 
    }
 
    /**
     * @param array $arUserField
     * @param array $value
     * @return array
     */
    public function CheckFields($arUserField, $value)
    {
        $aMsg = array();
        return $aMsg;
    }
 
}

Ну а как работать с значением свойства в публичной части сайта, думаю, уже разберётесь.