JSON API - Version 1.0

Version Description

Major release, see changelog for details.

Download this release

Release Info

Developer dphiffer
Plugin Icon wp plugin JSON API
Version 1.0
Comparing to
See all releases

Code changes from version 0.9.6 to 1.0

controllers/core.php ADDED
@@ -0,0 +1,311 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Name: Core
4
+ Description: Basic introspection methods
5
+ */
6
+
7
+ class JSON_API_Core_Controller {
8
+
9
+ public function info() {
10
+ global $json_api;
11
+ if (!empty($json_api->query->controller)) {
12
+ return $json_api->controller_info($json_api->query->controller);
13
+ } else {
14
+ $dir = dirname(dirname(__FILE__));
15
+ $php = file_get_contents("$dir/json-api.php");
16
+ if (preg_match('/^\s*Version:\s*(.+)$/m', $php, $matches)) {
17
+ $version = $matches[1];
18
+ } else {
19
+ $version = '(Unknown)';
20
+ }
21
+ $active_controllers = explode(',', get_option('json_api_controllers', 'core'));
22
+ $controllers = array_intersect($json_api->get_controllers(), $active_controllers);
23
+ return array(
24
+ 'json_api_version' => $version,
25
+ 'controllers' => $controllers
26
+ );
27
+ }
28
+ }
29
+
30
+ public function get_recent_posts() {
31
+ global $json_api;
32
+ $posts = $json_api->introspector->get_posts();
33
+ return $this->posts_result($posts);
34
+ }
35
+
36
+ public function get_post() {
37
+ global $json_api;
38
+ extract($json_api->query->get(array('id', 'slug', 'post_id', 'post_slug')));
39
+ if ($id || $post_id) {
40
+ if (!$id) {
41
+ $id = $post_id;
42
+ }
43
+ $posts = $json_api->introspector->get_posts(array(
44
+ 'p' => $id
45
+ ));
46
+ } else if ($slug || $post_slug) {
47
+ if (!$slug) {
48
+ $slug = $post_slug;
49
+ }
50
+ $posts = $json_api->introspector->get_posts(array(
51
+ 'name' => $slug
52
+ ));
53
+ } else {
54
+ $json_api->error("Include 'id' or 'slug' var in your request.");
55
+ }
56
+ if (count($posts) == 1) {
57
+ return array(
58
+ 'post' => $posts[0]
59
+ );
60
+ } else {
61
+ $json_api->error("Not found.");
62
+ }
63
+ }
64
+
65
+ public function get_page() {
66
+ global $json_api;
67
+ extract($json_api->query->get(array('id', 'slug', 'page_id', 'page_slug', 'children')));
68
+ if ($id || $page_id) {
69
+ if (!$id) {
70
+ $id = $page_id;
71
+ }
72
+ $posts = $json_api->introspector->get_posts(array(
73
+ 'page_id' => $id
74
+ ));
75
+ } else if ($slug || $page_slug) {
76
+ if (!$slug) {
77
+ $slug = $page_slug;
78
+ }
79
+ $posts = $json_api->introspector->get_posts(array(
80
+ 'pagename' => $slug
81
+ ));
82
+ } else {
83
+ $json_api->error("Include 'id' or 'slug' var in your request.");
84
+ }
85
+
86
+ // Workaround for https://core.trac.wordpress.org/ticket/12647
87
+ if (empty($posts)) {
88
+ $url = $_SERVER['REQUEST_URI'];
89
+ $parsed_url = parse_url($url);
90
+ $path = $parsed_url['path'];
91
+ if (preg_match('#^http://[^/]+(/.+)$#', get_bloginfo('url'), $matches)) {
92
+ $blog_root = $matches[1];
93
+ $path = preg_replace("#^$blog_root#", '', $path);
94
+ }
95
+ if (substr($path, 0, 1) == '/') {
96
+ $path = substr($path, 1);
97
+ }
98
+ $posts = $json_api->introspector->get_posts(array('pagename' => $path));
99
+ }
100
+
101
+ if (count($posts) == 1) {
102
+ if (!empty($children)) {
103
+ $json_api->introspector->attach_child_posts($posts[0]);
104
+ }
105
+ return array(
106
+ 'page' => $posts[0]
107
+ );
108
+ } else {
109
+ $json_api->error("Not found.");
110
+ }
111
+ }
112
+
113
+ public function get_date_posts() {
114
+ global $json_api;
115
+ if ($json_api->query->date) {
116
+ $date = preg_replace('/\D/', '', $json_api->query->date);
117
+ if (!preg_match('/^\d{4}(\d{2})?(\d{2})?$/', $date)) {
118
+ $json_api->error("Specify a date var in one of 'YYYY' or 'YYYY-MM' or 'YYYY-MM-DD' formats.");
119
+ }
120
+ $request = array('year' => substr($date, 0, 4));
121
+ if (strlen($date) > 4) {
122
+ $request['monthnum'] = (int) substr($date, 4, 2);
123
+ }
124
+ if (strlen($date) > 6) {
125
+ $request['day'] = (int) substr($date, 6, 2);
126
+ }
127
+ $posts = $json_api->introspector->get_posts($request);
128
+ } else {
129
+ $json_api->error("Include 'date' var in your request.");
130
+ }
131
+ return $this->posts_result($posts);
132
+ }
133
+
134
+ public function get_category_posts() {
135
+ global $json_api;
136
+ $category = $json_api->introspector->get_current_category();
137
+ if (!$category) {
138
+ $json_api->error("Not found.");
139
+ }
140
+ $posts = $json_api->introspector->get_posts(array(
141
+ 'cat' => $category->id
142
+ ));
143
+ return $this->posts_object_result($posts, $category);
144
+ }
145
+
146
+ public function get_tag_posts() {
147
+ global $json_api;
148
+ $tag = $json_api->introspector->get_current_tag();
149
+ if (!$tag) {
150
+ $json_api->error("Not found.");
151
+ }
152
+ $posts = $json_api->introspector->get_posts(array(
153
+ 'tag_id' => $tag->id
154
+ ));
155
+ return $this->posts_object_result($posts, $tag);
156
+ }
157
+
158
+ public function get_author_posts() {
159
+ global $json_api;
160
+ $author = $json_api->introspector->get_current_author();
161
+ if (!$author) {
162
+ $json_api->error("Not found.");
163
+ }
164
+ $posts = $json_api->introspector->get_posts(array(
165
+ 'author' => $author->id
166
+ ));
167
+ return $this->posts_object_result($posts, $author);
168
+ }
169
+
170
+ public function get_search_results() {
171
+ global $json_api;
172
+ if ($json_api->query->search) {
173
+ $posts = $json_api->introspector->get_posts(array(
174
+ 's' => $json_api->query->search
175
+ ));
176
+ } else {
177
+ $json_api->error("Include 'search' var in your request.");
178
+ }
179
+ return $this->posts_result($posts);
180
+ }
181
+
182
+ public function get_date_index() {
183
+ global $json_api;
184
+ $permalinks = $json_api->introspector->get_date_archive_permalinks();
185
+ $tree = $json_api->introspector->get_date_archive_tree($permalinks);
186
+ return array(
187
+ 'permalinks' => $permalinks,
188
+ 'tree' => $tree
189
+ );
190
+ }
191
+
192
+ public function get_category_index() {
193
+ global $json_api;
194
+ $categories = $json_api->introspector->get_categories();
195
+ return array(
196
+ 'count' => count($categories),
197
+ 'categories' => $categories
198
+ );
199
+ }
200
+
201
+ public function get_tag_index() {
202
+ global $json_api;
203
+ $tags = $json_api->introspector->get_tags();
204
+ return array(
205
+ 'count' => count($tags),
206
+ 'tags' => $tags
207
+ );
208
+ }
209
+
210
+ public function get_author_index() {
211
+ global $json_api;
212
+ $authors = $json_api->introspector->get_authors();
213
+ return array(
214
+ 'count' => count($authors),
215
+ 'authors' => array_values($authors)
216
+ );
217
+ }
218
+
219
+ public function get_page_index() {
220
+ global $json_api;
221
+ $pages = array();
222
+ $wp_posts = get_posts(array(
223
+ 'post_type' => 'page',
224
+ 'post_parent' => 0,
225
+ 'order' => 'ASC',
226
+ 'orderby' => 'menu_order'
227
+ ));
228
+ foreach ($wp_posts as $wp_post) {
229
+ $pages[] = new JSON_API_Post($wp_post);
230
+ }
231
+ foreach ($pages as $page) {
232
+ $json_api->introspector->attach_child_posts($page);
233
+ }
234
+ return array(
235
+ 'pages' => $pages
236
+ );
237
+ }
238
+
239
+ public function get_nonce() {
240
+ global $json_api;
241
+ extract($json_api->query->get(array('controller', 'method')));
242
+ if ($controller && $method) {
243
+ $controller = strtolower($controller);
244
+ if (!in_array($controller, $json_api->get_controllers())) {
245
+ $json_api->error("Unknown controller '$controller'.");
246
+ }
247
+ require_once $json_api->controller_path($controller);
248
+ if (!method_exists($json_api->controller_class($controller), $method)) {
249
+ $json_api->error("Unknown method '$method'.");
250
+ }
251
+ $nonce_id = $json_api->get_nonce_id($controller, $method);
252
+ return array(
253
+ 'controller' => $controller,
254
+ 'method' => $method,
255
+ 'nonce' => wp_create_nonce($nonce_id)
256
+ );
257
+ } else {
258
+ $json_api->error("Include 'controller' and 'method' vars in your request.");
259
+ }
260
+ }
261
+
262
+ protected function get_object_posts($object, $id_var, $slug_var) {
263
+ global $json_api;
264
+ $object_id = "{$type}_id";
265
+ $object_slug = "{$type}_slug";
266
+ extract($json_api->query->get(array('id', 'slug', $object_id, $object_slug)));
267
+ if ($id || $$object_id) {
268
+ if (!$id) {
269
+ $id = $$object_id;
270
+ }
271
+ $posts = $json_api->introspector->get_posts(array(
272
+ $id_var => $id
273
+ ));
274
+ } else if ($slug || $$object_slug) {
275
+ if (!$slug) {
276
+ $slug = $$object_slug;
277
+ }
278
+ $posts = $json_api->introspector->get_posts(array(
279
+ $slug_var => $slug
280
+ ));
281
+ } else {
282
+ $json_api->error("No $type specified. Include 'id' or 'slug' var in your request.");
283
+ }
284
+ return $posts;
285
+ }
286
+
287
+ protected function posts_result($posts) {
288
+ global $wp_query;
289
+ return array(
290
+ 'count' => count($posts),
291
+ 'count_total' => (int) $wp_query->found_posts,
292
+ 'pages' => $wp_query->max_num_pages,
293
+ 'posts' => $posts
294
+ );
295
+ }
296
+
297
+ protected function posts_object_result($posts, $object) {
298
+ global $wp_query;
299
+ // Convert something like "JSON_API_Category" into "category"
300
+ $object_key = strtolower(substr(get_class($object), 9));
301
+ return array(
302
+ 'count' => count($posts),
303
+ 'pages' => (int) $wp_query->max_num_pages,
304
+ $object_key => $object,
305
+ 'posts' => $posts
306
+ );
307
+ }
308
+
309
+ }
310
+
311
+ ?>
controllers/posts.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Name: Posts
4
+ Description: Data manipulation methods for posts
5
+ URL:
6
+ */
7
+
8
+ class JSON_API_Posts_Controller {
9
+
10
+ public function create_post() {
11
+ global $json_api;
12
+ if (!current_user_can('edit_posts')) {
13
+ $json_api->error("You need to login with a user capable of creating posts.");
14
+ }
15
+ if (!$json_api->query->nonce) {
16
+ $json_api->error("You must include a 'nonce' value to create posts. Use the `get_nonce` Core API method.");
17
+ }
18
+ $nonce_id = $json_api->get_nonce_id('posts', 'create_post');
19
+ if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
20
+ $json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.");
21
+ }
22
+ nocache_headers();
23
+ $post = new JSON_API_Post();
24
+ $id = $post->create($_REQUEST);
25
+ if (empty($id)) {
26
+ $json_api->error("Could not create post.");
27
+ }
28
+ return array(
29
+ 'post' => $post
30
+ );
31
+ }
32
+
33
+ }
34
+
35
+ ?>
controllers/respond.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Name: Respond
4
+ Description: Comment/trackback submission methods
5
+ URL:
6
+ */
7
+
8
+ class JSON_API_Respond_Controller {
9
+
10
+ function submit_comment() {
11
+ global $json_api;
12
+ nocache_headers();
13
+ if (empty($_REQUEST['post_id'])) {
14
+ $json_api->error("No post specified. Include 'post_id' var in your request.");
15
+ } else if (empty($_REQUEST['name']) ||
16
+ empty($_REQUEST['email']) ||
17
+ empty($_REQUEST['content'])) {
18
+ $json_api->error("Please include all required arguments (name, email, content).");
19
+ } else if (!is_email($_REQUEST['email'])) {
20
+ $json_api->error("Please enter a valid email address.");
21
+ }
22
+ $pending = new JSON_API_Comment();
23
+ return $pending->handle_submission();
24
+ }
25
+
26
+ }
27
+
28
+ ?>
json-api.php CHANGED
@@ -3,21 +3,34 @@
3
  Plugin Name: JSON API
4
  Plugin URI: http://wordpress.org/extend/plugins/json-api/
5
  Description: A RESTful API for WordPress
6
- Version: 0.9.6
7
  Author: Dan Phiffer
8
  Author URI: http://phiffer.org/
9
  */
10
 
11
- global $json_api_dir;
12
- $json_api_dir = WP_PLUGIN_DIR . '/json-api';
 
 
 
 
 
 
 
 
13
 
14
  function json_api_init() {
15
- // Initialize the controller and query inspector
16
- global $json_api, $json_api_dir;
17
- require_once "$json_api_dir/singletons/controller.php";
18
- require_once "$json_api_dir/singletons/query.php";
 
19
  add_filter('rewrite_rules_array', 'json_api_rewrites');
20
- $json_api = new JSON_API_Controller();
 
 
 
 
21
  }
22
 
23
  function json_api_activation() {
@@ -34,16 +47,365 @@ function json_api_deactivation() {
34
  }
35
 
36
  function json_api_rewrites($wp_rules) {
37
- // Register the rewrite rule /api/[method] => ?json=[method]
 
 
 
38
  $json_api_rules = array(
39
- 'api/(.+)$' => 'index.php?json=$matches[1]'
 
40
  );
41
  return array_merge($json_api_rules, $wp_rules);
42
  }
43
 
44
  // Add initialization and activation hooks
45
  add_action('init', 'json_api_init');
46
- register_activation_hook("$json_api_dir/json-api.php", 'json_api_activation');
47
- register_deactivation_hook("$json_api_dir/json-api.php", 'json_api_deactivation');
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  ?>
3
  Plugin Name: JSON API
4
  Plugin URI: http://wordpress.org/extend/plugins/json-api/
5
  Description: A RESTful API for WordPress
6
+ Version: 1.0
7
  Author: Dan Phiffer
8
  Author URI: http://phiffer.org/
9
  */
10
 
11
+ $dir = dirname(__FILE__);
12
+ require_once "$dir/singletons/query.php";
13
+ require_once "$dir/singletons/introspector.php";
14
+ require_once "$dir/singletons/response.php";
15
+ require_once "$dir/models/post.php";
16
+ require_once "$dir/models/comment.php";
17
+ require_once "$dir/models/category.php";
18
+ require_once "$dir/models/tag.php";
19
+ require_once "$dir/models/author.php";
20
+ require_once "$dir/models/attachment.php";
21
 
22
  function json_api_init() {
23
+ global $json_api;
24
+ if (phpversion() < 5) {
25
+ add_action('admin_notices', 'json_api_php_version_warning');
26
+ return;
27
+ }
28
  add_filter('rewrite_rules_array', 'json_api_rewrites');
29
+ $json_api = new JSON_API();
30
+ }
31
+
32
+ function json_api_php_version_warning() {
33
+ echo "<div id=\"json-api-warning\" class=\"updated fade\"><p>Sorry, JSON API requires PHP version 5.0 or greater.</p></div>";
34
  }
35
 
36
  function json_api_activation() {
47
  }
48
 
49
  function json_api_rewrites($wp_rules) {
50
+ $base = get_option('json_api_base', 'api');
51
+ if (empty($base)) {
52
+ return $wp_rules;
53
+ }
54
  $json_api_rules = array(
55
+ "$base\$" => 'index.php?json=info',
56
+ "$base/(.+)\$" => 'index.php?json=$matches[1]'
57
  );
58
  return array_merge($json_api_rules, $wp_rules);
59
  }
60
 
61
  // Add initialization and activation hooks
62
  add_action('init', 'json_api_init');
63
+ register_activation_hook("$dir/json-api.php", 'json_api_activation');
64
+ register_deactivation_hook("$dir/json-api.php", 'json_api_deactivation');
65
+
66
+
67
+ class JSON_API {
68
+
69
+ function __construct() {
70
+ $this->query = new JSON_API_Query();
71
+ $this->introspector = new JSON_API_Introspector();
72
+ $this->response = new JSON_API_Response();
73
+ add_action('template_redirect', array(&$this, 'template_redirect'));
74
+ add_action('admin_menu', array(&$this, 'admin_menu'));
75
+ add_action('update_option_json_api_base', array(&$this, 'flush_rewrite_rules'));
76
+ add_action('pre_update_option_json_api_controllers', array(&$this, 'update_controllers'));
77
+ }
78
+
79
+ function template_redirect() {
80
+ // Check to see if there's an appropriate API controller + method
81
+ $controller = strtolower($this->query->get_controller());
82
+ $available_controllers = $this->get_controllers();
83
+ $enabled_controllers = explode(',', get_option('json_api_controllers', 'core'));
84
+ $active_controllers = array_intersect($available_controllers, $enabled_controllers);
85
+
86
+ if ($controller) {
87
+
88
+ if (!in_array($controller, $active_controllers)) {
89
+ $this->error("Unknown controller '$controller'.");
90
+ }
91
+
92
+ $controller_path = $this->controller_path($controller);
93
+ if (file_exists($controller_path)) {
94
+ require_once $controller_path;
95
+ }
96
+ $controller_class = $this->controller_class($controller);
97
+
98
+ if (!class_exists($controller_class)) {
99
+ $this->error("Unknown controller '$controller_class'.");
100
+ }
101
+
102
+ $this->controller = new $controller_class();
103
+ $method = $this->query->get_method($controller);
104
+
105
+ if ($method) {
106
+
107
+ $this->response->setup();
108
+
109
+ // Run action hooks for method
110
+ do_action("json_api-{$controller}-$method");
111
+
112
+ // Error out if nothing is found
113
+ if ($method == '404') {
114
+ $this->error('Not found');
115
+ }
116
+
117
+ // Run the method
118
+ $result = $this->controller->$method();
119
+
120
+ // Handle the result
121
+ $this->response->respond($result);
122
+
123
+ // Done!
124
+ exit;
125
+ }
126
+ }
127
+ }
128
+
129
+ function admin_menu() {
130
+ add_options_page('JSON API Settings', 'JSON API', 'manage_options', 'json-api', array(&$this, 'admin_options'));
131
+ }
132
+
133
+ function admin_options() {
134
+ if (!current_user_can('manage_options')) {
135
+ wp_die( __('You do not have sufficient permissions to access this page.') );
136
+ }
137
+
138
+ $available_controllers = $this->get_controllers();
139
+ $active_controllers = explode(',', get_option('json_api_controllers', 'core'));
140
+
141
+ if (count($active_controllers) == 1 && empty($active_controllers[0])) {
142
+ $active_controllers = array();
143
+ }
144
+
145
+ if (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], "update-options")) {
146
+ if ((!empty($_REQUEST['action']) || !empty($_REQUEST['action2'])) &&
147
+ (!empty($_REQUEST['controller']) || !empty($_REQUEST['controllers']))) {
148
+ if (!empty($_REQUEST['action'])) {
149
+ $action = $_REQUEST['action'];
150
+ } else {
151
+ $action = $_REQUEST['action2'];
152
+ }
153
+
154
+ if (!empty($_REQUEST['controllers'])) {
155
+ $controllers = $_REQUEST['controllers'];
156
+ } else {
157
+ $controllers = array($_REQUEST['controller']);
158
+ }
159
+
160
+ foreach ($controllers as $controller) {
161
+ if (in_array($controller, $available_controllers)) {
162
+ if ($action == 'activate' && !in_array($controller, $active_controllers)) {
163
+ $active_controllers[] = $controller;
164
+ } else if ($action == 'deactivate') {
165
+ $index = array_search($controller, $active_controllers);
166
+ if ($index !== false) {
167
+ unset($active_controllers[$index]);
168
+ }
169
+ }
170
+ }
171
+ }
172
+ $this->save_option('json_api_controllers', implode(',', $active_controllers));
173
+ }
174
+ if (isset($_REQUEST['json_api_base'])) {
175
+ $this->save_option('json_api_base', $_REQUEST['json_api_base']);
176
+ }
177
+ }
178
+
179
+ ?>
180
+ <div class="wrap">
181
+ <div id="icon-options-general" class="icon32"><br /></div>
182
+ <h2>JSON API Settings</h2>
183
+ <form action="options-general.php?page=json-api" method="post">
184
+ <?php wp_nonce_field('update-options'); ?>
185
+ <h3>Controllers</h3>
186
+ <?php $this->print_controller_actions(); ?>
187
+ <table id="all-plugins-table" class="widefat">
188
+ <thead>
189
+ <tr>
190
+ <th class="manage-column check-column" scope="col"><input type="checkbox" /></th>
191
+ <th class="manage-column" scope="col">Controller</th>
192
+ <th class="manage-column" scope="col">Description</th>
193
+ </tr>
194
+ </thead>
195
+ <tfoot>
196
+ <tr>
197
+ <th class="manage-column check-column" scope="col"><input type="checkbox" /></th>
198
+ <th class="manage-column" scope="col">Controller</th>
199
+ <th class="manage-column" scope="col">Description</th>
200
+ </tr>
201
+ </tfoot>
202
+ <tbody class="plugins">
203
+ <?php
204
+
205
+ foreach ($available_controllers as $controller) {
206
+
207
+ $active = in_array($controller, $active_controllers);
208
+ $info = $this->controller_info($controller);
209
+
210
+ ?>
211
+ <tr class="<?php echo ($active ? 'active' : 'inactive'); ?>">
212
+ <th class="check-column" scope="row">
213
+ <input type="checkbox" name="controllers[]" value="<?php echo $controller; ?>" />
214
+ </th>
215
+ <td class="plugin-title">
216
+ <strong><?php echo $info['name']; ?></strong>
217
+ <div class="row-actions-visible">
218
+ <?php
219
+
220
+ if ($active) {
221
+ echo '<a href="' . wp_nonce_url('options-general.php?page=json-api&amp;action=deactivate&amp;controller=' . $controller, 'update-options') . '" title="' . __('Deactivate this controller') . '" class="edit">' . __('Deactivate') . '</a>';
222
+ } else {
223
+ echo '<a href="' . wp_nonce_url('options-general.php?page=json-api&amp;action=activate&amp;controller=' . $controller, 'update-options') . '" title="' . __('Activate this controller') . '" class="edit">' . __('Activate') . '</a>';
224
+ }
225
+
226
+ if ($info['url']) {
227
+ echo ' | ';
228
+ echo '<a href="' . $info['url'] . '" target="_blank">Docs</a></div>';
229
+ }
230
+
231
+ ?>
232
+ </td>
233
+ <td class="desc">
234
+ <p><?php echo $info['description']; ?></p>
235
+ <p>
236
+ <?php
237
+
238
+ foreach($info['methods'] as $method) {
239
+ $url = $this->get_method_url($controller, $method, array('dev' => 1));
240
+ if ($active) {
241
+ echo "<code><a href=\"$url\">$method</a></code> ";
242
+ } else {
243
+ echo "<code>$method</code> ";
244
+ }
245
+ }
246
+
247
+ ?>
248
+ </p>
249
+ </td>
250
+ </tr>
251
+ <?php } ?>
252
+ </tbody>
253
+ </table>
254
+ <?php $this->print_controller_actions('action2'); ?>
255
+ <h3>Address</h3>
256
+ <p>Specify a base URL for JSON API. For example, using <code>api</code> as your API base URL would enable the following <code><?php bloginfo('url'); ?>/api/get_recent_posts/</code>. If you assign a blank value the API will only be available by setting a <code>json</code> query variable.</p>
257
+ <table class="form-table">
258
+ <tr valign="top">
259
+ <th scope="row">API base</th>
260
+ <td><code><?php bloginfo('url'); ?>/</code><input type="text" name="json_api_base" value="<?php echo get_option('json_api_base', 'api'); ?>" size="15" /></td>
261
+ </tr>
262
+ </table>
263
+ <?php if (!get_option('permalink_structure', '')) { ?>
264
+ <br />
265
+ <p><strong>Note:</strong> User-friendly permalinks are not currently enabled. <a target="_blank" class="button" href="options-permalink.php">Change Permalinks</a>
266
+ <?php } ?>
267
+ <p class="submit">
268
+ <input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
269
+ </p>
270
+ </form>
271
+ </div>
272
+ <?php
273
+ }
274
+
275
+ function print_controller_actions($name = 'action') {
276
+ ?>
277
+ <div class="tablenav">
278
+ <div class="alignleft actions">
279
+ <select name="<?php echo $name; ?>">
280
+ <option selected="selected" value="-1">Bulk Actions</option>
281
+ <option value="activate">Activate</option>
282
+ <option value="deactivate">Deactivate</option>
283
+ </select>
284
+ <input type="submit" class="button-secondary action" id="doaction" name="doaction" value="Apply">
285
+ </div>
286
+ <div class="clear"></div>
287
+ </div>
288
+ <div class="clear"></div>
289
+ <?php
290
+ }
291
+
292
+ function get_method_url($controller, $method, $options = '') {
293
+ $url = get_bloginfo('url');
294
+ $base = get_option('json_api_base', 'api');
295
+ $permalink_structure = get_option('permalink_structure', '');
296
+ if (!empty($options) && is_array($options)) {
297
+ $args = array();
298
+ foreach ($options as $key => $value) {
299
+ $args[] = urlencode($key) . '=' . urlencode($value);
300
+ }
301
+ $args = implode('&', $args);
302
+ } else {
303
+ $args = $options;
304
+ }
305
+ if ($controller != 'core') {
306
+ $method = "$controller/$method";
307
+ }
308
+ if (!empty($base) && !empty($permalink_structure)) {
309
+ if (!empty($args)) {
310
+ $args = "?$args";
311
+ }
312
+ return "$url/$base/$method/$args";
313
+ } else {
314
+ return "$url?json=$method&$args";
315
+ }
316
+ }
317
+
318
+ function save_option($id, $value) {
319
+ $option_exists = (get_option($id, null) !== null);
320
+ if ($option_exists) {
321
+ update_option($id, $value);
322
+ } else {
323
+ add_option($id, $value);
324
+ }
325
+ }
326
+
327
+ function get_controllers() {
328
+ $controllers = array();
329
+ $dh = opendir(dirname(__FILE__) . '/controllers');
330
+ while ($file = readdir($dh)) {
331
+ if (preg_match('/(.+)\.php$/', $file, $matches)) {
332
+ $controllers[] = $matches[1];
333
+ }
334
+ }
335
+ return apply_filters('json_api_controllers', $controllers);
336
+ }
337
+
338
+ function controller_is_active($controller) {
339
+ $active_controllers = explode(',', get_option('json_api_controllers', 'core'));
340
+ return (in_array($controller, $active_controllers));
341
+ }
342
+
343
+ function update_controllers($controllers) {
344
+ if (is_array($controllers)) {
345
+ return implode(',', $controllers);
346
+ } else {
347
+ return $controllers;
348
+ }
349
+ }
350
+
351
+ function controller_info($controller) {
352
+ $path = $this->controller_path($controller);
353
+ $class = $this->controller_class($controller);
354
+ $response = array(
355
+ 'name' => $controller,
356
+ 'description' => '(No description available)',
357
+ 'methods' => array()
358
+ );
359
+ if (file_exists($path)) {
360
+ $source = file_get_contents($path);
361
+ if (preg_match('/^\s*Name:(.+)$/im', $source, $matches)) {
362
+ $response['name'] = trim($matches[1]);
363
+ }
364
+ if (preg_match('/^\s*Description:(.+)$/im', $source, $matches)) {
365
+ $response['description'] = trim($matches[1]);
366
+ }
367
+ if (preg_match('/^\s*Docs:(.+)$/im', $source, $matches)) {
368
+ $response['docs'] = trim($matches[1]);
369
+ }
370
+ require_once($path);
371
+ $response['methods'] = get_class_methods($class);
372
+ return $response;
373
+ } else {
374
+ $this->error("Unknown controller '$controller'.");
375
+ }
376
+ }
377
+
378
+ function controller_class($controller) {
379
+ return "json_api_{$controller}_controller";
380
+ }
381
+
382
+ function controller_path($controller) {
383
+ $dir = dirname(__FILE__);
384
+ $controller_class = $this->controller_class($controller);
385
+ return apply_filters("{$controller_class}_path", "$dir/controllers/$controller.php");
386
+ }
387
+
388
+ function get_nonce_id($controller, $method) {
389
+ $controller = strtolower($controller);
390
+ $method = strtolower($method);
391
+ return "json_api-$controller-$method";
392
+ }
393
+
394
+ function flush_rewrite_rules() {
395
+ global $wp_rewrite;
396
+ $wp_rewrite->flush_rules();
397
+ }
398
+
399
+ function error($message = 'Unknown error', $status = 'error') {
400
+ $this->response->respond(array(
401
+ 'error' => $message
402
+ ), $status);
403
+ }
404
+
405
+ function include_value($key) {
406
+ return $this->response->is_value_included($key);
407
+ }
408
+
409
+ }
410
 
411
  ?>
models/attachment.php CHANGED
@@ -37,6 +37,9 @@ class JSON_API_Attachment {
37
 
38
  function query_images() {
39
  $sizes = array('thumbnail', 'medium', 'large', 'full');
 
 
 
40
  $this->images = array();
41
  foreach ($sizes as $size) {
42
  list($url, $width, $height) = wp_get_attachment_image_src($this->id, $size);
37
 
38
  function query_images() {
39
  $sizes = array('thumbnail', 'medium', 'large', 'full');
40
+ if (function_exists('get_intermediate_image_sizes')) {
41
+ $sizes = array_merge(array('full'), get_intermediate_image_sizes());
42
+ }
43
  $this->images = array();
44
  foreach ($sizes as $size) {
45
  list($url, $width, $height) = wp_get_attachment_image_src($this->id, $size);
models/post.php CHANGED
@@ -6,6 +6,7 @@ class JSON_API_Post {
6
  // JSON_API_Post objects must be instantiated within The Loop.
7
 
8
  var $id; // Integer
 
9
  var $slug; // String
10
  var $url; // String
11
  var $status; // String ("draft", "published", or "pending")
@@ -56,6 +57,10 @@ class JSON_API_Post {
56
  $wp_values['ID'] = $values['id'];
57
  }
58
 
 
 
 
 
59
  if (!empty($values['status'])) {
60
  $wp_values['post_status'] = $values['status'];
61
  }
@@ -124,11 +129,12 @@ class JSON_API_Post {
124
  $date_format = $json_api->query->date_format;
125
  $this->id = (int) $wp_post->ID;
126
  setup_postdata($wp_post);
 
127
  $this->set_value('slug', $wp_post->post_name);
128
  $this->set_value('url', get_permalink($this->id));
129
  $this->set_value('status', $wp_post->post_status);
130
  $this->set_value('title', get_the_title($this->id));
131
- $this->set_value('title_plain', strip_tags($this->title));
132
  $this->set_content_value();
133
  $this->set_value('excerpt', get_the_excerpt());
134
  $this->set_value('date', get_the_time($date_format));
@@ -160,6 +166,8 @@ class JSON_API_Post {
160
  $content = apply_filters('the_content', $content);
161
  $content = str_replace(']]>', ']]&gt;', $content);
162
  $this->content = $content;
 
 
163
  }
164
  }
165
 
@@ -177,6 +185,8 @@ class JSON_API_Post {
177
  $this->categories[] = $category;
178
  }
179
  }
 
 
180
  }
181
  }
182
 
@@ -189,6 +199,8 @@ class JSON_API_Post {
189
  $this->tags[] = new JSON_API_Tag($wp_tag);
190
  }
191
  }
 
 
192
  }
193
  }
194
 
@@ -196,6 +208,8 @@ class JSON_API_Post {
196
  global $json_api;
197
  if ($json_api->include_value('author')) {
198
  $this->author = new JSON_API_Author($author_id);
 
 
199
  }
200
  }
201
 
@@ -203,6 +217,8 @@ class JSON_API_Post {
203
  global $json_api;
204
  if ($json_api->include_value('comments')) {
205
  $this->comments = $json_api->introspector->get_comments($this->id);
 
 
206
  }
207
  }
208
 
@@ -210,24 +226,26 @@ class JSON_API_Post {
210
  global $json_api;
211
  if ($json_api->include_value('attachments')) {
212
  $this->attachments = $json_api->introspector->get_attachments($this->id);
 
 
213
  }
214
  }
215
 
216
  function set_thumbnail_value() {
217
  global $json_api;
218
- $values = get_post_custom_values('_thumbnail_id', $this->id);
219
- if (empty($values)) {
220
  unset($this->thumbnail);
221
  return;
222
  }
223
- $attachments = $json_api->introspector->get_attachments($this->id);
224
- foreach ($attachments as $attachment) {
225
- if ($attachment->id == $values[0]) {
226
- $image = $attachment->images['thumbnail'];
227
- $this->thumbnail = $image->url;
228
- break;
229
- }
230
  }
 
 
 
231
  }
232
 
233
  function set_custom_fields_value() {
@@ -247,6 +265,16 @@ class JSON_API_Post {
247
  }
248
  }
249
 
 
 
 
 
 
 
 
 
 
 
250
  }
251
 
252
  ?>
6
  // JSON_API_Post objects must be instantiated within The Loop.
7
 
8
  var $id; // Integer
9
+ var $type; // String
10
  var $slug; // String
11
  var $url; // String
12
  var $status; // String ("draft", "published", or "pending")
57
  $wp_values['ID'] = $values['id'];
58
  }
59
 
60
+ if (!empty($values['type'])) {
61
+ $wp_values['post_type'] = $values['type'];
62
+ }
63
+
64
  if (!empty($values['status'])) {
65
  $wp_values['post_status'] = $values['status'];
66
  }
129
  $date_format = $json_api->query->date_format;
130
  $this->id = (int) $wp_post->ID;
131
  setup_postdata($wp_post);
132
+ $this->set_value('type', $wp_post->post_type);
133
  $this->set_value('slug', $wp_post->post_name);
134
  $this->set_value('url', get_permalink($this->id));
135
  $this->set_value('status', $wp_post->post_status);
136
  $this->set_value('title', get_the_title($this->id));
137
+ $this->set_value('title_plain', strip_tags(@$this->title));
138
  $this->set_content_value();
139
  $this->set_value('excerpt', get_the_excerpt());
140
  $this->set_value('date', get_the_time($date_format));
166
  $content = apply_filters('the_content', $content);
167
  $content = str_replace(']]>', ']]&gt;', $content);
168
  $this->content = $content;
169
+ } else {
170
+ unset($this->content);
171
  }
172
  }
173
 
185
  $this->categories[] = $category;
186
  }
187
  }
188
+ } else {
189
+ unset($this->categories);
190
  }
191
  }
192
 
199
  $this->tags[] = new JSON_API_Tag($wp_tag);
200
  }
201
  }
202
+ } else {
203
+ unset($this->tags);
204
  }
205
  }
206
 
208
  global $json_api;
209
  if ($json_api->include_value('author')) {
210
  $this->author = new JSON_API_Author($author_id);
211
+ } else {
212
+ unset($this->author);
213
  }
214
  }
215
 
217
  global $json_api;
218
  if ($json_api->include_value('comments')) {
219
  $this->comments = $json_api->introspector->get_comments($this->id);
220
+ } else {
221
+ unset($this->comments);
222
  }
223
  }
224
 
226
  global $json_api;
227
  if ($json_api->include_value('attachments')) {
228
  $this->attachments = $json_api->introspector->get_attachments($this->id);
229
+ } else {
230
+ unset($this->attachments);
231
  }
232
  }
233
 
234
  function set_thumbnail_value() {
235
  global $json_api;
236
+ if (!$json_api->include_value('thumbnail') ||
237
+ !function_exists('get_post_thumbnail_id')) {
238
  unset($this->thumbnail);
239
  return;
240
  }
241
+ $attachment_id = get_post_thumbnail_id($this->id);
242
+ if (!$attachment_id) {
243
+ unset($this->thumbnail);
244
+ return;
 
 
 
245
  }
246
+ $thumbnail_size = $this->get_thumbnail_size();
247
+ list($thumbnail) = wp_get_attachment_image_src($attachment_id, $thumbnail_size);
248
+ $this->thumbnail = $thumbnail;
249
  }
250
 
251
  function set_custom_fields_value() {
265
  }
266
  }
267
 
268
+ function get_thumbnail_size() {
269
+ if (function_exists('get_intermediate_image_sizes')) {
270
+ $sizes = get_intermediate_image_sizes();
271
+ if (in_array('post-thumbnail', $sizes)) {
272
+ return 'post-thumbnail';
273
+ }
274
+ }
275
+ return 'thumbnail';
276
+ }
277
+
278
  }
279
 
280
  ?>
readme.txt CHANGED
@@ -1,44 +1,76 @@
1
  === JSON API ===
2
  Contributors: dphiffer
 
3
  Tags: json, api, ajax, cms, admin, integration, moma
4
  Requires at least: 2.8
5
- Tested up to: 2.9
6
- Stable tag: 0.9.6
7
 
8
  A RESTful API for WordPress
9
 
10
  == Description ==
11
 
12
- This plugin was created for The Museum of Modern Art, whose weblog [Inside/Out](http://moma.org/explore/inside_out) appears within an existing structure built with Ruby on Rails. Instead of reimplementing the site templates as a WordPress theme, we opted for a Rails front-end that displays content served from a WordPress back-end. JSON API provides the necessary interface for retrieving content and accepting comment submissions.
13
 
14
- The current release implements a mostly-complete set of introspection methods and a method for submitting comments. I plan on offering a complete set of authentication & data manipulation methods, but my current focus is on features we're actually using at MoMA.org.
 
 
15
 
16
- See the Other Notes section for complete API documentation.
 
 
17
 
18
  == Installation ==
19
 
20
  1. Upload the `json-api` folder to the `/wp-content/plugins/` directory or install directly through the plugin installer.
21
- 1. Activate the plugin through the 'Plugins' menu in WordPress or by using the link provided by the plugin installer.
22
 
23
  == Screenshots ==
24
 
25
  1. Our old friend, in JSON format
26
 
27
- == Requests ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  Requests use a simple REST-style HTTP GET or POST. To invoke the API, include a non-empty query value for `json` in the URL.
30
 
31
  JSON API operates in two modes:
32
 
33
  1. *Implicit mode* is triggered by setting the `json` query var to a non-empty value on any WordPress page. The content that would normally appear on that page is returned in JSON format.
34
- 1. *Explicit mode* is triggered by setting `json` to a known method string. See the *API Reference* section below for a complete method listing.
35
 
36
  = Implicit mode examples: =
37
 
38
  * `http://www.example.org/?json=1`
39
  * `http://www.example.org/?p=47&json=1`
40
  * `http://www.example.org/tag/banana/?json=1`
41
-
42
  = Explicit mode examples: =
43
 
44
  * `http://www.example.org/?json=get_recent_posts`
@@ -51,7 +83,37 @@ JSON API operates in two modes:
51
  * `http://www.example.org/api/get_post/?post_id=47`
52
  * `http://www.example.org/api/get_tag_posts/?tag_slug=banana`
53
 
54
- == Responses ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
 
56
  The standard response format for JSON API is (as you may have guessed) [JSON](http://json.org/).
57
 
@@ -65,6 +127,7 @@ Here is an example response from `http://localhost/wordpress/?json=1` called on
65
  "posts": [
66
  {
67
  "id": 1,
 
68
  "slug": "hello-world",
69
  "url": "http:\/\/localhost\/wordpress\/?p=1",
70
  "title": "Hello world!",
@@ -101,166 +164,44 @@ Here is an example response from `http://localhost/wordpress/?json=1` called on
101
  ]
102
  }
103
 
104
- == API Reference ==
105
-
106
- The JSON API reference is split into four sections:
107
-
108
- 1. Request arguments
109
- 1. Response objects
110
- 1. Plugin hooks
111
- 1. Introspection methods
112
- 1. Data manipulation methods
113
-
114
- __About API changes__
115
- All methods are currently subject to change until the plugin reaches maturity. Please read the the changelog carefully before updating to subsequent releases.
116
-
117
- == 1. Request arguments ==
118
-
119
- The following arguments modify how you get results back from the API. The redirect response styles are intended for use with the data manipulation methods.
120
-
121
- * Setting `callback` to a JavaScript function name will trigger a JSONP-style callback.
122
- * Setting `redirect` to a URL will cause the user's browser to redirect to the specified URL with a `status` value appended to the query vars (see the *Response objects* section below for an explanation of status values).
123
- * Setting `redirect_[status]` allows you to control the resulting browser redirection depending on the `status` value.
124
- * Setting `dev` to a non-empty value formats a plain text response using PHP's `print_r()` function.
125
- * Not setting any of the above argument values will result in a standard JSON response.
126
-
127
- These arguments are available to modify all introspection methods:
128
-
129
- * `date_format` - Changes the format of date values. Uses the same syntax as PHP's date() function. Default value is `Y-m-d H:i:s`.
130
- * `read_more` - Changes the 'read more' link text in post content.
131
- * `include` - Specifies which post data fields to include. Expects a comma-separated list of post fields. Leaving this empty includes *all* fields.
132
- * `exclude` - Specifies which post data fields to exclude. Expects a comma-separated list of post fields.
133
- * `custom_fields` - Includes values from posts' Custom Fields. Expects a comma-separated list of custom field keys.
134
- * `author_meta` - Includes additional author metadata. Should be a comma-separated list of metadata fields.
135
- * `count` - Controls the number of posts to include (defaults to the number specified by WordPress)
136
-
137
- __About `include`/`exclude` arguments__
138
- By default you get all values included with each post object. Specify a list of `include` values will cause the post object to filter out the values absent from the list. Specifying `exclude` causes post objects to include all values except the fields you list. For example, the query `exclude=comments` includes everything *except* the comments.
139
-
140
- == 2. Response objects ==
141
-
142
- This section describes data objects you can retrieve from WordPress and the optional URL redirects.
143
-
144
- __Status values__
145
- All JSON API requests result in a status value. The two basic status values are `ok` and `error`. Additional status values are available for certain methods (such as `pending` in the case of the `submit_comment` method). API methods that result in custom status values include a *custom status values* section in their documentation.
146
-
147
- __Naming compatibility__
148
- Developers familiar with WordPress may notice that many names for properties and arguments have been changed. This was a stylistic choice that intends to provide more clarity and consistency in the interface.
149
-
150
- = Post response object =
151
-
152
- * `id` - Integer
153
- * `slug` - String
154
- * `url` - String
155
- * `title` - String
156
- * `title_plain` - String
157
- * `content` - String (modified by the `read_more` argument)
158
- * `excerpt` - String
159
- * `date` - String (modified by the `date_format` argument)
160
- * `modified` - String (modified by the `date_format` argument)
161
- * `categories` - Array of category objects
162
- * `tags` - Array of tag objects
163
- * `author` Author object
164
- * `comments` - Array of comment objects
165
- * `attachments` - Array of attachment objects
166
- * `comment_count` - Integer
167
- * `comment_status` - String (`"open"` or `"closed"`)
168
- * `thumbnail` - String (only included if a post thumbnail has been specified)
169
- * `custom_fields` - Object (included by setting the `custom_fields` argument to a comma-separated list of custom field names)
170
 
171
- = Category response object =
172
 
173
- * `id` - Integer
174
- * `slug` - String
175
- * `title` - String
176
- * `description` - String
177
- * `parent` - Integer
178
- * `post_count` - Integer
179
 
180
- = Tag response object =
181
-
182
- * `id` - Integer
183
- * `slug` - String
184
- * `title` - String
185
- * `description` - String
186
- * `post_count` - Integer
187
 
188
- = Author response object =
189
 
190
- * `id` - Integer
191
- * `slug` - String
192
- * `name` - String
193
- * `first_name` - String
194
- * `last_name` - String
195
- * `nickname` - String
196
- * `url` - String
197
- * `description` - String
198
-
199
- Note: You can include additional values by setting the `author_meta` argument to a comma-separated list of metadata fields.
200
 
201
- = Comment response object =
202
 
203
- * `id` - Integer
204
- * `name` - String
205
- * `url` - String
206
- * `date` - String
207
- * `content` - String
208
- * `parent` - Integer
209
- * `author` - Object (only set if the comment author was registered & logged in)
210
-
211
- = Attachment response object =
212
-
213
- * `id` - Integer
214
- * `url` - String
215
- * `slug` - String
216
- * `title` - String
217
- * `description` - String
218
- * `caption` - String
219
- * `parent` - Integer
220
- * `mime_type` - String
221
- * `images` - Object with values `thumbnail`, `medium`, `large`, `full`, each of which are objects with values `url`, `width` and `height` (only set if the attachment is an image)
222
-
223
- == Redirects ==
224
-
225
- The `redirect` response style is useful for when you need the user's browser to make a request directly rather than making proxy requests using a tool like cURL. Setting a `redirect` argument causes the user's browser to redirect back to the specified URL instead of returning a JSON object. The resulting `status` value is included as an extra query variable.
226
-
227
- For example calling an API method with `redirect` set to `http://www.example.com/foo` will result in a redirection to one of the following:
228
-
229
- * `http://www.example.com/foo?status=ok`
230
- * `http://www.example.com/foo?status=error`
231
-
232
- You can also set separate URLs to handle status values differently. You could set `redirect_ok` to `http://www.example.com/handle_ok` and `redirect_error` to `http://www.example.com/handle_error` in order to have more fine-tuned control over the method result.
233
-
234
- == 3. Plugin hooks ==
235
 
236
- JSON API currently exposes a single [filter hook](http://codex.wordpress.org/Plugin_API#Hooks.2C_Actions_and_Filters) for you to modify the output.
237
 
238
- == Filter: json_api_encode ==
239
 
240
- This is called just before the output is encoded into JSON format. The value passed will always be an associative array, according to the format described in each method's documentation. Those items described in the *Response objects* section are passed as PHP objects, not associative arrays.
 
 
 
 
 
 
241
 
242
- = Example =
243
 
244
- add_filter('json_api_encode', 'encode_kittens_field');
245
-
246
- encode_kittens_field($response) {
247
- if (isset($response['posts'])) {
248
- array_walk($response['posts'], 'add_kittens_field');
249
- } else if (isset($response['post'])) {
250
- add_kittens_field($response['post']);
251
- }
252
- return $response;
253
  }
254
 
255
- add_kittens_field(&$post) {
256
- $post->kittens = 'Kittens!';
257
- }
258
-
259
-
260
- == 4. Introspection methods ==
261
-
262
- Introspection methods are used to retrieve data from WordPress.
263
-
264
 
265
  == Method: get_recent_posts ==
266
 
@@ -292,8 +233,8 @@ Returns a single post object.
292
  = One of the following is required =
293
 
294
  * Invoking the JSON API implicitly (i.e., `?json=1`) on a post URL
295
- * `post_id` - set to the post's ID
296
- * `post_slug` - set to the post's URL slug
297
 
298
  = Response =
299
 
@@ -310,8 +251,12 @@ Returns a single page object.
310
  = One of the following is required =
311
 
312
  * Invoking the JSON API implicitly (i.e., `?json=1`) on a page URL
313
- * `page_id` - set to the page's ID
314
- * `page_slug` - set to the page's URL slug
 
 
 
 
315
 
316
  = Response =
317
 
@@ -327,7 +272,7 @@ Returns an array of posts/pages in a specific category.
327
  = One of the following is required =
328
 
329
  * Invoking the JSON API implicitly (i.e., `?json=1`) on a date archive page
330
- * `date` - set to a date in the format `YYYY` or `YYYYMM` or `YYYYMMDD`
331
 
332
  = Optional arguments =
333
 
@@ -354,8 +299,8 @@ Returns an array of posts/pages in a specific category.
354
  = One of the following is required =
355
 
356
  * Invoking the JSON API implicitly (i.e., `?json=1`) on a category archive page
357
- * `category_id` - set to the category's ID
358
- * `category_slug` - set to the category's URL slug
359
 
360
  = Optional arguments =
361
 
@@ -384,8 +329,8 @@ Returns an array of posts/pages with a specific tag.
384
  = One of the following is required =
385
 
386
  * Invoking the JSON API implicitly (i.e., `?json=1`) on a tag archive page
387
- * `tag_id` - set to the tag's ID
388
- * `tag_slug` - set to the tag's URL slug
389
 
390
  = Optional arguments =
391
 
@@ -414,8 +359,8 @@ Returns an array of posts/pages written by a specific author.
414
  = One of the following is required =
415
 
416
  * Invoking the JSON API implicitly (i.e., `?json=1`) on an author archive page
417
- * `author_id` - set to the author's ID
418
- * `author_slug` - set to the author's URL slug
419
 
420
  = Optional arguments =
421
 
@@ -540,18 +485,50 @@ Returns an array of active blog authors.
540
  }
541
 
542
 
543
- == 5. Data manipulation methods ==
 
 
 
 
544
 
545
- Data manipulation methods are used for saving content back to WordPress.
 
 
 
 
 
 
 
546
 
547
- __Incomplete__
548
- The data manipulation methods are still very incomplete.
549
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
550
 
551
  == Method: create_post ==
552
 
553
  Creates a new post.
554
 
 
 
 
 
555
  = Optional arguments =
556
 
557
  * `status` - sets the post status ("draft" or "publish"), default is "draft"
@@ -563,6 +540,9 @@ Creates a new post.
563
 
564
  Note: including a file upload field called `attachment` will cause an attachment to be stored with your new post.
565
 
 
 
 
566
  == Method: submit_comment ==
567
 
568
  Submits a comment to a WordPress post.
@@ -586,8 +566,296 @@ Submits a comment to a WordPress post.
586
  * `pending` - assigned if the comment submission is pending moderation
587
 
588
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
589
  == Changelog ==
590
 
 
 
 
 
 
 
 
 
 
 
 
 
591
  = 0.9.6 (2010-05-27): =
592
  * Fixed a bug introduced in 0.9.5
593
 
@@ -641,6 +909,9 @@ Submits a comment to a WordPress post.
641
 
642
  == Upgrade Notice ==
643
 
 
 
 
644
  = 0.9.6 =
645
  Bugfix release for something added in 0.9.5.
646
 
1
  === JSON API ===
2
  Contributors: dphiffer
3
+ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=DH4MEG99JR2WE
4
  Tags: json, api, ajax, cms, admin, integration, moma
5
  Requires at least: 2.8
6
+ Tested up to: 3.0
7
+ Stable tag: 1.0
8
 
9
  A RESTful API for WordPress
10
 
11
  == Description ==
12
 
13
+ JSON API allows you to retrieve and manipulate WordPress content using HTTP requests. There are three main goals:
14
 
15
+ 1. Provide a simple, consistent external interface
16
+ 2. Create a stable, understandable internal implementation
17
+ 3. Enable new types of extensions for WordPress
18
 
19
+ This plugin was created at [The Museum of Modern Art](http://moma.org/) for the weblog [Inside/Out](http://moma.org/explore/inside_out), which is served from Ruby on Rails. Instead of reimplementing the site templates as a WordPress theme, we opted for a Rails front-end that displays content served from a WordPress back-end. JSON API provides the necessary interface for retrieving content and accepting comment submissions.
20
+
21
+ See the [Other Notes](http://wordpress.org/extend/plugins/json-api/other_notes/) section for the complete documentation.
22
 
23
  == Installation ==
24
 
25
  1. Upload the `json-api` folder to the `/wp-content/plugins/` directory or install directly through the plugin installer.
26
+ 2. Activate the plugin through the 'Plugins' menu in WordPress or by using the link provided by the plugin installer.
27
 
28
  == Screenshots ==
29
 
30
  1. Our old friend, in JSON format
31
 
32
+ == Documentation ==
33
+
34
+ 1. General concepts
35
+ 1.1. Requests
36
+ 1.2. Controllers
37
+ 1.3. Responses
38
+ 2. Request methods
39
+ 2.1. Core controller methods
40
+ 2.2. Posts controller methods
41
+ 2.3. Respond controller methods
42
+ 3. Request arguments
43
+ 3.1. Output-modifying arguments
44
+ 3.2. Content-modifying arguments
45
+ 3.3. Using query_posts, include/exclude, and redirects
46
+ 4. Response objects
47
+ 4.1. Post response object
48
+ 4.2. Category response object
49
+ 4.3. Tag response object
50
+ 4.4. Author response object
51
+ 4.4. Comment response object
52
+ 4.5. Attachment response object
53
+ 5. Extending JSON API
54
+ 5.1. Plugin hooks
55
+ 5.2. Developing JSON API controllers
56
+
57
+ == 1. General Concepts ==
58
+
59
+ == 1.1. Requests ==
60
 
61
  Requests use a simple REST-style HTTP GET or POST. To invoke the API, include a non-empty query value for `json` in the URL.
62
 
63
  JSON API operates in two modes:
64
 
65
  1. *Implicit mode* is triggered by setting the `json` query var to a non-empty value on any WordPress page. The content that would normally appear on that page is returned in JSON format.
66
+ 2. *Explicit mode* is triggered by setting `json` to a known method string. See the *API Reference* section below for a complete method listing.
67
 
68
  = Implicit mode examples: =
69
 
70
  * `http://www.example.org/?json=1`
71
  * `http://www.example.org/?p=47&json=1`
72
  * `http://www.example.org/tag/banana/?json=1`
73
+
74
  = Explicit mode examples: =
75
 
76
  * `http://www.example.org/?json=get_recent_posts`
83
  * `http://www.example.org/api/get_post/?post_id=47`
84
  * `http://www.example.org/api/get_tag_posts/?tag_slug=banana`
85
 
86
+ __Further reading__
87
+ See Section 3: Request arguments for more information about request arguments to modify the response.
88
+
89
+ == 1.2. Controllers ==
90
+
91
+ The 1.0 release of JSON API introduced a modular controller system. This allows developers to flexibly add features to the API and give users more control over which methods they have enabled.
92
+
93
+ = The Core controller =
94
+
95
+ Most of the methods available prior to version 1.0 have been moved to the Core controller. The two exceptions are `submit_comment` and `create_post` which are now available from the Respond and Posts controllers, respectively. The Core controller is the only one enabled by default. All other functionality must be enabled from the JSON API Settings page (under Settings in the WordPress admin menu).
96
+
97
+ = Specifying a controller =
98
+
99
+ There are a few ways of specifying a controller, depending on how you are calling the API:
100
+
101
+ * `http://www.example.org/?json=get_recent_posts` (`core` controller is implied, method is `get_recent_posts`)
102
+ * `http://www.example.org/api/info/` (`core` controller is implied)
103
+ * `http://www.example.org/api/core/get_category_posts/` (`core` controller can also be explicitly specified)
104
+ * `http://www.example.org/?json=respond.submit_comment` (`respond` controller, `submit_comment` method)
105
+
106
+ __Legacy compatibility__
107
+ JSON API retains support for its pre-1.0 methods. For example, if you invoke the method `create_post` without a controller specified, the Posts controller is chosen instead of Core.
108
+
109
+ = Available controllers =
110
+
111
+ The current release includes three controllers: Core, Posts, and Respond. Developers are encouraged to suggest or submit additional controllers.
112
+
113
+ __Further reading__
114
+ See Section 2: Request methods for a complete reference of available controllers and methods. For documentation on extending JSON API with new controllers see Section 5.2: Developing JSON API Controllers.
115
+
116
+ == 1.3. Responses ==
117
 
118
  The standard response format for JSON API is (as you may have guessed) [JSON](http://json.org/).
119
 
127
  "posts": [
128
  {
129
  "id": 1,
130
+ "type": "post",
131
  "slug": "hello-world",
132
  "url": "http:\/\/localhost\/wordpress\/?p=1",
133
  "title": "Hello world!",
164
  ]
165
  }
166
 
167
+ == 2. Request methods ==
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
 
169
+ The JSON API reference is split into the following sections:
170
 
171
+ == 2.1. Core controller methods ==
 
 
 
 
 
172
 
173
+ The Core controller offers a mostly-complete set of introspection methods for retrieving content from WordPress.
 
 
 
 
 
 
174
 
 
175
 
176
+ == Method: info ==
 
 
 
 
 
 
 
 
 
177
 
178
+ Returns information about JSON API.
179
 
180
+ = Optional arguments =