Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

To reuse the same navigation on multiple PHP pages, put the menu markup in a separate file and load it with require or include:

<?php
require __DIR__ . '/includes/menu.php';
?>

PHP includes and executes the file on the server, placing its output where the statement appears in the page. It does not call the file through the browser or create a redirect.

Build a reusable PHP menu

Start with this project structure:

my-site/
├── index.php
├── about.php
└── includes/
    └── menu.php

Put only the reusable navigation fragment in includes/menu.php:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<nav aria-label="Primary navigation">
    <ul>
        <li><a href="/">Home</a></li>
        <li><a href="/about.php">About</a></li>
        <li><a href="/contact.php">Contact</a></li>
    </ul>
</nav>

The page containing the menu must be processed by PHP, so use a .php file and open it through a PHP-capable web server:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8">
    <title>Home</title>
</head>
<body>

<?php require __DIR__ . '/includes/menu.php'; ?>

<main>
    <h1>Home</h1>
</main>

</body>
</html>

Everything outside PHP tags in menu.php is sent as HTML. The menu file normally should not contain <!doctype html>, <html>, <head>, or <body>; the page itself should own that document structure.

require versus include

For a site-wide menu, require is usually the appropriate choice when the page should not continue without its navigation. If the file is missing, PHP stops execution with an error. PHP documents require as otherwise equivalent to include: require and include.

Statement If the file is missing Typical use
include Warning; execution may continue Optional fragment
require Error; execution stops Required layout or menu
include_once Warning; includes at most once Optional shared file
require_once Error; requires at most once Bootstrap, configuration, or library

The _once variants prevent the same file from being included more than once during one script execution. They are useful for declarations and initialization code, but a menu rendered once does not automatically need require_once. If a layout and a page both render the menu, require_once does not necessarily prevent duplicate HTML output caused by separate rendering logic.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Use __DIR__ for reliable paths

This basic form works only when PHP can resolve the file using the current path rules:

<?php include 'menu.php'; ?>

A more predictable form anchors the path to the directory of the PHP file containing the statement:

<?php
require __DIR__ . '/includes/menu.php';
?>

__DIR__ avoids depending on the process working directory or the configured PHP include_path. It is particularly helpful when a page is moved, run from the command line, or served through a different entry point. See PHP’s documentation for include-path behavior.

Common directory layouts

If the menu is beside the page:

site/
├── index.php
└── menu.php
require __DIR__ . '/menu.php';

If it is in an includes directory:

require __DIR__ . '/includes/menu.php';

If the page is nested one directory below the project root:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
site/
├── includes/
│   └── menu.php
└── admin/
    └── dashboard.php
// admin/dashboard.php
require __DIR__ . '/../includes/menu.php';

Here, .. moves from admin to its parent directory.

Highlight the current menu item

The clearest approach for a small site is to set an explicit page key before including the menu:

<?php
$currentPage = 'products';
require __DIR__ . '/includes/menu.php';
?>

Then use that value in menu.php:

<?php
$currentPage = $currentPage ?? '';
?>

<nav aria-label="Primary navigation">
    <ul>
        <li>
            <a href="/"
               class="<?= $currentPage === 'home' ? 'active' : '' ?>"
               <?= $currentPage === 'home' ? 'aria-current="page"' : '' ?>>
                Home
            </a>
        </li>
        <li>
            <a href="/products.php"
               class="<?= $currentPage === 'products' ? 'active' : '' ?>"
               <?= $currentPage === 'products' ? 'aria-current="page"' : '' ?>>
                Products
            </a>
        </li>
    </ul>
</nav>

Included files inherit variables available at the point of inclusion, which is why $currentPage is visible. An explicit key is more reliable than inspecting URLs when several public routes use one controller or URL rewriting. PHP documents this scope behavior in its include reference.

For simple sites, alternatives include $_SERVER['SCRIPT_NAME'] or a parsed $_SERVER['REQUEST_URI']. The former identifies the executed script, not always the public route; the latter represents the requested URI and may include a query string. Do not use either value as a file path. Avoid using PHP_SELF in output without proper handling because it can contain user-controlled path information: server variables.

Use a data-driven menu for larger navigation

Separating menu data from its HTML makes links easier to add and reorder:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
$currentPage = 'products';

$menuItems = [
    'home' => ['label' => 'Home', 'url' => '/'],
    'products' => ['label' => 'Products', 'url' => '/products.php'],
    'contact' => ['label' => 'Contact', 'url' => '/contact.php'],
];

require __DIR__ . '/includes/menu.php';

In includes/menu.php:

<nav aria-label="Primary navigation">
    <ul>
        <?php foreach ($menuItems as $key => $item): ?>
            <?php $isCurrent = $key === $currentPage; ?>
            <li>
                <a href="<?= htmlspecialchars($item['url'], ENT_QUOTES, 'UTF-8') ?>"
                   <?= $isCurrent ? 'aria-current="page"' : '' ?>>
                    <?= htmlspecialchars($item['label'], ENT_QUOTES, 'UTF-8') ?>
                </a>
            </li>
        <?php endforeach; ?>
    </ul>
</nav>

Use htmlspecialchars() when dynamic labels or URLs are inserted into HTML text or attributes. Specify UTF-8 explicitly; this is HTML-context escaping, not complete URL validation or permission checking. See PHP’s htmlspecialchars documentation.

Do not confuse PHP paths with browser URLs

The path in require identifies a file on the server. The href values in the generated menu are resolved by the browser.

This relative link can break on a nested page:

<a href="about.php">About</a>

From /admin/dashboard.php, the browser may request /admin/about.php. If the public page is at the site root, use:

<a href="/about.php">About</a>

For an application installed under /my-site, centralize the base path:

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
$basePath = '/my-site';
$url = $basePath . '/about.php';
?>
<a href="<?= htmlspecialchars($url, ENT_QUOTES, 'UTF-8') ?>">About</a>

A URL helper or framework router is preferable once deployment paths and routes become more complex.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Run and test the example

Do not double-click the PHP file and open it as a local document. From the project directory, use PHP’s built-in development server:

php -S localhost:8000

Then visit http://localhost:8000/. This server is intended for local development, not production hosting.

If PHP reports “Failed opening required,” temporarily inspect the resolved path:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
$menuPath = __DIR__ . '/includes/menu.php';

var_dump($menuPath, is_file($menuPath), is_readable($menuPath));
require $menuPath;
?>

Check the directory level, filename capitalization, deployment copy, and file permissions. Remove debugging output afterward. You can also fail with a clearer message:

<?php
$menuPath = __DIR__ . '/includes/menu.php';

if (!is_file($menuPath)) {
    throw new RuntimeException('Menu file not found: ' . $menuPath);
}

require $menuPath;

If PHP source appears in the browser, the server is not processing that file as PHP, the extension or server mapping is wrong, or the PHP tags are malformed.

Keep dynamic includes safe

Never allow request data to become an include path:

<?php
$page = $_GET['page'];
require __DIR__ . '/pages/' . $page . '.php';

Depending on validation and configuration, this can lead to local-file-inclusion or path-traversal vulnerabilities. Map user-facing keys to fixed server-side paths instead:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
<?php
$pages = [
    'home' => __DIR__ . '/pages/home.php',
    'about' => __DIR__ . '/pages/about.php',
];

$key = $_GET['page'] ?? 'home';

if (!array_key_exists($key, $pages)) {
    http_response_code(404);
    exit('Page not found');
}

require $pages[$key];

For sensitive configuration and application code, keep view or include files outside the public document root where practical:

project/
├── public/
│   └── index.php
└── src/
    └── views/
        └── menu.php
// public/index.php
require dirname(__DIR__) . '/src/views/menu.php';

This reduces accidental direct exposure but is not a replacement for correct server configuration, permissions, and application security. PHP discusses this layout consideration in its include documentation.

When to use a template system

Native require is enough for a small PHP site. A framework layout, Twig, or a component-based view system becomes worthwhile when the application needs layout inheritance, automatic escaping, reusable components, explicit view-data contracts, or route names that are independent of physical filenames.

For one shared menu, adding a framework is unnecessary. Start with a partial and reliable path; introduce a view system when repeated templates and routing complexity justify it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.