Обучаю битриксу программистов, интеграторов. Подробнee ⇒

Модули. Пример своего модуля.



Документация Битрикс:
  • /bitrix/modules - Модули системы (как штатные, так и загруженные из Marketplace)
  • /local/modules - пользовательские модули, но можно и в /bitrix/modules

Свой модуль
nikaverro.test
архив с модулем
где
  • nikaverro - мой код партнера
  • test - название модуля
папка /local/modules/nikaverro.test/



Файлы установки
папка /local/modules/nikaverro.test/install
в ней
  • /components/ - папка со своими компонентами (необязательно)
  • /js/ - папка с js скриптами для админки (необязательно)
  • /panel/ - папка с css скриптами для админки (необязательно)
  • index.php - с нашим классом, который расширяет битриксовский CModule
  • version.php - дата версии и номер версии модуля
install/index.php
функции битрикса для работы с файловой системой сайта:
DeleteDirFilesEx
CopyDirFiles
<?php

use Bitrix\Main\Localization\Loc;
use Bitrix\Main\ModuleManager;

Loc::loadMessages(__FILE__);

class nikaverro_test extends CModule
{
    public $MODULE_ID = 'nikaverro.test';
    public $MODULE_VERSION;
    public $MODULE_VERSION_DATE;
    public $MODULE_NAME;
    public $MODULE_DESCRIPTION;
    public $PARTNER_URI;
    public $MODULE_GROUP_RIGHTS;

    public function __construct()
    {
        $arModuleVersion = [];

        include __DIR__ . '/version.php';

        if (is_array($arModuleVersion) && array_key_exists('VERSION', $arModuleVersion)) {
            $this->MODULE_VERSION = $arModuleVersion['VERSION'];
            $this->MODULE_VERSION_DATE = $arModuleVersion['VERSION_DATE'];
        }

        $this->MODULE_NAME = Loc::getMessage('nikaverro_test_module_name');
        $this->MODULE_DESCRIPTION = Loc::getMessage('nikaverro_test_module_description');
        $this->PARTNER_NAME = Loc::getMessage('nikaverro_test_partner_name');
        $this->PARTNER_URI = Loc::getMessage('nikaverro_test_partner_uri');
        $this->MODULE_GROUP_RIGHTS = 'N';
    }

     public  function InstallDB($arParams = []) //создание своих таблиц в БД
    {   global $DB, $APPLICATION;      
        //проверяем, есть ли таблицы
        $errors = false;
        //создаем таблицы, если они еще не существуют
        $errors = $DB->RunSQLBatch($_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/db/".strtolower($DB->type)."/install.sql");
        if (!empty($errors)){
            $APPLICATION->ThrowException(implode("", $errors));
            return false;
        }
       
        return true;
    }

     public  function UnInstallDB($arParams = []) //удаление своих таблиц в БД
    {   global $DB, $DBType, $APPLICATION;
        
        if(array_key_exists("SAVEDATA", $arParams) and $arParams["SAVEDATA"] == "N"){ //удаляем, если параметр сохранить = "N"
            $errors = false;
            $errors = $DB->RunSQLBatch($_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/db/".strtolower($DB->type)."/uninstall.sql");
            if (!empty($errors)){
                $APPLICATION->ThrowException(implode("", $errors));
                return false;
            }
        }
        
        return true;
    }

   

     public function InstallFiles($arParams = [])
    {
        if (is_dir($p = $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/admin")){
            if ($dir = opendir($p)){
                while (false !== $item = readdir($dir)){
                    if ($item == ".." || $item == "." || $item == "menu.php")
                        continue;
                    file_put_contents($file = $_SERVER['DOCUMENT_ROOT'].'/bitrix/admin/'.$this->MODULE_ID.'_'.$item,
                    '<'.'? require($_SERVER["DOCUMENT_ROOT"]."/local/modules/'.$this->MODULE_ID.'/admin/'.$item.'");?'.'>');
                }
                closedir($dir);
            }
        }
        if (is_dir($p = $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/components")){
            if ($dir = opendir($p)){
                while (false !== $item = readdir($dir)){
                    if ($item == ".." || $item == ".")
                        continue;
                    CopyDirFiles($p."/".$item, $_SERVER["DOCUMENT_ROOT"]."/bitrix/components/".$item, $ReWrite = True, $Recursive = True);
                }
                closedir($dir);
            }
        }
        //создаем папку для собственных нужд
        if(is_dir($_SERVER["DOCUMENT_ROOT"]."/upload/testfolder")){
            //ставим права
            chmod($_SERVER["DOCUMENT_ROOT"]."/upload/testfolder", 0755);
        }
        else{
            mkdir($_SERVER["DOCUMENT_ROOT"]."/upload/testfolder", 0755, true);
        }
        //копируем стили
        if (is_dir($p = $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/panel")){
            if ($dir = opendir($p)){
                while (false !== $item = readdir($dir)){
                    if ($item == ".." || $item == ".")
                        continue;
                    CopyDirFiles($p."/".$item, $_SERVER["DOCUMENT_ROOT"]."/bitrix/themes/.default/".$this->MODULE_ID."/".$item, $ReWrite = True, $Recursive = True);
                }
                closedir($dir);
            }
        }

        //копируем js
        if (is_dir($p = $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/js")){
            if ($dir = opendir($p)){
                while (false !== $item = readdir($dir)){
                    if ($item == ".." || $item == ".")
                        continue;
                    CopyDirFiles($p."/".$item, $_SERVER["DOCUMENT_ROOT"]."/bitrix/js/".$this->MODULE_ID."/".$item, $ReWrite = True, $Recursive = True);
                }
                closedir($dir);
            }
        }

        return true;
    }

    public function UnInstallFiles()
    {
        //удаляем папку с админ скриптами
        if (is_dir($p = $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/admin")) 
        {
            if ($dir = opendir($p))
            {
                while (false !== $item = readdir($dir))
                {
                    if ($item == ".." || $item == ".")
                        continue;
                    unlink($_SERVER["DOCUMENT_ROOT"]."/bitrix/admin/".$this->MODULE_ID."_".$item);
                }
                closedir($dir);
            }
        }
        //удаляем компоненты
        if (is_dir($p = $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/components"))
        {
            if ($dir = opendir($p))
            {
                while (false !== $item = readdir($dir))
                {
                    if ($item == ".." || $item == "." || !is_dir($p0 = $p."/".$item))
                        continue;

                    $dir0 = opendir($p0);
                    while (false !== $item0 = readdir($dir0))
                    {
                        if ($item0 == ".." || $item0 == ".")
                            continue;
                        DeleteDirFilesEx("/bitrix/components/".$item."/".$item0);
                    }
                    closedir($dir0);
                }
                closedir($dir);
            }
        }
        //удаляем папку
        if(is_dir($_SERVER["DOCUMENT_ROOT"]."/upload/testfolder")){                   
            DeleteDirFilesEx("/upload/testfolder");
        }
        //удаляем стили
        if(is_dir($_SERVER["DOCUMENT_ROOT"]."/bitrix/themes/.default/".$this->MODULE_ID)){                       
            DeleteDirFilesEx("/bitrix/themes/.default/".$this->MODULE_ID);
        }
        //удаляем js
        if(is_dir($_SERVER["DOCUMENT_ROOT"]."/bitrix/js/".$this->MODULE_ID)){                    
            DeleteDirFilesEx("/bitrix/js/".$this->MODULE_ID);
        }
        
        return true;

    }    

    public function InstallEvents()
    {
         //RegisterModuleDependences("main", "OnBuildGlobalMenu", $this->MODULE_ID, "CAlfateamWordstat", "OnBuildGlobalMenu"); //старый вариант
        $eventManager = \Bitrix\Main\EventManager::getInstance(); 
        $eventManager->registerEventHandler(   "main",
           "OnProlog",
           $this->MODULE_ID,
           "nikaverro\\test\\MyClass",
           "onProlog"
        );

        return true;
    }

     public function UnInstallEvents()
    {
        //UnRegisterModuleDependences("main", "OnBuildGlobalMenu", $this->MODULE_ID, "CAlfateamWordstat", "OnBuildGlobalMenu"); //старый вариант
        $eventManager = \Bitrix\Main\EventManager::getInstance(); 
        $eventManager->unRegisterEventHandler(   "main",
           "OnProlog",
           $this->MODULE_ID,
           "nikaverro\\test\\MyClass",
           "onProlog"
        );
        return true;
    }

    public function RegisterAgents() {

        $allowedAgents = [
            '\\nikaverro\\test\\MyClass::agent()' => [
                "MODULE_ID" => $this->MODULE_ID,
                "NAME" => '\\nikaverro\\test\\MyClass::agent();',
                "AGENT_INTERVAL" => 300,
                "IS_PERIOD" => "Y"
            ]
        ];

        $needToInstall = [];

        $res = CAgent::GetList([], ["MODULE_ID" => $this->MODULE_ID]);
        while ($arAgent = $res->Fetch()) {

            if (array_key_exists($arAgent["NAME"], $allowedAgents)) {
                unset($allowedAgents[$arAgent["NAME"]]);
            }
        }

        $agentObject = new \CAgent();

        foreach ($allowedAgents as $agent) {
            $agentObject->Add($agent);
        }

    }
    public function UnRegisterAgents() {
        \CAgent::RemoveModuleAgents($this->MODULE_ID);
    }    
        
    public function DoInstall()
    {
        //$this->InstallFiles();
        $this->InstallDB();
        //$this->InstallEvents();
        //$this->RegisterAgents();

        ModuleManager::registerModule($this->MODULE_ID);
    }

    
    /*public function DoUninstall() //удаляем модуль за 1 шаг
    {
        //$this->UnInstallFiles();
        //$this->UnInstallEvents();
        //$this->UnRegisterAgents();

        ModuleManager::unRegisterModule($this->MODULE_ID);
    }*/

    public function DoUninstall() //удаляем модуль за 2 шага - спрашиваем, сохранить ли таблицы
    {
        global $APPLICATION, $step; 
        $step = IntVal($step);
        if($step<2){    
            $APPLICATION->IncludeAdminFile(Loc::getMessage('nikaverro_test_partner_name'), $_SERVER["DOCUMENT_ROOT"]."/local/modules/".$this->MODULE_ID."/install/unstep1.php");
        }
        elseif(($step == 2) and (array_key_exists("nextstep", $_REQUEST))){                        
            //$this->UnInstallFiles();
            //$this->UnInstallEvents();
            //$this->UnRegisterAgents();

            ModuleManager::unRegisterModule($this->MODULE_ID);
            $this->UnInstallDB(["SAVEDATA" => $_REQUEST["savedata"]]);
        }       
    }  
    
    
}
install/version.php
<?php
$arModuleVersion = [
   'VERSION' => '1.0.0',
   'VERSION_DATE' => '2024-04-12',
];
install/step.php - может отсутствовать
install/unstep.php - может отсутствовать

install/unstep1.php
<?if(!check_bitrix_sessid()) return;
use Bitrix\Main\Localization\Loc;
IncludeModuleLangFile(__FILE__);
echo CAdminMessage::ShowNote(Loc::getMessage('nikaverro_test_partner_name'));
?>
<form action="<?=$APPLICATION->GetCurPage(); ?>">
   <?=bitrix_sessid_post(); ?>
   <input type="hidden" name="step" value="2">
   <input type="hidden" name="id" value="nikaverro.test">
   <input type="hidden" name="uninstall" value="Y">
   <p><b><?=GetMessage("SAVE_OR_DELETE_DATA")?>:</b><Br>
      <input type="radio" name="savedata" value="Y" CHECKED><?=GetMessage("SAVE")?><Br>
      <input type="radio" name="savedata" value="N"><?=GetMessage("DELETE_")?><Br>
   </p>
   <input type="submit" name="nextstep" value="<?=GetMessage("NEXT")?>">
   <input type="submit" name="cancel" value="<?=GetMessage("CANCEL")?>">
</form>

install/db/mysql/install.sql
создаем свои 2 таблицы
create table if not exists n_words(
   ID INT(255) auto_increment,   
   WORD VARCHAR(100) NOT NULL,
   PROFILE_ID INT(10) NOT NULL,
   SORT INT(10)  DEFAULT 500,
   primary key (ID)
);

create table if not exists n_profiles(
   PROFILE_ID INT(10) auto_increment,   
   NAME VARCHAR(100) NOT NULL,
   DATE_CREATE DATE NOT NULL,
   CREATED_BY SMALLINT(4)NOT NULL,
   DATE_MODIFIED DATE NOT NULL,
   MODIFIED_BY SMALLINT(4)NOT NULL,
   AGENT_START DATETIME,
   AGENT_EXISTS BOOLEAN DEFAULT 0,
   REGIONS VARCHAR(8000),
   PERIODICITY SMALLINT(4)NOT NULL,
   ACTIVE BOOLEAN DEFAULT 0,
   IBLOCK BOOLEAN DEFAULT 0,
   IBLOCK_ID SMALLINT(4) DEFAULT 0,
   IBLOCK_FROM VARCHAR(100), 
   IBLOCK_TO VARCHAR(100),
   primary key (PROFILE_ID)
);

install/db/mysql/uninstall.sql
удаляем таблицы
drop table n_words;
drop table n_profiles;

Языковые файлы (Ланги)
/local/modules/nikaverro.test/lang/

пример /local/modules/nikaverro.test/lang/ru/install/index.php
$MESS["nikaverro_test_module_name"] = "Тестовый модуль";
$MESS["nikaverro_test_module_description"] = "Описание тестового модуля";
$MESS["nikaverro_test_partner_name"] = 'Вероника Малышева';
$MESS["nikaverro_test_partner_uri"] = "https://nikaverro.ru/?utm_source=nikaverro.test&utm_medium=modules";
$MESS["nikaverro_test_delete_step1"] = "Удаление модуля шаг1";
модуль появился в решениях маркетплейс
/bitrix/admin/partner_modules.php?lang=ru

Перед удалением вопрос


Настройки модуля
TEST_OPTION1, TEST_OPTION2
option.php
<?

use Bitrix\Main\Config\Option;
use Bitrix\Main\Context;

// если администратор
if($USER->IsAdmin() && CModule::IncludeModule('nikaverro.test')):

   $request = Context::getCurrent()->getRequest(); // формируем объект запроса

   // если переданы данные из формы
   if($request->getRequestMethod() == 'POST' && !empty($request->getPost('apply')) && check_bitrix_sessid()){

        Option::set("nikaverro.test", "TEST_OPTION1", $request->getPost("TestOption1"));
        Option::set("nikaverro.test", "TEST_OPTION2", $request->getPost("TestOption2"));

   }

   // табы
   $arTabs = array(
      array(
         'DIV' => 'MainSettings',
         'TAB' => 'Первая вкладка',
         'TITLE' => 'Основные настройки Тестового модуля'

      ),
      array(
         'DIV' => 'SecondSettings',
         'TAB' => 'Вторая вкладка',
         'TITLE' => 'Дополнительные настройки Тестового модуля'

      ),
   );      

   // инициализируем вывод табов
   $tabControl = new CAdminTabControl('tabControl', $arTabs);
   $tabControl->Begin();
   ?>

   <form method="post" name="webhooks" action="<? echo $APPLICATION->GetCurPage() ?>?mid=<?=urlencode($mid)?>&lang=<? echo LANGUAGE_ID ?>">
      <?=bitrix_sessid_post();?>

      <?$tabControl->BeginNextTab();?>
        <tr>

            <td valign="middle" width="40%" class="adm-detail-content-cell-l">
              опция 1
            </td>

            <td valign="middle" width="60%" class="adm-detail-content-cell-r">
               <?$arOptionVariants = [1,2,3]?>

                <select name="TestOption1" >
                    <?foreach ($arOptionVariants as $option):?>
                        <option <?=($option ==  Option::get("nikaverro.test", "TEST_OPTION1"))?"selected":""?> value="<?=$option?>"><?=$option?></option>
                    <?endforeach;?>
                </select>
            </td>
        </tr>
        <?$tabControl->BeginNextTab();?>
        <tr>
            <td valign="middle" width="40%" class="adm-detail-content-cell-l">
                опция 2
            </td>
            <td valign="middle" width="60%" class="adm-detail-content-cell-r">
                <input value="<?=Option::get("nikaverro.test", "TEST_OPTION2")?>" type="text" name="TestOption2" style="width: 50px;">
            </td>

        </tr>
      <?$tabControl->Buttons();
      bitrix_sessid_post();
      ?>
      <input type="submit" name="apply" value="<?=GetMessage('MAIN_SAVE')?>" title="<?=GetMessage('MAIN_OPT_SAVE_TITLE')?>" class="adm-btn-save">
      <?$tabControl->End();?>
      </form>
<?endif;
дефолтные значения
default_option.php
<?
$nikaverro_test_default_option = [
   "TEST_OPTION1" => "1",
   "TEST_OPTION2" => "test2",
];


Свои классы и логика
Из документации Битрикса:
для автоматического подключения располагаем в
/bitrix/modules/#namemodule#/lib  (или /local/modules/#namemodule#/lib )

  • Файлы классов должны именоваться в нижнем регистре, при этом название класса равно название файла. Пример: /lib/myclass.php.
  • Файлы должны содержать правильный namespace. Пример: если модуль подключается как:
    Loader::includeModule('company.shotname');
    то в классе должен быть прописан namespace: namespace Company\Shotname.
  • Там где классы модуля используются в административной части - модуль должен быть подключен.
в моем модуле
/local/modules/nikaverro.test/lib/myclass.php
<? namespace nikaverro\test;
use Bitrix\Main\Config\Option;

class MyClass{
   public static function Hello(){
      echo "Hello World!";
      echo Option::get("nikaverro.test", "TEST_OPTION1");
   }
   public static function OnProlog(){

   }
   public static function agent($i = 0){
      $i++;
      return '\\nikaverro\\test\\MyClass::agent('.$i.');';
   }
}

вызов класса
if(CModule::IncludeModule('nikaverro.test')){
   nikaverro\test\MyClass::Hello();
}
Свои скрипты для админского раздела
/local/modules/nikaverro.test/admin/

файл меню /local/modules/nikaverro.test/admin/menu.php
  • global_menu_content - раздел "Контент"
  • global_menu_marketing - раздел "Маркетинг"
  • global_menu_store - раздел "Магазин"
  • global_menu_services - раздел "Сервисы"
  • global_menu_statistics - раздел "Аналитика"
  • global_menu_marketplace - раздел "Marketplace"
  • global_menu_settings - раздел "Настройки"
<?
$MODULE_ID = "nikaverro.test";
$aMenu = [
   "parent_menu" => "testmenu",//global_menu_services, 
   "section" => $MODULE_ID."_Тестовый админский блок",
   "sort" => 50,
   "text" => "Тестовый админский блок (".$MODULE_ID.")",
   "title" => "Тестовый админский блок",
   "url" => "javascript:void(0)",
   "icon" => "fav_menu_icon",
   "page_icon" => "",
   "items_id" => $MODULE_ID."_items",
   "more_url" => [],
   "items" => []
];      
$aMenu["items"][] = [
    "text" => "Админская страница 1",
    "url"  => $MODULE_ID."_"."page1.php",
    "icon" => "form_menu_icon",
    "page_icon" => "form_page_icon",
    "more_url"  => [$MODULE_ID."_"."page1_add.php"],
    "title" => "Админская страница"
];
$aMenu["items"][] = [
    "text" => "Админская страница 2",
    "url"  => $MODULE_ID."_"."page2.php",
    "icon" => "form_menu_icon",
    "page_icon" => "form_page_icon",
    "more_url"  => [],
    "title" => "Админская страница 2"
];
return $aMenu;
/local/modules/nikaverro.test/admin/page1.php
<?require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_before.php");
$APPLICATION->SetTitle("Заголовок страницы 1");
global $DB;

$tableProfiles = "n_profiles";
$tableWords = "n_words";
$moduleId = "nikaverro.test";
$sTableID = "tbl_profile"; // ID таблицы
$oSort = new CAdminSorting($sTableID, "PROFILE_ID", "desc"); // объект сортировки
$lAdmin = new CAdminList($sTableID, $oSort); // основной объект списка


// ******************************************************************** //
//               ПРОВЕРКА ПРАВ ДОСТУПА                                  //
// ******************************************************************** //
$POST_RIGHT = $APPLICATION->GetGroupRight($moduleId);
if ($POST_RIGHT == "D"){
    $APPLICATION->AuthForm(GetMessage("ACCESS_DENIED"));
}

// ******************************************************************** //
//                ОБРАБОТКА ДЕЙСТВИЙ НАД ЭЛЕМЕНТАМИ СПИСКА              //
// ******************************************************************** //

// сохранение отредактированных элементов
if($lAdmin->EditAction() && $POST_RIGHT=="W")
{
  // пройдем по списку переданных элементов
  foreach($FIELDS as $profileid=>$newarFields)
  {
    if(!$lAdmin->IsUpdated($profileid))
      continue;
    
    // сохраним изменения каждого элемента
    $profileid = IntVal($profileid);
    $newarFields["DATE_MODIFIED"] = date("d.m.Y");      
    $newarFields["MODIFIED_BY"] = $USER->GetID();           
    if($newarFields['ACTIVE'] == "Y") { 
      $newarFields["ACTIVE"] = 1;  
    }
    else{
      $newarFields["ACTIVE"] = 0;
    }
    $strUpdate = $DB->PrepareUpdate($tableProfiles, $newarFields);
    $DB->Query("UPDATE ".$tableProfiles." SET ".$strUpdate." WHERE PROFILE_ID=".$profileid, true);    
  }
}



if(($arProfileId = $lAdmin->GroupAction()) && $POST_RIGHT=="W"){ // если выбрано "Для всех элементов"
  if($_REQUEST['action_target']=='selected'){
    $rsData = $DB->Query("SELECT * FROM ".$tableProfiles);     
      while($arFields = $rsData->GetNext()){      
          $arProfileId[] = $arFields['PROFILE_ID'];
      }
  }  
  // пройдем по списку элементов
  foreach($arProfileId as $profileid){
    if(strlen($profileid)<=0){
        continue;
    }
    $profileid = IntVal($profileid);      
    // для каждого элемента совершим требуемое действие
    if($_REQUEST['action'] == "delete"){
    // удаление       
      $DB->StartTransaction();
      if(!$DB->Query("DELETE FROM ".$tableProfiles." WHERE PROFILE_ID=".$profileid)){
          $message .= 'Error!';
          $DB->Rollback();
      }
      else{
          $DB->Commit();
          $DB->StartTransaction();
          if(!$DB->Query("DELETE FROM ".$tableWords." WHERE PROFILE_ID=".$profileid)){
              $message .= 'Error!';
              $DB->Rollback();
          }
          else{
              $DB->Commit();
          }
      }
    }
    elseif(($_REQUEST['action'] == "active")or($_REQUEST['action'] == "deactive")){
      $arFields = array();
      if($_REQUEST['action'] == "active") { 
        $arFields["ACTIVE"] = 1;  
      }
      else{
        $arFields["ACTIVE"] = 0;
      }
      $strUpdate = $DB->PrepareUpdate($tableProfiles, $arFields);
      $DB->Query("UPDATE ".$tableProfiles." SET ".$strUpdate." WHERE PROFILE_ID=".$profileid, true);
    }
      
  }
}


// ******************************************************************** //
//                ВЫБОРКА ЭЛЕМЕНТОВ СПИСКА                              //
// ******************************************************************** //
$rsData = $DB->Query("SELECT * FROM ".$tableProfiles." ORDER BY ".$by." ".$order);
$rsData = new CAdminResult($rsData, $sTableID);
// аналогично CDBResult инициализируем постраничную навигацию.
$rsData->NavStart();
// отправим вывод переключателя страниц в основной объект $lAdmin
$lAdmin->NavText($rsData->GetNavPrint(GetMessage("rub_nav")));

// ******************************************************************** //
//                ПОДГОТОВКА СПИСКА К ВЫВОДУ                            //
// ******************************************************************** //

//сформируем заголовки таблицы
$headers = array(); 
$headers [] = array(       
  "id"    =>"PROFILE_ID",
    "content"  =>"ID",
    "sort"    =>"PROFILE_ID",
    "align"    =>"right",
    "default"  =>true
 ); 

$headers [] = array(       
  "id"    =>"NAME",
    "content"  =>GetMessage("NAME"),
    "sort"    =>"NAME",
    "align"    =>"right",
    "default"  =>true
 ); 
$headers [] = array(
  "id"    =>"ACTIVE",
    "content"  =>GetMessage("ACTIVE"),
    "sort"    =>"ACTIVE",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"AGENT_START",
    "content"  =>GetMessage("NEXT_AGENT"),
    "sort"    =>"AGENT_START",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(  
  "id"    =>"REGIONS",
    "content"  => GetMessage("REGIONS"),
    "sort"    =>"REGIONS",
    "align"    =>"right",
    "default"  =>true
 ); 
$headers [] = array(
  "id"    =>"PERIODICITY",
    "content"  =>GetMessage("PERIODICITY"),
    "sort"    =>"PERIODICITY",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"AGENT_EXISTS",
    "content"  =>GetMessage("AGENT_EXISTS"),
    "sort"    =>"AGENT_EXISTS",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"DATE_CREATE",
    "content"  =>GetMessage("DATE_CREATE"),
    "sort"    =>"DATE_CREATE",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"CREATED_BY",
    "content"  =>GetMessage("CREATED_BY"),
    "sort"    =>"CREATED_BY",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"DATE_MODIFIED",
    "content"  =>GetMessage("DATE_MODIFIED"),
    "sort"    =>"DATE_MODIFIED",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"MODIFIED_BY",
    "content"  => GetMessage("MODIFIED_BY"),
    "sort"    =>"MODIFIED_BY",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"IBLOCK",
    "content"  => "Источник слов".GetMessage("WORDS_RESOURCE"),
    "sort"    =>"IBLOCK",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"IBLOCK_ID",
    "content"  =>"IBLOCK_ID".GetMessage("IBLOCK_ID"),
    "sort"    =>"IBLOCK_ID",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"IBLOCK_FROM",
    "content"  =>"поле FROM".GetMessage("IBLOCK_FROM"),
    "sort"    =>"IBLOCK_FROM",
    "align"    =>"right",
    "default"  =>true
);
$headers [] = array(
  "id"    =>"IBLOCK_TO",
    "content"  =>"поле ТО".GetMessage("IBLOCK_TO"),
    "sort"    =>"IBLOCK_TO",
    "align"    =>"right",
    "default"  =>true
);
$lAdmin->AddHeaders($headers);


//получим данные для таблицы
while($arRes = $rsData->NavNext(true, "f_")){  
  $arRes ["REGIONS"] = unserialize($arRes ["REGIONS"]);
  //$arRes["REGIONS"] = implode(",", $arRes["REGIONS"]);
  $arRes["REGIONS"] = $arRes["REGIONS"]["NAME"];
  if($arRes ["ACTIVE"] == '1'){
    $arRes ["ACTIVE"] = 'Y';
  }
  else{
    $arRes ["ACTIVE"] = 'N';
  }
  if($arRes["AGENT_EXISTS"] == 1){
    $arRes["AGENT_EXISTS"] = GetMessage("YES");
  }
  else{
    $arRes["AGENT_EXISTS"] = GetMessage("NO");
  }
  if($arRes["IBLOCK"] == 0){
    $arRes["IBLOCK"] = "простой";
  }
  else{
    $arRes["IBLOCK"] = "инфоблок"; 
  }
  $arRes["AGENT_START"] = ConvertTimeStamp(MakeTimeStamp($arRes["AGENT_START"], "YYYY-MM-DD HH:MI:SS"), 'FULL');
  $arRes["DATE_MODIFIED"] = ConvertTimeStamp(MakeTimeStamp($arRes["DATE_MODIFIED"], "YYYY-MM-DD"), 'SHORT');
  $arRes["DATE_CREATE"] = ConvertTimeStamp(MakeTimeStamp($arRes["DATE_CREATE"], "YYYY-MM-DD"), 'SHORT');
  $row =& $lAdmin->AddRow($f_PROFILE_ID, $arRes);
  $row->AddInputField("NAME", array("size"=>20));
  $row->AddInputField("PERIODICITY", array("size"=>20));
  $row->AddCheckField("ACTIVE"); 
  // сформируем контекстное меню
  $arActions = array();

  // редактирование элемента
  $arActions[] = array(
      "ICON"=>"edit",
      "DEFAULT"=>true,
      "TEXT"=>GetMessage("EDIT"),
      "ACTION"=>$lAdmin->ActionRedirect($moduleId."_profile_edit.php?profileid=".$f_PROFILE_ID)
  );    
  // удаление элемента
  if ($POST_RIGHT>="W")
      $arActions[] = array(
        "ICON"=>"delete",
        "TEXT"=>GetMessage("DELETE_"),
        "ACTION"=>"if(confirm('".GetMessage("DELETE_")."')) ".$lAdmin->ActionDoGroup($f_PROFILE_ID, "delete")
  );
  // вставим разделитель
  $arActions[] = array("SEPARATOR"=>true);
  // применим контекстное меню к строке
  $row->AddActions($arActions);
}

// резюме таблицы
$lAdmin->AddFooter(
  array(
    array("title"=>GetMessage("MAIN_ADMIN_LIST_SELECTED"), "value"=>$rsData->SelectedRowsCount()), // кол-во элементов
    array("counter"=>true, "title"=>GetMessage("MAIN_ADMIN_LIST_CHECKED"), "value"=>"0"), // счетчик выбранных элементов
  )
);

// групповые действия
$lAdmin->AddGroupActionTable(Array(
  "delete"=>"", // удалить выбранные профили
  "active"=>GetMessage("DO_ACTIVE"), // активировать выбранные профили
  "deactive"=>GetMessage("DO_DEACTIVE"), // деактивировать выбранные профили  
  ));


$aContext = array(
  array(
    "TEXT"=>GetMessage("ADD"),
    "LINK"=>$moduleId."_page2.php?lang=".LANG,
    "TITLE"=>GetMessage("ADD"),
    "ICON"=>"btn_new",
  ),
);

// и прикрепим его к списку
$lAdmin->AddAdminContextMenu($aContext);

// ******************************************************************** //
//                ВЫВОД                                                 //
// ******************************************************************** //

// альтернативный вывод
$lAdmin->CheckListMode();
require_once($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/prolog_admin_after.php");
$lAdmin->DisplayList();
?>
<?require($_SERVER["DOCUMENT_ROOT"]."/bitrix/modules/main/include/epilog_admin.php");?>
Если блог был полезным, можете угостить меня "чашечкой кофе" :)

Сбер по номеру телефона +7 (953) 585-13-09 Вероника.
Спасибо!