diff --git a/phpunit.xml b/phpunit.xml
index c09b5bc..61c031c 100644
--- a/phpunit.xml
+++ b/phpunit.xml
@@ -22,7 +22,8 @@
-
+
+
diff --git a/routes/web.php b/routes/web.php
index bb65cc6..f6a3e9a 100644
--- a/routes/web.php
+++ b/routes/web.php
@@ -8,5 +8,13 @@
Route::get('/author/{author}', [PostController::class, 'authorPosts'])->name('author.posts');
Route::get('/category/{category}', [PostController::class, 'categoryPosts'])->name('category.posts');
Route::get('/tag/{slug}', [PostController::class, 'tagPosts'])->name('tag.posts');
-Route::get('/{year}/{month}', [PostController::class, 'yearMonthPosts'])->name('year-month.posts');
-Route::get('/{year}/{month}/{slug}', [PostController::class, 'show'])->name('post');
+// Mirrors the WordPress permalink structure (%year%/%monthnum%/%postname%).
+// Without the constraints these two act as catch-alls for any 2- and
+// 3-segment path, answering 200 with an empty archive instead of 404.
+Route::get('/{year}/{month}', [PostController::class, 'yearMonthPosts'])
+ ->where(['year' => '[0-9]{4}', 'month' => '0[1-9]|1[0-2]'])
+ ->name('year-month.posts');
+
+Route::get('/{year}/{month}/{slug}', [PostController::class, 'show'])
+ ->where(['year' => '[0-9]{4}', 'month' => '0[1-9]|1[0-2]'])
+ ->name('post');
diff --git a/tests/Feature/ArchiveRouteConstraintsTest.php b/tests/Feature/ArchiveRouteConstraintsTest.php
new file mode 100644
index 0000000..d83450a
--- /dev/null
+++ b/tests/Feature/ArchiveRouteConstraintsTest.php
@@ -0,0 +1,55 @@
+get($path)->assertNotFound();
+})->with([
+ '/foo/bar',
+ '/abcd/ef',
+ '/wp-admin/setup-config.php',
+ '/assets/app',
+]);
+
+it('rejects out-of-range months', function (string $path) {
+ $this->get($path)->assertNotFound();
+})->with([
+ '/2026/00',
+ '/2026/13',
+ '/2026/99',
+ '/2026/7', // month must be zero padded, as WordPress emits it
+ '/2026/007',
+]);
+
+it('rejects malformed years', function (string $path) {
+ $this->get($path)->assertNotFound();
+})->with([
+ '/26/07',
+ '/20260/07',
+ '/2026a/07',
+]);
+
+it('rejects the same malformed paths on the single post route', function (string $path) {
+ $this->get($path)->assertNotFound();
+})->with([
+ '/foo/bar/some-slug',
+ '/2026/13/some-slug',
+ '/2026/7/some-slug',
+]);
+
+it('still matches well formed archive paths', function () {
+ // Reaching the controller means the route matched. The controller then hits
+ // wp_posts, which does not exist here, so anything other than 404 proves
+ // the constraint let the request through.
+ $this->get('/2026/07')->assertStatus(500);
+});
+
+it('does not shadow the named static routes', function () {
+ expect(route('year-month.posts', ['year' => '2026', 'month' => '07']))
+ ->toEndWith('/2026/07');
+
+ expect(route('post', ['year' => '2026', 'month' => '07', 'slug' => 'meu-post']))
+ ->toEndWith('/2026/07/meu-post');
+});