Skip to content
Merged
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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,18 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).

## [Unreleased]

### Changed

- Everything that knows about the Breeze plugin now lives under
`src/Breeze/` (namespace `Parisek\TimberKit\Breeze`), so a project that
does not run Breeze can see in one directory what is dead weight. A test
enforces the boundary: naming Breeze anywhere else under `src/` fails the
build. `StarterBase` is the one exception — it keeps the opt-in flags,
whose names are unchanged.
- `Parisek\TimberKit\BreezeWarmupSitemap` is now
`Parisek\TimberKit\Breeze\WarmupSitemap`. The old name keeps resolving
through a class alias, so no consumer breaks on upgrade.

### Added

- `$breeze_warmup_priority` — order the Breeze warmup list by importance
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,16 @@ wp timber-kit wpml-cleanup-theme-domain --apply # delete the rows and compil

## Cache warm-up (Breeze)

`BreezeWarmupSitemap` feeds Breeze's Cache Warmup preloader with every URL from
Everything in this package that knows about Breeze lives under `src/Breeze/`
(`Parisek\TimberKit\Breeze`). A project that does not run the plugin can treat
that whole directory as dead weight, and a test in the suite fails the build if
Breeze is named anywhere else under `src/` — the boundary is enforced, not just
documented. The one exception is `StarterBase`, which keeps the opt-in flags.

The class was called `BreezeWarmupSitemap` before the move; the old name still
resolves through an alias.

`Breeze\WarmupSitemap` feeds Breeze's Cache Warmup preloader with every URL from
the site's XML sitemap via the `breeze_preload_urls` filter.

Breeze 2.5 re-warms the cache after a full purge, but its own URL sources are
Expand Down
20 changes: 20 additions & 0 deletions compat/aliases.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php
/**
* Class names this package has already published under a previous layout.
*
* Everything Breeze-specific moved under `Parisek\TimberKit\Breeze` so a
* project that does not run the plugin can see in one directory what is dead
* weight. `BreezeWarmupSitemap` had already shipped, so its old name keeps
* resolving here rather than breaking on upgrade.
*
* The class is `final`, so a subclass shim is not an option — an alias is.
*/

declare(strict_types=1);

if ( ! class_exists( 'Parisek\TimberKit\BreezeWarmupSitemap', false ) ) {
class_alias(
\Parisek\TimberKit\Breeze\WarmupSitemap::class,
'Parisek\TimberKit\BreezeWarmupSitemap'
);
}
5 changes: 4 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@
"autoload": {
"psr-4": {
"Parisek\\TimberKit\\": "src/"
}
},
"files": [
"compat/aliases.php"
]
},
"autoload-dev": {
"psr-4": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\Health\Check;
namespace Parisek\TimberKit\Breeze\Health;

use Parisek\TimberKit\Health\HealthCheck;
use Parisek\TimberKit\Health\Result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\BreezeWarmup;
namespace Parisek\TimberKit\Breeze;

/**
* Divides the URL budget between languages.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\BreezeWarmup;
namespace Parisek\TimberKit\Breeze;

/**
* The last-known-good ordering, and the guard that keeps two writers from
Expand Down
2 changes: 1 addition & 1 deletion src/BreezeWarmup/Scorer.php → src/Breeze/Scorer.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\BreezeWarmup;
namespace Parisek\TimberKit\Breeze;

/**
* The scoring core: turns a sitemap record plus a weight map into one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\BreezeWarmup;
namespace Parisek\TimberKit\Breeze;

/**
* Reads the three signals a sitemap cannot carry: which URLs sit in a menu,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\BreezeWarmup;
namespace Parisek\TimberKit\Breeze;

/**
* Derives the two provenance signals a sitemap carries implicitly: which
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

declare(strict_types=1);

namespace Parisek\TimberKit\BreezeWarmup;
namespace Parisek\TimberKit\Breeze;

/**
* One canonical shape for a URL, used as the key that joins signals coming
Expand Down
10 changes: 2 additions & 8 deletions src/BreezeWarmupSitemap.php → src/Breeze/WarmupSitemap.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,8 @@

declare(strict_types=1);

namespace Parisek\TimberKit;
namespace Parisek\TimberKit\Breeze;

use Parisek\TimberKit\BreezeWarmup\LanguageQuota;
use Parisek\TimberKit\BreezeWarmup\PriorityStore;
use Parisek\TimberKit\BreezeWarmup\Scorer;
use Parisek\TimberKit\BreezeWarmup\SignalCollector;
use Parisek\TimberKit\BreezeWarmup\SourceNaming;
use Parisek\TimberKit\BreezeWarmup\UrlCanonicalizer;

/**
* Feeds Breeze's Cache Warmup preloader with every URL from the site's XML
Expand Down Expand Up @@ -56,7 +50,7 @@
* `false`) plus Breeze being active. Per-project runtime kill switch, even
* when the flag is on: `add_filter( 'timberkit_warmup_sitemap_enabled', '__return_false' )`.
*/
final class BreezeWarmupSitemap {
final class WarmupSitemap {

/** @var bool Prevent duplicate hook registration. */
private static bool $registered = false;
Expand Down
10 changes: 5 additions & 5 deletions src/StarterBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@
use Parisek\Twig\AttributeExtension;
use Parisek\Twig\TypographyExtension;
use Parisek\TimberKit\BlockRenderer;
use Parisek\TimberKit\BreezeWarmupSitemap;
use Parisek\TimberKit\Breeze\Health\PreloadChainHealthy;
use Parisek\TimberKit\Breeze\WarmupSitemap;
use Parisek\TimberKit\Health\Check\AuthorSitemapDisabled;
use Parisek\TimberKit\Health\Check\PreloadChainHealthy;
use Parisek\TimberKit\Health\Check\FileEditingDisabled;
use Parisek\TimberKit\Health\Check\GtmContainerNotDuplicated;
use Parisek\TimberKit\Health\Check\RestUsersRestricted;
Expand Down Expand Up @@ -544,7 +544,7 @@ class StarterBase extends Site {
protected bool $clear_cache_on_menu_update = true;

/**
* Feed Breeze's Cache Warmup preloader ({@see BreezeWarmupSitemap}) with
* Feed Breeze's Cache Warmup preloader ({@see WarmupSitemap}) with
* every URL from the site's XML sitemap via the `breeze_preload_urls`
* filter, instead of only the homepage + auto-detected pages + a
* 30-URL manual list. Opt-in (default off): for a project with the
Expand Down Expand Up @@ -1294,7 +1294,7 @@ protected function setup_wpforms_config_bridge(): void {
* why this is opt-in rather than auto-activating) and by Breeze itself
* being active. The per-project runtime opt-out filter
* (`timberkit_warmup_sitemap_enabled`, default true) is re-checked inside
* {@see BreezeWarmupSitemap::register()} so the module stays self-guarding.
* {@see WarmupSitemap::register()} so the module stays self-guarding.
*
* @return void
*/
Expand All @@ -1307,7 +1307,7 @@ protected function setup_breeze_warmup_sitemap(): void {
return;
}

BreezeWarmupSitemap::register(
WarmupSitemap::register(
$this->breeze_warmup_priority,
$this->breeze_warmup_priority_weights
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

declare(strict_types=1);

namespace Tests\Property\BreezeWarmup;
namespace Tests\Property\Breeze;

use Eris\Generator;
use Parisek\TimberKit\BreezeWarmup\Scorer;
use Parisek\TimberKit\Breeze\Scorer;
use Tests\Property\Support\PropertyTestCase;

/**
Expand Down
60 changes: 60 additions & 0 deletions tests/Unit/Architecture/BackwardCompatibleAliasTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
<?php

declare(strict_types=1);

namespace Tests\Unit\Architecture;

use PHPUnit\Framework\TestCase;

/**
* The pre-move class name must keep resolving.
*
* `BreezeWarmupSitemap` shipped in v1.37.0 and v1.38.0, so a consumer may
* reference it. The move to `Breeze\WarmupSitemap` keeps it alive through a
* `class_alias` in `compat/aliases.php`, wired as a Composer `files` autoload
* entry.
*
* Without this test the whole shim is invisible to the suite: every other test
* uses the new name, so dropping the autoload entry, mistyping the alias, or
* having it fail under an optimised autoloader would all leave the build
* green. The one thing that must not break on upgrade is the one thing nothing
* else exercises.
*/
class BackwardCompatibleAliasTest extends TestCase {

/** @var string The name this package published before the move. */
private const LEGACY = 'Parisek\TimberKit\BreezeWarmupSitemap';

/** @var string Where that code lives now. */
private const CURRENT = 'Parisek\TimberKit\Breeze\WarmupSitemap';

public function test_the_published_class_name_still_resolves(): void {
$this->assertTrue(
class_exists( self::LEGACY ),
self::LEGACY . ' shipped in v1.37.0 and must keep resolving after the move'
);
}

public function test_the_legacy_name_points_at_the_moved_class(): void {
// Resolving is not enough — it has to resolve to the right thing. An
// alias pointing at some other class would satisfy class_exists().
$this->assertTrue( is_a( self::LEGACY, self::CURRENT, true ) );
}

public function test_the_alias_is_wired_through_composer(): void {
// The shim only loads because composer.json lists it under
// autoload.files. Dropping that entry breaks the alias without
// touching a single line of PHP, so pin it explicitly.
$manifest = json_decode(
(string) file_get_contents( dirname( __DIR__, 3 ) . '/composer.json' ),
true
);

$this->assertIsArray( $manifest );
$this->assertContains(
'compat/aliases.php',
$manifest['autoload']['files'] ?? array(),
'the alias shim must stay in composer.json autoload.files'
);
}
}
84 changes: 84 additions & 0 deletions tests/Unit/Architecture/BreezeBoundaryTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
<?php

declare(strict_types=1);

namespace Tests\Unit\Architecture;

use PHPUnit\Framework\TestCase;

/**
* Everything that knows about the Breeze plugin lives under `src/Breeze/`.
*
* The point is excision: a project that does not run Breeze should be able to
* see, at a glance, exactly which directory is dead weight. A boundary nobody
* enforces blurs within months — one helper reaching for `breeze_get_option()`
* from somewhere convenient, and the directory stops meaning anything.
*
* Two exceptions, both deliberate:
* - `StarterBase` carries the opt-in flags and delegates. The flag names are
* public API — six projects in the fleet set them — so they stay put even
* though the implementation moved.
* - `compat/aliases.php` keeps the pre-move class name resolving.
*/
class BreezeBoundaryTest extends TestCase {

/** @var array<int, string> Paths allowed to name Breeze outside src/Breeze/. */
private const ALLOWED = array(
'src/StarterBase.php',
);

/**
* @return array<int, string>
*/
private function phpFilesUnderSrc(): array {
$root = dirname( __DIR__, 3 ) . '/src';
$files = array();

$iterator = new \RecursiveIteratorIterator( new \RecursiveDirectoryIterator( $root ) );
foreach ( $iterator as $file ) {
if ( $file->isFile() && 'php' === $file->getExtension() ) {
$files[] = $file->getPathname();
}
}

sort( $files );

return $files;
}

public function test_only_the_breeze_directory_names_breeze(): void {
$root = dirname( __DIR__, 3 );
$offenders = array();

foreach ( $this->phpFilesUnderSrc() as $path ) {
$relative = ltrim( str_replace( $root, '', $path ), '/' );

if ( str_starts_with( $relative, 'src/Breeze/' ) ) {
continue;
}
if ( in_array( $relative, self::ALLOWED, true ) ) {
continue;
}

$contents = (string) file_get_contents( $path );
if ( 1 === preg_match( '/breeze/i', $contents ) ) {
$offenders[] = $relative;
}
}

$this->assertSame(
array(),
$offenders,
"These files name Breeze outside src/Breeze/:\n" . implode( "\n", $offenders )
);
}

public function test_the_breeze_directory_exists_and_is_not_empty(): void {
// Guards against the boundary passing vacuously if the directory were
// ever removed or renamed without updating this test.
$dir = dirname( __DIR__, 3 ) . '/src/Breeze';

$this->assertDirectoryExists( $dir );
$this->assertNotEmpty( glob( $dir . '/*.php' ) );
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

declare(strict_types=1);

namespace Tests\Unit\Health\Check;
namespace Tests\Unit\Breeze\Health;

use Brain\Monkey;
use Brain\Monkey\Functions;
use PHPUnit\Framework\TestCase;
use Parisek\TimberKit\Health\Check\PreloadChainHealthy;
use Parisek\TimberKit\Breeze\Health\PreloadChainHealthy;
use Parisek\TimberKit\Health\HealthCheck;
use Parisek\TimberKit\Health\Result;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

declare(strict_types=1);

namespace Tests\Unit\BreezeWarmup;
namespace Tests\Unit\Breeze;

use PHPUnit\Framework\TestCase;
use Parisek\TimberKit\BreezeWarmup\LanguageQuota;
use Parisek\TimberKit\Breeze\LanguageQuota;

/**
* Covers the per-language budget split.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@

declare(strict_types=1);

namespace Tests\Unit\BreezeWarmup;
namespace Tests\Unit\Breeze;

use Brain\Monkey;
use Brain\Monkey\Functions;
use PHPUnit\Framework\TestCase;
use Parisek\TimberKit\BreezeWarmup\PriorityStore;
use Parisek\TimberKit\Breeze\PriorityStore;

/**
* Covers the option row and its optimistic lock.
Expand Down
Loading
Loading