Skip to content

Re-implement RemoteReaderPost in Swift - Part 1 #561

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: translate-objc-to-swift
Choose a base branch
from
16 changes: 12 additions & 4 deletions WordPressKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@
4A68E3D329406AA0004AC3DC /* RemoteMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D029406AA0004AC3DC /* RemoteMenu.swift */; };
4A68E3D429406AA0004AC3DC /* RemoteMenuItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D129406AA0004AC3DC /* RemoteMenuItem.swift */; };
4A68E3D529406AA0004AC3DC /* RemoteMenuLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D229406AA0004AC3DC /* RemoteMenuLocation.swift */; };
4A68E40B294922A8004AC3DC /* RemoteReaderPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E40A294922A8004AC3DC /* RemoteReaderPost.swift */; };
4A68E40D294930CC004AC3DC /* RemoteReaderPostTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E40C294930CC004AC3DC /* RemoteReaderPostTests.swift */; };
4A68E3D729406DA2004AC3DC /* RemoteUser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D629406DA2004AC3DC /* RemoteUser.swift */; };
4A68E3D929406E0D004AC3DC /* RemoteTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3D829406E0D004AC3DC /* RemoteTheme.swift */; };
4A68E3DB29406EA0004AC3DC /* RemoteSourcePostAttribution.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4A68E3DA29406EA0004AC3DC /* RemoteSourcePostAttribution.swift */; };
Expand Down Expand Up @@ -346,7 +348,7 @@
82FFBF521F45F04100F4573F /* RemoteBlogJetpackMonitorSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82FFBF511F45F04100F4573F /* RemoteBlogJetpackMonitorSettings.swift */; };
82FFBF561F460DD400F4573F /* BlogJetpackSettingsServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = 82FFBF551F460DD400F4573F /* BlogJetpackSettingsServiceRemote.swift */; };
8B074A4E27AC2FFD003A2EB8 /* dashboard-400-invalid-card.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B074A4D27AC2FFD003A2EB8 /* dashboard-400-invalid-card.json */; };
8B16CE8E25250039007BE5A9 /* RemoteReaderPost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B16CE8D25250039007BE5A9 /* RemoteReaderPost.swift */; };
8B16CE8E25250039007BE5A9 /* ReaderPostsEnvelope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B16CE8D25250039007BE5A9 /* ReaderPostsEnvelope.swift */; };
8B16CE92252502C4007BE5A9 /* RemoteReaderPostTests+V2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B16CE91252502C4007BE5A9 /* RemoteReaderPostTests+V2.swift */; };
8B16CE962525045F007BE5A9 /* reader-posts-success.json in Resources */ = {isa = PBXBuildFile; fileRef = 8B16CE952525045F007BE5A9 /* reader-posts-success.json */; };
8B2F4BE524ABB3C70056C08A /* RemoteReaderPostTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 8B2F4BE424ABB3C70056C08A /* RemoteReaderPostTests.m */; };
Expand Down Expand Up @@ -775,6 +777,8 @@
4A68E3D029406AA0004AC3DC /* RemoteMenu.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenu.swift; sourceTree = "<group>"; };
4A68E3D129406AA0004AC3DC /* RemoteMenuItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenuItem.swift; sourceTree = "<group>"; };
4A68E3D229406AA0004AC3DC /* RemoteMenuLocation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteMenuLocation.swift; sourceTree = "<group>"; };
4A68E40A294922A8004AC3DC /* RemoteReaderPost.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderPost.swift; sourceTree = "<group>"; };
4A68E40C294930CC004AC3DC /* RemoteReaderPostTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteReaderPostTests.swift; sourceTree = "<group>"; };
4A68E3D629406DA2004AC3DC /* RemoteUser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteUser.swift; sourceTree = "<group>"; };
4A68E3D829406E0D004AC3DC /* RemoteTheme.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteTheme.swift; sourceTree = "<group>"; };
4A68E3DA29406EA0004AC3DC /* RemoteSourcePostAttribution.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteSourcePostAttribution.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -994,7 +998,7 @@
82FFBF511F45F04100F4573F /* RemoteBlogJetpackMonitorSettings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RemoteBlogJetpackMonitorSettings.swift; sourceTree = "<group>"; };
82FFBF551F460DD400F4573F /* BlogJetpackSettingsServiceRemote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlogJetpackSettingsServiceRemote.swift; sourceTree = "<group>"; };
8B074A4D27AC2FFD003A2EB8 /* dashboard-400-invalid-card.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "dashboard-400-invalid-card.json"; sourceTree = "<group>"; };
8B16CE8D25250039007BE5A9 /* RemoteReaderPost.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteReaderPost.swift; sourceTree = "<group>"; };
8B16CE8D25250039007BE5A9 /* ReaderPostsEnvelope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderPostsEnvelope.swift; sourceTree = "<group>"; };
8B16CE91252502C4007BE5A9 /* RemoteReaderPostTests+V2.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "RemoteReaderPostTests+V2.swift"; sourceTree = "<group>"; };
8B16CE952525045F007BE5A9 /* reader-posts-success.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "reader-posts-success.json"; sourceTree = "<group>"; };
8B2F4BE424ABB3C70056C08A /* RemoteReaderPostTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RemoteReaderPostTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1489,6 +1493,7 @@
7430C9BB1F192C0F0051B8E6 /* ReaderTopicServiceRemoteTests.m */,
17CE77F320C701C8001DEA5A /* ReaderSiteSearchServiceRemoteTests.swift */,
8B2F4BE424ABB3C70056C08A /* RemoteReaderPostTests.m */,
4A68E40C294930CC004AC3DC /* RemoteReaderPostTests.swift */,
8B2F4BE824ABC9DC0056C08A /* ReaderPostServiceRemote+CardsTests.swift */,
FACBDD3725ECB4480026705B /* ReaderPostServiceRemote+RelatedPostsTests.swift */,
FA87FE0624EB39C4003FBEE3 /* ReaderPostServiceRemote+SubscriptionTests.swift */,
Expand Down Expand Up @@ -1927,11 +1932,12 @@
74E2294F1F1E741B0085F7F2 /* RemotePublicizeConnection.swift */,
74E2294D1F1E73FE0085F7F2 /* RemotePublicizeService.swift */,
7430C9D61F1933200051B8E6 /* RemoteReaderCrossPostMeta.swift */,
8B16CE8D25250039007BE5A9 /* RemoteReaderPost.swift */,
8B16CE8D25250039007BE5A9 /* ReaderPostsEnvelope.swift */,
8B2F4BEE24ACCC120056C08A /* RemoteReaderCard.swift */,
8B2F4BF024ACE3C30056C08A /* RemoteReaderInterest.swift */,
7430C9A91F1927C50051B8E6 /* RemoteReaderPost.h */,
7430C9AA1F1927C50051B8E6 /* RemoteReaderPost.m */,
4A68E40A294922A8004AC3DC /* RemoteReaderPost.swift */,
FACBDD1D25ECA7F90026705B /* RemoteReaderSimplePost.swift */,
4A68E3DC294070A7004AC3DC /* RemoteReaderSite.swift */,
4A68E3E0294076C1004AC3DC /* RemoteReaderSiteInfo.swift */,
Expand Down Expand Up @@ -3006,7 +3012,7 @@
F9E56DF624EB11EF00916770 /* FeatureFlag.swift in Sources */,
8B2F4BE724ABC8A90056C08A /* ReaderPostServiceRemote+Cards.swift in Sources */,
4A68E3D529406AA0004AC3DC /* RemoteMenuLocation.swift in Sources */,
8B16CE8E25250039007BE5A9 /* RemoteReaderPost.swift in Sources */,
8B16CE8E25250039007BE5A9 /* ReaderPostsEnvelope.swift in Sources */,
74E2294E1F1E73FE0085F7F2 /* RemotePublicizeService.swift in Sources */,
8B749DED25AF3E4600023F03 /* JetpackCapabilitiesServiceRemote.swift in Sources */,
9F3E0BA22087345F009CB5BA /* ServiceRequest.swift in Sources */,
Expand All @@ -3026,6 +3032,7 @@
9F3E0B9E208733C3009CB5BA /* ReaderServiceDeliveryFrequency.swift in Sources */,
74E2295E1F1E777B0085F7F2 /* RemoteSharingButton.swift in Sources */,
93BD27701EE737A8002BB00B /* ServiceRemoteWordPressComREST.m in Sources */,
4A68E40B294922A8004AC3DC /* RemoteReaderPost.swift in Sources */,
E61A51A621B172A900A5F902 /* RemoteWpcomPlan.swift in Sources */,
93BD277F1EE73944002BB00B /* WordPressComOAuthClient.swift in Sources */,
740B23B91F17EC7300067A2A /* PostServiceRemoteREST.m in Sources */,
Expand Down Expand Up @@ -3235,6 +3242,7 @@
803DE81128FFA9C4007D4E9C /* RemoteConfigRemoteTests.swift in Sources */,
74B5F0DE1EF82A9600B411E7 /* BlogServiceRemoteRESTTests.m in Sources */,
ABD95B7F25DD6C4B00735BEE /* CommentServiceRemoteRESTLikesTests.swift in Sources */,
4A68E40D294930CC004AC3DC /* RemoteReaderPostTests.swift in Sources */,
8B749E8225AF7DDA00023F03 /* JetpackCapabilitiesServiceRemoteTests.swift in Sources */,
74E2294B1F1E73340085F7F2 /* SharingServiceRemoteTests.m in Sources */,
FEFFD99B26C1598F00F34231 /* ShareAppContentServiceRemoteTests.swift in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions WordPressKit/ReaderPostsEnvelope.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation
Copy link
Contributor

Choose a reason for hiding this comment

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

This import might be unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, that's true for the current project setup. But I think it's needed for SPM support.


struct ReaderPostsEnvelope: Decodable {
var posts: [RemoteReaderPost]
var nextPageHandle: String?

private enum CodingKeys: String, CodingKey {
case posts
case nextPageHandle = "next_page_handle"
}

public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
let postDictionary = try container.decode([String: Any].self, forKey: .posts)
posts = [RemoteReaderPost(dictionary: postDictionary)]
}
}
151 changes: 8 additions & 143 deletions WordPressKit/RemoteReaderPost.m
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
NSString * const PostRESTKeyDiscoverMetadata = @"discover_metadata";
NSString * const PostRESTKeyDiscussion = @"discussion";
NSString * const PostRESTKeyEditorial = @"editorial";
NSString * const PostRESTKeyEmail = @"email";
NSString * const PostRESTKeyExcerpt = @"excerpt";
NSString * const PostRESTKeyFeaturedMedia = @"featured_media";
NSString * const PostRESTKeyFeaturedImage = @"featured_image";
Expand All @@ -41,10 +40,6 @@
NSString * const PostRESTKeyScore = @"score";
NSString * const PostRESTKeySharingEnabled = @"sharing_enabled";
NSString * const PostRESTKeySiteID = @"site_ID";
NSString * const PostRESTKeySiteIsAtomic = @"site_is_atomic";
NSString * const PostRESTKeySiteIsPrivate = @"site_is_private";
NSString * const PostRESTKeySiteName = @"site_name";
NSString * const PostRESTKeySiteURL = @"site_URL";
NSString * const PostRESTKeySlug = @"slug";
NSString * const PostRESTKeyStatus = @"status";
NSString * const PostRESTKeyTitle = @"title";
Expand Down Expand Up @@ -74,8 +69,6 @@
NSString * const CrossPostMetaXPostOrigin = @"xpost_origin";
NSString * const CrossPostMetaCommentPrefix = @"comment-";

static const NSInteger AvgWordsPerMinuteRead = 250;
static const NSInteger MinutesToReadThreshold = 2;
static const NSUInteger ReaderPostTitleLength = 30;

@implementation RemoteReaderPost
Expand All @@ -95,12 +88,12 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict;
self.author = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyNiceName]]; // typically the author's screen name
self.authorAvatarURL = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyAvatarURL]];
self.authorDisplayName = [[self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyName]] stringByDecodingXMLCharacters]; // Typically the author's given name
self.authorEmail = [self authorEmailFromAuthorDictionary:authorDict];
self.authorEmail = [RemoteReaderPost authorEmailFromAuthorDictionary:authorDict];
self.authorURL = [self stringOrEmptyString:[authorDict stringForKey:PostRESTKeyURL]];
self.siteIconURL = [self stringOrEmptyString:[dict stringForKeyPath:@"meta.data.site.icon.img"]];
self.blogName = [self siteNameFromPostDictionary:dict];
self.blogName = [RemoteReaderPost siteNameFromPostDictionary:dict];
self.blogDescription = [self siteDescriptionFromPostDictionary:dict];
self.blogURL = [self siteURLFromPostDictionary:dict];
self.blogURL = [RemoteReaderPost siteURLFromPostDictionary:dict];
self.commentCount = [discussionDict numberForKey:PostRESTKeyCommentCount];
self.commentsOpen = [[discussionDict numberForKey:PostRESTKeyCommentsOpen] boolValue];
self.content = [self postContentFromPostDictionary:dict];
Expand All @@ -109,12 +102,12 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict;
self.feedID = [dict numberForKey:PostRESTKeyFeedID];
self.feedItemID = [dict numberForKey:PostRESTKeyFeedItemID];
self.globalID = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyGlobalID]];
self.isBlogAtomic = [self siteIsAtomicFromPostDictionary:dict];
self.isBlogPrivate = [self siteIsPrivateFromPostDictionary:dict];
self.isBlogAtomic = [RemoteReaderPost siteIsAtomicFromPostDictionary:dict];
self.isBlogPrivate = [RemoteReaderPost siteIsPrivateFromPostDictionary:dict];
self.isFollowing = [[dict numberForKey:PostRESTKeyIsFollowing] boolValue];
self.isLiked = [[dict numberForKey:PostRESTKeyILike] boolValue];
self.isReblogged = [[dict numberForKey:PostRESTKeyIsReblogged] boolValue];
self.isWPCom = [self isWPComFromPostDictionary:dict];
self.isWPCom = [RemoteReaderPost isWPComFromPostDictionary:dict];
self.likeCount = [dict numberForKey:PostRESTKeyLikeCount];
self.permalink = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyURL]];
self.postID = [dict numberForKey:PostRESTKeyID];
Expand All @@ -125,7 +118,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict;
self.sortRank = @(self.sortDate.timeIntervalSinceReferenceDate);
self.status = [self stringOrEmptyString:[dict stringForKey:PostRESTKeyStatus]];
self.summary = [self postSummaryFromPostDictionary:dict orPostContent:self.content];
self.tags = [self tagsFromPostDictionary:dict];
self.tags = [RemoteReaderPost tagsFromPostDictionary:dict];
self.isSharingEnabled = [[dict numberForKey:PostRESTKeySharingEnabled] boolValue];
self.isLikesEnabled = [[dict numberForKey:PostRESTKeyLikesEnabled] boolValue];
self.organizationID = [dict numberForKeyPath:PostRESTKeyOrganizationID] ?: @0;
Expand Down Expand Up @@ -157,7 +150,7 @@ - (instancetype)initWithDictionary:(NSDictionary *)dict;
self.isExternal = [[dict numberForKey:PostRESTKeyIsExternal] boolValue];
self.isJetpack = [[dict numberForKey:PostRESTKeyIsJetpack] boolValue];
self.wordCount = [dict numberForKey:PostRESTKeyWordCount];
self.readingTime = [self readingTimeForWordCount:self.wordCount];
self.readingTime = [RemoteReaderPost readingTimeForWordCount:self.wordCount];

NSDictionary *railcar = [dict dictionaryForKey:PostRESTKeyRailcar];
if (railcar) {
Expand Down Expand Up @@ -281,16 +274,6 @@ - (NSDictionary *)primaryAndSecondaryTagsFromPostDictionary:(NSDictionary *)dict
};
}

- (NSNumber *)readingTimeForWordCount:(NSNumber *)wordCount
{
NSInteger count = [wordCount integerValue];
NSInteger minutesToRead = count / AvgWordsPerMinuteRead;
if (minutesToRead < MinutesToReadThreshold) {
return @(0);
}
return @(minutesToRead);
}

/**
Composes discover attribution if needed.

Expand Down Expand Up @@ -394,55 +377,6 @@ - (NSString *)sanitizeFeaturedImageString:(NSString *)img

#pragma mark - Data sanitization methods

/**
The v1 API result is inconsistent in that it will return a 0 when there is no author email.

@param dict The author dictionary.
@return The author's email address or an empty string.
*/
- (NSString *)authorEmailFromAuthorDictionary:(NSDictionary *)dict
{
NSString *authorEmail = [dict stringForKey:PostRESTKeyEmail];

// if 0 or less than minimum email length. [email protected]
if ([authorEmail isEqualToString:@"0"] || [authorEmail length] < 6) {
authorEmail = @"";
}

return authorEmail;
}

/**
Parse whether the post belongs to a wpcom blog.

@param dict A dictionary representing a post object from the REST API
@return YES if the post belongs to a wpcom blog, else NO
*/
- (BOOL)isWPComFromPostDictionary:(NSDictionary *)dict
{
BOOL isExternal = [[dict numberForKey:PostRESTKeyIsExternal] boolValue];
BOOL isJetpack = [[dict numberForKey:PostRESTKeyIsJetpack] boolValue];

return !isJetpack && !isExternal;
}

/**
Get the tags assigned to a post and return them as a comma separated string.

@param dict A dictionary representing a post object from the REST API.
@return A comma separated list of tags, or an empty string if no tags are found.
*/
- (NSString *)tagsFromPostDictionary:(NSDictionary *)dict
{
NSDictionary *tagsDict = [dict dictionaryForKey:PostRESTKeyTags];
NSArray *tagsList = [NSArray arrayWithArray:[tagsDict allKeys]];
NSString *tags = [tagsList componentsJoinedByString:@", "];
if (tags == nil) {
tags = @"";
}
return tags;
}

/**
Get the date the post should be sorted by.

Expand Down Expand Up @@ -528,32 +462,6 @@ - (NSString *)suitableImageFromPostContent:(NSDictionary *)dict {
return [self stringOrEmptyString:imageToDisplay];
}

/**
Get the name of the post's site.

@param dict A dictionary representing a post object from the REST API.
@return The name of the post's site or an empty string.
*/
- (NSString *)siteNameFromPostDictionary:(NSDictionary *)dict
{
// Blog Name
NSString *siteName = [self stringOrEmptyString:[dict stringForKey:PostRESTKeySiteName]];

// For some endpoints blogname is defined in meta
NSString *metaBlogName = [dict stringForKeyPath:@"meta.data.site.name"];
if (metaBlogName != nil) {
siteName = metaBlogName;
}

// Values set in editorial trumps the rest
NSString *editorialSiteName = [dict stringForKeyPath:@"editorial.blog_name"];
if (editorialSiteName != nil) {
siteName = editorialSiteName;
}

return [self makePlainText:siteName];
}

/**
Get the description of the post's site.

Expand All @@ -566,24 +474,6 @@ - (NSString *)siteDescriptionFromPostDictionary:(NSDictionary *)dict
return [self makePlainText:description];
}

/**
Retrives the post site's URL

@param dict A dictionary representing a post object from the REST API.
@return The URL path of the post's site.
*/
- (NSString *)siteURLFromPostDictionary:(NSDictionary *)dict
{
NSString *siteURL = [self stringOrEmptyString:[dict stringForKey:PostRESTKeySiteURL]];

NSString *metaSiteURL = [dict stringForKeyPath:@"meta.data.site.URL"];
if (metaSiteURL != nil) {
siteURL = metaSiteURL;
}

return siteURL;
}

/**
Retrives the post content from results dictionary

Expand Down Expand Up @@ -623,31 +513,6 @@ - (NSString *)postSummaryFromPostDictionary:(NSDictionary *)dict orPostContent:(
return summary;
}

- (BOOL)siteIsAtomicFromPostDictionary:(NSDictionary *)dict
{
NSNumber *isAtomic = [dict numberForKey:PostRESTKeySiteIsAtomic];

return [isAtomic boolValue];
}

/**
Retrives the privacy preference for the post's site.

@param dict A dictionary representing a post object from the REST API.
@return YES if the site is private.
*/
- (BOOL)siteIsPrivateFromPostDictionary:(NSDictionary *)dict
{
NSNumber *isPrivate = [dict numberForKey:PostRESTKeySiteIsPrivate];

NSNumber *metaIsPrivate = [dict numberForKeyPath:@"meta.data.site.is_private"];
if (metaIsPrivate != nil) {
isPrivate = metaIsPrivate;
}

return [isPrivate boolValue];
}

- (NSArray *)slugsFromDiscoverPostTaxonomies:(NSArray *)discoverPostTaxonomies
{
return [discoverPostTaxonomies wp_map:^id(NSDictionary *dict) {
Expand Down
Loading