0

I am trying to create an iOS app which (besides a few other things) needs to load in the content of a Wordpress-Page

When I use the getPosts feature from Wordpress's XML-RPC feature, I get the following returned:

<?xml version="1.0" encoding="UTF-8"?>
<methodResponse>
  <params>
    <param>
      <value>
      <array><data>
  <value><struct>
  <member><name>post_id</name><value><string>23</string></value></member>
  <member><name>post_title</name><value><string>&lt;!--:de--&gt;Post1&lt;!--:--&gt;&lt;!--:en--&gt;Post1&lt;!--:--&gt;</string></value></member>
  <member><name>post_date</name><value><dateTime.iso8601>20140211T14:26:39</dateTime.iso8601></value></member>
  <member><name>post_date_gmt</name><value><dateTime.iso8601>20140211T12:26:39</dateTime.iso8601></value></member>
  <member><name>post_modified</name><value><dateTime.iso8601>20140217T22:32:45</dateTime.iso8601></value></member>
  <member><name>post_modified_gmt</name><value><dateTime.iso8601>20140217T20:32:45</dateTime.iso8601></value></member>
  <member><name>post_status</name><value><string>publish</string></value></member>
  <member><name>post_type</name><value><string>post</string></value></member>
  <member><name>post_name</name><value><string>im-notfall</string></value></member>
  <member><name>post_author</name><value><string>1</string></value></member>
  <member><name>post_password</name><value><string></string></value></member>
  <member><name>post_excerpt</name><value><string></string></value></member>
  <member><name>post_content</name><value><string>&lt;!--:de--&gt;&lt;b&gt;Post1&lt;/b&gt;&lt;!--:--&gt;&lt;!--:en--&gt;&lt;b&gt;Post1&lt;/b&gt;&lt;!--:--&gt;</string></value></member>
  <member><name>post_parent</name><value><string>0</string></value></member>
  <member><name>post_mime_type</name><value><string></string></value></member>
  <member><name>link</name><value><string>http://example.com/ExampleProjekt/?p=23</string></value></member>
  <member><name>guid</name><value><string>http://example.com/ExampleProjekt/?p=23</string></value></member>
  <member><name>menu_order</name><value><int>5</int></value></member>
  <member><name>comment_status</name><value><string>closed</string></value></member>
  <member><name>ping_status</name><value><string>open</string></value></member>
  <member><name>sticky</name><value><boolean>0</boolean></value></member>
  <member><name>post_thumbnail</name><value><array><data>
</data></array></value></member>
  <member><name>post_format</name><value><string>standard</string></value></member>
  <member><name>terms</name><value><array><data>
  <value><struct>
  <member><name>term_id</name><value><string>1</string></value></member>
  <member><name>name</name><value><string>Allgemein</string></value></member>
  <member><name>slug</name><value><string>allgemein</string></value></member>
  <member><name>term_group</name><value><string>0</string></value></member>
  <member><name>term_taxonomy_id</name><value><string>1</string></value></member>
  <member><name>taxonomy</name><value><string>category</string></value></member>
  <member><name>description</name><value><string></string></value></member>
  <member><name>parent</name><value><string>0</string></value></member>
  <member><name>count</name><value><int>3</int></value></member>
</struct></value>
</data></array></value></member>
  <member><name>custom_fields</name><value><array><data>
</data></array></value></member>
</struct></value>
  <value><struct>
  <member><name>post_id</name><value><string>9</string></value></member>
  <member><name>post_title</name><value><string>&lt;!--:de--&gt;Post2&lt;!--:--&gt;&lt;!--:en--&gt;Post2&lt;!--:--&gt;</string></value></member>
  <member><name>post_date</name><value><dateTime.iso8601>20140206T13:16:56</dateTime.iso8601></value></member>
  <member><name>post_date_gmt</name><value><dateTime.iso8601>20140206T11:16:56</dateTime.iso8601></value></member>
  <member><name>post_modified</name><value><dateTime.iso8601>20140217T22:33:01</dateTime.iso8601></value></member>
  <member><name>post_modified_gmt</name><value><dateTime.iso8601>20140217T20:33:01</dateTime.iso8601></value></member>
  <member><name>post_status</name><value><string>publish</string></value></member>
  <member><name>post_type</name><value><string>post</string></value></member>
  <member><name>post_name</name><value><string>neuer-erster-beitrag</string></value></member>
  <member><name>post_author</name><value><string>1</string></value></member>
  <member><name>post_password</name><value><string></string></value></member>
  <member><name>post_excerpt</name><value><string></string></value></member>
  <member><name>post_content</name><value><string>&lt;!--:de--&gt;&lt;b&gt;Post2&lt;/b&gt;&lt;!--:--&gt;&lt;!--:en--&gt;&lt;b&gt;Post2&lt;/b&gt;&lt;!--:--&gt;</string></value></member>
  <member><name>post_parent</name><value><string>0</string></value></member>
  <member><name>post_mime_type</name><value><string></string></value></member>
  <member><name>link</name><value><string>http://example.com/ExampleProjekt/?p=9</string></value></member>
  <member><name>guid</name><value><string>http://example.com/ExampleProjekt/?p=9</string></value></member>
  <member><name>menu_order</name><value><int>3</int></value></member>
  <member><name>comment_status</name><value><string>closed</string></value></member>
  <member><name>ping_status</name><value><string>open</string></value></member>
  <member><name>sticky</name><value><boolean>0</boolean></value></member>
  <member><name>post_thumbnail</name><value><array><data>
</data></array></value></member>
  <member><name>post_format</name><value><string>standard</string></value></member>
  <member><name>terms</name><value><array><data>
  <value><struct>
  <member><name>term_id</name><value><string>1</string></value></member>
  <member><name>name</name><value><string>Allgemein</string></value></member>
  <member><name>slug</name><value><string>allgemein</string></value></member>
  <member><name>term_group</name><value><string>0</string></value></member>
  <member><name>term_taxonomy_id</name><value><string>1</string></value></member>
  <member><name>taxonomy</name><value><string>category</string></value></member>
  <member><name>description</name><value><string></string></value></member>
  <member><name>parent</name><value><string>0</string></value></member>
  <member><name>count</name><value><int>3</int></value></member>
</struct></value>
</data></array></value></member>
  <member><name>custom_fields</name><value><array><data>
</data></array></value></member>
</struct></value>
  <value><struct>
  <member><name>post_id</name><value><string>5</string></value></member>
  <member><name>post_title</name><value><string>&lt;!--:de--&gt;Post3&lt;!--:--&gt;&lt;!--:en--&gt;Post3&lt;!--:--&gt;</string></value></member>
  <member><name>post_date</name><value><dateTime.iso8601>20131217T17:32:09</dateTime.iso8601></value></member>
  <member><name>post_date_gmt</name><value><dateTime.iso8601>20131217T15:32:09</dateTime.iso8601></value></member>
  <member><name>post_modified</name><value><dateTime.iso8601>20140217T22:33:18</dateTime.iso8601></value></member>
  <member><name>post_modified_gmt</name><value><dateTime.iso8601>20140217T20:33:18</dateTime.iso8601></value></member>
  <member><name>post_status</name><value><string>publish</string></value></member>
  <member><name>post_type</name><value><string>post</string></value></member>
  <member><name>post_name</name><value><string>test-beitrag-2</string></value></member>
  <member><name>post_author</name><value><string>1</string></value></member>
  <member><name>post_password</name><value><string></string></value></member>
  <member><name>post_excerpt</name><value><string></string></value></member>
  <member><name>post_content</name><value><string>&lt;!--:de--&gt;&lt;b&gt;Post3&lt;/b&gt;&lt;!--:--&gt;&lt;!--:en--&gt;&lt;b&gt;Post3&lt;/b&gt;&lt;!--:--&gt;</string></value></member>
  <member><name>post_parent</name><value><string>0</string></value></member>
  <member><name>post_mime_type</name><value><string></string></value></member>
  <member><name>link</name><value><string>http://example.com/ExampleProjekt/?p=5</string></value></member>
  <member><name>guid</name><value><string>http://example.com/ExampleProjekt/?p=5</string></value></member>
  <member><name>menu_order</name><value><int>4</int></value></member>
  <member><name>comment_status</name><value><string>closed</string></value></member>
  <member><name>ping_status</name><value><string>open</string></value></member>
  <member><name>sticky</name><value><boolean>0</boolean></value></member>
  <member><name>post_thumbnail</name><value><array><data>
</data></array></value></member>
  <member><name>post_format</name><value><string>standard</string></value></member>
  <member><name>terms</name><value><array><data>
  <value><struct>
  <member><name>term_id</name><value><string>1</string></value></member>
  <member><name>name</name><value><string>Allgemein</string></value></member>
  <member><name>slug</name><value><string>allgemein</string></value></member>
  <member><name>term_group</name><value><string>0</string></value></member>
  <member><name>term_taxonomy_id</name><value><string>1</string></value></member>
  <member><name>taxonomy</name><value><string>category</string></value></member>
  <member><name>description</name><value><string></string></value></member>
  <member><name>parent</name><value><string>0</string></value></member>
  <member><name>count</name><value><int>3</int></value></member>
</struct></value>
</data></array></value></member>
  <member><name>custom_fields</name><value><array><data>
</data></array></value></member>
</struct></value>
</data></array>
      </value>
    </param>
  </params>
</methodResponse>

Specifically I would need the following fields:

  • post_id
  • post_title
  • post_motified
  • post_content
  • menu_order

I've tried a few options to achieve this. One was using Gdata, which has been recommended in another post, but the example is for a simpler xml, and I can't seem to get it to work for me.

    NSArray *tempPosts = [XMLdoc nodesForXPath:@"//methodResponse/params/param/value/array/data/value/struct/member" error:nil];

I also tried using the WPXMLRPC framework -> https://github.com/wordpress-mobile/wpxmlrpc

Using this code:

WPXMLRPCDecoder *decodedWPXML = [[WPXMLRPCDecoder alloc] initWithData:XMLcontent];
if ([decodedWPXML isFault]) {
    NSLog(@"XML-RPC error %ld: %@", (long)[decodedWPXML faultCode], [decodedWPXML faultString]);
} else {
    NSLog(@"XML-RPC response: %@", [decodedWPXML object]);
}

I manage to receive an object, which I can output via NSLog(@"%@", object); But I fail to further process any data I receive that way. I am (maybe obvious for some) very new to objective-c. I have also looked at the official wordpress for iOS app, but I wasn't able to make use of any code.

Any help would be appreciated, I don't mind using any different frameworks/technologies, etc. if they help getting to my solution.

Kevin Grabher
  • 399
  • 1
  • 4
  • 18

2 Answers2

0

I am happy with Wordpress JSON plugin, it's free. You can easily fine tune your requests to specific pages and post types, it's well documented. What you get back from your site is always a structure of dictionaries and arrays in JSON (better then XML ;). Good way to examine the JSON structure is a JSON viewer.

Some sample code to get started.

- (void)loadNewsForPage:(NSUInteger)page
{

    NSURLSession *session = [NSURLSession sharedSession];
    [[session dataTaskWithURL:[NSURL URLWithString:[NSString stringWithFormat:@"http://www.mywordpresssite.com/api/get_posts/?page=%lu", (unsigned long)page]]
            completionHandler:^(NSData *data,
                                NSURLResponse *response,
                                NSError *error) {

                // handle response
                NSError *jsonError = nil;
                id jsonObject = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&jsonError];

                if (!jsonError) {
                    if ([jsonObject isKindOfClass:[NSDictionary class]]) {

                        // fill datastore
                        [self newsIntoDataStore:(NSDictionary *)jsonObject forPage:page];
                    }
                    else {
                        NSLog(@"returned jsonObject is not a dictionary!");
                    }
                } else {
                    NSLog(@"jsonError, news: %@", jsonError);
                }

            }] resume];
}

- (void)newsIntoDataStore:(NSDictionary *)news forPage:(NSUInteger)page
{
    if ([[news objectForKey:@"status"] isEqualToString:@"ok"]) {

        self.newsPages = [[news objectForKey:@"pages"] integerValue];
        NSArray *posts = [news objectForKey:@"posts"];

        if (posts.count > 0) {
            // store individual posts

            for (NSDictionary *post in posts) {

                // determine post slug
                NSArray *categoriesArray = [post objectForKey:@"categories"];
                NSString *postSlug = nil;
                NSString *desiredSlug = @"news";

                if (categoriesArray.count > 0) {
                    for (NSDictionary *category in categoriesArray) {
                        if ([[category objectForKey:@"slug"] isEqualToString:desiredSlug]) {
                            postSlug = desiredSlug;
                        }
                    }
                }

                    NSString *title = [post objectForKey:@"title"];

                    NSDate *dateFromAPI = [self.dateFormatterFromAPI dateFromString:[post objectForKey:@"date"]];
                    NSString *date = [self.dateFormatterForCell stringFromDate:dateFromAPI];

                    NSString *imageURLStringOrg = [[[post objectForKey:@"thumbnail_images"] objectForKey:@"full"] objectForKey:@"url"];
                    NSString *imageURLStringConverted = [imageURLStringOrg stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];

                    NSAttributedString *attributedContentString = [[NSAttributedString alloc] initWithData:[[post objectForKey:@"excerpt"] dataUsingEncoding:NSUTF8StringEncoding] options:@{NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType, NSCharacterEncodingDocumentAttribute: [NSNumber numberWithInt:NSUTF8StringEncoding]} documentAttributes:nil error:nil];
                    NSString *content = [attributedContentString string];

                    NSString *url = [post objectForKey:@"url"];

                    if (title && date && imageURLStringConverted && content && url) {

                        NSDictionary *postDictionary = @{@"title" : title, @"date" : date, @"imageURL" : imageURLStringConverted, @"content" : content, @"url" : url};

                        [self.newsArray addObject:postDictionary];

                    } else {
                        NSLog(@"some post item empty, skipping this post: %lu", (unsigned long)[posts indexOfObject:post]);
                    }
                }

            }

            dispatch_async(dispatch_get_main_queue(), ^{

                if (self.pageLoaded < self.newsPages) {
                    [self loadNewsForPage:self.pageLoaded + 1];
                } else {

                    [self.delegate newsFetchingCompleted];
                }
            });

        } else {
            NSLog(@"no objects in the array");
        }
    } else {
        NSLog(@"returned status NOT OK");
    }
}
Martin Koles
  • 5,177
  • 8
  • 39
  • 59
  • onfortunately, this way I can't get the menu_order, which removes the ability to manually sort posts in the wordpress backend it seems the WPXMLRPCDecoder also returns json-code, however it is then just saved as an Object (in fact an NSobject), is there some way to convert this into an NSDictionary? – Kevin Grabher Feb 17 '14 at 21:56
  • NSObject is just superclass of NSDictionary. Handling of the returned object is part of the sample code, see under // handle response. There is a check for the kind of returned object. Once you succeed with NSDictionary, you just start to parse it. – Martin Koles Feb 17 '14 at 22:05
  • it works on your code, if I use the if object iskindofclass nsdictionary on the object returned from WPXMLRPCDecoder it returns false, even tho NSLog on that object outputs code on the console that looks exactly alike with JSON – Kevin Grabher Feb 17 '14 at 22:20
  • I don't know how the decoder works, but if you said it is capable of returning JSON, it should return JSON. I would configure the service to return JSON as you said and paste the output to the JSON viewer. Not the print of the NSLog, but the data output from URL session/connection. If the viewer reads the output, it is then recognized and JSON and you can examine the structure and parse it. – Martin Koles Feb 17 '14 at 22:26
0
GDataXMLDocument *XMLdoc = [[GDataXMLDocument alloc] initWithData:XMLcontent options:0 error:nil];
NSArray *XMLofPosts = [XMLdoc  nodesForXPath:@"//methodResponse/params/param/value/array/data/value/struct/member" error:nil];

gives me an array of all post members that i can iterate via
for(GDataXMLElement *postMember in XMLofPosts){ ... }

Thansk for the help. I've opened a new post for a more detailed question on the subject, since I found it's pretty much a different question, since it's on GDataXML more than getting the Wordpress XML GDataXML nodesForXPath on Node contains items of entire GDataXMLDocument

Community
  • 1
  • 1
Kevin Grabher
  • 399
  • 1
  • 4
  • 18