25. Jak na aktivní položky menu v PHP

Při vytváření menu někdy chceme, aby položka, na kterou je kliknuto zůstala aktivní - zůstala např. podržená, zvýrazněná apod. Řešíme to nejčastěji pomocí pseudotřídy v CSS - a:hover. Pokud máme webové stránky v PHP skládané s jednotlivých částí pomocí příkazu include nebo require, pak máme společné menu v jednom souboru, pak tento požadavek můžeme řešit např. za pomoci podmínky. Klasické menu vypadá např. takto:

<ul>
<li><a href="/index.php">Úvod</a></li>
<li><a href="/o-nas.php">O nás</a></li>
<li><a href="/reference.php">Reference</a></li>
<li><a href="/kontakt.php">Kontakt</a></li>
</ul>

V rámci frameworku Bootstrap pak dále např. takto:

<nav class="navbar navbar-expand-md bg-dark navbar-dark">  
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="collapsibleNavbar">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a class="nav-link" href="/index.php">Úvod</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/o-nas.php">O nás</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/reference.php">Reference</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/kontakt.php">Kontakt</a>
      </li>        
    </ul>
  </div>  
</nav>

 Pokud chceme, aby zůstala aktivní položka menu, na kterou bylo kliknuto, stačí přidat třídu active (v příkladu níže je to položka Reference):

<nav class="navbar navbar-expand-md bg-dark navbar-dark">  
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
    <span class="navbar-toggler-icon"></span>
  </button>
  <div class="collapse navbar-collapse" id="collapsibleNavbar">
    <ul class="navbar-nav">
      <li class="nav-item">
        <a class="nav-link" href="/index.php">Úvod</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/o-nas.php">O nás</a>
      </li>
      <li class="nav-item active">
        <a class="nav-link" href="/reference.php">Reference</a>
      </li>
      <li class="nav-item">
        <a class="nav-link" href="/kontakt.php">Kontakt</a>
      </li>        
    </ul>
  </div>  
</nav>

Tato varianta ale nebude fungovat, pokud budeme mít ve stránce menu vložené (např. pomocí příkazu include...), a tedy stále stejné na každé stránce, kterou načítáme. Tak že tam už musíme použít např. podmínku:

<nav>
    <ul>
        <li <?php if($_GET['stranka'] == 'uvod' || $_GET['stranka'] == ''): ?>class="aktivni"<?php endif; ?>><a href="/index.php">Titulní strana</a></li>
        <li <?php if($_GET['stranka'] == 'o-mne'): ?>class="aktivni"<?php endif; ?>><a href="/php/25-jak-na-aktivni-polozky-menu-v-php?stranka=o-mne">O mně</a></li>
        <li <?php if($_GET['stranka'] == 'reference'): ?>class="aktivni"<?php endif; ?>><a href="/php/25-jak-na-aktivni-polozky-menu-v-php?stranka=reference">Reference</a></li>
        <li <?php if($_GET['stranka'] == 'kontakt'): ?>class="aktivni"<?php endif; ?>><a href="/php/25-jak-na-aktivni-polozky-menu-v-php?stranka=kontakt">Kontakt</a></li>
    </ul>
</nav>
  1. Pozn. 1: tato varianta není doplněna o Bootstrap styly.
  2. Pozn. 2: u první položky "Titulní strana" si všimněte, že podmínka kontroluje, zda bylo kliknuto na položku uvod nebo pokud je načtena čistá adresa webu, tedy bez jakýchkoliv parametrů v adrese (přes metodu _GET)
  3. Pozn. 3: samotný kód takto testovat nemůžete. Musel by se ještě doplnit o chybějící definice.

Existuje spousta dalších možností, jak to můžeme vyřešit. Jednou z nich je např. použití pole - array (viz níže). Součástí kódu je i "obarvení" aktivní (nakliknuté) položky na červeno. Některé řádky jsou vysvětleny přímo v kódu.

<style>
/* aktivní položky menu budou mít červenou barvu */
li.active a {
    color: red;
}
</style>
<nav>
    <ul>
    <!-- Vytvoření proměnné menu, které bude obsahovat pole, reprezentované stránkami.-->
    <!-- názvy polí josu součásti URL adresy, načítané přes metodu _GET-->
    <?php $menu = array(
           'uvod' => 'Úvod',
           'onas'  => 'O nás',
           'reference' => 'Reference',
           'kontakt' => 'Kontakt',
        );
        /* Vytvoření proměnné active, do které se dosadí hodnota z metody _GET s názvem stranka, pokud existuje (je nastavena) přes konstrukt isset. Pokud ne, dosadí se uvod - tedy titulní stránka webu. Toto funguje až od verze PHP 7 */ 
        $active = isset($_GET['stranka']) ? $_GET['stranka'] : 'uvod';
   ?>

  <!-- Cyklus foreach postupně vypisuje pole obsažené v proměnné menu, a to tak, že z tohoto pole vypíše vždy jeho název (title), což je pak položka menu -->
  <?php foreach ($menu as $url=>$title) : ?>
      <!-- V každé položce menu (položka nečíslovaného seznamu li) se zavolá třída active tehdy, pokud je součástí URL. Pokud ne, bude to pouze odkaz -->
      <li <?= $url == $active ? 'class="active"' : '' ?>>
           <a href="/php/25-jak-na-aktivni-polozky-menu-v-php?stranka=&lt;?=%20$url%20?&gt;=">
                  <?= $title ?>
           </a>
      </li>
  <?php endforeach ?>
</ul>
  </div>
</nav>

Vyzkoušejte v tomto demu. Dále je vhodné doplnit kód o fragmenty frameworku Bootstrap (tentokrát již bez vysvětlování v kódu):

<nav class="navbar navbar-expand-sm bg-info navbar-dark">

  <!-- Položky menu -->
  <ul class="navbar-nav">
  <?php $menu = array(
           'uvod' => 'Úvod',
           'onas'  => 'O nás',
           'reference' => 'Reference',
           'kontakt' => 'Kontakt',
        );
        $active = isset($_GET['stranka']) ? $_GET['stranka'] : 'uvod';
   ?>

  <?php foreach ($menu as $url=>$title) : ?>
      <li <?= $url == $active ? 'class="active"' : '' ?>>
           <a class="nav-link" href="/php/25-jak-na-aktivni-polozky-menu-v-php?stranka=&lt;?=%20$url%20?&gt;=">
                  <?= $title ?>
           </a>
      </li>
  <?php endforeach ?>
</ul>
  
</nav>

Bez napojení na knihovny Bootstrap to samozřejmě nebude fungovat, tak že si musíme tyto položky doplnit. nejlépe tak, že celé menu zakomponujeme do hotové stránky. To opět můžeme učinit např. za pomoci příkazu include:

<!DOCTYPE html>
<html lang="cs-cz">
<head>
  <title>Vzorový web s napojením na BS 4</title>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css">
  <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"></script>
   <script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.min.js"></script>
<link rel="stylesheet" href="/mujstyl.css">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.7.0/css/all.css" integrity="sha384-lZN37f5QGtY3VHgisS14W3ExzMWZxybE1SJSEsQp9S+oqd12jhcu+A56Ebc1zFSJ" crossorigin="anonymous">
<link rel="icon" href="/foto/favikona.ico" type="image/x-icon">
</head>
<body>
<div class="container">
  <div class="jumbotron">
    <h1>Ukázka dynamického provedení menu</h1>
  </div>
  <!-- Tady bude menu -->
  <?php
    include 'menu.php';
  ?>
  <!-- Konec menu -->  

  <div class="jumbotron text-center paticka">
    <p>Patička webu (Footer)... &copy; <?php echo date('Y')?></p>
  </div>
<!-- nemazat -->
</div>

</body>
</html>

Součástí je také soubor mujstyl.css v adresáři css. Ten může vypadat nějak takto:

.navbar-dark .navbar-nav .nav-link:focus, .navbar-dark .navbar-nav .nav-link:hover {
    color: rgba(255,255,255,.75);
    background-color: rgb(255, 0, 0);
}
.active {
    background-color: red;
}

.paticka {
    padding: 10px 0px;
    background-color: #383d41;
    color: white;
}

Výsledek pak vypadá takto:

 

 Živá ukázka zde.

Ještě potřebujeme, aby se po kliknutí na danou položku zobrazoval správný obsah webu.