From c5bed6bb4359ad6aa13ca7dac4aa5f0e2f18c654 Mon Sep 17 00:00:00 2001 From: Olivier Gorzalka Date: Wed, 21 Oct 2026 11:22:16 +0200 Subject: [PATCH] fix: read an APP_URL without a scheme as http:// Closes #518 --- CHANGELOG.md | 10 +++- .../Infrastructure/Checks/AppUrlCheck.php | 54 +++++++++++++++++++ .../Providers/DoctorServiceProvider.php | 2 + .../WordPressInstallLoaderService.php | 5 +- src/WordPress/AppUrl.php | 42 +++++++++++++++ src/WordPress/Bootstrap.php | 8 +-- .../Commands/LaunchPadInstallCommand.php | 3 +- tests/Feature/Doctor/InstallChecksTest.php | 25 +++++++++ tests/Unit/WordPress/AppUrlTest.php | 35 ++++++++++++ 9 files changed, 176 insertions(+), 8 deletions(-) create mode 100644 src/Doctor/Infrastructure/Checks/AppUrlCheck.php create mode 100644 src/WordPress/AppUrl.php create mode 100644 tests/Unit/WordPress/AppUrlTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index d8c5ab7b..7f09db89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,15 @@ All notable changes to the Pollora framework will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [Unreleased](https://github.com/Pollora/framework/compare/v13.38.0...develop) +## [Unreleased](https://github.com/Pollora/framework/compare/v13.38.1...develop) + +## [v13.38.1](https://github.com/Pollora/framework/compare/v13.38.0...v13.38.1) - 2026-10-21 + +### Fixed +- An `APP_URL` without a scheme (`APP_URL=pollora.test`, written by hand in `.env`) no longer breaks the site: every Artisan command failed with `Undefined array key "host"`, and `/wp-admin/` answered a 404 because WordPress built its URLs relative to the current path. The value is read as `http://pollora.test` for `WP_HOME`, `WP_SITEURL`, the cookie path and the console host (#518) + +### Added +- `pollora:doctor` warns when `APP_URL` has no scheme, and gives the value to write ## [v13.38.0](https://github.com/Pollora/framework/compare/v13.37.1...v13.38.0) - 2026-10-21 diff --git a/src/Doctor/Infrastructure/Checks/AppUrlCheck.php b/src/Doctor/Infrastructure/Checks/AppUrlCheck.php new file mode 100644 index 00000000..57389d95 --- /dev/null +++ b/src/Doctor/Infrastructure/Checks/AppUrlCheck.php @@ -0,0 +1,54 @@ +getCookiePath($appUrl); diff --git a/src/WordPress/AppUrl.php b/src/WordPress/AppUrl.php new file mode 100644 index 00000000..13c62085 --- /dev/null +++ b/src/WordPress/AppUrl.php @@ -0,0 +1,42 @@ + 'pollora.test']); + + $result = (new AppUrlCheck)->run(RunContext::Console); + + expect($result->status->value)->toBe('warning') + ->and($result->details)->toContain('Pollora reads it as http://pollora.test') + ->and($result->fix)->toContain('APP_URL=http://pollora.test'); + }); + + it('passes a URL with a scheme, and a port', function (string $url): void { + config(['app.url' => $url]); + + expect((new AppUrlCheck)->run(RunContext::Console)->status->value)->toBe('ok'); + })->with(['https://pollora.test', 'http://localhost:8000']); + + it('is skipped without an APP_URL', function (): void { + config(['app.url' => '']); + + expect((new AppUrlCheck)->run(RunContext::Console)->status->value)->toBe('skipped'); + }); +}); + describe('Discovery cache', function (): void { function discoveryCheck(bool $cacheEnabled, array $missing): DiscoveryCacheCheck { diff --git a/tests/Unit/WordPress/AppUrlTest.php b/tests/Unit/WordPress/AppUrlTest.php new file mode 100644 index 00000000..34a28137 --- /dev/null +++ b/tests/Unit/WordPress/AppUrlTest.php @@ -0,0 +1,35 @@ +toBe($expected); + })->with([ + 'a host' => ['pollora.test', 'http://pollora.test'], + 'a host and a port' => ['localhost:8888', 'http://localhost:8888'], + 'a host with a path' => ['pollora.test/site', 'http://pollora.test/site'], + 'a protocol-relative URL' => ['//pollora.test', 'http://pollora.test'], + 'spaces around' => [' pollora.test ', 'http://pollora.test'], + ]); + + it('leaves a URL that has a scheme alone', function (string $url): void { + expect(AppUrl::normalize($url))->toBe($url); + })->with(['http://pollora.test', 'https://pollora.test', 'https://pollora.test/', 'HTTPS://pollora.test']); + + it('leaves an empty value alone', function (): void { + expect(AppUrl::normalize(''))->toBe(''); + }); +}); + +describe('host', function (): void { + it('finds the host with and without a scheme', function (string $url): void { + expect(AppUrl::host($url))->toBe('pollora.test'); + })->with(['pollora.test', 'http://pollora.test', 'https://pollora.test:8443/cms', 'pollora.test:8000']); + + it('has no host for an empty value', function (): void { + expect(AppUrl::host(''))->toBeNull(); + }); +});