Реализация вкладок в админ-панели на PHP

Раздел: Веб-разработка -> Интерфейс вкладок

Организация вкладок в административной панели на PHP

Интерфейс вкладок (tabs) часто применяется в админках для группировки разнородного контента. Ниже приведены несколько подходов, каждый со своими целями и ограничениями.

Как сделать вкладки на Bootstrap 5 с передачей активной вкладки через GET-параметр?

Наиболее эффективное решение - использовать встроенные компоненты Bootstrap 5 (nav-tabs) и обрабатывать переключение через PHP, считывая параметр tab из URL. Это не требует JavaScript для базовой навигации, но для сохранения состояния между перезагрузками страницы можно добавить небольшой скрипт.


<?php
$activeTab = $_GET['tab'] ?? 'general';
?>
<ul class="nav nav-tabs" id="adminTabs">
  <li class="nav-item">
    <a class="nav-link <?= $activeTab === 'general' ? 'active' : '' ?>" href="?tab=general">Общие</a>
  </li>
  <li class="nav-item">
    <a class="nav-link <?= $activeTab === 'security' ? 'active' : '' ?>" href="?tab=security">Безопасность</a>
  </li>
  <li class="nav-item">
    <a class="nav-link <?= $activeTab === 'mail' ? 'active' : '' ?>" href="?tab=mail">Почта</a>
  </li>
</ul>
<div class="tab-content mt-3">
  <?php include __DIR__ . "/tabs/{$activeTab}.php"; ?>
</div>
  

Php admin tab (вкладки в админке php)

Типичные ошибки и их решение:

  • Небезопасное подключение файла: Переменная $activeTab может содержать вредоносные пути. Решение - проверять значение по белому списку: $allowed = ['general','security','mail']; if (!in_array($activeTab, $allowed)) $activeTab = 'general';
  • Потеря активной вкладки при отправке форм: После POST-запроса параметр tab в URL может исчезнуть. Решение - сохранять $activeTab в сессии или добавлять скрытое поле в форму.
  • Конфликт с другими GET-параметрами: Если в URL уже есть другие параметры, их нужно сохранять. Можно использовать http_build_query для построения ссылки.

Цели: простота, поддержка без JavaScript, быстрая реализация для небольшой админки. Подходит, когда вкладки не требуют сложного динамического поведения.

Как сделать вкладки только средствами PHP без Bootstrap?

Если нет возможности внедрять CSS-фреймворки, можно написать минимальную разметку и обработку через PHP. Вкладки переключаются по GET-параметру, а для стилей используется собственный CSS.


<?php
$tabs = ['info', 'logs', 'backup'];
$current = $_GET['section'] ?? 'info';
?>
<style>
  .tab-list { list-style: none; padding: 0; display: flex; }
  .tab-list li a { padding: 8px 16px; background: #eee; border: 1px solid #ccc; }
  .tab-list li a.active { background: #fff; border-bottom: 1px solid #fff; }
</style>
<ul class="tab-list">
  <?php foreach ($tabs as $tab): ?>
    <li><a href="?section=<?= $tab ?>" class="<?= $current === $tab ? 'active' : '' ?>"><?= ucfirst($tab) ?></a></li>
  <?php endforeach; ?>
</ul>
<div>
  <?php
  $file = __DIR__ . "/sections/{$current}.php";
  if (file_exists($file)) include $file;
  else echo "Раздел не найден.";
  ?>
</div>
  

Проблема: при большом количестве вкладок код раздувается. Решение - вынести логику в класс или функцию. Другая ошибка - отсутствие фильтрации имени файла (LFI-уязвимость).

Цель: полный контроль над разметкой и стилями, подходит для минималистичных проектов без внешних зависимостей.

Как сделать динамическую загрузку вкладок через AJAX (jQuery)?

Когда содержимое вкладок велико или требует частого обновления, удобно подгружать его асинхронно. Клик по вкладке отправляет GET-запрос к PHP-скрипту, который возвращает HTML для конкретной вкладки.


<!-- JavaScript -->
$(document).ready(function() {
    $('.ajax-tab').click(function(e) {
        e.preventDefault();
        var tab = $(this).data('tab');
        $('#tab-content').load('ajax_handler.php?tab=' + tab);
        $('.ajax-tab').removeClass('active');
        $(this).addClass('active');
    });
});
<!-- HTML -->
<ul>
    <li><a href="#" class="ajax-tab" data-tab="users">Пользователи</a></li>
    <li><a href="#" class="ajax-tab" data-tab="roles">Роли</a></li>
</ul>
<div id="tab-content">Выберите вкладку</div>
  

<?php // ajax_handler.php
$allowed = ['users', 'roles'];
$tab = $_GET['tab'] ?? 'users';
if (!in_array($tab, $allowed)) die('Invalid tab');
// Здесь формируется HTML для вкладки
include __DIR__ . "/tabs/{$tab}.php";
?>
  

Ошибки: забытый exit после вывода - тогда скрипт продолжит выполнение и может вывести лишний HTML. Решение - использовать die() или завершать скрипт после вывода. Также важно обрабатывать ошибки AJAX (например, при 500 ошибке сервера).

Цель: улучшение производительности - загружается только нужный контент. Подходит для “тяжелых” страниц с большим количеством данных.

Как сделать вкладки с сохранением состояния через сессию?

Если нужно, чтобы после перехода на другую страницу или перезагрузки браузера активная вкладка оставалась прежней, можно хранить её идентификатор в сессии PHP.


session_start();
$activeTab = $_GET['tab'] ?? $_SESSION['admin_tab'] ?? 'dashboard';
$_SESSION['admin_tab'] = $activeTab;
// Далее стандартный вывод вкладок
  

Проблема: сессия не учитывает пользователей с отключенными cookie. Решение - добавить fallback на GET-параметр. Также стоит очищать сессию при выходе из админки.

Цель: удобство для администратора - не нужно каждый раз выбирать нужную вкладку.

Как реализовать вкладки в Laravel с использованием Livewire?

В современных фреймворках можно избежать написания множества связующего кода. Laravel Livewire позволяет создать компонент с вкладками, где PHP обрабатывает клики без перезагрузки.


// Компонент AdminTabs.php
class AdminTabs extends Component
{
    public $activeTab = 'general';

    public function setTab($tab)
    {
        $this->activeTab = $tab;
    }

    public function render()
    {
        return view('livewire.admin-tabs');
    }
}
// View (blade)
<div>
    <button wire:click="setTab('general')" class="@if($activeTab === 'general') active @endif">Общие</button>
    <button wire:click="setTab('security')" ...>Безопасность</button>
    <div>
        @if($activeTab === 'general')
            @include('tabs.general')
        @elseif($activeTab === 'security')
            @include('tabs.security')
        @endif
    </div>
</div>
  

Ошибки: Неправильная настройка Livewire (не указан @livewireStyles и @livewireScripts). Проблемы с кэшированием компонентов после изменений - требуется php artisan livewire:publish.

Цель: современный реактивный интерфейс без написания JavaScript. Подходит для проектов на Laravel.

Дополнительные примеры и расширенное использование

Пример 1: Вкладки с передачей дополнительных параметров (ID раздела) через URL

Пример

<?php
$sectionId = $_GET['section_id'] ?? 0;
$activeTab = $_GET['tab'] ?? 'info';
$allowedTabs = ['info', 'prices', 'reviews'];
if (!in_array($activeTab, $allowedTabs)) $activeTab = 'info';
?>
<ul class="nav nav-tabs">
  <li class="nav-item">
    <a class="nav-link <?= $activeTab === 'info' ? 'active' : '' ?>"
       href="?tab=info&section_id=<?= $sectionId ?>">Информация</a>
  </li>
  <li class="nav-item">
    <a class="nav-link <?= $activeTab === 'prices' ? 'active' : '' ?>"
       href="?tab=prices&section_id=<?= $sectionId ?>">Цены</a>
  </li>
  <li class="nav-item">
    <a class="nav-link <?= $activeTab === 'reviews' ? 'active' : '' ?>"
       href="?tab=reviews&section_id=<?= $sectionId ?>">Отзывы</a>
  </li>
</ul>
<div class="tab-content">
  <?php
  $file = __DIR__ . "/tabs/{$activeTab}.php";
  if (file_exists($file)) {
      // Передаем $sectionId в подключаемый файл
      include $file;
  }
  ?>
</div>
Результат: URL вида /admin?tab=prices&section_id=5. При переключении вкладок ID раздела сохраняется, контент зависит от выбранной вкладки и раздела.

Пример 2: Множественные группы вкладок на одной странице (с префиксами)

Пример

<?php
// Определяем префиксы для разных групп вкладок
$groups = [
    'tab1' => ['active' => $_GET['tab1'] ?? 'a', 'tabs' => ['a','b','c']],
    'tab2' => ['active' => $_GET['tab2'] ?? 'x', 'tabs' => ['x','y','z']]
];
foreach ($groups as $prefix => &$group) {
    $group['active'] = in_array($group['active'], $group['tabs']) ? $group['active'] : $group['tabs'][0];
}
?>
<div class="tab-group">
  <h3>Первая группа</h3>
  <ul class="nav nav-tabs">
    <?php foreach ($groups['tab1']['tabs'] as $t): ?>
      <li class="nav-item">
        <a class="nav-link <?= $groups['tab1']['active'] === $t ? 'active' : '' ?>"
           href="?tab1=<?= $t ?>&tab2=<?= $groups['tab2']['active'] ?>"><?= strtoupper($t) ?></a>
      </li>
    <?php endforeach; ?>
  </ul>
  <div><?php include "tabs/group1_{$groups['tab1']['active']}.php"; ?></div>
</div>
<div class="tab-group">
  <h3>Вторая группа</h3>
  <ul class="nav nav-tabs">
    <?php foreach ($groups['tab2']['tabs'] as $t): ?>
      <li class="nav-item">
        <a class="nav-link <?= $groups['tab2']['active'] === $t ? 'active' : '' ?>"
           href="?tab1=<?= $groups['tab1']['active'] ?>&tab2=<?= $t ?>"><?= strtoupper($t) ?></a>
      </li>
    <?php endforeach; ?>
  </ul>
  <div><?php include "tabs/group2_{$groups['tab2']['active']}.php"; ?></div>
</div>
Результат: На странице отображаются две независимые группы вкладок. Активное состояние каждой из них передаётся через параметры URL (tab1, tab2) и никак не влияет друг на друга.

Пример 3: Вкладки с формами и сохранением введенных данных при переключении

Пример

<?php
session_start();
$activeTab = $_GET['tab'] ?? 'first';
$allowed = ['first', 'second'];
if (!in_array($activeTab, $allowed)) $activeTab = 'first';

// Сохраняем POST-данные в сессию при отправке формы
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['tab_form'])) {
    $_SESSION['tab_form'][$_POST['current_tab']] = $_POST;
    // редирект на ту же вкладку чтобы избежать повторной отправки
    header('Location: ?tab=' . $_POST['current_tab']);
    exit;
}
?>
<form method="post" action="">
    <input type="hidden" name="tab_form" value="1">
    <input type="hidden" name="current_tab" value="<?= $activeTab ?>">
    <ul class="nav nav-tabs">
        <li class="nav-item">
            <a class="nav-link <?= $activeTab === 'first' ? 'active' : '' ?>"
               href="?tab=first">Первая</a>
        </li>
        <li class="nav-item">
            <a class="nav-link <?= $activeTab === 'second' ? 'active' : '' ?>"
               href="?tab=second">Вторая</a>
        </li>
    </ul>
    <div class="tab-content">
        <?php if ($activeTab === 'first'): ?>
            <div>
                <label>Имя:<br>
                    <input type="text" name="name" value="<?= $_SESSION['tab_form']['first']['name'] ?? '' ?>">
                </label>
            </div>
        <?php elseif ($activeTab === 'second'): ?>
            <div>
                <label>Email:<br>
                    <input type="email" name="email" value="<?= $_SESSION['tab_form']['second']['email'] ?? '' ?>">
                </label>
            </div>
        <?php endif; ?>
        <button type="submit">Сохранить</button>
    </div>
</form>
Результат: Данные сохраняются в сессию при отправке формы, и при переключении между вкладками заполненные поля не теряются. Редирект после POST не даёт повторно отправить форму при обновлении страницы.

Вкладки в админке PHP - comments

En
Php admin tab (php)