Fixing WordPress Multisite Subdirectory Routing in Laravel Valet with a Custom Driver

Laravel Valet is a great tool for quickly spinning up local development environments on macOS. However, if you’ve ever tried to run a WordPress multisite installation using subdirectories (like /de/category/post-name) under Valet, you might have noticed something’s not quite right.

In this post, I’ll show you how I fixed this routing issue by creating a custom Valet driver specifically for WordPress multisite subdirectory setups.

🧩 The Problem

Valet uses “drivers” to determine how to serve requests for different types of projects (Laravel, WordPress, etc.). The default WordPress driver works fine for single-site installs or subdomain multisites, but not for subdirectory-based multisites.

For example, visiting:

http://wordpress-site.com/de/category/post-slug/

incorrectly routes you to the home page instead of resolving the correct category or post.

🔧 The Solution: Custom Valet Driver

To solve this, I created a custom Valet driver that handles WordPress multisites using subdirectory installations. Here’s the custom driver:

// ~/.config/valet/Drivers/WordPressMultisiteSubdirectoryValetDriver.php

namespace Valet\Drivers\Custom;

use Valet\Drivers\BasicValetDriver;

class WordPressMultisiteSubdirectoryValetDriver extends BasicValetDriver
{
    public $wp_root = false;

    public function serves(string $sitePath, string $siteName, string $uri): bool
    {
        return file_exists($sitePath . '/wp-config.php') &&
            strpos(file_get_contents($sitePath . '/wp-config.php'), 'MULTISITE') !== false &&
            (
                strpos(file_get_contents($sitePath . '/wp-config.php'), "define('SUBDOMAIN_INSTALL',false)") ||
                strpos(file_get_contents($sitePath . '/wp-config.php'), "define('SUBDOMAIN_INSTALL', false)") ||
                strpos(file_get_contents($sitePath . '/wp-config.php'), "define( 'SUBDOMAIN_INSTALL', false )")
            );
    }

    public function frontControllerPath(string $sitePath, string $siteName, string $uri): string
    {
        $_SERVER['PHP_SELF']    = $uri;
        $_SERVER['SERVER_ADDR'] = '127.0.0.1';
        $_SERVER['SERVER_NAME'] = $_SERVER['HTTP_HOST'];

        if (stripos($uri, 'wp-admin') !== false || stripos($uri, 'wp-content') !== false || stripos($uri, 'wp-includes') !== false) {
            if (stripos($uri, 'wp-admin/network') === false) {
                $uri = substr($uri, stripos($uri, '/wp-'));
            }

            if ($this->wp_root !== false && file_exists($sitePath . "/{$this->wp_root}/wp-admin")) {
                $uri = "/{$this->wp_root}" . $uri;
            }
        }

        if (stripos($uri, 'wp-cron.php') !== false) {
            $new_uri = substr($uri, stripos($uri, '/wp-'));

            if (file_exists($sitePath . $new_uri)) {
                return $sitePath . $new_uri;
            }
        }

        return parent::frontControllerPath($sitePath, $siteName, $this->forceTrailingSlash($uri));
    }

    public function isStaticFile(string $sitePath, string $siteName, string $uri)
    {
        if (stripos($uri, 'wp-admin') !== false || stripos($uri, 'wp-content') !== false || stripos($uri, 'wp-includes') !== false) {
            if (substr($uri, -1, 1) == "/") return false;

            $new_uri = substr($uri, stripos($uri, '/wp-'));

            if ($this->wp_root !== false && file_exists($sitePath . "/{$this->wp_root}/wp-admin")) {
                $new_uri = "/{$this->wp_root}" . $new_uri;
            }

            if (file_exists($sitePath . $new_uri)) {
                return $sitePath . $new_uri;
            }
        }

        return parent::isStaticFile($sitePath, $siteName, $uri);
    }

    private function forceTrailingSlash(string $uri): string
    {
        if (substr($uri, -9) == '/wp-admin') {
            header('Location: '.$uri.'/'); die;
        }
        return $uri;
    }
}

How to Use It

  1. Create a custom driver file at:

    ~/.config/valet/Drivers/WordPressMultisiteSubdirectoryValetDriver.php

  2. Paste the code above into the file.
  3. Run:

  4. Visit your multisite subdirectory URLs like /de/category/...they should now work as expected!

 

 

If you’re working with WordPress multisite on Laravel Valet using subdirectories, this custom driver is a simple and effective fix. It’s lightweight, and integrates seamlessly with how Valet expects drivers to behave.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.