Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 5 additions & 12 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,26 +12,19 @@ jobs:

strategy:
matrix:
php: [8.1, 8.2, 8.3, 8.4]
laravel: [10.*, 11.*, 12.*]
php: [8.2, 8.3, 8.4]
laravel: [11.*, 12.*]
stability: [prefer-lowest, prefer-stable]
os: [ubuntu-latest]
include:
- os: windows-latest
php: 8.3
laravel: 10.*
stability: prefer-stable
- os: windows-latest
php: 8.3
laravel: 11.*
stability: prefer-stable
exclude:
- php: 8.1
laravel: 11.*
- php: 8.1
- os: windows-latest
php: 8.4
laravel: 12.*
- php: 8.4
laravel: 10.*
stability: prefer-stable

name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }}

Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@
}
},
"require": {
"statamic/cms": "^5.41"
"statamic/cms": "dev-url-trailing-slashes as 6.0"
},
"require-dev": {
"orchestra/testbench": "^8.28 || ^9.6.1 || ^10.0",
"phpunit/phpunit": "^10.5.35 || ^11.0"
"orchestra/testbench": "^9.6.1 || ^10.0",
"phpunit/phpunit": "^11.0"
},
"config": {
"allow-plugins": {
Expand Down
13 changes: 13 additions & 0 deletions config/ssg.php
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,19 @@
//
],

/*
|--------------------------------------------------------------------------
| Trailing Slashes
|--------------------------------------------------------------------------
|
| Enable to enforce trailing slashes on generated URLs. Some static site
| hosts expect trailing slashes on URLs for things like SEO sitemaps
| and RSS feeds in order to comply with the server configuration.
|
*/

'enforce_trailing_slashes' => false,

/*
|--------------------------------------------------------------------------
| Pagination Route
Expand Down
5 changes: 5 additions & 0 deletions src/Commands/StaticSiteGenerate.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Illuminate\Console\Command;
use Statamic\Console\RunsInPlease;
use Statamic\Facades\URL;
use Statamic\StaticSite\GenerationFailedException;
use Statamic\StaticSite\Generator;
use Wilderborn\Partyline\Facade as Partyline;
Expand Down Expand Up @@ -53,6 +54,10 @@ public function __construct(Generator $generator)
*/
public function handle()
{
if (config('statamic.ssg.enforce_trailing_slashes')) {
URL::enforceTrailingSlashes();
}

Partyline::bind($this);

if (config('statamic.editions.pro') && ! config('statamic.system.license_key')) {
Expand Down
17 changes: 5 additions & 12 deletions src/Generator.php
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,9 @@ protected function makeContentGenerationClosures($pages, $request)
$oldCarbonFormat = $this->getToStringFormat();

if ($this->shouldSetCarbonFormat($page)) {
Carbon::setToStringFormat(Statamic::dateFormat());
Date::setToStringFormat(function (Carbon $date) {
return $date->setTimezone(Statamic::displayTimezone())->format(Statamic::dateFormat());
});
}

$this->updateCurrentSite($page->site());
Expand Down Expand Up @@ -461,7 +463,7 @@ protected function shouldSetCarbonFormat($page)

protected function makeAbsoluteUrl($url)
{
return URL::tidy(Str::start($url, $this->config['base_url'].'/'));
return URL::assemble($this->config['base_url'], $url);
}

protected function shouldRejectPage($page, $outputError = false)
Expand Down Expand Up @@ -489,19 +491,10 @@ protected function shouldRejectPage($page, $outputError = false)
*
* @throws \ReflectionException
*/
protected function getToStringFormat(): ?string
protected function getToStringFormat(): string|\Closure|null
{
$reflection = new ReflectionClass($date = Date::now());

// Carbon 2.x
if ($reflection->hasProperty('toStringFormat')) {
$format = $reflection->getProperty('toStringFormat');
$format->setAccessible(true);

return $format->getValue();
}

// Carbon 3.x
$factory = $reflection->getMethod('getFactory');
$factory->setAccessible(true);

Expand Down
3 changes: 2 additions & 1 deletion src/Page.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Http\RedirectResponse;
use Statamic\Facades\Blink;
use Statamic\Facades\URL;

class Page
{
Expand Down Expand Up @@ -135,7 +136,7 @@ public function site()

public function is404()
{
return $this->url() === '/404';
return $this->url() === URL::tidy('/404');
}

public function setPaginationCurrentPage($currentPage)
Expand Down
2 changes: 1 addition & 1 deletion src/Route.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function toResponse($request)
$kernel->terminate($request, $response);

if ($e = $response->exception) {
if ($response->status() === 404 && $this->url() === '/404') {
if ($response->status() === 404 && $this->url() === URL::tidy('/404')) {
return $response;
}

Expand Down
68 changes: 68 additions & 0 deletions tests/GenerateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,21 @@

use Illuminate\Filesystem\Filesystem;
use Statamic\Facades\Config;
use Statamic\Facades\URL;
use Tests\Concerns\RunsGeneratorCommand;

class GenerateTest extends TestCase
{
use RunsGeneratorCommand;

protected function tearDown(): void
{
URL::enforceTrailingSlashes(false);
URL::clearUrlCache();

parent::tearDown();
}

/** @test */
public function it_generates_pages_for_site_fixture()
{
Expand Down Expand Up @@ -354,4 +363,63 @@ public function it_generates_associated_paginated_pages_when_generating_only_url
$this->assertStringContainsString('Total Pages: 3', $index);
$this->assertStringContainsString('Prev Link: /articles/page/2', $index);
}

/** @test */
public function it_enforces_trailing_slashes_when_config_enabled()
{
Config::set('statamic.ssg.enforce_trailing_slashes', true);

$files = $this->generate();

$index = $files['articles/index.html'];
$this->assertStringContainsString('<a href="http://cool-runnings.com/articles/one/">One</a>', $index);
$this->assertStringContainsString('<a href="http://cool-runnings.com/articles/two/">Two</a>', $index);
$this->assertStringContainsString('<a href="http://cool-runnings.com/articles/three/">Three</a>', $index);
}

/** @test */
public function it_enforces_trailing_slashes_on_paginated_urls_when_config_enabled()
{
Config::set('statamic.ssg.enforce_trailing_slashes', true);

$this->files->put(resource_path('views/articles/index.antlers.html'), <<<'EOT'
{{ collection:articles sort="date:asc" paginate="3" as="articles" }}
{{ articles }}
<a href="{{ permalink }}">{{ title }}</a>
{{ /articles }}

{{ paginate }}
Current Page: {{ current_page }}
Total Pages: {{ total_pages }}
Prev Link: {{ prev_page }}
Next Link: {{ next_page }}
{{ /paginate }}
{{ /collection:articles }}
EOT
);

$files = $this->generate();

$index = $files['articles/index.html'];
$this->assertStringContainsString('Next Link: /articles/page/2/', $index);

$page2 = $files['articles/page/2/index.html'];
$this->assertStringContainsString('Prev Link: /articles/page/1/', $page2);
$this->assertStringContainsString('Next Link: /articles/page/3/', $page2);

$page3 = $files['articles/page/3/index.html'];
$this->assertStringContainsString('Prev Link: /articles/page/2/', $page3);
}

/** @test */
public function it_still_generates_404_when_trailing_slashes_config_is_enabled()
{
Config::set('statamic.ssg.enforce_trailing_slashes', true);

$files = $this->generate();

$this->assertContains('404.html', array_keys($files));

$this->assertStringContainsString('<h1>404!</h1>', $files['404.html']);
}
}
72 changes: 72 additions & 0 deletions tests/Localized/GenerateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
use Illuminate\Filesystem\Filesystem;
use Statamic\Facades\Config;
use Statamic\Facades\Site;
use Statamic\Facades\URL;
use Tests\Concerns\RunsGeneratorCommand;
use Tests\TestCase;

Expand Down Expand Up @@ -40,6 +41,14 @@ protected function getEnvironmentSetUp($app)
]);
}

protected function tearDown(): void
{
URL::enforceTrailingSlashes(false);
URL::clearUrlCache();

parent::tearDown();
}

/** @test */
public function it_generates_pages_for_localized_site_fixture()
{
Expand Down Expand Up @@ -301,4 +310,67 @@ public function it_generates_associated_paginated_pages_when_generating_only_loc
$this->assertStringContainsString('Total Pages: 2', $index);
$this->assertStringContainsString('Prev Link: /fr/le-articles/page/1', $index);
}

/** @test */
public function it_enforces_trailing_slashes_when_config_enabled()
{
Config::set('statamic.ssg.enforce_trailing_slashes', true);

$files = $this->generate();

$index = $files['articles/index.html'];
$this->assertStringContainsString('<a href="http://cool-runnings.com/articles/one/">One</a>', $index);
$this->assertStringContainsString('<a href="http://cool-runnings.com/articles/two/">Two</a>', $index);
$this->assertStringContainsString('<a href="http://cool-runnings.com/articles/three/">Three</a>', $index);

$frIndex = $files['fr/le-articles/index.html'];
$this->assertStringContainsString('<a href="http://cool-runnings.com/fr/le-articles/le-one/">Le One</a>', $frIndex);
$this->assertStringContainsString('<a href="http://cool-runnings.com/fr/le-articles/le-two/">Le Two</a>', $frIndex);
$this->assertStringContainsString('<a href="http://cool-runnings.com/fr/le-articles/le-three/">Le Three</a>', $frIndex);
}

/** @test */
public function it_enforces_trailing_slashes_on_localized_paginated_urls_when_config_enabled()
{
Config::set('statamic.ssg.enforce_trailing_slashes', true);

$this->files->put(resource_path('views/articles/index.antlers.html'), <<<'EOT'
{{ collection:articles sort="date:asc" paginate="3" as="articles" }}
{{ articles }}
<a href="{{ permalink }}">{{ title }}</a>
{{ /articles }}

{{ paginate }}
Current Page: {{ current_page }}
Total Pages: {{ total_pages }}
Prev Link: {{ prev_page }}
Next Link: {{ next_page }}
{{ /paginate }}
{{ /collection:articles }}
EOT
);

$files = $this->generate();

$index = $files['articles/index.html'];
$this->assertStringContainsString('Next Link: /articles/page/2/', $index);

$frIndex = $files['fr/le-articles/index.html'];
$this->assertStringContainsString('Next Link: /fr/le-articles/page/2/', $frIndex);

$frPage2 = $files['fr/le-articles/page/2/index.html'];
$this->assertStringContainsString('Prev Link: /fr/le-articles/page/1/', $frPage2);
}

/** @test */
public function it_still_generates_404_when_trailing_slashes_config_is_enabled()
{
Config::set('statamic.ssg.enforce_trailing_slashes', true);

$files = $this->generate();

$this->assertContains('404.html', array_keys($files));

$this->assertStringContainsString('<h1>404!</h1>', $files['404.html']);
}
}