From 635db4501c5b514cd85fcfdc8da91f3df5dc7285 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 28 Jul 2026 21:31:05 +1200 Subject: [PATCH 1/3] Exclude built-in types from custom post type pins --- .../CustomPostTypes/PinnedPostTypeTests.swift | 23 +++++++++++++++++++ .../BlogDetailsTableViewModel.swift | 2 ++ .../CustomPostTypes/PinnedPostTypeView.swift | 4 ++++ 3 files changed, 29 insertions(+) create mode 100644 Tests/KeystoneTests/Tests/Features/CustomPostTypes/PinnedPostTypeTests.swift diff --git a/Tests/KeystoneTests/Tests/Features/CustomPostTypes/PinnedPostTypeTests.swift b/Tests/KeystoneTests/Tests/Features/CustomPostTypes/PinnedPostTypeTests.swift new file mode 100644 index 000000000000..2700288a0f63 --- /dev/null +++ b/Tests/KeystoneTests/Tests/Features/CustomPostTypes/PinnedPostTypeTests.swift @@ -0,0 +1,23 @@ +import Testing + +@testable import WordPress + +@Suite("PinnedPostType") +struct PinnedPostTypeTests { + @Test("identifies the built-in post type") + func identifiesPosts() { + #expect(PinnedPostType.posts.isBuiltInPostOrPage) + } + + @Test("identifies the built-in page type") + func identifiesPages() { + #expect(PinnedPostType.pages.isBuiltInPostOrPage) + } + + @Test("does not identify a custom post type as built-in") + func acceptsCustomPostType() { + let postType = PinnedPostType(slug: "book", name: "Books", icon: nil) + + #expect(!postType.isBuiltInPostOrPage) + } +} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift index eaa328b125ca..cf4a506754d1 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift @@ -595,6 +595,7 @@ private extension BlogDetailsTableViewModel { if FeatureFlag.customPostTypes.enabled && blog.supportsCoreRESTAPI { let pinned = SiteStorageAccess.pinnedPostTypes(for: TaggedManagedObjectID(blog)) + .filter { !$0.isBuiltInPostOrPage } for type in pinned { rows.append(Row.pinnedPostType(type, viewController: viewController)) } @@ -679,6 +680,7 @@ private extension BlogDetailsTableViewModel { if FeatureFlag.customPostTypes.enabled && blog.supportsCoreRESTAPI { let pinned = SiteStorageAccess.pinnedPostTypes(for: TaggedManagedObjectID(blog)) + .filter { !$0.isBuiltInPostOrPage } for type in pinned { rows.append(Row.pinnedPostType(type, viewController: viewController)) } diff --git a/WordPress/Classes/ViewRelated/CustomPostTypes/PinnedPostTypeView.swift b/WordPress/Classes/ViewRelated/CustomPostTypes/PinnedPostTypeView.swift index 4e28e17a7a1b..f3d6eb98ebf2 100644 --- a/WordPress/Classes/ViewRelated/CustomPostTypes/PinnedPostTypeView.swift +++ b/WordPress/Classes/ViewRelated/CustomPostTypes/PinnedPostTypeView.swift @@ -92,6 +92,10 @@ struct PinnedPostType: Codable, Hashable { extension PinnedPostType { // TODO: Ideally use the post type details directly instead of PinnedPostType, // once the CPT infrastructure is more mature. + var isBuiltInPostOrPage: Bool { + slug == Self.posts.slug || slug == Self.pages.slug + } + static let posts = PinnedPostType(slug: "post", name: "Posts", icon: nil) static let pages = PinnedPostType(slug: "page", name: "Pages", icon: nil) } From c3cfdc3324b0a628684168f43c4a4cd10be8ae10 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 28 Jul 2026 21:41:48 +1200 Subject: [PATCH 2/3] Remove Custom Post Types feature flag --- .../CustomPostTypeServiceTests.swift | 34 +++++++++++++++++++ .../BuildInformation/FeatureFlag.swift | 4 --- .../BlogDetailsTableViewModel.swift | 4 +-- .../CustomPostTypeService.swift | 2 +- .../ExperimentalFeaturesDataProvider.swift | 1 - 5 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 Tests/KeystoneTests/Tests/Features/CustomPostTypes/CustomPostTypeServiceTests.swift diff --git a/Tests/KeystoneTests/Tests/Features/CustomPostTypes/CustomPostTypeServiceTests.swift b/Tests/KeystoneTests/Tests/Features/CustomPostTypes/CustomPostTypeServiceTests.swift new file mode 100644 index 000000000000..25f91c0af974 --- /dev/null +++ b/Tests/KeystoneTests/Tests/Features/CustomPostTypes/CustomPostTypeServiceTests.swift @@ -0,0 +1,34 @@ +import Testing +import WordPressData + +@testable import WordPress + +@MainActor +@Suite("CustomPostTypeService") +struct CustomPostTypeServiceTests { + @Test("rejects a WordPress.com Simple site") + func rejectsSimpleSite() { + let contextManager = ContextManager.forTesting() + let blog = BlogBuilder(contextManager.mainContext) + .with(atomic: false) + .isHostedAtWPcom() + .withAnAccount() + .build() + + #expect(!blog.supportsCoreRESTAPI) + #expect(CustomPostTypeService(blog: blog) == nil) + } + + @Test("accepts a WordPress.com Atomic site") + func acceptsAtomicSite() { + let contextManager = ContextManager.forTesting() + let blog = BlogBuilder(contextManager.mainContext) + .with(atomic: true) + .isHostedAtWPcom() + .withAnAccount() + .build() + + #expect(blog.supportsCoreRESTAPI) + #expect(CustomPostTypeService(blog: blog) != nil) + } +} diff --git a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift index 90fac5e2cee0..e51025a726c3 100644 --- a/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift +++ b/WordPress/Classes/Utility/BuildInformation/FeatureFlag.swift @@ -26,7 +26,6 @@ public enum FeatureFlag: Int, CaseIterable { case newSupport case nativeBlockInserter case statsAds - case customPostTypes case mediaLibraryV2 /// Returns a boolean indicating if the feature is enabled. @@ -85,8 +84,6 @@ public enum FeatureFlag: Int, CaseIterable { return true case .statsAds: return BuildConfiguration.current == .debug - case .customPostTypes: - return BuildConfiguration.current == .debug case .mediaLibraryV2: return BuildConfiguration.current == .debug } @@ -131,7 +128,6 @@ extension FeatureFlag { case .newSupport: "New Support" case .nativeBlockInserter: "Native Block Inserter" case .statsAds: "Stats Ads Tab" - case .customPostTypes: "Custom Post Types" case .mediaLibraryV2: "Media Library v2" } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift index cf4a506754d1..514c22165e9b 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsTableViewModel.swift @@ -593,7 +593,7 @@ private extension BlogDetailsTableViewModel { rows.append(Row.media(viewController: viewController)) rows.append(Row.comments(viewController: viewController)) - if FeatureFlag.customPostTypes.enabled && blog.supportsCoreRESTAPI { + if blog.supportsCoreRESTAPI { let pinned = SiteStorageAccess.pinnedPostTypes(for: TaggedManagedObjectID(blog)) .filter { !$0.isBuiltInPostOrPage } for type in pinned { @@ -678,7 +678,7 @@ private extension BlogDetailsTableViewModel { rows.append(Row.comments(viewController: viewController)) - if FeatureFlag.customPostTypes.enabled && blog.supportsCoreRESTAPI { + if blog.supportsCoreRESTAPI { let pinned = SiteStorageAccess.pinnedPostTypes(for: TaggedManagedObjectID(blog)) .filter { !$0.isBuiltInPostOrPage } for type in pinned { diff --git a/WordPress/Classes/ViewRelated/CustomPostTypes/CustomPostTypeService.swift b/WordPress/Classes/ViewRelated/CustomPostTypes/CustomPostTypeService.swift index 4e828934e4e1..92be11c2dd80 100644 --- a/WordPress/Classes/ViewRelated/CustomPostTypes/CustomPostTypeService.swift +++ b/WordPress/Classes/ViewRelated/CustomPostTypes/CustomPostTypeService.swift @@ -17,7 +17,7 @@ class CustomPostTypeService { } init?(blog: Blog) { - guard FeatureFlag.customPostTypes.enabled, let site = try? WordPressSite(blog: blog) else { return nil } + guard blog.supportsCoreRESTAPI, let site = try? WordPressSite(blog: blog) else { return nil } self.blog = TaggedManagedObjectID(blog) self.client = WordPressClientFactory.shared.instance(for: site) } diff --git a/WordPress/Classes/ViewRelated/Me/App Settings/ExperimentalFeaturesDataProvider.swift b/WordPress/Classes/ViewRelated/Me/App Settings/ExperimentalFeaturesDataProvider.swift index 1cc02bc588e7..fb6990624a4c 100644 --- a/WordPress/Classes/ViewRelated/Me/App Settings/ExperimentalFeaturesDataProvider.swift +++ b/WordPress/Classes/ViewRelated/Me/App Settings/ExperimentalFeaturesDataProvider.swift @@ -9,7 +9,6 @@ class ExperimentalFeaturesDataProvider: ExperimentalFeaturesViewModel.DataProvid FeatureFlag.intelligence, FeatureFlag.newStats, RemoteFeatureFlag.newGutenberg, - FeatureFlag.customPostTypes, FeatureFlag.newSupport, ] From c475fda7c063abf662030e906365f178e5a23c25 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Wed, 29 Jul 2026 09:26:53 +1200 Subject: [PATCH 3/3] Add a release note --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 718fbe84fd7c..ff12a9729966 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,5 +1,6 @@ 27.2 ----- +* [*] Custom Post Types: Make custom post types with REST API and editor support available in My Site [#25849] 27.1