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
3 changes: 2 additions & 1 deletion RELEASE-NOTES.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
26.6
-----
* [*] Fix horizontal insets in Reader article view [#25010]


26.5
Expand All @@ -11,13 +10,15 @@
* [*] Add "Access" section to "Post Settings" [#24942]
* [*] Add "Discussion" to "Post Settings" [#24948]
* [*] Add "File Size" to Site Media Details [#24947]
* [*] Fix an issue with posts duplicated in Discover [#25015]
* [*] Add "Email to Subscribers" row to "Publishing" sheet [#24946]
* [*] Add permalink preview in the slug editor and make other improvements [#24949]
* [*] Add two accessible font sizes to Reader display settings [#25013]
* [*] Add "Taxonomies" to Site Settings [#24955]
* [*] Update "Categories" picker to indicate multiple selection [#24952]
* [*] Fix overly long related post titles in Reader [#25011]
* [*] Increase number of lines for post tiles in Reader to three [#25019]
* [*] Fix horizontal insets in Reader article view [#25010]

26.4
-----
Expand Down
36 changes: 29 additions & 7 deletions Sources/WordPressData/Swift/ReaderCard+CoreDataClass.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,25 +43,47 @@ public class ReaderCard: NSManagedObject {
sites?.array as? [ReaderSiteTopic] ?? []
}

public convenience init?(context: NSManagedObjectContext, from remoteCard: RemoteReaderCard) {
public static func createOrReuse(context: NSManagedObjectContext, from remoteCard: RemoteReaderCard) -> ReaderCard? {
guard remoteCard.type != .unknown else {
return nil
}

self.init(context: context)

switch remoteCard.type {
case .post:
post = ReaderPost.createOrReplace(fromRemotePost: remoteCard.post, for: nil, context: context)
let post = ReaderPost.createOrReplace(fromRemotePost: remoteCard.post, for: nil, context: context)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can update the ReaderPost.createOrReplace signature to declare a nonnull return type, and then the ReaderPost? in findExistingCard(with post: ReaderPost?, ...) can become non-optional ReaderPost.

Copy link
Contributor Author

@kean kean Nov 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather keep the changes to the minimum. I'm not completely sure createOrReplace is non-optional. It looks like it is.

The containing function will still return optional for now due to:

guard remoteCard.type != .unknown else {
            return nil
        }


// Check if a card already exists with this post to prevent duplicates
if let existingCard = findExistingCard(with: post, context: context) {
return existingCard
}

let card = ReaderCard(context: context)
card.post = post
return card

case .interests:
return nil // Disabled in v26.6
return nil // Disabled in v26.5
case .sites:
sites = NSOrderedSet(array: remoteCard.sites?.prefix(3).map {
let card = ReaderCard(context: context)
card.sites = NSOrderedSet(array: remoteCard.sites?.prefix(3).map {
ReaderSiteTopic.createIfNeeded(from: $0, context: context)
} ?? [])
return card

default:
break
return nil
}
}

private static func findExistingCard(with post: ReaderPost?, context: NSManagedObjectContext) -> ReaderCard? {
guard let post else {
return nil
}

let fetchRequest = ReaderCard.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "post = %@", post)
fetchRequest.fetchLimit = 1

return try? context.fetch(fetchRequest).first
}
}
8 changes: 4 additions & 4 deletions Tests/KeystoneTests/Tests/Models/ReaderCardTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class ReaderCardTests: CoreDataTestCase {
let expectation = self.expectation(description: "Create a Reader Card of type post")

remoteCard(ofType: .post) { remoteCard in
let card = ReaderCard(context: self.mainContext, from: remoteCard)
let card = ReaderCard.createOrReuse(context: self.mainContext, from: remoteCard)

expect(card?.post).toNot(beNil())
expect(card?.post?.postTitle).to(equal("Pats, Please"))
Expand All @@ -28,7 +28,7 @@ class ReaderCardTests: CoreDataTestCase {
let expectation = self.expectation(description: "Create a Reader Card of type interests")

remoteCard(ofType: .interests) { remoteCard in
let card = ReaderCard(context: self.mainContext, from: remoteCard)
let card = ReaderCard.createOrReuse(context: self.mainContext, from: remoteCard)
let topics = card?.topicsArray

// THEN return 0 as these were disabled in 26.5
Expand All @@ -45,7 +45,7 @@ class ReaderCardTests: CoreDataTestCase {
let expectation = self.expectation(description: "Create a Reader Card of type sites")

remoteCard(ofType: .sites) { remoteCard in
let card = ReaderCard(context: self.mainContext, from: remoteCard)
let card = ReaderCard.createOrReuse(context: self.mainContext, from: remoteCard)
let topics = card?.sitesArray

expect(topics?.count).to(equal(1))
Expand All @@ -63,7 +63,7 @@ class ReaderCardTests: CoreDataTestCase {
let expectation = self.expectation(description: "Don't create a Reader Card")

remoteCard(ofType: .unknown) { remoteCard in
let card = ReaderCard(context: self.mainContext, from: remoteCard)
let card = ReaderCard.createOrReuse(context: self.mainContext, from: remoteCard)

expect(card).to(beNil())
expectation.fulfill()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class ReaderCardServiceTests: CoreDataTestCase {

service.fetch(isFirstPage: true, success: { _, _ in
let cards = try? self.mainContext.fetch(NSFetchRequest(entityName: ReaderCard.classNameWithoutNamespaces()))
expect(cards?.count).to(equal(10))
expect(cards?.count).to(equal(9))
expectation.fulfill()
}, failure: { _ in })

Expand Down Expand Up @@ -74,7 +74,7 @@ class ReaderCardServiceTests: CoreDataTestCase {
// Fetch again, this time the 1st page
service.fetch(isFirstPage: true, success: { _, _ in
let cards = try? self.mainContext.fetch(NSFetchRequest(entityName: ReaderCard.classNameWithoutNamespaces())) as? [ReaderCard]
expect(cards?.count).to(equal(10))
expect(cards?.count).to(equal(9))
expectation.fulfill()
}, failure: { _ in })
}, failure: {_ in })
Expand Down
2 changes: 1 addition & 1 deletion WordPress/Classes/Services/ReaderCardService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ class ReaderCardService {
}

updatedCards.enumerated().forEach { index, remoteCard in
let card = ReaderCard(context: context, from: remoteCard)
let card = ReaderCard.createOrReuse(context: context, from: remoteCard)

// Assign each interest an endpoint
card?
Expand Down