Skip to content
This repository was archived by the owner on Sep 15, 2025. It is now read-only.
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
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.8.0-beta.1):
- WordPressKit (2.0.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: f2edbc8f99f7c698306193cfe216fd6e5b74fa54
WordPressKit: f54ffbba343061975b72e64e5d49615c28156147
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.8.0"
s.version = "2.0.0-beta.1"
s.summary = "WordPressKit offers a clean and simple WordPress.com and WordPress.org API."

s.description = <<-DESC
Expand Down
4 changes: 4 additions & 0 deletions WordPressKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
73A2F38A21E7F81E00388609 /* WordPressComServiceRemote+SiteVerticalsPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A2F38921E7F81E00388609 /* WordPressComServiceRemote+SiteVerticalsPrompt.swift */; };
73A2F38D21E7FC8200388609 /* WordPressComServiceRemoteTests+SiteVerticalsPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A2F38C21E7FC8200388609 /* WordPressComServiceRemoteTests+SiteVerticalsPrompt.swift */; };
73A2F38E21E7FD9B00388609 /* site-verticals-prompt.json in Resources */ = {isa = PBXBuildFile; fileRef = 73A2F38B21E7FC2A00388609 /* site-verticals-prompt.json */; };
73B3DAD621FBB20D00B2CF18 /* WordPressComRestApiTests+Locale.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73B3DAD521FBB20D00B2CF18 /* WordPressComRestApiTests+Locale.swift */; };
73D592FB21E550D300E4CF84 /* site-verticals-multiple.json in Resources */ = {isa = PBXBuildFile; fileRef = 73D592F821E550D200E4CF84 /* site-verticals-multiple.json */; };
73D592FC21E550D300E4CF84 /* site-verticals-single.json in Resources */ = {isa = PBXBuildFile; fileRef = 73D592F921E550D300E4CF84 /* site-verticals-single.json */; };
73D592FD21E550D300E4CF84 /* site-verticals-empty.json in Resources */ = {isa = PBXBuildFile; fileRef = 73D592FA21E550D300E4CF84 /* site-verticals-empty.json */; };
Expand Down Expand Up @@ -510,6 +511,7 @@
73A2F38921E7F81E00388609 /* WordPressComServiceRemote+SiteVerticalsPrompt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WordPressComServiceRemote+SiteVerticalsPrompt.swift"; sourceTree = "<group>"; };
73A2F38B21E7FC2A00388609 /* site-verticals-prompt.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "site-verticals-prompt.json"; sourceTree = "<group>"; };
73A2F38C21E7FC8200388609 /* WordPressComServiceRemoteTests+SiteVerticalsPrompt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WordPressComServiceRemoteTests+SiteVerticalsPrompt.swift"; sourceTree = "<group>"; };
73B3DAD521FBB20D00B2CF18 /* WordPressComRestApiTests+Locale.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WordPressComRestApiTests+Locale.swift"; sourceTree = "<group>"; };
73D592F821E550D200E4CF84 /* site-verticals-multiple.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-verticals-multiple.json"; sourceTree = "<group>"; };
73D592F921E550D300E4CF84 /* site-verticals-single.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-verticals-single.json"; sourceTree = "<group>"; };
73D592FA21E550D300E4CF84 /* site-verticals-empty.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "site-verticals-empty.json"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1132,6 +1134,7 @@
740B23D51F17F7C100067A2A /* XMLRPCTestable.swift */,
FFE247A620C891D1002DF3A2 /* WordPressComOAuthTests.swift */,
74B335D91F06F3D60053A184 /* WordPressComRestApiTests.swift */,
73B3DAD521FBB20D00B2CF18 /* WordPressComRestApiTests+Locale.swift */,
74B335DB1F06F4180053A184 /* WordPressOrgXMLRPCApiTests.swift */,
93BD273E1EE732CC002BB00B /* Accounts */,
826016FE1F9FD59400533B6C /* Activity */,
Expand Down Expand Up @@ -2304,6 +2307,7 @@
74B335D81F06F1CA0053A184 /* MockWordPressComRestApi.swift in Sources */,
74B5F0DE1EF82A9600B411E7 /* BlogServiceRemoteRESTTests.m in Sources */,
74E2294B1F1E73340085F7F2 /* SharingServiceRemoteTests.m in Sources */,
73B3DAD621FBB20D00B2CF18 /* WordPressComRestApiTests+Locale.swift in Sources */,
9F3E0BAC20873785009CB5BA /* ServiceRequestTest.swift in Sources */,
93AC8EDE1ED32FD000900F5A /* StatsItemTests.m in Sources */,
740B23D31F17F6BB00067A2A /* PostServiceRemoteXMLRPCTests.swift in Sources */,
Expand Down
74 changes: 44 additions & 30 deletions WordPressKit/WordPressComRestApi.swift
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ open class WordPressComRestApi: NSObject {

fileprivate let backgroundUploads: Bool

fileprivate static let localeKey = "locale"
static let localeKey = "locale"

fileprivate let oAuthToken: String?
fileprivate let userAgent: String?
Expand Down Expand Up @@ -145,7 +145,7 @@ open class WordPressComRestApi: NSObject {
success: @escaping SuccessResponseBlock,
failure: @escaping FailureReponseBlock) -> Progress? {

guard let URLString = buildRequestURLFor(path: urlString) else {
guard let URLString = buildRequestURLFor(path: urlString, parameters: parameters) else {
let error = NSError(domain: String(describing: WordPressComRestApiError.self),
code: WordPressComRestApiError.requestSerializationFailed.rawValue,
userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Failed to serialize request to the REST API.", comment: "Error message to show when wrong URL format is used to access the REST API")])
Expand Down Expand Up @@ -241,7 +241,7 @@ open class WordPressComRestApi: NSObject {
success: @escaping SuccessResponseBlock,
failure: @escaping FailureReponseBlock) -> Progress? {

guard let URLString = buildRequestURLFor(path: URLString) else {
guard let URLString = buildRequestURLFor(path: URLString, parameters: parameters) else {
let error = NSError(domain: String(describing: WordPressComRestApiError.self),
code: WordPressComRestApiError.requestSerializationFailed.rawValue,
userInfo: [NSLocalizedDescriptionKey: NSLocalizedString("Failed to serialize request to the REST API.", comment: "Error message to show when wrong URL format is used to access the REST API")])
Expand Down Expand Up @@ -299,18 +299,52 @@ open class WordPressComRestApi: NSObject {
return "\(String(describing: oAuthToken)),\(String(describing: userAgent))".hashValue
}

fileprivate func buildRequestURLFor(path: String) -> String? {
let pathWithLocale = appendLocaleIfNeeded(path)
/// This method assembles a valid request URL for the specified path & parameters.
/// The framework relies on a field (`appendsPreferredLanguageLocale`) to influence whether or not locale should be
/// added to the path of requests. This approach did not consider request parameters.
///
/// This method now considers both the path and specified request parameters when performing the substitution.
/// It only accounts for the locale parameter. AlamoFire encodes other parameters via `SessionManager.request(_:method:parameters:encoding:headers:)`
///
/// - Parameters:
/// - path: the path for the request, which might include `locale`
/// - parameters: the request parameters, which could conceivably include `locale`
/// - localeKey: the locale key to search for (`locale` in v1 endpoints, `_locale` for v2)
/// - Returns: a request URL if successful, `nil` otherwise.
///
func buildRequestURLFor(path: String, parameters: [String: AnyObject]? = [:], localeKey: String = WordPressComRestApi.localeKey) -> String? {

let baseURL = URL(string: WordPressComRestApi.apiBaseURLString)
let requestURLString = URL(string: pathWithLocale, relativeTo: baseURL)?.absoluteString
return requestURLString

guard let requestURLString = URL(string: path, relativeTo: baseURL)?.absoluteString,
let urlComponents = URLComponents(string: requestURLString) else {

return nil
}

let urlComponentsWithLocale = applyLocaleIfNeeded(urlComponents: urlComponents, parameters: parameters, localeKey: localeKey)

return urlComponentsWithLocale?.url?.absoluteString
}

fileprivate func appendLocaleIfNeeded(_ path: String) -> String {
private func applyLocaleIfNeeded(urlComponents: URLComponents, parameters: [String: AnyObject]? = [:], localeKey: String) -> URLComponents? {
guard appendsPreferredLanguageLocale else {
return path
return urlComponents
}
return WordPressComRestApi.pathByAppendingPreferredLanguageLocale(path)

var componentsWithLocale = urlComponents
var existingQueryItems = componentsWithLocale.queryItems ?? []

let existingLocaleQueryItems = existingQueryItems.filter { $0.name == localeKey }
if let parameters = parameters, parameters[localeKey] == nil, existingLocaleQueryItems.isEmpty {
let preferredLanguageIdentifier = WordPressComLanguageDatabase().deviceLanguage.slug
let localeQueryItem = URLQueryItem(name: localeKey, value: preferredLanguageIdentifier)

existingQueryItems.append(localeQueryItem)
}
componentsWithLocale.queryItems = existingQueryItems

return componentsWithLocale
}

@objc public func temporaryFileURL(withExtension fileExtension: String) -> URL {
Expand Down Expand Up @@ -412,7 +446,6 @@ extension WordPressComRestApi {
let errorWithLocalizedMessage = NSError(domain: nsError.domain, code: nsError.code, userInfo:userInfo)
return errorWithLocalizedMessage
}

}

extension WordPressComRestApi {
Expand All @@ -421,25 +454,6 @@ extension WordPressComRestApi {
@objc class public func anonymousApi(userAgent: String) -> WordPressComRestApi {
return WordPressComRestApi(oAuthToken: nil, userAgent: userAgent)
}

/// Append the user's preferred device locale as a query param to the URL path.
/// If the locale already exists the original path is returned.
///
/// - Parameters:
/// - path: A URL string. Can be an absolute or relative URL string.
///
/// - Returns: The path with the locale appended, or the original path if it already had a locale param.
///
@objc class public func pathByAppendingPreferredLanguageLocale(_ path: String) -> String {
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we no longer need to use this method on ObjC in the main app?

Copy link
Author

@ghost ghost Jan 29, 2019

Choose a reason for hiding this comment

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

I searched for consumers of this in the try/wordpresskit-72-validation branch I created, and could not find any.

let localeKey = WordPressComRestApi.localeKey
if path.isEmpty || path.contains("\(localeKey)=") {
return path
}
let preferredLanguageIdentifier = WordPressComLanguageDatabase().deviceLanguage.slug
let separator = path.contains("?") ? "&" : "?"
return "\(path)\(separator)\(localeKey)=\(preferredLanguageIdentifier)"
}

}

@objc extension Progress {
Expand Down
167 changes: 167 additions & 0 deletions WordPressKitTests/WordPressComRestApiTests+Locale.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
import Foundation
import XCTest

import WordPressShared
@testable import WordPressKit

extension WordPressComRestApiTests {

func testThatAppendingLocaleWorks() {
// Given
let path = "/path/path"
let preferredLanguageIdentifier = WordPressComLanguageDatabase().deviceLanguage.slug

// When
let localeAppendedPath = WordPressComRestApi().buildRequestURLFor(path: path)

// Then
XCTAssertNotNil(localeAppendedPath)
let actualURL = URL(string: localeAppendedPath!, relativeTo: URL(string: WordPressComRestApi.apiBaseURLString))
XCTAssertNotNil(actualURL)

let actualURLComponents = URLComponents(url: actualURL!, resolvingAgainstBaseURL: false)
XCTAssertNotNil(actualURLComponents)

let expectedPath = path
let actualPath = actualURLComponents!.path
XCTAssertEqual(expectedPath, actualPath)

let actualQueryItems = actualURLComponents!.queryItems
XCTAssertNotNil(actualQueryItems)

let expectedQueryItemCount = 1
let actualQueryItemCount = actualQueryItems!.count
XCTAssertEqual(expectedQueryItemCount, actualQueryItemCount)

let actualQueryItem = actualQueryItems!.first
XCTAssertNotNil(actualQueryItem!)

let actualQueryItemKey = actualQueryItem!.name
let expectedQueryItemKey = WordPressComRestApi.localeKey
XCTAssertEqual(expectedQueryItemKey, actualQueryItemKey)

let actualQueryItemValue = actualQueryItem!.value
XCTAssertNotNil(actualQueryItemValue)

let expectedQueryItemValue = preferredLanguageIdentifier
XCTAssertEqual(expectedQueryItemValue, actualQueryItemValue!)
}

func testThatAppendingLocaleWorksWithExistingParams() {
// Given
let path = "/path/path"
let params: [String: AnyObject] = [
"someKey": "value" as AnyObject
]

// When
let localeAppendedPath = WordPressComRestApi().buildRequestURLFor(path: path, parameters: params)

// Then
XCTAssertNotNil(localeAppendedPath)
let actualURL = URL(string: localeAppendedPath!, relativeTo: URL(string: WordPressComRestApi.apiBaseURLString))
XCTAssertNotNil(actualURL)

let actualURLComponents = URLComponents(url: actualURL!, resolvingAgainstBaseURL: false)
XCTAssertNotNil(actualURLComponents)

let expectedPath = "/path/path"
let actualPath = actualURLComponents!.path
XCTAssertEqual(expectedPath, actualPath)

let actualQueryItems = actualURLComponents!.queryItems
XCTAssertNotNil(actualQueryItems)

let expectedQueryItemCount = 1
let actualQueryItemCount = actualQueryItems!.count
XCTAssertEqual(expectedQueryItemCount, actualQueryItemCount)

let actualQueryString = actualURLComponents?.query
XCTAssertNotNil(actualQueryString)

let queryStringIncludesLocale = actualQueryString!.contains(WordPressComRestApi.localeKey)
XCTAssertTrue(queryStringIncludesLocale)
}

func testThatLocaleIsNotAppendedIfAlreadyIncludedInPath() {
// Given
let preferredLanguageIdentifier = "foo"
let path = "/path/path?locale=\(preferredLanguageIdentifier)"

// When
let localeAppendedPath = WordPressComRestApi().buildRequestURLFor(path: path)

// Then
XCTAssertNotNil(localeAppendedPath)
let actualURL = URL(string: localeAppendedPath!, relativeTo: URL(string: WordPressComRestApi.apiBaseURLString))
XCTAssertNotNil(actualURL)

let actualURLComponents = URLComponents(url: actualURL!, resolvingAgainstBaseURL: false)
XCTAssertNotNil(actualURLComponents)

let expectedPath = "/path/path"
let actualPath = actualURLComponents!.path
XCTAssertEqual(expectedPath, actualPath)

let actualQueryItems = actualURLComponents!.queryItems
XCTAssertNotNil(actualQueryItems)

let expectedQueryItemCount = 1
let actualQueryItemCount = actualQueryItems!.count
XCTAssertEqual(expectedQueryItemCount, actualQueryItemCount)

let actualQueryItem = actualQueryItems!.first
XCTAssertNotNil(actualQueryItem!)

let actualQueryItemKey = actualQueryItem!.name
let expectedQueryItemKey = WordPressComRestApi.localeKey
XCTAssertEqual(expectedQueryItemKey, actualQueryItemKey)

let actualQueryItemValue = actualQueryItem!.value
XCTAssertNotNil(actualQueryItemValue)

let expectedQueryItemValue = preferredLanguageIdentifier
XCTAssertEqual(expectedQueryItemValue, actualQueryItemValue!)
}

func testThatAppendingLocaleIgnoresIfAlreadyIncludedInRequestParameters() {
// Given
let inputPath = "/path/path"
let expectedLocaleValue = "foo"
let params: [String : AnyObject] = [
WordPressComRestApi.localeKey: expectedLocaleValue as AnyObject
]

// When
let requestURLString = WordPressComRestApi().buildRequestURLFor(path: inputPath, parameters: params)

// Then
let preferredLanguageIdentifier = WordPressComLanguageDatabase().deviceLanguage.slug
XCTAssertFalse(requestURLString!.contains(preferredLanguageIdentifier))
}

func testThatLocaleIsNotAppendedWhenDisabled() {
// Given
let path = "/path/path"

// When
let api = WordPressComRestApi()
api.appendsPreferredLanguageLocale = false
let localeAppendedPath = api.buildRequestURLFor(path: path)

// Then
XCTAssertNotNil(localeAppendedPath)
let actualURL = URL(string: localeAppendedPath!, relativeTo: URL(string: WordPressComRestApi.apiBaseURLString))
XCTAssertNotNil(actualURL)

let actualURLComponents = URLComponents(url: actualURL!, resolvingAgainstBaseURL: false)
XCTAssertNotNil(actualURLComponents)

let expectedPath = path
let actualPath = actualURLComponents!.path
XCTAssertEqual(expectedPath, actualPath)

let actualQueryItems = actualURLComponents!.queryItems
XCTAssertNil(actualQueryItems)
}
}
Loading