Development of Custom Administrative Pages in 1C-Bitrix
The standard administrative section covers typical tasks — catalog management, orders, users. But as soon as business specifics appear — manual stock synchronization from external system, bulk price update by formula, integration settings management — custom administrative pages are needed. Can't develop directly in /bitrix/admin/ (updates will wipe changes), correct path — /local/.
Where to Place Custom Administrative Pages
Custom page files placed in /local/admin/. Bitrix automatically includes this path in administrative page search. Page becomes accessible at /bitrix/admin/my_page.php if file is in /local/admin/my_page.php.
Alternative — create page as component in /local/components/ and connect via wrapper. This preferred approach for complex interfaces.
Structure of Minimal Administrative Page
<?php
// /local/admin/my_custom_page.php
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_before.php');
// Permission check
$APPLICATION->SetTitle('My Page');
if (!$USER->IsAdmin() && !$USER->CanDoOperation('edit_php')) {
$APPLICATION->AuthForm('No access');
}
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/prolog_admin_after.php');
// Page content
?>
<div class="adm-content-wrap">
<!-- HTML interface -->
</div>
<?php
require_once($_SERVER['DOCUMENT_ROOT'] . '/bitrix/modules/main/include/epilog_admin.php');
Three required includes form correct wrapper: header, navigation, footer of administrative section. Without them page opens without styling.
Using Bitrix Administrative Helpers
Bitrix provides set of classes for building standard administrative UI elements. Using these gives native look and saves from markup.
CAdminList — table with sorting, pagination and filter:
use Bitrix\Main\UI\Filter\Options as FilterOptions;
$oList = new CAdminList('my_list_id');
// Add columns
$lAdmin->AddHeaders([
['id' => 'ID', 'content' => 'ID', 'sort' => 'ID'],
['id' => 'NAME', 'content' => 'Name', 'sort' => 'NAME'],
['id' => 'DATE', 'content' => 'Date'],
]);
// Fill with rows
while ($row = $rsData->Fetch()) {
$oRow = &$oList->AddRow('ID_' . $row['ID'], $row);
$oRow->AddActions([
['TEXT' => 'Edit', 'ONCLICK' => "jsUtils.Redirect([], 'my_edit.php?ID=" . $row['ID'] . "')"],
['TEXT' => 'Delete', 'ACTION' => $oList->ActionDoGroup($row['ID'], 'delete')],
]);
}
$oList->DisplayList();
CAdminForm — edit form with tabs:
$oTabControl = new CAdminTabControl('tabControl', [
['DIV' => 'tab1', 'TAB' => 'Basic', 'ICON' => 'main_user_edit'],
['DIV' => 'tab2', 'TAB' => 'Additional'],
]);
$oTabControl->Begin();
$oTabControl->BeginNextTab();
// first tab fields
$oTabControl->BeginNextTab();
// second tab fields
$oTabControl->Buttons(['btnSave' => true, 'btnApply' => true, 'btnCancel' => true]);
$oTabControl->End();
Adding Page to Administrative Menu
Page must be accessible from menu, not just direct URL. Registration via event handler in /local/php_interface/init.php:
AddEventHandler('main', 'OnBuildGlobalMenu', function(&$globalMenu, &$moduleMenu) {
$moduleMenu[] = [
'parent_menu' => 'global_menu_services', // menu section
'sort' => 500,
'text' => 'Synchronization',
'title' => 'Manage external system synchronization',
'url' => 'my_custom_page.php',
'icon' => 'main_menu_tasks', // icon CSS class
'page_icon' => 'main_page_icon',
'more_url' => ['my_custom_page.php', 'my_custom_edit.php'],
];
});
Parameter more_url needed to keep menu item active when navigating related pages (e.g., edit form).
Working with Data: D7 vs Old API
For custom pages recommended using D7 ORM (\Bitrix\Main\ORM). If data stored in own tables — entity class created:
namespace Local\MyModule;
use Bitrix\Main\ORM\Data\DataManager;
use Bitrix\Main\ORM\Fields;
class MyEntityTable extends DataManager
{
public static function getTableName(): string
{
return 'my_custom_table';
}
public static function getMap(): array
{
return [
new Fields\IntegerField('ID', ['primary' => true, 'autocomplete' => true]),
new Fields\StringField('NAME', ['required' => true]),
new Fields\DatetimeField('CREATED_AT'),
];
}
}
After this MyEntityTable::getList(), ::add(), ::update(), ::delete() work via standard Bitrix ORM.
Form Processing and AJAX
Bitrix administrative pages traditionally use POST forms with CSRF token (bitrix_sessid_post()). For AJAX requests:
// Check session token
if (!check_bitrix_sessid()) {
die(json_encode(['error' => 'Invalid session']));
}
// In JavaScript (using BX.ajax)
BX.ajax.runAction('local:my.action', {
data: { param: value },
sessid: BX.bitrix_sessid()
});
For modern AJAX interfaces can use \Bitrix\Main\Engine\Controller with routing via /.action.php — D7 approach, recommended for new development.
Access Control for Custom Pages
Custom page must check permissions itself. Options:
- Check
$USER->IsAdmin()— for pages accessible only to administrators - Check
$USER->CanDoOperation('operation_name')— for granular control - Check module permission:
CModule::IncludeModule('main') && $USER->GetRights('mymodule') >= 'W'
If page should be accessible to specific group — better create own module with permission registration via RegisterModuleDependences.
Typical Tasks for Custom Pages
- Synchronization control panel with 1C or external APIs (manual run, latest operations log)
- Bulk product editing by non-standard criteria
- Analytics dashboard based on data from multiple modules
- Integration settings management (API keys, webhooks, field mapping)
- Content migration tools between environments
Execution Timeline
Simple custom page with form and CRUD table — 1–2 days. Multi-page section with filters, AJAX, access rights and own database table — 3–5 days. Full-featured custom module with menu integration, rights and events — 1–2 weeks.







