Skip to content

Commit 52a5588

Browse files
committed
Post Settings: Support custom taxonomies
1 parent 8326351 commit 52a5588

31 files changed

+639
-84
lines changed

Modules/Sources/WordPressKit/RemotePostParameters.swift

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ public struct RemotePostCreateParameters: Equatable {
2121
public var format: String?
2222
public var isSticky = false
2323
public var tags: [String] = []
24+
public var otherTerms: [String: [String]] = [:]
2425
public var categoryIDs: [Int] = []
2526
public var metadata: Set<RemotePostMetadataItem> = []
2627
public var discussion: RemotePostDiscussionSettings = .default
@@ -52,6 +53,7 @@ public struct RemotePostUpdateParameters: Equatable {
5253
public var format: String??
5354
public var isSticky: Bool?
5455
public var tags: [String]?
56+
public var otherTerms: [String: [String]]?
5557
public var categoryIDs: [Int]?
5658
public var metadata: Set<RemotePostMetadataItem>?
5759
public var discussion: RemotePostDiscussionSettings?
@@ -138,6 +140,9 @@ extension RemotePostCreateParameters {
138140
if previous.tags != tags {
139141
changes.tags = tags
140142
}
143+
if !RemotePost.compareOtherTerms(previous.otherTerms, withAnother: otherTerms) {
144+
changes.otherTerms = otherTerms
145+
}
141146
if Set(previous.categoryIDs) != Set(categoryIDs) {
142147
changes.categoryIDs = categoryIDs
143148
}
@@ -191,6 +196,9 @@ extension RemotePostCreateParameters {
191196
if let tags = changes.tags {
192197
self.tags = tags
193198
}
199+
if let otherTerms = changes.otherTerms {
200+
self.otherTerms = otherTerms
201+
}
194202
if let categoryIDs = changes.categoryIDs {
195203
self.categoryIDs = categoryIDs
196204
}
@@ -253,9 +261,19 @@ struct RemotePostCreateParametersWordPressComEncoder: Encodable {
253261

254262
// Posts
255263
try container.encodeIfPresent(parameters.format, forKey: .format)
264+
265+
// Terms (including tags)
266+
var terms = [String: [String]]()
256267
if !parameters.tags.isEmpty {
257-
try container.encode([RemotePostWordPressComCodingKeys.postTags: parameters.tags], forKey: .terms)
268+
terms[RemotePostWordPressComCodingKeys.postTags] = parameters.tags
258269
}
270+
if !parameters.otherTerms.isEmpty {
271+
terms.merge(parameters.otherTerms) { old, _ in old }
272+
}
273+
if !terms.isEmpty {
274+
try container.encode(terms, forKey: .terms)
275+
}
276+
259277
if !parameters.categoryIDs.isEmpty {
260278
try container.encodeIfPresent(parameters.categoryIDs, forKey: .categoryIDs)
261279
}
@@ -330,16 +348,25 @@ struct RemotePostUpdateParametersWordPressComEncoder: Encodable {
330348
try container.encode(metadata, forKey: .metadata)
331349
}
332350

351+
// Terms (including tags)
352+
var terms = [String: [String]]()
353+
if let tags = parameters.tags, !tags.isEmpty {
354+
terms[RemotePostWordPressComCodingKeys.postTags] = tags
355+
}
356+
if let otherTerms = parameters.otherTerms, !otherTerms.isEmpty {
357+
terms.merge(otherTerms) { old, _ in old }
358+
}
359+
if !terms.isEmpty {
360+
try container.encode(terms, forKey: .terms)
361+
}
362+
333363
// Pages
334364
if let parentPageID = parameters.parentPageID {
335365
try container.encodeNullableID(parentPageID, forKey: .parentPageID)
336366
}
337367

338368
// Posts
339369
try container.encodeIfPresent(parameters.format, forKey: .format)
340-
if let tags = parameters.tags {
341-
try container.encode([RemotePostWordPressComCodingKeys.postTags: tags], forKey: .terms)
342-
}
343370
try container.encodeIfPresent(parameters.categoryIDs, forKey: .categoryIDs)
344371
try container.encodeIfPresent(parameters.isSticky, forKey: .isSticky)
345372
if let discussion = parameters.discussion {
@@ -395,14 +422,23 @@ struct RemotePostCreateParametersXMLRPCEncoder: Encodable {
395422
try container.encode(metadata, forKey: .metadata)
396423
}
397424

425+
// Terms (including tags)
426+
var terms = [String: [String]]()
427+
if !parameters.tags.isEmpty {
428+
terms[RemotePostXMLRPCCodingKeys.taxonomyTag] = parameters.tags
429+
}
430+
if !parameters.otherTerms.isEmpty {
431+
terms.merge(parameters.otherTerms) { old, _ in old }
432+
}
433+
if !terms.isEmpty {
434+
try container.encode(terms, forKey: .termNames)
435+
}
436+
398437
// Pages
399438
try container.encodeIfPresent(parameters.parentPageID, forKey: .parentPageID)
400439

401440
// Posts
402441
try container.encodeIfPresent(parameters.format, forKey: .format)
403-
if !parameters.tags.isEmpty {
404-
try container.encode([RemotePostXMLRPCCodingKeys.taxonomyTag: parameters.tags], forKey: .termNames)
405-
}
406442
if !parameters.categoryIDs.isEmpty {
407443
try container.encode([RemotePostXMLRPCCodingKeys.taxonomyCategory: parameters.categoryIDs], forKey: .terms)
408444
}
@@ -438,16 +474,25 @@ struct RemotePostUpdateParametersXMLRPCEncoder: Encodable {
438474
try container.encode(metadata, forKey: .metadata)
439475
}
440476

477+
// Terms (including tags)
478+
var terms = [String: [String]]()
479+
if let tags = parameters.tags, !tags.isEmpty {
480+
terms[RemotePostXMLRPCCodingKeys.taxonomyTag] = tags
481+
}
482+
if let otherTerms = parameters.otherTerms, !otherTerms.isEmpty {
483+
terms.merge(otherTerms) { old, _ in old }
484+
}
485+
if !terms.isEmpty {
486+
try container.encode(terms, forKey: .termNames)
487+
}
488+
441489
// Pages
442490
if let parentPageID = parameters.parentPageID {
443491
try container.encodeNullableID(parentPageID, forKey: .parentPageID)
444492
}
445493

446494
// Posts
447495
try container.encodeStringIfPresent(parameters.format, forKey: .format)
448-
if let tags = parameters.tags {
449-
try container.encode([RemotePostXMLRPCCodingKeys.taxonomyTag: tags], forKey: .termNames)
450-
}
451496
if let categoryIDs = parameters.categoryIDs {
452497
try container.encode([RemotePostXMLRPCCodingKeys.taxonomyCategory: categoryIDs], forKey: .terms)
453498
}

Modules/Sources/WordPressKitObjC/PostServiceRemoteREST.m

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import "PostServiceRemoteREST.h"
22
#import "RemotePost.h"
33
#import "RemotePostCategory.h"
4+
#import "RemotePostTerm.h"
45
#import "FilePart.h"
56
#import "WPMapFilterReduce.h"
67
#import "DisplayableImageHelper.h"
@@ -453,6 +454,7 @@ + (RemotePost *)remotePostFromJSONDictionary:(NSDictionary *)jsonPost {
453454
post.categories = [self remoteCategoriesFromJSONArray:[categories allValues]];
454455
}
455456
post.tags = [self tagNamesFromJSONDictionary:jsonPost[@"tags"]];
457+
post.otherTerms = [RemotePostTerm simpleMappingRepresentation:[self otherTermsFromJSONDictionary:jsonPost[@"terms"]]];
456458

457459
post.revisions = [jsonPost arrayForKey:@"revisions"];
458460

@@ -522,11 +524,19 @@ - (NSDictionary *)parametersWithRemotePost:(RemotePost *)post
522524
parameters[@"categories_by_id"] = [post.categories valueForKey:@"categoryID"];
523525
}
524526

525-
if (post.tags) {
526-
NSArray *tags = post.tags;
527-
NSDictionary *postTags = @{@"post_tag":tags};
528-
parameters[@"terms"] = postTags;
527+
{
528+
NSMutableDictionary *terms = [NSMutableDictionary dictionary];
529+
if (post.tags) {
530+
terms[@"post_tag"] = post.tags;
531+
}
532+
[post.otherTerms enumerateKeysAndObjectsUsingBlock:^(NSString *taxonomy, NSArray<NSString *> *theTerms, BOOL *stop) {
533+
terms[taxonomy] = theTerms;
534+
}];
535+
if (terms.count > 0) {
536+
parameters[@"terms"] = terms;
537+
}
529538
}
539+
530540
if (post.format) {
531541
parameters[@"format"] = post.format;
532542
}
@@ -596,6 +606,26 @@ + (NSArray *)tagNamesFromJSONDictionary:(NSDictionary *)jsonTags {
596606
return [jsonTags allKeys];
597607
}
598608

609+
+ (NSArray<RemotePostTerm *> *)otherTermsFromJSONDictionary:(NSDictionary *)terms {
610+
NSMutableArray<RemotePostTerm *> *otherTerms = [NSMutableArray array];
611+
612+
for (NSString *taxonomySlug in terms) {
613+
if ([taxonomySlug isEqualToString:@"category"] ||
614+
[taxonomySlug isEqualToString:@"post_tag"] ||
615+
[taxonomySlug isEqualToString:@"post_format"]) {
616+
continue;
617+
}
618+
619+
NSDictionary *taxonomyTerms = terms[taxonomySlug];
620+
for (NSString *termKey in taxonomyTerms) {
621+
NSDictionary *termData = taxonomyTerms[termKey];
622+
[otherTerms addObject:[[RemotePostTerm alloc] initWithRESTAPIResponse:termData taxonomySlug:taxonomySlug]];
623+
}
624+
}
625+
626+
return [otherTerms copy];
627+
}
628+
599629
/**
600630
* @brief Returns an array of RemoteLikeUser based on provided JSON
601631
* representation of users.

Modules/Sources/WordPressKitObjC/PostServiceRemoteXMLRPC.m

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#import "PostServiceRemoteXMLRPC.h"
22
#import "RemotePost.h"
33
#import "RemotePostCategory.h"
4+
#import "RemotePostTerm.h"
45
#import "NSMutableDictionary+Helpers.h"
56
#import "NSString+Helpers.h"
67
#import "WPMapFilterReduce.h"
@@ -333,6 +334,7 @@ + (RemotePost *)remotePostFromXMLRPCDictionary:(NSDictionary *)xmlrpcDictionary
333334
NSArray *terms = [xmlrpcDictionary arrayForKey:@"terms"];
334335
post.tags = [self tagsFromXMLRPCTermsArray:terms];
335336
post.categories = [self remoteCategoriesFromXMLRPCTermsArray:terms];
337+
post.otherTerms = [RemotePostTerm simpleMappingRepresentation:[self otherTermsFromXMLRPCTermsArray:terms]];
336338

337339
post.commentsStatus = [xmlrpcDictionary stringForKey:@"comment_status"];
338340
post.pingsStatus = [xmlrpcDictionary stringForKey:@"ping_status"];
@@ -373,6 +375,15 @@ + (NSArray *)remoteCategoriesFromXMLRPCTermsArray:(NSArray *)terms {
373375
}];
374376
}
375377

378+
+ (NSArray<RemotePostTerm *> *)otherTermsFromXMLRPCTermsArray:(NSArray *)terms {
379+
return [[terms wpkit_filter:^BOOL(NSDictionary *category) {
380+
return ![[category stringForKey:@"taxonomy"] isEqualToString:@"category"]
381+
&& ![[category stringForKey:@"taxonomy"] isEqualToString:@"post_tag"];
382+
}] wpkit_map:^id(NSDictionary *term) {
383+
return [[RemotePostTerm alloc] initWithXMLRPCResponse:term];
384+
}];
385+
}
386+
376387
+ (RemotePostCategory *)remoteCategoryFromXMLRPCDictionary:(NSDictionary *)xmlrpcCategory {
377388
RemotePostCategory *category = [RemotePostCategory new];
378389
category.categoryID = [xmlrpcCategory numberForKey:@"term_id"];
@@ -425,6 +436,10 @@ - (NSDictionary *)parametersWithRemotePost:(RemotePost *)post
425436
postParams[@"categories"] = categoryNames;
426437
}
427438

439+
if (post.otherTerms.count > 0) {
440+
postParams[@"terms_names"] = post.otherTerms;
441+
}
442+
428443
if ([post.metadata count] > 0) {
429444
postParams[@"custom_fields"] = post.metadata;
430445
}

Modules/Sources/WordPressKitObjC/RemotePost.m

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,25 @@ - (id)initWithSiteID:(NSNumber *)siteID status:(NSString *)status title:(NSStrin
2323
return self;
2424
}
2525

26+
+ (BOOL)compareOtherTerms:(NSDictionary<NSString *, NSArray<NSString *> *> *)lhs withAnother:(NSDictionary<NSString *, NSArray<NSString *> *> *)rhs
27+
{
28+
if (lhs.count != rhs.count) {
29+
return NO;
30+
}
31+
32+
NSMutableDictionary<NSString *, NSSet<NSString *> *> *lhsNormalized = [NSMutableDictionary dictionary];
33+
for (NSString *key in lhs) {
34+
lhsNormalized[key] = [NSSet setWithArray:lhs[key]];
35+
}
36+
37+
NSMutableDictionary<NSString *, NSSet<NSString *> *> *rhsNormalized = [NSMutableDictionary dictionary];
38+
for (NSString *key in rhs) {
39+
rhsNormalized[key] = [NSSet setWithArray:rhs[key]];
40+
}
41+
42+
return [lhsNormalized isEqualToDictionary:rhsNormalized];
43+
}
44+
2645
- (NSString *)debugDescription {
2746
NSDictionary *properties = [self debugProperties];
2847
return [NSString stringWithFormat:@"<%@: %p> (%@)", NSStringFromClass([self class]), self, properties];
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
#import "RemotePostTerm.h"
2+
3+
@import NSObject_SafeExpectations;
4+
5+
@implementation RemotePostTerm
6+
7+
- (instancetype)initWithXMLRPCResponse:(NSDictionary *)response
8+
{
9+
self = [super init];
10+
if (self) {
11+
self.termID = [response numberForKey:@"term_id"];
12+
self.name = [response stringForKey:@"name"];
13+
self.slug = [response stringForKey:@"slug"];
14+
self.taxonomySlug = [response stringForKey:@"taxonomy"];
15+
self.termDescription = [response stringForKey:@"description"];
16+
self.count = [response numberForKey:@"count"];
17+
}
18+
return self;
19+
}
20+
21+
- (instancetype)initWithRESTAPIResponse:(NSDictionary *)response taxonomySlug:(NSString *)taxonomySlug
22+
{
23+
self = [super init];
24+
if (self) {
25+
self.termID = [response numberForKey:@"ID"];
26+
self.name = [response stringForKey:@"name"];
27+
self.slug = [response stringForKey:@"slug"];
28+
self.taxonomySlug = taxonomySlug;
29+
self.termDescription = [response stringForKey:@"description"];
30+
self.count = [response numberForKey:@"post_count"];
31+
}
32+
return self;
33+
}
34+
35+
- (NSDictionary *)RESTAPIRepresentation
36+
{
37+
return @{
38+
@"ID": self.termID,
39+
@"name": self.name,
40+
@"slug": self.slug,
41+
@"description": self.termDescription ?: @"",
42+
@"post_count": self.count
43+
};
44+
}
45+
46+
+ (NSDictionary<NSString *, NSArray<NSString *> *> *)simpleMappingRepresentation:(NSArray<RemotePostTerm *> *)terms
47+
{
48+
NSMutableDictionary<NSString *, NSMutableArray<NSString *> *> *dict = [NSMutableDictionary dictionary];
49+
for (RemotePostTerm *term in terms) {
50+
NSMutableArray *termNames = dict[term.taxonomySlug];
51+
if (termNames == nil) {
52+
termNames = [NSMutableArray array];
53+
dict[term.taxonomySlug] = termNames;
54+
}
55+
[termNames addObject:term.name];
56+
}
57+
return [dict copy];
58+
}
59+
60+
- (NSString *)debugDescription
61+
{
62+
NSDictionary *properties = @{
63+
@"ID": self.termID,
64+
@"name": self.name
65+
};
66+
return [NSString stringWithFormat:@"<%@: %p> (%@)", NSStringFromClass([self class]), self, properties];
67+
}
68+
69+
- (NSString *)description
70+
{
71+
return [NSString stringWithFormat:@"<%@: %p> %@[%@]", NSStringFromClass([self class]), self, self.name, self.termID];
72+
}
73+
74+
@end

Modules/Sources/WordPressKitObjC/include/RemotePost.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#import <Foundation/Foundation.h>
2+
23
@class RemotePostAutosave;
4+
@class RemotePostTerm;
35

46
extern NSString * const PostStatusDraft;
57
extern NSString * const PostStatusPending;
@@ -54,6 +56,8 @@ extern NSString * const PostStatusDeleted;
5456
@property (nonatomic, strong) NSArray *categories;
5557
@property (nonatomic, strong) NSArray *revisions;
5658
@property (nonatomic, strong) NSArray *tags;
59+
//@property (nonatomic, strong) NSArray<RemotePostTerm *> *otherTerms;
60+
@property (nonatomic, strong) NSDictionary<NSString *, NSArray<NSString *> *> *otherTerms;
5761
@property (nonatomic, strong) NSString *pathForDisplayImage;
5862
@property (nonatomic, assign) NSNumber *isStickyPost;
5963
@property (nonatomic, assign) BOOL isFeaturedImageChanged;
@@ -63,6 +67,8 @@ extern NSString * const PostStatusDeleted;
6367
*/
6468
@property (nonatomic, strong) NSArray *metadata;
6569

70+
+ (BOOL)compareOtherTerms:(NSDictionary<NSString *, NSArray<NSString *> *> *)lhs withAnother:(NSDictionary<NSString *, NSArray<NSString *> *> *)rhs;
71+
6672
// Featured images?
6773
// Geolocation?
6874
// Attachments?

0 commit comments

Comments
 (0)