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
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "1.0.0"
".": "1.0.1"
}
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Changelog

## [1.0.1](https://github.com/nlemoine/page-for-custom-post-type/compare/1.0.0...1.0.1) (2026-05-08)


### Bug Fixes

* drop stale page mapping when CPT becomes ineligible ([021857b](https://github.com/nlemoine/page-for-custom-post-type/commit/021857ba309ca305a3c1ffac0ee420d50a9d5c56)), closes [#12](https://github.com/nlemoine/page-for-custom-post-type/issues/12)

## [1.0.0](https://github.com/nlemoine/page-for-custom-post-type/compare/0.5.0...1.0.0) (2026-05-08)


Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "page-for-custom-post-type",
"version": "1.0.0",
"version": "1.0.1",
"private": true,
"description": "Editor scripts for the Page for custom post type WordPress plugin",
"packageManager": "pnpm@10.33.0",
Expand Down
2 changes: 1 addition & 1 deletion plugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Plugin URI: https://github.com/nlemoine/page-for-custom-post-type
* Description: Allows you to set pages for any custom post type archive
* x-release-please-start-version
* Version: 1.0.0
* Version: 1.0.1
* x-release-please-end
* Author: Nicolas Lemoine
* Author URI: https://n5s.dev/
Expand Down
10 changes: 10 additions & 0 deletions src/Frontend/Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
namespace n5s\PageForCustomPostType\Frontend;

use n5s\PageForCustomPostType\Core\Api;
use WP_Post_Type;
use WP_Query;

/**
Expand Down Expand Up @@ -54,6 +55,15 @@ public function withQueryProperties(WP_Query $query): void
return;
}

// Defensive fallback: if the CPT is not registered at all this request
// (e.g. the plugin that registers it is deactivated), no
// registered_post_type hook fires, so the cleanup in LifecycleManager
// can't delete the stale option. Bail here to avoid hijacking the page.
$postTypeObject = get_post_type_object($postType);
if (!$postTypeObject instanceof WP_Post_Type || !$this->api->shouldConsiderPostType($postTypeObject)) {
return;
}

// Modify query conditionals
$query->is_singular = false;
$query->is_page = false;
Expand Down
8 changes: 7 additions & 1 deletion src/Lifecycle/LifecycleManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ public function __construct(
public function watchOptions(string $postType, WP_Post_Type $postTypeObject): void
{
if (!$this->api->shouldConsiderPostType($postTypeObject)) {
// The mapping outlives CPT arg changes; drop it when the type is no
// longer eligible so frontend/admin don't operate on stale state.
if ($this->api->getPageIdFromPostType($postType, false) !== null) {
$this->deleteOption($postType);
}

return;
}

Expand Down Expand Up @@ -213,7 +219,7 @@ private function onOptionChange(string $name, mixed $value): void
$pageIds = (array) get_option(Api::OPTION_PAGE_IDS, []);
$pageIds[$postType] = $value;

update_option(Api::OPTION_PAGE_IDS, array_filter($pageIds));
update_option(Api::OPTION_PAGE_IDS, array_filter($pageIds), true);

$this->rewriteManager->flushRewriteRules($postType);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Lifecycle/Migrator.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ final class Migrator
{
private const DB_VERSION_OPTION = 'pfcpt_db_version';
// x-release-please-start-version
private const CURRENT_VERSION = '1.0.0';
private const CURRENT_VERSION = '1.0.1';
// x-release-please-end

public function migrate(): void
Expand Down
43 changes: 43 additions & 0 deletions tests/Integration/EdgeCaseTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -143,4 +143,47 @@ public function testQueriedObjectIsPageNotPosts(): void
$this->assertSame('page', $queriedObject->post_type);
$this->assertEquals($this->homeForBookId, $queriedObject->ID);
}

public function testUnregisteredCptDoesNotHijackQuery(): void
{
$bookHomeUrl = $this->getBookHomeUrl();

unregister_post_type(self::BOOK_POST_TYPE);

flush_rewrite_rules();

$this->get($bookHomeUrl);

global $wp_query;

$this->assertTrue($wp_query->is_page);
$this->assertFalse($wp_query->is_home);
$this->assertFalse(\n5s\PageForCustomPostType\is_page_for_custom_post_type());
}

public function testNonEligibleCptDeletesMappingOnRegistration(): void
{
$bookHomeUrl = $this->getBookHomeUrl();

$this->assertNotFalse(get_option('page_for_' . self::BOOK_POST_TYPE));

unregister_post_type(self::BOOK_POST_TYPE);
register_post_type(self::BOOK_POST_TYPE, [
'public' => false,
'publicly_queryable' => false,
'label' => 'Books',
]);

$this->assertFalse(get_option('page_for_' . self::BOOK_POST_TYPE));

flush_rewrite_rules();

$this->get($bookHomeUrl);

global $wp_query;

$this->assertTrue($wp_query->is_page);
$this->assertFalse($wp_query->is_home);
$this->assertFalse(\n5s\PageForCustomPostType\is_page_for_custom_post_type());
}
}
Loading