Skip to content

Instantly share code, notes, and snippets.

@MouseEatsCat
Last active July 17, 2023 17:15
Show Gist options
  • Save MouseEatsCat/dfc2090b68f2effa02c42a5b8d3f75fc to your computer and use it in GitHub Desktop.
Save MouseEatsCat/dfc2090b68f2effa02c42a5b8d3f75fc to your computer and use it in GitHub Desktop.

Locomotive Bedrock (Wordpress) Valet Driver

This adds Wordpress Bedrock project support for Laravel Valet.

The driver will match any Bedrock project with a public directory of web or www. It support having either wp or wordpress as the wordpress install directory.

Setup

  • Run the following command to place the LocomotiveBedrockValetDriver.php driver file into ~/.config/valet/Drivers/.
curl https://gist.githubusercontent.com/raw/dfc2090b68f2effa02c42a5b8d3f75fc/LocomotiveBedrockValetDriver.php -o ~/.config/valet/Drivers/LocomotiveBedrockValetDriver.php
<?php
/**
* Locomotive Bedrock Valet Driver
*
* Supported Valet Version: 4
*/
namespace Valet\Drivers\Custom;
use Illuminate\Support\Collection;
use Valet\Drivers\BasicValetDriver;
class LocomotiveBedrockValetDriver extends BasicValetDriver
{
public const PUBLIC_PATHS = [ 'www', 'web' ];
public const WP_PATHS = [ 'wp', 'wordpress' ];
public const STATIC_FILE_TYPES = [ 'jpe?g', 'gif', 'pdf', 'png', 'svg', 'mp4' ];
/** @var ?array<string, mixed> */
public $valetSiteConfig = null;
/** @var ?string */
public $valetSiteName = null;
/** @var ?string */
public $valetSitePath = null;
/** @var array<string, mixed> */
public $valetSiteOptions = [
'remote_assets_domain' => null,
'allow_indexphp_files' => false,
'redirect_trailing_slashes' => false,
];
/**
* Determine if the driver serves the request.
*/
public function serves(string $sitePath, string $siteName, string $uri): bool
{
$hasBedrockAutoloader = $this->composerRequires($sitePath, 'roots/bedrock-autoloader');
foreach (static::PUBLIC_PATHS as $publicPath) {
if (
$hasBedrockAutoloader ||
file_exists("{$sitePath}/{$publicPath}/mu-plugins/bedrock-autoloader.php") ||
(
is_dir("{$sitePath}/{$publicPath}/") &&
file_exists("{$sitePath}/{$publicPath}/wp-config.php") &&
file_exists("{$sitePath}/config/application.php")
)
) {
return true;
}
}
return false;
}
/**
* Determine if the incoming request is for a static file.
*
* @return string|false
*/
public function isStaticFile(string $sitePath, string $siteName, string $uri)
{
foreach (static::PUBLIC_PATHS as $publicPath) {
$staticFilePath = "{$sitePath}/{$publicPath}{$uri}";
if ($this->isActualFile($staticFilePath)) {
return $staticFilePath;
}
}
// Use remote assets as fallback
$this->isRemoteFile($sitePath, $siteName, $uri);
return false;
}
/**
* Determine if the incoming request is for a remote static file.
*
* @return void
*/
public function isRemoteFile(string $sitePath, string $siteName, string $uri): void
{
$removeAssetHost = $this->getValetConfig('remote_assets_domain');
$regexpEligibleFiles = '/^(.*)\.('.implode('|', static::STATIC_FILE_TYPES).')$/i';
if ($removeAssetHost && preg_match($regexpEligibleFiles, $uri)) {
header("Location: {$removeAssetHost}{$uri}");
exit;
}
}
/**
* Get the fully resolved path to the application's front controller.
*/
public function frontControllerPath(string $sitePath, string $siteName, string $uri): string
{
// Do not allow direct use of "index.php"
if (!$this->getValetConfig('allow_indexphp_files') && preg_match('!/index.php$!', $uri)) {
$uri = str_replace('index.php', '', $uri);
header('Location: ' . $uri);
exit;
}
$uri = (
$this->getValetConfig('redirect_trailing_slashes')
? $uri
: $this->forceTrailingSlash($uri)
);
foreach (static::PUBLIC_PATHS as $publicPath) {
if (!is_dir("{$sitePath}/{$publicPath}/")) {
continue;
}
$path = parent::frontControllerPath(
"{$sitePath}/{$publicPath}",
$siteName,
$uri
);
foreach (static::WP_PATHS as $wpPath) {
if (!is_dir("$sitePath/$publicPath/$wpPath")) {
continue;
}
if (!str_contains($_SERVER['PHP_SELF'], "{$wpPath}/wp-admin")) {
$_SERVER['PHP_SELF'] = '/index.php';
}
}
return $path;
}
}
/**
* Redirect to uri with trailing slash.
*
* @param string $uri
* @return string
*/
public function forceTrailingSlash($uri)
{
foreach (static::WP_PATHS as $wpPath) {
$path = "/{$wpPath}/wp-admin";
if (substr($uri, -1 * strlen($path)) === $path) {
header("Location: {$uri}/");
exit;
}
}
return $uri;
}
/**
* Load server environment variables if available.
* Processes any '*' entries first, and then adds site-specific entries.
*/
public function loadServerEnvironmentVariables(string $sitePath, string $siteName): void
{
parent::loadServerEnvironmentVariables($sitePath, $siteName);
$this->valetSitePath = $sitePath;
$this->valetSiteName = $siteName;
$this->loadValetConfig($sitePath, $siteName);
}
/**
* Determine if valet config file exists.
*
* @return bool
*/
public function hasValetConfig()
{
return $this->valetSitePath && file_exists($this->valetSitePath . '/' . static::VALET_CONFIG_FILE);
}
/**
* Get the driver configuration options or a single option.
*
* @param string|null $key The single driver configuration option.
* @return mixed|null Returns null when no matching option is found.
*/
public function getValetConfig(?string $key = null)
{
if (is_null($this->valetSiteConfig)) {
$this->loadValetConfig($this->valetSitePath, $this->valetSiteName);
}
if ($key) {
return $this->valetSiteConfig[$key] ?? null;
}
return $this->valetSiteConfig;
}
/**
* Load driver configuration if available.
* Processes any '*' entries first, and then adds site-specific entries.
*/
public function loadValetConfig(string $sitePath, string $siteName): array
{
$this->valetSiteConfig = $this->valetSiteOptions;
$confFilePath = $sitePath.'/.valet-config.php';
if (file_exists($confFilePath)) {
// Load .valet-config.php
$config = include $confFilePath;
} else {
$confFilePath = $sitePath.'/valet-config.json';
if (file_exists($confFilePath)) {
// Load valet-config.json
$config = json_decode(
file_get_contents($confFilePath), true
);
} else {
// Fallback to global valet config.json
$config = json_decode(
file_get_contents(VALET_HOME_PATH.'/config.json'), true
);
}
}
if (! isset($config) || ! is_array($config)) {
return $this->valetSiteConfig;
}
if (isset($config['*']) && is_array($config['*'])) {
$this->valetSiteConfig = array_merge($this->valetSiteConfig, $config['*']);
}
if (isset($config[$siteName]) && is_array($config[$siteName])) {
$this->valetSiteConfig = array_merge($this->valetSiteConfig, $config[$siteName]);
}
// Backwards compatibility with initial "valet-config.json" file.
if ($config = array_intersect_key($config, $this->valetSiteOptions)) {
$this->valetSiteConfig = array_merge($this->valetSiteConfig, $config);
}
return $this->valetSiteConfig;
}
}
if (!function_exists('str_contains')) {
function str_contains($haystack, $needle) {
return $needle !== '' && mb_strpos($haystack, $needle) !== false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment