Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.
Merged
4 changes: 2 additions & 2 deletions Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ PODS:
- OHHTTPStubs/Swift (6.1.0):
- OHHTTPStubs/Default
- UIDeviceIdentifier (1.1.4)
- WordPressKit (1.7.0-beta.4):
- WordPressKit (1.8.0-beta.1):
- Alamofire (~> 4.7.3)
- CocoaLumberjack (= 3.4.2)
- NSObject-SafeExpectations (= 0.0.3)
Expand Down Expand Up @@ -70,7 +70,7 @@ SPEC CHECKSUMS:
OCMock: 43565190abc78977ad44a61c0d20d7f0784d35ab
OHHTTPStubs: 1e21c7d2c084b8153fc53d48400d8919d2d432d0
UIDeviceIdentifier: 8f8a24b257a4d978c8d40ad1e7355b944ffbfa8c
WordPressKit: c46c1ec1e175282742e88a851d0066c77eed1cbd
WordPressKit: f2edbc8f99f7c698306193cfe216fd6e5b74fa54
WordPressShared: a2fc2db66c210a05d317ae9678b5823dd6a4d708
wpxmlrpc: 6ba55c773cfa27083ae4a2173e69b19f46da98e2

Expand Down
2 changes: 1 addition & 1 deletion WordPressKit.podspec
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "WordPressKit"
s.version = "1.7.0"
Copy link

@ghost ghost Jan 22, 2019

Choose a reason for hiding this comment

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

I'm not sure we should be updating the patch version in this case. It seems like we should be updating the minor version, yes?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated!

s.version = "1.8.0-beta.1"
s.summary = "WordPressKit offers a clean and simple WordPress.com and WordPress.org API."

s.description = <<-DESC
Expand Down
20 changes: 20 additions & 0 deletions WordPressKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,11 @@
B5A4822B20AC6C0B009D95F6 /* CocoaLumberjack.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A4822A20AC6C0B009D95F6 /* CocoaLumberjack.swift */; };
B5A4822E20AC6C1A009D95F6 /* WPKitLogging.m in Sources */ = {isa = PBXBuildFile; fileRef = B5A4822C20AC6C19009D95F6 /* WPKitLogging.m */; };
B5A4822F20AC6C1A009D95F6 /* WPKitLogging.h in Headers */ = {isa = PBXBuildFile; fileRef = B5A4822D20AC6C1A009D95F6 /* WPKitLogging.h */; };
D813437621F6D70D0060D99A /* SiteSegmentsResponseDecodingTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D813437521F6D70D0060D99A /* SiteSegmentsResponseDecodingTests.swift */; };
D813437821F6D7DC0060D99A /* site-segments-single.json in Resources */ = {isa = PBXBuildFile; fileRef = D813437721F6D7DC0060D99A /* site-segments-single.json */; };
D816857121EDACD10049883E /* WordPressComServiceRemote+SiteSegments.swift in Sources */ = {isa = PBXBuildFile; fileRef = D816857021EDACD10049883E /* WordPressComServiceRemote+SiteSegments.swift */; };
D8DB404021EF222000B8238E /* SiteCreationSegmentsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8DB403F21EF222000B8238E /* SiteCreationSegmentsTests.swift */; };
D8DB404221EF22B500B8238E /* site-segments-multiple.json in Resources */ = {isa = PBXBuildFile; fileRef = D8DB404121EF22B500B8238E /* site-segments-multiple.json */; };
E11C2AD21FA77FB90023BDE2 /* SitePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = E11C2AD11FA77FB90023BDE2 /* SitePlugin.swift */; };
E13EE1471F33258E00C15787 /* PluginServiceRemote.swift in Sources */ = {isa = PBXBuildFile; fileRef = E13EE1461F33258E00C15787 /* PluginServiceRemote.swift */; };
E13EE1491F332B8500C15787 /* site-plugins-success.json in Resources */ = {isa = PBXBuildFile; fileRef = E13EE1481F332B8500C15787 /* site-plugins-success.json */; };
Expand Down Expand Up @@ -875,6 +880,11 @@
BEEC8B5D92DA614468900BD7 /* Pods-WordPressKit.release-alpha.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.release-alpha.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.release-alpha.xcconfig"; sourceTree = "<group>"; };
C5953994B3865AF409BA4210 /* Pods-WordPressKitTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKitTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKitTests/Pods-WordPressKitTests.release.xcconfig"; sourceTree = "<group>"; };
CA5ABD95F40077D001644BCC /* Pods-WordPressKit.release-internal.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-WordPressKit.release-internal.xcconfig"; path = "Pods/Target Support Files/Pods-WordPressKit/Pods-WordPressKit.release-internal.xcconfig"; sourceTree = "<group>"; };
D813437521F6D70D0060D99A /* SiteSegmentsResponseDecodingTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteSegmentsResponseDecodingTests.swift; sourceTree = "<group>"; };
D813437721F6D7DC0060D99A /* site-segments-single.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-segments-single.json"; sourceTree = "<group>"; };
D816857021EDACD10049883E /* WordPressComServiceRemote+SiteSegments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WordPressComServiceRemote+SiteSegments.swift"; sourceTree = "<group>"; };
D8DB403F21EF222000B8238E /* SiteCreationSegmentsTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SiteCreationSegmentsTests.swift; sourceTree = "<group>"; };
D8DB404121EF22B500B8238E /* site-segments-multiple.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-segments-multiple.json"; sourceTree = "<group>"; };
E11C2AD11FA77FB90023BDE2 /* SitePlugin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SitePlugin.swift; sourceTree = "<group>"; };
E13EE1461F33258E00C15787 /* PluginServiceRemote.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginServiceRemote.swift; sourceTree = "<group>"; };
E13EE1481F332B8500C15787 /* site-plugins-success.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-plugins-success.json"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1296,6 +1306,7 @@
93F50A351F226B9300B5BEBA /* WordPressComServiceRemote.h */,
93F50A361F226B9300B5BEBA /* WordPressComServiceRemote.m */,
7328420321CD786C00126755 /* WordPressComServiceRemote+SiteCreation.swift */,
D816857021EDACD10049883E /* WordPressComServiceRemote+SiteSegments.swift */,
730E869E21E44EFD00753E1A /* WordPressComServiceRemote+SiteVerticals.swift */,
73A2F38921E7F81E00388609 /* WordPressComServiceRemote+SiteVerticalsPrompt.swift */,
9368C7A11EC62F800092CE8E /* WPStatsServiceRemote.h */,
Expand Down Expand Up @@ -1419,6 +1430,8 @@
93BD273E1EE732CC002BB00B /* Accounts */ = {
isa = PBXGroup;
children = (
D813437521F6D70D0060D99A /* SiteSegmentsResponseDecodingTests.swift */,
D8DB403F21EF222000B8238E /* SiteCreationSegmentsTests.swift */,
93BD27401EE73311002BB00B /* AccountServiceRemoteRESTTests.swift */,
7403A2E51EF06F7000DED7DC /* AccountSettingsRemoteTests.swift */,
93F50A391F226BB600B5BEBA /* WordPressComServiceRemoteRestTests.swift */,
Expand Down Expand Up @@ -1546,6 +1559,7 @@
74D67F101F15C2D70010C5ED /* site-users-update-role-success.json */,
74D67F111F15C2D70010C5ED /* site-users-update-role-unknown-site-failure.json */,
7434E1DD1F17C3C900C40DDB /* site-users-update-role-unknown-user-failure.json */,
D8DB404121EF22B500B8238E /* site-segments-multiple.json */,
73D592FA21E550D300E4CF84 /* site-verticals-empty.json */,
73D592F821E550D200E4CF84 /* site-verticals-multiple.json */,
73A2F38B21E7FC2A00388609 /* site-verticals-prompt.json */,
Expand Down Expand Up @@ -1591,6 +1605,7 @@
740B23DE1F17FB4200067A2A /* xmlrpc-wp-getpost-bad-xml-failure.xml */,
740B23DF1F17FB4200067A2A /* xmlrpc-wp-getpost-invalid-id-failure.xml */,
740B23E01F17FB4200067A2A /* xmlrpc-wp-getpost-success.xml */,
D813437721F6D7DC0060D99A /* site-segments-single.json */,
);
path = "Mock Data";
sourceTree = "<group>";
Expand Down Expand Up @@ -1905,6 +1920,7 @@
74D67F1F1F15C3240010C5ED /* people-send-invitation-success.json in Resources */,
FFE247B020C891E6002DF3A2 /* WordPressComAuthenticateWithIDToken2FANeededSuccess.json in Resources */,
436D563E2118E34D00CEAA33 /* supported-states-success.json in Resources */,
D813437821F6D7DC0060D99A /* site-segments-single.json in Resources */,
93BD27561EE73442002BB00B /* auth-send-login-email-invalid-secret-failure.json in Resources */,
436D564C211CCCB900CEAA33 /* domain-contact-information-response-success.json in Resources */,
93BD275A1EE73442002BB00B /* is-available-email-success.json in Resources */,
Expand Down Expand Up @@ -1966,6 +1982,7 @@
93AC8ECA1ED32FD000900F5A /* stats-v1.1-country-views-day.json in Resources */,
74C473BF1EF32B64009918F2 /* site-export-bad-json-failure.json in Resources */,
74D67F151F15C2D70010C5ED /* site-roles-success.json in Resources */,
D8DB404221EF22B500B8238E /* site-segments-multiple.json in Resources */,
740B23E11F17FB4200067A2A /* xmlrpc-metaweblog-editpost-bad-xml-failure.xml in Resources */,
93AC8ED51ED32FD000900F5A /* stats-v1.1-tags-categories-views-day.json in Resources */,
17BF9A7520C7E18200BF57D2 /* reader-site-search-success-no-icon.json in Resources */,
Expand Down Expand Up @@ -2160,6 +2177,7 @@
73A2F38A21E7F81E00388609 /* WordPressComServiceRemote+SiteVerticalsPrompt.swift in Sources */,
740B23BB1F17EC7300067A2A /* PostServiceRemoteXMLRPC.m in Sources */,
74B5F0E31EF82D2100B411E7 /* SiteServiceRemoteWordPressComREST.m in Sources */,
D816857121EDACD10049883E /* WordPressComServiceRemote+SiteSegments.swift in Sources */,
74E2295C1F1E77290085F7F2 /* KeyringConnectionExternalUser.swift in Sources */,
E1BD95151FD5A2B800CD5CE3 /* PluginDirectoryServiceRemote.swift in Sources */,
7430C9D71F1933210051B8E6 /* RemoteReaderCrossPostMeta.swift in Sources */,
Expand Down Expand Up @@ -2293,6 +2311,7 @@
74FC6F3B1F191BB400112505 /* NotificationSyncServiceRemoteTests.swift in Sources */,
731BA83821DECD97000FDFCD /* SiteCreationResponseDecodingTests.swift in Sources */,
74FA25F71F1FDA200044BC54 /* MediaServiceRemoteRESTTests.swift in Sources */,
D8DB404021EF222000B8238E /* SiteCreationSegmentsTests.swift in Sources */,
7433BC051EFC4556002D9E92 /* PlanServiceRemoteTests.swift in Sources */,
740B23D61F17F7C100067A2A /* XMLRPCTestable.swift in Sources */,
FFE247A720C891D1002DF3A2 /* WordPressComOAuthTests.swift in Sources */,
Expand All @@ -2315,6 +2334,7 @@
93AC8EE21ED32FD000900F5A /* WPStatsServiceRemoteTests.m in Sources */,
E1787DB2200E5690004CB3AF /* TimeZoneServiceRemoteTests.swift in Sources */,
740B23D21F17F6BB00067A2A /* PostServiceRemoteRESTTests.m in Sources */,
D813437621F6D70D0060D99A /* SiteSegmentsResponseDecodingTests.swift in Sources */,
436D56382118DC4B00CEAA33 /* TransactionsServiceRemoteTests.swift in Sources */,
9F3E0BA82087355E009CB5BA /* RemoteReaderSiteInfoSubscriptionTests.swift in Sources */,
7430C9BE1F192C0F0051B8E6 /* ReaderTopicServiceRemoteTests.m in Sources */,
Expand Down
142 changes: 142 additions & 0 deletions WordPressKit/WordPressComServiceRemote+SiteSegments.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/// Models a type of site.
public struct SiteSegment {
public let identifier: Int64 // we use a numeric ID for segments; see p9wMUP-bH-612-p2 for discussion
public let title: String
public let subtitle: String
public let icon: URL?
public let iconColor: String?
public let mobile: Bool

public init(identifier: Int64, title: String, subtitle: String, icon: URL?, iconColor: String?, mobile: Bool) {
self.identifier = identifier
self.title = title
self.subtitle = subtitle
self.icon = icon
self.iconColor = iconColor
self.mobile = mobile
}
}

extension SiteSegment {
public static let blogSegmentIdentifier = Int64(1)
}

extension SiteSegment: Equatable {
public static func ==(lhs: SiteSegment, rhs: SiteSegment) -> Bool {
return lhs.identifier == rhs.identifier
}
}

extension SiteSegment: Decodable {
enum CodingKeys: String, CodingKey {
case segmentId = "id"
case segmentTypeTitle = "segment_type_title"
case segmentTypeSubtitle = "segment_type_subtitle"
case iconURL = "icon_URL"
case iconColor = "icon_color"
case mobile = "mobile"
}

public init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
identifier = try values.decode(Int64.self, forKey: .segmentId)
title = try values.decode(String.self, forKey: .segmentTypeTitle)
subtitle = try values.decode(String.self, forKey: .segmentTypeSubtitle)
if let iconString = try values.decodeIfPresent(String.self, forKey: .iconURL) {
icon = URL(string: iconString)
} else {
icon = nil
}

if let iconColorString = try values.decodeIfPresent(String.self, forKey: .iconColor) {
var cleanIconColorString = iconColorString
if iconColorString.hasPrefix("#") {
cleanIconColorString = String(iconColorString.dropFirst(1))
}

iconColor = cleanIconColorString
} else {
iconColor = nil
}

mobile = try values.decode(Bool.self, forKey: .mobile)

}
}

// MARK: - WordPressComServiceRemote (Site Segments)

/// Describes the errors that could arise when searching for site verticals.
///
/// - requestEncodingFailure: unable to encode the request parameters.
/// - responseDecodingFailure: unable to decode the server response.
/// - serviceFailure: the service returned an unexpected error.
///
public enum SiteSegmentsError: Error {
case requestEncodingFailure
case responseDecodingFailure
case serviceFailure
}

/// Advises the caller of results related to requests for site segments.
///
/// - success: the site segments request succeeded with the accompanying result.
/// - failure: the site segments request failed due to the accompanying error.
///
public enum SiteSegmentsResult {
case success([SiteSegment])
case failure(SiteSegmentsError)
}

public typealias SiteSegmentsServiceCompletion = (SiteSegmentsResult) -> Void

/// Site segments service, exclusive to WordPress.com.
///
public extension WordPressComServiceRemote {
func retrieveSegments(completion: @escaping SiteSegmentsServiceCompletion) {
let endpoint = "segments"
let remotePath = path(forEndpoint: endpoint, withVersion: ._2_0)

wordPressComRestApi.GET(
remotePath,
parameters: nil,
success: { [weak self] responseObject, httpResponse in
DDLogInfo("\(responseObject) | \(String(describing: httpResponse))")

guard let self = self else {
return
}

do {
let response = try self.decodeResponse(responseObject: responseObject)
let validContent = self.validSegments(response)
completion(.success(validContent))
} catch {
DDLogError("Failed to decode \([SiteVertical].self) : \(error.localizedDescription)")
completion(.failure(SiteSegmentsError.responseDecodingFailure))
}
},
failure: { error, httpResponse in
DDLogError("\(error) | \(String(describing: httpResponse))")
completion(.failure(SiteSegmentsError.serviceFailure))
})
}
}

// MARK: - Serialization support

private extension WordPressComServiceRemote {
private func decodeResponse(responseObject: AnyObject) throws -> [SiteSegment] {
let decoder = JSONDecoder()
let data = try JSONSerialization.data(withJSONObject: responseObject, options: [])
let response = try decoder.decode([SiteSegment].self, from: data)

return response
}

private func validSegments(_ allSegments: [SiteSegment]) -> [SiteSegment] {
return allSegments.filter {
return $0.mobile == true
}
}
}
56 changes: 56 additions & 0 deletions WordPressKitTests/Mock Data/site-segments-multiple.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
[
{
"icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_blogger.png",
"icon_color" : "#0087be",
"id" : 1,
"mobile" : true,
"segment_type_subtitle" : "Share and discuss ideas, updates, or creations.",
"segment_type_title" : "Blog",
"slug" : "blog"
},
{
"icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_business.png",
"icon_color" : "#f0b849",
"id" : 2,
"mobile" : true,
"segment_type_subtitle" : "Promote products and services.",
"segment_type_title" : "Business",
"slug" : "business"
},
{
"icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_professional.png",
"icon_color" : "#f0b849",
"id" : 3,
"mobile" : true,
"segment_type_subtitle" : "Showcase your portfolio, skills or work.",
"segment_type_title" : "Professional",
"slug" : "professional"
},
{
"icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_educator.png",
"icon_color" : "#d94f4f",
"id" : 4,
"mobile" : true,
"segment_type_subtitle" : "Share school projects and class info.",
"segment_type_title" : "Education",
"slug" : "education"
},
{
"icon_URL" : "",
"icon_color" : "",
"id" : 5,
"mobile" : false,
"segment_type_subtitle" : "Sell your collection of products online.",
"segment_type_title" : "Online store",
"slug" : "online-store"
},
{
"icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_blank_canvas.png",
"icon_color" : "#87a6bc",
"id" : 6,
"mobile" : true,
"segment_type_subtitle" : "Start with a blank site.",
"segment_type_title" : "Blank Canvas",
"slug" : "blank-canvas"
}
]
9 changes: 9 additions & 0 deletions WordPressKitTests/Mock Data/site-segments-single.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"icon_URL" : "https://s.wp.com/i/mobile_segmentation_icons/monochrome/ic_blogger.png",
"icon_color" : "#0087be",
"id" : 1,
"mobile" : true,
"segment_type_subtitle" : "Share and discuss ideas, updates, or creations.",
"segment_type_title" : "Blog",
"slug" : "blog"
}
34 changes: 34 additions & 0 deletions WordPressKitTests/SiteCreationSegmentsTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import XCTest
@testable import WordPressKit

final class SiteCreationSegmentsTests: RemoteTestCase, RESTTestable {

func testSiteSegmentsRequest_Succeeds() {
// Given
let endpoint = "segments"
let fileName = "site-segments-multiple.json"
stubRemoteResponse(endpoint, filename: fileName, contentType: .ApplicationJSON)

let expectedSegmentsCount = 5

// When, Then
let segmentsExpectation = expectation(description: "Initiate site segments request")
let remote = WordPressComServiceRemote(wordPressComRestApi: getRestApi())
remote.retrieveSegments(completion: { result in
segmentsExpectation.fulfill()
switch result {
case .success(let segments):
XCTAssertNotNil(segments)

let mobileSegmentsCount = segments.count
XCTAssertEqual(mobileSegmentsCount, expectedSegmentsCount)

case .failure(_):
XCTFail()
}
})

waitForExpectations(timeout: timeout)
}

}
Loading