【WordPress】WordPressの記事をJSON形式で出力し、アプリで受け取る方法【Swift】

誰でも投稿できるサイトをWordPressで作り、その投稿をアプリに反映させたい!ということでやってみました。

 

まずは流れです。

【WordPress上ですること】

・誰でも投稿できるフォームを作成する。(ここは別記事にします!)

・JSON形式のデータを作成する

【Xcode上ですること】

・JSONデータから必要なデータを取得する

 

JSONデータを作成して、それを受け取る!そのまんまですね。

 

WordPressの投稿をJSONデータにする

まずはWordPressから。

今回はプラグインは使いません!

プラグインを用いることももちろんできるのですが、今回カスタム投稿を使用していたため、なかなか思い通りにいかず、結局プラグインなしでできる方法を見つけたのでそちらでいきます。

 

まずはページのテンプレートを作ります。適当にapi-page.phpとしておきます。

その中にこのコードを書きましょう。

<?php
$args = array(
  'numberposts' => -1,
  'orderby'     => 'post_date',
  'order'       => 'DESC',
//カスタム投稿の場合ここに'post_type' = 'custom' 
);
$posts = get_posts($args);

if($posts): foreach($posts as $post):
  setup_postdata($post);
  $json[] = $post;
endforeach; endif;

header("Content-Type: application/json; charset=utf-8");
echo json_encode($json);

 

カスタム投稿の場合はスラッグ名を書くことで、その投稿のみを取得することができます。

今回は全記事を取得したいので numberpostsは-1にしています。

 

次に固定ページを作成します

スクリーンショット-2016-01-24-0.41.43

 

タイトルは適当につけて、テンプレートを先ほど作ったAPI Pageに設定します。

そして公開して指定したリンク先に飛んでみましょう!

 

ピャーッ

スクリーンショット-2016-01-24-0.49.21

 

とりあえず最新3記事にしたんですけど膨大な量ですね。てか単に文字のエンコードがひどくて長くなってるだけなのもあると思うけども・・・。

JSONファイルの形式は下のような形です

[
    {
        "breakfast":"パン",
        "lunch":"ラーメン",
        "dinner":"焼肉"
    },
    {
        "breakfast":"",
        "lunch":"パスタ",
        "dinner":"生姜焼き"
    },
    {
        "breakfast":"トースト",
        "lunch":"天津飯",
        "dinner":"鍋"
    }
]

 

こんな感じの配列になっています。

JSONLintにて少し見やすくしてみましょう。

 

スクリーンショット-2016-01-24-0.59.45

 

これだとわかりやすいですね!

エンコードされてしまった文字列を確認したい場合は、Web便利ツール/URLエンコード・デコードフォーム – TAG index Webサイトにて確認してみてください。

 

WordPress側ですることはこれだけです。

 

アプリでJSONデータを受け取る

続いてXcodeで作業していきます。

こちらはライブラリを使っていきます「swift-json」というものを使用していきます。swiftyではないので注意ですよ!

 

json.swiftというファイルを作成しておき

https://github.com/dankogai/swift-json/blob/master/json/json.swift」こちらのコードをまるっとコピーして貼り付けましょう。 【2019.02.04】リンク切れ削除。多分リンク的にコレでしょうか。https://github.com/dankogai/swift-json/blob/master/Sources/JSON/JSON.swift

 

そして必要な箇所にて使用していきます

 override func viewDidLoad() {
        super.viewDidLoad()
        getJson()
}    

func getJson(){
        // APIからJsonを取得してパース
        let json = JSON(url:"http://~~") //さっきのwordpressのリンク
        // 特定の要素の取り出し
        let title = json[0]["post_title"]
        print("post_title \(title)")
}

 

これで1番目の”post_title”のデータが取得できます。

 

しかし何故かこんなエラーが出る

Application Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app’s Info.plist file.

 

この対処法の詳しい説明はこちらの記事に書かれていました->[iOS 9] iOS 9 で追加された App Transport Security の概要

やり方としてはプロジェクトの中にひっそりといるInfo.plistというファイルを少しいじるだけです。

 

右クリックでadd Rowを選択して以下を追加していきます。

スクリーンショット-2016-01-24-1.16.37

App Transport Security Settings(Dictionary型)を用意し

その中にException Domains(Dictionary型)を入れます。

その中に通信を許可したいサイトのドメインを入れます。(サブドメインを使用している場合はメインのドメイン)

NSTemporaryExceptionRequiresForwardSecrecy = true にすればOKです

 

もうひとつのNSIncludesSubdomainsはサブドメインも許可するかどうかです。許可する場合は付け足しておきましょう。

 

これでやっとJSONデータを取得できるはずです!

 

おまけ:

JSONファイルから記事のタイトルのみを全て抽出するときは

let json = JSON(url:"https://uruly.xyz/api/")
var x = 0
var titleArray:NSMutableArray = []
//配列の個数を数える
for i in json{
     x++
     print("i\(i)")
}
//用意しておいた配列に抽出したタイトルを入れる
for var i = 0; i < x;i++ {
     let title = json[i]["post_title"]
     titleArray.addObject(title.asString!)
     print(title)
}

 

こんな感じにまず配列の個数を数えてからその分だけ繰り返しfor文を行うようにしてみました。

配列の個数を返してくれるものがあるのかもしれませんが、とりあえずわからなかったので。

let title = json[i]["post_title"].asString!

最後に.asString!をつけることでJSONからStringに変換します。

Intとかも同様に.asIntで変換できますよ。

 

 

先ほど説明で用いたこちらのJSONデータを取得するとします

[
    {
        "breakfast":"パン",
        "lunch":"ラーメン",
        "dinner":"焼肉"
    },
    {
        "breakfast":"",
        "lunch":"パスタ",
        "dinner":"生姜焼き"
    },
    {
        "breakfast":"トースト",
        "lunch":"天津飯",
        "dinner":"鍋"
    }
]

 

コンソールに表示させればわかるんですが

print(json)

と書くとJSONデータの全てを取得します。

つまり、上記全てです。

 

次にjson[0]とします

let meal = json[0]
print(meal)

これだと一番最初のデータを取得します

    {
        "breakfast":"パン",
        "lunch":"ラーメン",
        "dinner":"焼肉"
    }

この部分です。

 

最後にjson[1][“lunch”]を取得してみます

let meal = json[1]["lunch"]
print(meal)

結果は「パスタ」となります。

 

この程度でしか使用していないのですが、とにかく思ったより楽にできた!気がします。

 

感想

めちゃくちゃ時間がかかると思っていたのですが、意外とすんなりできました(それでも半日以上は悩んでましたけど)

wordpressでjsonファイルを作るとき、通常の投稿を取得するだけならばプラグインを用いた方が早いと思います。

「WP REST API」のプラグインは導入するだけでURLの最後にwp-json/を付け加えるだけでJSONデータを作成してくれるので簡単です。そこからカスタム投稿と上手く繋げることができなかったため今回の方法をとりました。

 

アプリ側ではSwiftyJSONやAlamofireを使用しようとしていたのですがエラーエラーで使えず。そういえば以前も同じようにこれらを使用してターミナルと戦ってた気がします。

とにもかくにもプラグインやライブラリを用いずにできるならばそれに越したことはないかなとも思いますので結果はよかったのかな・・・・?

 

アプリも後はメモリ管理とリリース前のアイコン作成とかのみになりました。今月中にはなんとかリリースできそうです。頑張ります!

それでは

 

 

2019/02/04追記 お茶濁し
ideaDASHをリニューアルする時にまた触ることになると思うのでSwift4での再現はまたいずれ。

最近作ったアプリのJSONファイルから読み込みするところを貼ってお茶濁し。

    func readHelp(){
        self.questionAnswer = []
        let path = Bundle.main.path(forResource: "help", ofType: "json")
        do {
            let jsonString = try String(contentsOfFile: path!)
            let colorData: Data =  jsonString.data(using: String.Encoding.utf8)!
            do {
                let json = try JSONSerialization.jsonObject(with: colorData, options: JSONSerialization.ReadingOptions.allowFragments)
                let top = json as! NSArray
                for object in top {
                    let set = object as! NSDictionary
                    guard let question = set["質問"] as? String else {
                        continue
                    }
                    guard let answer = set["答え"] as? String else {
                        continue
                    }
                    guard let id = set["id"] as? String else {
                        continue
                    }
                    self.questionAnswer.append((question,answer,id))
                    
                }
            } catch {
                print(error)
            }
        }catch {
            print(error)
        }
    }
これはhelp.jsonの中身はこんな感じ
[{
 "質問": "ラベルを編集したい",
 "答え": "編集したいラベルを2回、タタッとタップすると編集できます。",
 "id" : "edit_label"
 }, 
 {
 "質問": "Appの並び順を変えたい",
 "答え": "移動させたいAppを長押しすると、移動できます。",
 "id" : "order_app"
 }]
AppAppという私のもうストアに並ぶことのないアプリより。 help.jsonはそのままプロジェクトにぶち込んだやつです。 本記事とは少し違いますが何か参考になれば嬉しいです。 ではでは。
Swift , ,

Comments...

2018/12/18 02:12

本投稿、とても参考にさせていただいております。

下記のリンクが切れているようなので、ご確認いただけると嬉しいです。
https://github.com/dankogai/swift-json/blob/master/json/json.swift

アバター
from.ys
    2018/12/20 08:12

    コメント・ご報告ありがとうございます。
    現在少し仕事に追われててんてこ舞いなので、落ち着き次第修正させていただきます。すみません。

    Swift4からはCodableが利用できますので、jsonの扱いはもっと簡単にできるようになりました。
    ご存知なければ是非Codableも調べてみてください!

    アバター
    from.Reo(管理人)
コメントは認証制です。詳しくは下記の注意をお読みください。お気軽にコメントお願いします!

Write a Comment

コメント時の注意

「Twitter」「Facebook」「Google+」「WordPress」のいずれかのアカウントをお持ちの方は各アカウントと連携することでコメントできます。 コメントしたことはSNSに流れませんので、アカウントをお持ちの方はこちらの方法でコメントを投稿して下さると嬉しいです。 アカウントをお持ちでない方はメールアドレスで投稿することができます。 初回コメント時は承認後に表示されます。

Related Memo...

UINavigationController + UIScrollView の組み合わせで使っている時に謎の余白ができる時

UINavigationController + UIScrollView の組み合わせで使っていて、UIScrollView 上に AutoLayout で上下左右0で View を設置しているのに、30px程度上にずれてしまうとき。

`navigationController.navigationBar.isTranslucent = false` にすると直るかもしれない。

ScrollView上のコンテンツとNavigationBarの重なっているところが透過していたら多分これで直せるはず。

通常のターゲットではちゃんと動いているのに、iOSSnapshotTestCase を用いたテストでだけこの対応が必要なのよくわからないけれど。。。

iOS

記事を書くほどでもないけれどメモっておきたいこと

テスト投稿。

例えばiphone7 の画面サイズ

750 × 1334
半分375 × 667

iOS

UITableView.RowAnimation の .none はアニメーションするよ

UITableView.RowAnimation の .none はアニメーションがnoneなわけじゃなく、デフォルトの設定を使うよという意味らしい。

The inserted or deleted rows use the default animations.

なのでアニメーションしちゃう。今更の気づき。

 

iOS
more