Version Description
Download this release
Release Info
Developer | dphiffer |
Plugin | JSON API |
Version | 1.1.2 |
Comparing to | |
See all releases |
Code changes from version 1.1.1 to 1.1.2
- controllers/posts.php +12 -12
- models/comment.php +2 -2
- singletons/api.php +2 -2
- singletons/query.php +1 -1
- singletons/response.php +5 -5
- trunk/controllers/core.php +339 -0
- trunk/controllers/posts.php +85 -0
- trunk/controllers/respond.php +27 -0
- trunk/controllers/widgets.php +108 -0
- trunk/json-api.php +83 -0
- trunk/library/JSON.php +933 -0
- trunk/models/attachment.php +64 -0
- trunk/models/author.php +62 -0
- trunk/models/category.php +29 -0
- trunk/models/comment.php +80 -0
- trunk/models/post.php +319 -0
- trunk/models/tag.php +26 -0
- trunk/readme.txt +1241 -0
- trunk/screenshot-1.png +0 -0
- trunk/singletons/api.php +394 -0
- trunk/singletons/introspector.php +345 -0
- trunk/singletons/query.php +194 -0
- trunk/singletons/response.php +205 -0
- trunk/tests/core.get_author_index-01.phpt +21 -0
- trunk/tests/core.get_author_posts-01.phpt +22 -0
- trunk/tests/core.get_author_posts-02.phpt +22 -0
- trunk/tests/core.get_author_posts-03.phpt +22 -0
- trunk/tests/core.get_category_index-01.phpt +21 -0
- trunk/tests/core.get_category_posts-01.phpt +21 -0
- trunk/tests/core.get_date_index-01.phpt +80 -0
- trunk/tests/core.get_date_posts-01.phpt +21 -0
- trunk/tests/core.get_date_posts-02.phpt +21 -0
- trunk/tests/core.get_date_posts-03.phpt +21 -0
- trunk/tests/core.get_page-01.phpt +19 -0
- trunk/tests/core.get_page-02.phpt +25 -0
- trunk/tests/core.get_post-01.phpt +18 -0
- trunk/tests/core.get_posts-01.phpt +21 -0
- trunk/tests/core.get_posts-02.phpt +24 -0
- trunk/tests/core.get_posts-03.phpt +23 -0
- trunk/tests/core.get_recent_posts-01.phpt +21 -0
- trunk/tests/core.get_recent_posts-02.phpt +21 -0
- trunk/tests/core.get_recent_posts-03.phpt +21 -0
- trunk/tests/core.get_search_posts-01.phpt +21 -0
- trunk/tests/core.get_tag_index-01.phpt +803 -0
- trunk/tests/core.get_tag_posts-01.phpt +21 -0
- trunk/tests/core.info-01.phpt +29 -0
- trunk/tests/core.info-02.phpt +57 -0
- trunk/tests/query-01.phpt +21 -0
controllers/posts.php
CHANGED
@@ -9,20 +9,20 @@ class JSON_API_Posts_Controller {
|
|
9 |
public function create_post() {
|
10 |
global $json_api;
|
11 |
if (!current_user_can('edit_posts')) {
|
12 |
-
$json_api->error("You need to login with a user that has 'edit_posts' capacity.");
|
13 |
}
|
14 |
if (!$json_api->query->nonce) {
|
15 |
-
$json_api->error("You must include a 'nonce' value to create posts. Use the `get_nonce` Core API method.");
|
16 |
}
|
17 |
$nonce_id = $json_api->get_nonce_id('posts', 'create_post');
|
18 |
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
19 |
-
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.");
|
20 |
}
|
21 |
nocache_headers();
|
22 |
$post = new JSON_API_Post();
|
23 |
$id = $post->create($_REQUEST);
|
24 |
if (empty($id)) {
|
25 |
-
$json_api->error("Could not create post.");
|
26 |
}
|
27 |
return array(
|
28 |
'post' => $post
|
@@ -36,14 +36,14 @@ class JSON_API_Posts_Controller {
|
|
36 |
$json_api->error("Post not found.");
|
37 |
}
|
38 |
if (!current_user_can('edit_post', $post->ID)) {
|
39 |
-
$json_api->error("You need to login with a user that has the 'edit_post' capacity for that post.");
|
40 |
}
|
41 |
if (!$json_api->query->nonce) {
|
42 |
-
$json_api->error("You must include a 'nonce' value to update posts. Use the `get_nonce` Core API method.");
|
43 |
}
|
44 |
$nonce_id = $json_api->get_nonce_id('posts', 'update_post');
|
45 |
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
46 |
-
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.");
|
47 |
}
|
48 |
nocache_headers();
|
49 |
$post = new JSON_API_Post($post);
|
@@ -60,20 +60,20 @@ class JSON_API_Posts_Controller {
|
|
60 |
$json_api->error("Post not found.");
|
61 |
}
|
62 |
if (!current_user_can('edit_post', $post->ID)) {
|
63 |
-
$json_api->error("You need to login with a user that has the 'edit_post' capacity for that post.");
|
64 |
}
|
65 |
if (!current_user_can('delete_posts')) {
|
66 |
-
$json_api->error("You need to login with a user that has the 'delete_posts' capacity.");
|
67 |
}
|
68 |
if ($post->post_author != get_current_user_id() && !current_user_can('delete_other_posts')) {
|
69 |
-
$json_api->error("You need to login with a user that has the 'delete_other_posts' capacity.");
|
70 |
}
|
71 |
if (!$json_api->query->nonce) {
|
72 |
-
$json_api->error("You must include a 'nonce' value to update posts. Use the `get_nonce` Core API method.");
|
73 |
}
|
74 |
$nonce_id = $json_api->get_nonce_id('posts', 'delete_post');
|
75 |
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
76 |
-
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.");
|
77 |
}
|
78 |
nocache_headers();
|
79 |
wp_delete_post($post->ID);
|
9 |
public function create_post() {
|
10 |
global $json_api;
|
11 |
if (!current_user_can('edit_posts')) {
|
12 |
+
$json_api->error("You need to login with a user that has 'edit_posts' capacity.", 403);
|
13 |
}
|
14 |
if (!$json_api->query->nonce) {
|
15 |
+
$json_api->error("You must include a 'nonce' value to create posts. Use the `get_nonce` Core API method.", 403);
|
16 |
}
|
17 |
$nonce_id = $json_api->get_nonce_id('posts', 'create_post');
|
18 |
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
19 |
+
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.", 403);
|
20 |
}
|
21 |
nocache_headers();
|
22 |
$post = new JSON_API_Post();
|
23 |
$id = $post->create($_REQUEST);
|
24 |
if (empty($id)) {
|
25 |
+
$json_api->error("Could not create post.", 500);
|
26 |
}
|
27 |
return array(
|
28 |
'post' => $post
|
36 |
$json_api->error("Post not found.");
|
37 |
}
|
38 |
if (!current_user_can('edit_post', $post->ID)) {
|
39 |
+
$json_api->error("You need to login with a user that has the 'edit_post' capacity for that post.", 403);
|
40 |
}
|
41 |
if (!$json_api->query->nonce) {
|
42 |
+
$json_api->error("You must include a 'nonce' value to update posts. Use the `get_nonce` Core API method.", 403);
|
43 |
}
|
44 |
$nonce_id = $json_api->get_nonce_id('posts', 'update_post');
|
45 |
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
46 |
+
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.", 403);
|
47 |
}
|
48 |
nocache_headers();
|
49 |
$post = new JSON_API_Post($post);
|
60 |
$json_api->error("Post not found.");
|
61 |
}
|
62 |
if (!current_user_can('edit_post', $post->ID)) {
|
63 |
+
$json_api->error("You need to login with a user that has the 'edit_post' capacity for that post.", 403);
|
64 |
}
|
65 |
if (!current_user_can('delete_posts')) {
|
66 |
+
$json_api->error("You need to login with a user that has the 'delete_posts' capacity.", 403);
|
67 |
}
|
68 |
if ($post->post_author != get_current_user_id() && !current_user_can('delete_other_posts')) {
|
69 |
+
$json_api->error("You need to login with a user that has the 'delete_other_posts' capacity.", 403);
|
70 |
}
|
71 |
if (!$json_api->query->nonce) {
|
72 |
+
$json_api->error("You must include a 'nonce' value to update posts. Use the `get_nonce` Core API method.", 403);
|
73 |
}
|
74 |
$nonce_id = $json_api->get_nonce_id('posts', 'delete_post');
|
75 |
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
76 |
+
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.", 403);
|
77 |
}
|
78 |
nocache_headers();
|
79 |
wp_delete_post($post->ID);
|
models/comment.php
CHANGED
@@ -60,12 +60,12 @@ class JSON_API_Comment {
|
|
60 |
|
61 |
function comment_closed() {
|
62 |
global $json_api;
|
63 |
-
$json_api->error("Post is closed for comments.");
|
64 |
}
|
65 |
|
66 |
function comment_on_draft() {
|
67 |
global $json_api;
|
68 |
-
$json_api->error("You cannot comment on unpublished posts.");
|
69 |
}
|
70 |
|
71 |
function comment_post_redirect() {
|
60 |
|
61 |
function comment_closed() {
|
62 |
global $json_api;
|
63 |
+
$json_api->error("Post is closed for comments.", 403);
|
64 |
}
|
65 |
|
66 |
function comment_on_draft() {
|
67 |
global $json_api;
|
68 |
+
$json_api->error("You cannot comment on unpublished posts.", 403);
|
69 |
}
|
70 |
|
71 |
function comment_post_redirect() {
|
singletons/api.php
CHANGED
@@ -379,10 +379,10 @@ class JSON_API {
|
|
379 |
$wp_rewrite->flush_rules();
|
380 |
}
|
381 |
|
382 |
-
function error($message = 'Unknown error', $
|
383 |
$this->response->respond(array(
|
384 |
'error' => $message
|
385 |
-
), $
|
386 |
}
|
387 |
|
388 |
function include_value($key) {
|
379 |
$wp_rewrite->flush_rules();
|
380 |
}
|
381 |
|
382 |
+
function error($message = 'Unknown error', $http_status = 404) {
|
383 |
$this->response->respond(array(
|
384 |
'error' => $message
|
385 |
+
), 'error', $http_status);
|
386 |
}
|
387 |
|
388 |
function include_value($key) {
|
singletons/query.php
CHANGED
@@ -168,7 +168,7 @@ class JSON_API_Query {
|
|
168 |
return 'get_search_results';
|
169 |
} else if (is_home()) {
|
170 |
if (empty($_GET['json'])) {
|
171 |
-
$json_api->error("
|
172 |
}
|
173 |
return 'get_recent_posts';
|
174 |
} else if (is_page()) {
|
168 |
return 'get_search_results';
|
169 |
} else if (is_home()) {
|
170 |
if (empty($_GET['json'])) {
|
171 |
+
$json_api->error("Unknown method '$method'.");
|
172 |
}
|
173 |
return 'get_recent_posts';
|
174 |
} else if (is_page()) {
|
singletons/response.php
CHANGED
@@ -74,7 +74,7 @@ class JSON_API_Response {
|
|
74 |
}
|
75 |
}
|
76 |
|
77 |
-
function respond($result, $status = 'ok') {
|
78 |
global $json_api;
|
79 |
$json = $this->get_json($result, $status);
|
80 |
$status_redirect = "redirect_$status";
|
@@ -97,15 +97,15 @@ class JSON_API_Response {
|
|
97 |
$this->callback($json_api->query->callback, $json);
|
98 |
} else {
|
99 |
// Output the result
|
100 |
-
$this->output($json);
|
101 |
}
|
102 |
exit;
|
103 |
}
|
104 |
|
105 |
-
function output($result) {
|
106 |
$charset = get_option('blog_charset');
|
107 |
if (!headers_sent()) {
|
108 |
-
|
109 |
header("Content-Type: application/json; charset=$charset", true);
|
110 |
}
|
111 |
echo $result;
|
@@ -114,7 +114,7 @@ class JSON_API_Response {
|
|
114 |
function callback($callback, $result) {
|
115 |
$charset = get_option('blog_charset');
|
116 |
if (!headers_sent()) {
|
117 |
-
|
118 |
header("Content-Type: application/javascript; charset=$charset", true);
|
119 |
}
|
120 |
echo "$callback($result)";
|
74 |
}
|
75 |
}
|
76 |
|
77 |
+
function respond($result, $status = 'ok', $http_status = 200) {
|
78 |
global $json_api;
|
79 |
$json = $this->get_json($result, $status);
|
80 |
$status_redirect = "redirect_$status";
|
97 |
$this->callback($json_api->query->callback, $json);
|
98 |
} else {
|
99 |
// Output the result
|
100 |
+
$this->output($json, $http_status);
|
101 |
}
|
102 |
exit;
|
103 |
}
|
104 |
|
105 |
+
function output($result, $http_status = 200) {
|
106 |
$charset = get_option('blog_charset');
|
107 |
if (!headers_sent()) {
|
108 |
+
status_header($http_status);
|
109 |
header("Content-Type: application/json; charset=$charset", true);
|
110 |
}
|
111 |
echo $result;
|
114 |
function callback($callback, $result) {
|
115 |
$charset = get_option('blog_charset');
|
116 |
if (!headers_sent()) {
|
117 |
+
status_header(200);
|
118 |
header("Content-Type: application/javascript; charset=$charset", true);
|
119 |
}
|
120 |
echo "$callback($result)";
|
trunk/controllers/core.php
ADDED
@@ -0,0 +1,339 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Controller name: Core
|
4 |
+
Controller description: Basic introspection methods
|
5 |
+
*/
|
6 |
+
|
7 |
+
class JSON_API_Core_Controller {
|
8 |
+
|
9 |
+
public function info() {
|
10 |
+
global $json_api;
|
11 |
+
$php = '';
|
12 |
+
if (!empty($json_api->query->controller)) {
|
13 |
+
return $json_api->controller_info($json_api->query->controller);
|
14 |
+
} else {
|
15 |
+
$dir = json_api_dir();
|
16 |
+
if (file_exists("$dir/json-api.php")) {
|
17 |
+
$php = file_get_contents("$dir/json-api.php");
|
18 |
+
} else {
|
19 |
+
// Check one directory up, in case json-api.php was moved
|
20 |
+
$dir = dirname($dir);
|
21 |
+
if (file_exists("$dir/json-api.php")) {
|
22 |
+
$php = file_get_contents("$dir/json-api.php");
|
23 |
+
}
|
24 |
+
}
|
25 |
+
if (preg_match('/^\s*Version:\s*(.+)$/m', $php, $matches)) {
|
26 |
+
$version = $matches[1];
|
27 |
+
} else {
|
28 |
+
$version = '(Unknown)';
|
29 |
+
}
|
30 |
+
$active_controllers = explode(',', get_option('json_api_controllers', 'core'));
|
31 |
+
$controllers = array_intersect($json_api->get_controllers(), $active_controllers);
|
32 |
+
return array(
|
33 |
+
'json_api_version' => $version,
|
34 |
+
'controllers' => array_values($controllers)
|
35 |
+
);
|
36 |
+
}
|
37 |
+
}
|
38 |
+
|
39 |
+
public function get_recent_posts() {
|
40 |
+
global $json_api;
|
41 |
+
$posts = $json_api->introspector->get_posts();
|
42 |
+
return $this->posts_result($posts);
|
43 |
+
}
|
44 |
+
|
45 |
+
public function get_posts() {
|
46 |
+
global $json_api;
|
47 |
+
$url = parse_url($_SERVER['REQUEST_URI']);
|
48 |
+
$defaults = array(
|
49 |
+
'ignore_sticky_posts' => true
|
50 |
+
);
|
51 |
+
$query = wp_parse_args($url['query']);
|
52 |
+
unset($query['json']);
|
53 |
+
unset($query['post_status']);
|
54 |
+
$query = array_merge($defaults, $query);
|
55 |
+
$posts = $json_api->introspector->get_posts($query);
|
56 |
+
$result = $this->posts_result($posts);
|
57 |
+
$result['query'] = $query;
|
58 |
+
return $result;
|
59 |
+
}
|
60 |
+
|
61 |
+
public function get_post() {
|
62 |
+
global $json_api, $post;
|
63 |
+
$post = $json_api->introspector->get_current_post();
|
64 |
+
if ($post) {
|
65 |
+
$previous = get_adjacent_post(false, '', true);
|
66 |
+
$next = get_adjacent_post(false, '', false);
|
67 |
+
$response = array(
|
68 |
+
'post' => new JSON_API_Post($post)
|
69 |
+
);
|
70 |
+
if ($previous) {
|
71 |
+
$response['previous_url'] = get_permalink($previous->ID);
|
72 |
+
}
|
73 |
+
if ($next) {
|
74 |
+
$response['next_url'] = get_permalink($next->ID);
|
75 |
+
}
|
76 |
+
return $response;
|
77 |
+
} else {
|
78 |
+
$json_api->error("Not found.");
|
79 |
+
}
|
80 |
+
}
|
81 |
+
|
82 |
+
public function get_page() {
|
83 |
+
global $json_api;
|
84 |
+
extract($json_api->query->get(array('id', 'slug', 'page_id', 'page_slug', 'children')));
|
85 |
+
if ($id || $page_id) {
|
86 |
+
if (!$id) {
|
87 |
+
$id = $page_id;
|
88 |
+
}
|
89 |
+
$posts = $json_api->introspector->get_posts(array(
|
90 |
+
'page_id' => $id
|
91 |
+
));
|
92 |
+
} else if ($slug || $page_slug) {
|
93 |
+
if (!$slug) {
|
94 |
+
$slug = $page_slug;
|
95 |
+
}
|
96 |
+
$posts = $json_api->introspector->get_posts(array(
|
97 |
+
'pagename' => $slug
|
98 |
+
));
|
99 |
+
} else {
|
100 |
+
$json_api->error("Include 'id' or 'slug' var in your request.");
|
101 |
+
}
|
102 |
+
|
103 |
+
// Workaround for https://core.trac.wordpress.org/ticket/12647
|
104 |
+
if (empty($posts)) {
|
105 |
+
$url = $_SERVER['REQUEST_URI'];
|
106 |
+
$parsed_url = parse_url($url);
|
107 |
+
$path = $parsed_url['path'];
|
108 |
+
if (preg_match('#^http://[^/]+(/.+)$#', get_bloginfo('url'), $matches)) {
|
109 |
+
$blog_root = $matches[1];
|
110 |
+
$path = preg_replace("#^$blog_root#", '', $path);
|
111 |
+
}
|
112 |
+
if (substr($path, 0, 1) == '/') {
|
113 |
+
$path = substr($path, 1);
|
114 |
+
}
|
115 |
+
$posts = $json_api->introspector->get_posts(array('pagename' => $path));
|
116 |
+
}
|
117 |
+
|
118 |
+
if (count($posts) == 1) {
|
119 |
+
if (!empty($children)) {
|
120 |
+
$json_api->introspector->attach_child_posts($posts[0]);
|
121 |
+
}
|
122 |
+
return array(
|
123 |
+
'page' => $posts[0]
|
124 |
+
);
|
125 |
+
} else {
|
126 |
+
$json_api->error("Not found.");
|
127 |
+
}
|
128 |
+
}
|
129 |
+
|
130 |
+
public function get_date_posts() {
|
131 |
+
global $json_api;
|
132 |
+
if ($json_api->query->date) {
|
133 |
+
$date = preg_replace('/\D/', '', $json_api->query->date);
|
134 |
+
if (!preg_match('/^\d{4}(\d{2})?(\d{2})?$/', $date)) {
|
135 |
+
$json_api->error("Specify a date var in one of 'YYYY' or 'YYYY-MM' or 'YYYY-MM-DD' formats.");
|
136 |
+
}
|
137 |
+
$request = array('year' => substr($date, 0, 4));
|
138 |
+
if (strlen($date) > 4) {
|
139 |
+
$request['monthnum'] = (int) substr($date, 4, 2);
|
140 |
+
}
|
141 |
+
if (strlen($date) > 6) {
|
142 |
+
$request['day'] = (int) substr($date, 6, 2);
|
143 |
+
}
|
144 |
+
$posts = $json_api->introspector->get_posts($request);
|
145 |
+
} else {
|
146 |
+
$json_api->error("Include 'date' var in your request.");
|
147 |
+
}
|
148 |
+
return $this->posts_result($posts);
|
149 |
+
}
|
150 |
+
|
151 |
+
public function get_category_posts() {
|
152 |
+
global $json_api;
|
153 |
+
$category = $json_api->introspector->get_current_category();
|
154 |
+
if (!$category) {
|
155 |
+
$json_api->error("Not found.");
|
156 |
+
}
|
157 |
+
$posts = $json_api->introspector->get_posts(array(
|
158 |
+
'cat' => $category->id
|
159 |
+
));
|
160 |
+
return $this->posts_object_result($posts, $category);
|
161 |
+
}
|
162 |
+
|
163 |
+
public function get_tag_posts() {
|
164 |
+
global $json_api;
|
165 |
+
$tag = $json_api->introspector->get_current_tag();
|
166 |
+
if (!$tag) {
|
167 |
+
$json_api->error("Not found.");
|
168 |
+
}
|
169 |
+
$posts = $json_api->introspector->get_posts(array(
|
170 |
+
'tag' => $tag->slug
|
171 |
+
));
|
172 |
+
return $this->posts_object_result($posts, $tag);
|
173 |
+
}
|
174 |
+
|
175 |
+
public function get_author_posts() {
|
176 |
+
global $json_api;
|
177 |
+
$author = $json_api->introspector->get_current_author();
|
178 |
+
if (!$author) {
|
179 |
+
$json_api->error("Not found.");
|
180 |
+
}
|
181 |
+
$posts = $json_api->introspector->get_posts(array(
|
182 |
+
'author' => $author->id
|
183 |
+
));
|
184 |
+
return $this->posts_object_result($posts, $author);
|
185 |
+
}
|
186 |
+
|
187 |
+
public function get_search_results() {
|
188 |
+
global $json_api;
|
189 |
+
if ($json_api->query->search) {
|
190 |
+
$posts = $json_api->introspector->get_posts(array(
|
191 |
+
's' => $json_api->query->search
|
192 |
+
));
|
193 |
+
} else {
|
194 |
+
$json_api->error("Include 'search' var in your request.");
|
195 |
+
}
|
196 |
+
return $this->posts_result($posts);
|
197 |
+
}
|
198 |
+
|
199 |
+
public function get_date_index() {
|
200 |
+
global $json_api;
|
201 |
+
$permalinks = $json_api->introspector->get_date_archive_permalinks();
|
202 |
+
$tree = $json_api->introspector->get_date_archive_tree($permalinks);
|
203 |
+
return array(
|
204 |
+
'permalinks' => $permalinks,
|
205 |
+
'tree' => $tree
|
206 |
+
);
|
207 |
+
}
|
208 |
+
|
209 |
+
public function get_category_index() {
|
210 |
+
global $json_api;
|
211 |
+
$args = null;
|
212 |
+
if (!empty($json_api->query->parent)) {
|
213 |
+
$args = array(
|
214 |
+
'parent' => $json_api->query->parent
|
215 |
+
);
|
216 |
+
}
|
217 |
+
$categories = $json_api->introspector->get_categories($args);
|
218 |
+
return array(
|
219 |
+
'count' => count($categories),
|
220 |
+
'categories' => $categories
|
221 |
+
);
|
222 |
+
}
|
223 |
+
|
224 |
+
public function get_tag_index() {
|
225 |
+
global $json_api;
|
226 |
+
$tags = $json_api->introspector->get_tags();
|
227 |
+
return array(
|
228 |
+
'count' => count($tags),
|
229 |
+
'tags' => $tags
|
230 |
+
);
|
231 |
+
}
|
232 |
+
|
233 |
+
public function get_author_index() {
|
234 |
+
global $json_api;
|
235 |
+
$authors = $json_api->introspector->get_authors();
|
236 |
+
return array(
|
237 |
+
'count' => count($authors),
|
238 |
+
'authors' => array_values($authors)
|
239 |
+
);
|
240 |
+
}
|
241 |
+
|
242 |
+
public function get_page_index() {
|
243 |
+
global $json_api;
|
244 |
+
$pages = array();
|
245 |
+
$post_type = $json_api->query->post_type ? $json_api->query->post_type : 'page';
|
246 |
+
|
247 |
+
// Thanks to blinder for the fix!
|
248 |
+
$numberposts = empty($json_api->query->count) ? -1 : $json_api->query->count;
|
249 |
+
$wp_posts = get_posts(array(
|
250 |
+
'post_type' => $post_type,
|
251 |
+
'post_parent' => 0,
|
252 |
+
'order' => 'ASC',
|
253 |
+
'orderby' => 'menu_order',
|
254 |
+
'numberposts' => $numberposts
|
255 |
+
));
|
256 |
+
foreach ($wp_posts as $wp_post) {
|
257 |
+
$pages[] = new JSON_API_Post($wp_post);
|
258 |
+
}
|
259 |
+
foreach ($pages as $page) {
|
260 |
+
$json_api->introspector->attach_child_posts($page);
|
261 |
+
}
|
262 |
+
return array(
|
263 |
+
'pages' => $pages
|
264 |
+
);
|
265 |
+
}
|
266 |
+
|
267 |
+
public function get_nonce() {
|
268 |
+
global $json_api;
|
269 |
+
extract($json_api->query->get(array('controller', 'method')));
|
270 |
+
if ($controller && $method) {
|
271 |
+
$controller = strtolower($controller);
|
272 |
+
if (!in_array($controller, $json_api->get_controllers())) {
|
273 |
+
$json_api->error("Unknown controller '$controller'.");
|
274 |
+
}
|
275 |
+
require_once $json_api->controller_path($controller);
|
276 |
+
if (!method_exists($json_api->controller_class($controller), $method)) {
|
277 |
+
$json_api->error("Unknown method '$method'.");
|
278 |
+
}
|
279 |
+
$nonce_id = $json_api->get_nonce_id($controller, $method);
|
280 |
+
return array(
|
281 |
+
'controller' => $controller,
|
282 |
+
'method' => $method,
|
283 |
+
'nonce' => wp_create_nonce($nonce_id)
|
284 |
+
);
|
285 |
+
} else {
|
286 |
+
$json_api->error("Include 'controller' and 'method' vars in your request.");
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
protected function get_object_posts($object, $id_var, $slug_var) {
|
291 |
+
global $json_api;
|
292 |
+
$object_id = "{$type}_id";
|
293 |
+
$object_slug = "{$type}_slug";
|
294 |
+
extract($json_api->query->get(array('id', 'slug', $object_id, $object_slug)));
|
295 |
+
if ($id || $$object_id) {
|
296 |
+
if (!$id) {
|
297 |
+
$id = $$object_id;
|
298 |
+
}
|
299 |
+
$posts = $json_api->introspector->get_posts(array(
|
300 |
+
$id_var => $id
|
301 |
+
));
|
302 |
+
} else if ($slug || $$object_slug) {
|
303 |
+
if (!$slug) {
|
304 |
+
$slug = $$object_slug;
|
305 |
+
}
|
306 |
+
$posts = $json_api->introspector->get_posts(array(
|
307 |
+
$slug_var => $slug
|
308 |
+
));
|
309 |
+
} else {
|
310 |
+
$json_api->error("No $type specified. Include 'id' or 'slug' var in your request.");
|
311 |
+
}
|
312 |
+
return $posts;
|
313 |
+
}
|
314 |
+
|
315 |
+
protected function posts_result($posts) {
|
316 |
+
global $wp_query;
|
317 |
+
return array(
|
318 |
+
'count' => count($posts),
|
319 |
+
'count_total' => (int) $wp_query->found_posts,
|
320 |
+
'pages' => $wp_query->max_num_pages,
|
321 |
+
'posts' => $posts
|
322 |
+
);
|
323 |
+
}
|
324 |
+
|
325 |
+
protected function posts_object_result($posts, $object) {
|
326 |
+
global $wp_query;
|
327 |
+
// Convert something like "JSON_API_Category" into "category"
|
328 |
+
$object_key = strtolower(substr(get_class($object), 9));
|
329 |
+
return array(
|
330 |
+
'count' => count($posts),
|
331 |
+
'pages' => (int) $wp_query->max_num_pages,
|
332 |
+
$object_key => $object,
|
333 |
+
'posts' => $posts
|
334 |
+
);
|
335 |
+
}
|
336 |
+
|
337 |
+
}
|
338 |
+
|
339 |
+
?>
|
trunk/controllers/posts.php
ADDED
@@ -0,0 +1,85 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Controller name: Posts
|
4 |
+
Controller description: Data manipulation methods for posts
|
5 |
+
*/
|
6 |
+
|
7 |
+
class JSON_API_Posts_Controller {
|
8 |
+
|
9 |
+
public function create_post() {
|
10 |
+
global $json_api;
|
11 |
+
if (!current_user_can('edit_posts')) {
|
12 |
+
$json_api->error("You need to login with a user that has 'edit_posts' capacity.", 403);
|
13 |
+
}
|
14 |
+
if (!$json_api->query->nonce) {
|
15 |
+
$json_api->error("You must include a 'nonce' value to create posts. Use the `get_nonce` Core API method.", 403);
|
16 |
+
}
|
17 |
+
$nonce_id = $json_api->get_nonce_id('posts', 'create_post');
|
18 |
+
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
19 |
+
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.", 403);
|
20 |
+
}
|
21 |
+
nocache_headers();
|
22 |
+
$post = new JSON_API_Post();
|
23 |
+
$id = $post->create($_REQUEST);
|
24 |
+
if (empty($id)) {
|
25 |
+
$json_api->error("Could not create post.", 500);
|
26 |
+
}
|
27 |
+
return array(
|
28 |
+
'post' => $post
|
29 |
+
);
|
30 |
+
}
|
31 |
+
|
32 |
+
public function update_post() {
|
33 |
+
global $json_api;
|
34 |
+
$post = $json_api->introspector->get_current_post();
|
35 |
+
if (empty($post)) {
|
36 |
+
$json_api->error("Post not found.");
|
37 |
+
}
|
38 |
+
if (!current_user_can('edit_post', $post->ID)) {
|
39 |
+
$json_api->error("You need to login with a user that has the 'edit_post' capacity for that post.", 403);
|
40 |
+
}
|
41 |
+
if (!$json_api->query->nonce) {
|
42 |
+
$json_api->error("You must include a 'nonce' value to update posts. Use the `get_nonce` Core API method.", 403);
|
43 |
+
}
|
44 |
+
$nonce_id = $json_api->get_nonce_id('posts', 'update_post');
|
45 |
+
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
46 |
+
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.", 403);
|
47 |
+
}
|
48 |
+
nocache_headers();
|
49 |
+
$post = new JSON_API_Post($post);
|
50 |
+
$post->update($_REQUEST);
|
51 |
+
return array(
|
52 |
+
'post' => $post
|
53 |
+
);
|
54 |
+
}
|
55 |
+
|
56 |
+
public function delete_post() {
|
57 |
+
global $json_api;
|
58 |
+
$post = $json_api->introspector->get_current_post();
|
59 |
+
if (empty($post)) {
|
60 |
+
$json_api->error("Post not found.");
|
61 |
+
}
|
62 |
+
if (!current_user_can('edit_post', $post->ID)) {
|
63 |
+
$json_api->error("You need to login with a user that has the 'edit_post' capacity for that post.", 403);
|
64 |
+
}
|
65 |
+
if (!current_user_can('delete_posts')) {
|
66 |
+
$json_api->error("You need to login with a user that has the 'delete_posts' capacity.", 403);
|
67 |
+
}
|
68 |
+
if ($post->post_author != get_current_user_id() && !current_user_can('delete_other_posts')) {
|
69 |
+
$json_api->error("You need to login with a user that has the 'delete_other_posts' capacity.", 403);
|
70 |
+
}
|
71 |
+
if (!$json_api->query->nonce) {
|
72 |
+
$json_api->error("You must include a 'nonce' value to update posts. Use the `get_nonce` Core API method.", 403);
|
73 |
+
}
|
74 |
+
$nonce_id = $json_api->get_nonce_id('posts', 'delete_post');
|
75 |
+
if (!wp_verify_nonce($json_api->query->nonce, $nonce_id)) {
|
76 |
+
$json_api->error("Your 'nonce' value was incorrect. Use the 'get_nonce' API method.", 403);
|
77 |
+
}
|
78 |
+
nocache_headers();
|
79 |
+
wp_delete_post($post->ID);
|
80 |
+
return array();
|
81 |
+
}
|
82 |
+
|
83 |
+
}
|
84 |
+
|
85 |
+
?>
|
trunk/controllers/respond.php
ADDED
@@ -0,0 +1,27 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Controller name: Respond
|
4 |
+
Controller description: Comment/trackback submission methods
|
5 |
+
*/
|
6 |
+
|
7 |
+
class JSON_API_Respond_Controller {
|
8 |
+
|
9 |
+
function submit_comment() {
|
10 |
+
global $json_api;
|
11 |
+
nocache_headers();
|
12 |
+
if (empty($_REQUEST['post_id'])) {
|
13 |
+
$json_api->error("No post specified. Include 'post_id' var in your request.");
|
14 |
+
} else if (empty($_REQUEST['name']) ||
|
15 |
+
empty($_REQUEST['email']) ||
|
16 |
+
empty($_REQUEST['content'])) {
|
17 |
+
$json_api->error("Please include all required arguments (name, email, content).");
|
18 |
+
} else if (!is_email($_REQUEST['email'])) {
|
19 |
+
$json_api->error("Please enter a valid email address.");
|
20 |
+
}
|
21 |
+
$pending = new JSON_API_Comment();
|
22 |
+
return $pending->handle_submission();
|
23 |
+
}
|
24 |
+
|
25 |
+
}
|
26 |
+
|
27 |
+
?>
|
trunk/controllers/widgets.php
ADDED
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Controller name: Widgets
|
4 |
+
Controller description: Retrieve sidebar widgets
|
5 |
+
*/
|
6 |
+
|
7 |
+
class JSON_API_Widgets_Controller {
|
8 |
+
|
9 |
+
function get_sidebar() {
|
10 |
+
global $json_api;
|
11 |
+
$index = @$_REQUEST['sidebar_id'];
|
12 |
+
if (empty($_REQUEST['sidebar_id'])) {
|
13 |
+
$json_api->error("No sidebar specified. Include 'sidebar_id' var in your request.");
|
14 |
+
} else if (!is_active_sidebar($index)) {
|
15 |
+
$json_api->error("Sidebar '$index' is not active.");
|
16 |
+
}
|
17 |
+
|
18 |
+
$widget_params = array(
|
19 |
+
'before_widget',
|
20 |
+
'after_widget',
|
21 |
+
'before_title',
|
22 |
+
'after_title'
|
23 |
+
);
|
24 |
+
$json_api_params = array();
|
25 |
+
foreach ($widget_params as $param) {
|
26 |
+
if (isset($_REQUEST[$param])) {
|
27 |
+
$json_api_params[$param] = $_REQUEST[$param];
|
28 |
+
}
|
29 |
+
}
|
30 |
+
|
31 |
+
$widgets = array();
|
32 |
+
|
33 |
+
global $wp_registered_sidebars, $wp_registered_widgets;
|
34 |
+
|
35 |
+
if ( is_int($index) ) {
|
36 |
+
$index = "sidebar-$index";
|
37 |
+
} else {
|
38 |
+
$index = sanitize_title($index);
|
39 |
+
foreach ( (array) $wp_registered_sidebars as $key => $value ) {
|
40 |
+
if ( sanitize_title($value['name']) == $index ) {
|
41 |
+
$index = $key;
|
42 |
+
break;
|
43 |
+
}
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
$sidebars_widgets = wp_get_sidebars_widgets();
|
48 |
+
|
49 |
+
if ( empty($wp_registered_sidebars[$index]) || !array_key_exists($index, $sidebars_widgets) || !is_array($sidebars_widgets[$index]) || empty($sidebars_widgets[$index]) )
|
50 |
+
return false;
|
51 |
+
|
52 |
+
$sidebar = $wp_registered_sidebars[$index];
|
53 |
+
|
54 |
+
$did_one = false;
|
55 |
+
foreach ( (array) $sidebars_widgets[$index] as $id ) {
|
56 |
+
|
57 |
+
if ( !isset($wp_registered_widgets[$id]) ) continue;
|
58 |
+
|
59 |
+
$params = array_merge(
|
60 |
+
array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']), $json_api_params ) ),
|
61 |
+
(array) $wp_registered_widgets[$id]['params']
|
62 |
+
);
|
63 |
+
|
64 |
+
|
65 |
+
// Substitute HTML id and class attributes into before_widget
|
66 |
+
$classname_ = '';
|
67 |
+
foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
|
68 |
+
if ( is_string($cn) )
|
69 |
+
$classname_ .= '_' . $cn;
|
70 |
+
elseif ( is_object($cn) )
|
71 |
+
$classname_ .= '_' . get_class($cn);
|
72 |
+
}
|
73 |
+
$classname_ = ltrim($classname_, '_');
|
74 |
+
$params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_);
|
75 |
+
|
76 |
+
$params = apply_filters( 'dynamic_sidebar_params', $params );
|
77 |
+
|
78 |
+
$callback = $wp_registered_widgets[$id]['callback'];
|
79 |
+
|
80 |
+
do_action( 'dynamic_sidebar', $wp_registered_widgets[$id] );
|
81 |
+
|
82 |
+
if ( is_callable($callback) ) {
|
83 |
+
ob_start();
|
84 |
+
$object = $callback[0];
|
85 |
+
$settings = $object->get_settings();
|
86 |
+
$widget_params = $wp_registered_widgets[$id]['params'];
|
87 |
+
$number = $widget_params[0]['number'];
|
88 |
+
$instance = $settings[$number];
|
89 |
+
call_user_func_array($callback, $params);
|
90 |
+
$widgets[] = array(
|
91 |
+
'id' => $id,
|
92 |
+
'widget' => trim(ob_get_contents()),
|
93 |
+
'params' => $params[0],
|
94 |
+
'instance' => $instance
|
95 |
+
);
|
96 |
+
ob_end_clean();
|
97 |
+
}
|
98 |
+
}
|
99 |
+
|
100 |
+
return array(
|
101 |
+
'sidebar_id' => $index,
|
102 |
+
'widgets' => $widgets
|
103 |
+
);
|
104 |
+
}
|
105 |
+
|
106 |
+
}
|
107 |
+
|
108 |
+
?>
|
trunk/json-api.php
ADDED
@@ -0,0 +1,83 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/*
|
3 |
+
Plugin Name: JSON API
|
4 |
+
Plugin URI: http://wordpress.org/plugins/json-api/
|
5 |
+
Description: A RESTful API for WordPress
|
6 |
+
Version: 1.1.1
|
7 |
+
Author: Dan Phiffer
|
8 |
+
Author URI: http://phiffer.org/
|
9 |
+
*/
|
10 |
+
|
11 |
+
$dir = json_api_dir();
|
12 |
+
@include_once "$dir/singletons/api.php";
|
13 |
+
@include_once "$dir/singletons/query.php";
|
14 |
+
@include_once "$dir/singletons/introspector.php";
|
15 |
+
@include_once "$dir/singletons/response.php";
|
16 |
+
@include_once "$dir/models/post.php";
|
17 |
+
@include_once "$dir/models/comment.php";
|
18 |
+
@include_once "$dir/models/category.php";
|
19 |
+
@include_once "$dir/models/tag.php";
|
20 |
+
@include_once "$dir/models/author.php";
|
21 |
+
@include_once "$dir/models/attachment.php";
|
22 |
+
|
23 |
+
function json_api_init() {
|
24 |
+
global $json_api;
|
25 |
+
if (phpversion() < 5) {
|
26 |
+
add_action('admin_notices', 'json_api_php_version_warning');
|
27 |
+
return;
|
28 |
+
}
|
29 |
+
if (!class_exists('JSON_API')) {
|
30 |
+
add_action('admin_notices', 'json_api_class_warning');
|
31 |
+
return;
|
32 |
+
}
|
33 |
+
add_filter('rewrite_rules_array', 'json_api_rewrites');
|
34 |
+
$json_api = new JSON_API();
|
35 |
+
}
|
36 |
+
|
37 |
+
function json_api_php_version_warning() {
|
38 |
+
echo "<div id=\"json-api-warning\" class=\"updated fade\"><p>Sorry, JSON API requires PHP version 5.0 or greater.</p></div>";
|
39 |
+
}
|
40 |
+
|
41 |
+
function json_api_class_warning() {
|
42 |
+
echo "<div id=\"json-api-warning\" class=\"updated fade\"><p>Oops, JSON_API class not found. If you've defined a JSON_API_DIR constant, double check that the path is correct.</p></div>";
|
43 |
+
}
|
44 |
+
|
45 |
+
function json_api_activation() {
|
46 |
+
// Add the rewrite rule on activation
|
47 |
+
global $wp_rewrite;
|
48 |
+
add_filter('rewrite_rules_array', 'json_api_rewrites');
|
49 |
+
$wp_rewrite->flush_rules();
|
50 |
+
}
|
51 |
+
|
52 |
+
function json_api_deactivation() {
|
53 |
+
// Remove the rewrite rule on deactivation
|
54 |
+
global $wp_rewrite;
|
55 |
+
$wp_rewrite->flush_rules();
|
56 |
+
}
|
57 |
+
|
58 |
+
function json_api_rewrites($wp_rules) {
|
59 |
+
$base = get_option('json_api_base', 'api');
|
60 |
+
if (empty($base)) {
|
61 |
+
return $wp_rules;
|
62 |
+
}
|
63 |
+
$json_api_rules = array(
|
64 |
+
"$base\$" => 'index.php?json=info',
|
65 |
+
"$base/(.+)\$" => 'index.php?json=$matches[1]'
|
66 |
+
);
|
67 |
+
return array_merge($json_api_rules, $wp_rules);
|
68 |
+
}
|
69 |
+
|
70 |
+
function json_api_dir() {
|
71 |
+
if (defined('JSON_API_DIR') && file_exists(JSON_API_DIR)) {
|
72 |
+
return JSON_API_DIR;
|
73 |
+
} else {
|
74 |
+
return dirname(__FILE__);
|
75 |
+
}
|
76 |
+
}
|
77 |
+
|
78 |
+
// Add initialization and activation hooks
|
79 |
+
add_action('init', 'json_api_init');
|
80 |
+
register_activation_hook("$dir/json-api.php", 'json_api_activation');
|
81 |
+
register_deactivation_hook("$dir/json-api.php", 'json_api_deactivation');
|
82 |
+
|
83 |
+
?>
|
trunk/library/JSON.php
ADDED
@@ -0,0 +1,933 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
/**
|
4 |
+
* Converts to and from JSON format.
|
5 |
+
*
|
6 |
+
* JSON (JavaScript Object Notation) is a lightweight data-interchange
|
7 |
+
* format. It is easy for humans to read and write. It is easy for machines
|
8 |
+
* to parse and generate. It is based on a subset of the JavaScript
|
9 |
+
* Programming Language, Standard ECMA-262 3rd Edition - December 1999.
|
10 |
+
* This feature can also be found in Python. JSON is a text format that is
|
11 |
+
* completely language independent but uses conventions that are familiar
|
12 |
+
* to programmers of the C-family of languages, including C, C++, C#, Java,
|
13 |
+
* JavaScript, Perl, TCL, and many others. These properties make JSON an
|
14 |
+
* ideal data-interchange language.
|
15 |
+
*
|
16 |
+
* This package provides a simple encoder and decoder for JSON notation. It
|
17 |
+
* is intended for use with client-side Javascript applications that make
|
18 |
+
* use of HTTPRequest to perform server communication functions - data can
|
19 |
+
* be encoded into JSON notation for use in a client-side javascript, or
|
20 |
+
* decoded from incoming Javascript requests. JSON format is native to
|
21 |
+
* Javascript, and can be directly eval()'ed with no further parsing
|
22 |
+
* overhead
|
23 |
+
*
|
24 |
+
* All strings should be in ASCII or UTF-8 format!
|
25 |
+
*
|
26 |
+
* LICENSE: Redistribution and use in source and binary forms, with or
|
27 |
+
* without modification, are permitted provided that the following
|
28 |
+
* conditions are met: Redistributions of source code must retain the
|
29 |
+
* above copyright notice, this list of conditions and the following
|
30 |
+
* disclaimer. Redistributions in binary form must reproduce the above
|
31 |
+
* copyright notice, this list of conditions and the following disclaimer
|
32 |
+
* in the documentation and/or other materials provided with the
|
33 |
+
* distribution.
|
34 |
+
*
|
35 |
+
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
36 |
+
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
37 |
+
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
38 |
+
* NO EVENT SHALL CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
39 |
+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
40 |
+
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
41 |
+
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
42 |
+
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
43 |
+
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
|
44 |
+
* USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
|
45 |
+
* DAMAGE.
|
46 |
+
*
|
47 |
+
* @category
|
48 |
+
* @package Services_JSON
|
49 |
+
* @author Michal Migurski <mike-json@teczno.com>
|
50 |
+
* @author Matt Knapp <mdknapp[at]gmail[dot]com>
|
51 |
+
* @author Brett Stimmerman <brettstimmerman[at]gmail[dot]com>
|
52 |
+
* @copyright 2005 Michal Migurski
|
53 |
+
* @version CVS: $Id: JSON.php 305040 2010-11-02 23:19:03Z alan_k $
|
54 |
+
* @license http://www.opensource.org/licenses/bsd-license.php
|
55 |
+
* @link http://pear.php.net/pepr/pepr-proposal-show.php?id=198
|
56 |
+
*/
|
57 |
+
|
58 |
+
/**
|
59 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
60 |
+
*/
|
61 |
+
define('SERVICES_JSON_SLICE', 1);
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
65 |
+
*/
|
66 |
+
define('SERVICES_JSON_IN_STR', 2);
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
70 |
+
*/
|
71 |
+
define('SERVICES_JSON_IN_ARR', 3);
|
72 |
+
|
73 |
+
/**
|
74 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
75 |
+
*/
|
76 |
+
define('SERVICES_JSON_IN_OBJ', 4);
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Marker constant for Services_JSON::decode(), used to flag stack state
|
80 |
+
*/
|
81 |
+
define('SERVICES_JSON_IN_CMT', 5);
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Behavior switch for Services_JSON::decode()
|
85 |
+
*/
|
86 |
+
define('SERVICES_JSON_LOOSE_TYPE', 16);
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Behavior switch for Services_JSON::decode()
|
90 |
+
*/
|
91 |
+
define('SERVICES_JSON_SUPPRESS_ERRORS', 32);
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Behavior switch for Services_JSON::decode()
|
95 |
+
*/
|
96 |
+
define('SERVICES_JSON_USE_TO_JSON', 64);
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Converts to and from JSON format.
|
100 |
+
*
|
101 |
+
* Brief example of use:
|
102 |
+
*
|
103 |
+
* <code>
|
104 |
+
* // create a new instance of Services_JSON
|
105 |
+
* $json = new Services_JSON();
|
106 |
+
*
|
107 |
+
* // convert a complexe value to JSON notation, and send it to the browser
|
108 |
+
* $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
|
109 |
+
* $output = $json->encode($value);
|
110 |
+
*
|
111 |
+
* print($output);
|
112 |
+
* // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
|
113 |
+
*
|
114 |
+
* // accept incoming POST data, assumed to be in JSON notation
|
115 |
+
* $input = file_get_contents('php://input', 1000000);
|
116 |
+
* $value = $json->decode($input);
|
117 |
+
* </code>
|
118 |
+
*/
|
119 |
+
class Services_JSON
|
120 |
+
{
|
121 |
+
/**
|
122 |
+
* constructs a new JSON instance
|
123 |
+
*
|
124 |
+
* @param int $use object behavior flags; combine with boolean-OR
|
125 |
+
*
|
126 |
+
* possible values:
|
127 |
+
* - SERVICES_JSON_LOOSE_TYPE: loose typing.
|
128 |
+
* "{...}" syntax creates associative arrays
|
129 |
+
* instead of objects in decode().
|
130 |
+
* - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
|
131 |
+
* Values which can't be encoded (e.g. resources)
|
132 |
+
* appear as NULL instead of throwing errors.
|
133 |
+
* By default, a deeply-nested resource will
|
134 |
+
* bubble up with an error, so all return values
|
135 |
+
* from encode() should be checked with isError()
|
136 |
+
* - SERVICES_JSON_USE_TO_JSON: call toJSON when serializing objects
|
137 |
+
* It serializes the return value from the toJSON call rather
|
138 |
+
* than the object it'self, toJSON can return associative arrays,
|
139 |
+
* strings or numbers, if you return an object, make sure it does
|
140 |
+
* not have a toJSON method, otherwise an error will occur.
|
141 |
+
*/
|
142 |
+
function Services_JSON($use = 0)
|
143 |
+
{
|
144 |
+
$this->use = $use;
|
145 |
+
$this->_mb_strlen = function_exists('mb_strlen');
|
146 |
+
$this->_mb_convert_encoding = function_exists('mb_convert_encoding');
|
147 |
+
$this->_mb_substr = function_exists('mb_substr');
|
148 |
+
}
|
149 |
+
// private - cache the mbstring lookup results..
|
150 |
+
var $_mb_strlen = false;
|
151 |
+
var $_mb_substr = false;
|
152 |
+
var $_mb_convert_encoding = false;
|
153 |
+
|
154 |
+
/**
|
155 |
+
* convert a string from one UTF-16 char to one UTF-8 char
|
156 |
+
*
|
157 |
+
* Normally should be handled by mb_convert_encoding, but
|
158 |
+
* provides a slower PHP-only method for installations
|
159 |
+
* that lack the multibye string extension.
|
160 |
+
*
|
161 |
+
* @param string $utf16 UTF-16 character
|
162 |
+
* @return string UTF-8 character
|
163 |
+
* @access private
|
164 |
+
*/
|
165 |
+
function utf162utf8($utf16)
|
166 |
+
{
|
167 |
+
// oh please oh please oh please oh please oh please
|
168 |
+
if($this->_mb_convert_encoding) {
|
169 |
+
return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
|
170 |
+
}
|
171 |
+
|
172 |
+
$bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
|
173 |
+
|
174 |
+
switch(true) {
|
175 |
+
case ((0x7F & $bytes) == $bytes):
|
176 |
+
// this case should never be reached, because we are in ASCII range
|
177 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
178 |
+
return chr(0x7F & $bytes);
|
179 |
+
|
180 |
+
case (0x07FF & $bytes) == $bytes:
|
181 |
+
// return a 2-byte UTF-8 character
|
182 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
183 |
+
return chr(0xC0 | (($bytes >> 6) & 0x1F))
|
184 |
+
. chr(0x80 | ($bytes & 0x3F));
|
185 |
+
|
186 |
+
case (0xFFFF & $bytes) == $bytes:
|
187 |
+
// return a 3-byte UTF-8 character
|
188 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
189 |
+
return chr(0xE0 | (($bytes >> 12) & 0x0F))
|
190 |
+
. chr(0x80 | (($bytes >> 6) & 0x3F))
|
191 |
+
. chr(0x80 | ($bytes & 0x3F));
|
192 |
+
}
|
193 |
+
|
194 |
+
// ignoring UTF-32 for now, sorry
|
195 |
+
return '';
|
196 |
+
}
|
197 |
+
|
198 |
+
/**
|
199 |
+
* convert a string from one UTF-8 char to one UTF-16 char
|
200 |
+
*
|
201 |
+
* Normally should be handled by mb_convert_encoding, but
|
202 |
+
* provides a slower PHP-only method for installations
|
203 |
+
* that lack the multibye string extension.
|
204 |
+
*
|
205 |
+
* @param string $utf8 UTF-8 character
|
206 |
+
* @return string UTF-16 character
|
207 |
+
* @access private
|
208 |
+
*/
|
209 |
+
function utf82utf16($utf8)
|
210 |
+
{
|
211 |
+
// oh please oh please oh please oh please oh please
|
212 |
+
if($this->_mb_convert_encoding) {
|
213 |
+
return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
|
214 |
+
}
|
215 |
+
|
216 |
+
switch($this->strlen8($utf8)) {
|
217 |
+
case 1:
|
218 |
+
// this case should never be reached, because we are in ASCII range
|
219 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
220 |
+
return $utf8;
|
221 |
+
|
222 |
+
case 2:
|
223 |
+
// return a UTF-16 character from a 2-byte UTF-8 char
|
224 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
225 |
+
return chr(0x07 & (ord($utf8{0}) >> 2))
|
226 |
+
. chr((0xC0 & (ord($utf8{0}) << 6))
|
227 |
+
| (0x3F & ord($utf8{1})));
|
228 |
+
|
229 |
+
case 3:
|
230 |
+
// return a UTF-16 character from a 3-byte UTF-8 char
|
231 |
+
// see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
232 |
+
return chr((0xF0 & (ord($utf8{0}) << 4))
|
233 |
+
| (0x0F & (ord($utf8{1}) >> 2)))
|
234 |
+
. chr((0xC0 & (ord($utf8{1}) << 6))
|
235 |
+
| (0x7F & ord($utf8{2})));
|
236 |
+
}
|
237 |
+
|
238 |
+
// ignoring UTF-32 for now, sorry
|
239 |
+
return '';
|
240 |
+
}
|
241 |
+
|
242 |
+
/**
|
243 |
+
* encodes an arbitrary variable into JSON format (and sends JSON Header)
|
244 |
+
*
|
245 |
+
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
246 |
+
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
247 |
+
* if var is a strng, note that encode() always expects it
|
248 |
+
* to be in ASCII or UTF-8 format!
|
249 |
+
*
|
250 |
+
* @return mixed JSON string representation of input var or an error if a problem occurs
|
251 |
+
* @access public
|
252 |
+
*/
|
253 |
+
function encode($var)
|
254 |
+
{
|
255 |
+
header('Content-type: application/json');
|
256 |
+
return $this->encodeUnsafe($var);
|
257 |
+
}
|
258 |
+
/**
|
259 |
+
* encodes an arbitrary variable into JSON format without JSON Header - warning - may allow XSS!!!!)
|
260 |
+
*
|
261 |
+
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
262 |
+
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
263 |
+
* if var is a strng, note that encode() always expects it
|
264 |
+
* to be in ASCII or UTF-8 format!
|
265 |
+
*
|
266 |
+
* @return mixed JSON string representation of input var or an error if a problem occurs
|
267 |
+
* @access public
|
268 |
+
*/
|
269 |
+
function encodeUnsafe($var)
|
270 |
+
{
|
271 |
+
// see bug #16908 - regarding numeric locale printing
|
272 |
+
$lc = setlocale(LC_NUMERIC, 0);
|
273 |
+
setlocale(LC_NUMERIC, 'C');
|
274 |
+
$ret = $this->_encode($var);
|
275 |
+
setlocale(LC_NUMERIC, $lc);
|
276 |
+
return $ret;
|
277 |
+
|
278 |
+
}
|
279 |
+
/**
|
280 |
+
* PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format
|
281 |
+
*
|
282 |
+
* @param mixed $var any number, boolean, string, array, or object to be encoded.
|
283 |
+
* see argument 1 to Services_JSON() above for array-parsing behavior.
|
284 |
+
* if var is a strng, note that encode() always expects it
|
285 |
+
* to be in ASCII or UTF-8 format!
|
286 |
+
*
|
287 |
+
* @return mixed JSON string representation of input var or an error if a problem occurs
|
288 |
+
* @access public
|
289 |
+
*/
|
290 |
+
function _encode($var)
|
291 |
+
{
|
292 |
+
|
293 |
+
switch (gettype($var)) {
|
294 |
+
case 'boolean':
|
295 |
+
return $var ? 'true' : 'false';
|
296 |
+
|
297 |
+
case 'NULL':
|
298 |
+
return 'null';
|
299 |
+
|
300 |
+
case 'integer':
|
301 |
+
return (int) $var;
|
302 |
+
|
303 |
+
case 'double':
|
304 |
+
case 'float':
|
305 |
+
return (float) $var;
|
306 |
+
|
307 |
+
case 'string':
|
308 |
+
// STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
|
309 |
+
$ascii = '';
|
310 |
+
$strlen_var = $this->strlen8($var);
|
311 |
+
|
312 |
+
/*
|
313 |
+
* Iterate over every character in the string,
|
314 |
+
* escaping with a slash or encoding to UTF-8 where necessary
|
315 |
+
*/
|
316 |
+
for ($c = 0; $c < $strlen_var; ++$c) {
|
317 |
+
|
318 |
+
$ord_var_c = ord($var{$c});
|
319 |
+
|
320 |
+
switch (true) {
|
321 |
+
case $ord_var_c == 0x08:
|
322 |
+
$ascii .= '\b';
|
323 |
+
break;
|
324 |
+
case $ord_var_c == 0x09:
|
325 |
+
$ascii .= '\t';
|
326 |
+
break;
|
327 |
+
case $ord_var_c == 0x0A:
|
328 |
+
$ascii .= '\n';
|
329 |
+
break;
|
330 |
+
case $ord_var_c == 0x0C:
|
331 |
+
$ascii .= '\f';
|
332 |
+
break;
|
333 |
+
case $ord_var_c == 0x0D:
|
334 |
+
$ascii .= '\r';
|
335 |
+
break;
|
336 |
+
|
337 |
+
case $ord_var_c == 0x22:
|
338 |
+
case $ord_var_c == 0x2F:
|
339 |
+
case $ord_var_c == 0x5C:
|
340 |
+
// double quote, slash, slosh
|
341 |
+
$ascii .= '\\'.$var{$c};
|
342 |
+
break;
|
343 |
+
|
344 |
+
case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
|
345 |
+
// characters U-00000000 - U-0000007F (same as ASCII)
|
346 |
+
$ascii .= $var{$c};
|
347 |
+
break;
|
348 |
+
|
349 |
+
case (($ord_var_c & 0xE0) == 0xC0):
|
350 |
+
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
351 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
352 |
+
if ($c+1 >= $strlen_var) {
|
353 |
+
$c += 1;
|
354 |
+
$ascii .= '?';
|
355 |
+
break;
|
356 |
+
}
|
357 |
+
|
358 |
+
$char = pack('C*', $ord_var_c, ord($var{$c + 1}));
|
359 |
+
$c += 1;
|
360 |
+
$utf16 = $this->utf82utf16($char);
|
361 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
362 |
+
break;
|
363 |
+
|
364 |
+
case (($ord_var_c & 0xF0) == 0xE0):
|
365 |
+
if ($c+2 >= $strlen_var) {
|
366 |
+
$c += 2;
|
367 |
+
$ascii .= '?';
|
368 |
+
break;
|
369 |
+
}
|
370 |
+
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
371 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
372 |
+
$char = pack('C*', $ord_var_c,
|
373 |
+
@ord($var{$c + 1}),
|
374 |
+
@ord($var{$c + 2}));
|
375 |
+
$c += 2;
|
376 |
+
$utf16 = $this->utf82utf16($char);
|
377 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
378 |
+
break;
|
379 |
+
|
380 |
+
case (($ord_var_c & 0xF8) == 0xF0):
|
381 |
+
if ($c+3 >= $strlen_var) {
|
382 |
+
$c += 3;
|
383 |
+
$ascii .= '?';
|
384 |
+
break;
|
385 |
+
}
|
386 |
+
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
387 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
388 |
+
$char = pack('C*', $ord_var_c,
|
389 |
+
ord($var{$c + 1}),
|
390 |
+
ord($var{$c + 2}),
|
391 |
+
ord($var{$c + 3}));
|
392 |
+
$c += 3;
|
393 |
+
$utf16 = $this->utf82utf16($char);
|
394 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
395 |
+
break;
|
396 |
+
|
397 |
+
case (($ord_var_c & 0xFC) == 0xF8):
|
398 |
+
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
399 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
400 |
+
if ($c+4 >= $strlen_var) {
|
401 |
+
$c += 4;
|
402 |
+
$ascii .= '?';
|
403 |
+
break;
|
404 |
+
}
|
405 |
+
$char = pack('C*', $ord_var_c,
|
406 |
+
ord($var{$c + 1}),
|
407 |
+
ord($var{$c + 2}),
|
408 |
+
ord($var{$c + 3}),
|
409 |
+
ord($var{$c + 4}));
|
410 |
+
$c += 4;
|
411 |
+
$utf16 = $this->utf82utf16($char);
|
412 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
413 |
+
break;
|
414 |
+
|
415 |
+
case (($ord_var_c & 0xFE) == 0xFC):
|
416 |
+
if ($c+5 >= $strlen_var) {
|
417 |
+
$c += 5;
|
418 |
+
$ascii .= '?';
|
419 |
+
break;
|
420 |
+
}
|
421 |
+
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
422 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
423 |
+
$char = pack('C*', $ord_var_c,
|
424 |
+
ord($var{$c + 1}),
|
425 |
+
ord($var{$c + 2}),
|
426 |
+
ord($var{$c + 3}),
|
427 |
+
ord($var{$c + 4}),
|
428 |
+
ord($var{$c + 5}));
|
429 |
+
$c += 5;
|
430 |
+
$utf16 = $this->utf82utf16($char);
|
431 |
+
$ascii .= sprintf('\u%04s', bin2hex($utf16));
|
432 |
+
break;
|
433 |
+
}
|
434 |
+
}
|
435 |
+
return '"'.$ascii.'"';
|
436 |
+
|
437 |
+
case 'array':
|
438 |
+
/*
|
439 |
+
* As per JSON spec if any array key is not an integer
|
440 |
+
* we must treat the the whole array as an object. We
|
441 |
+
* also try to catch a sparsely populated associative
|
442 |
+
* array with numeric keys here because some JS engines
|
443 |
+
* will create an array with empty indexes up to
|
444 |
+
* max_index which can cause memory issues and because
|
445 |
+
* the keys, which may be relevant, will be remapped
|
446 |
+
* otherwise.
|
447 |
+
*
|
448 |
+
* As per the ECMA and JSON specification an object may
|
449 |
+
* have any string as a property. Unfortunately due to
|
450 |
+
* a hole in the ECMA specification if the key is a
|
451 |
+
* ECMA reserved word or starts with a digit the
|
452 |
+
* parameter is only accessible using ECMAScript's
|
453 |
+
* bracket notation.
|
454 |
+
*/
|
455 |
+
|
456 |
+
// treat as a JSON object
|
457 |
+
if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
|
458 |
+
$properties = array_map(array($this, 'name_value'),
|
459 |
+
array_keys($var),
|
460 |
+
array_values($var));
|
461 |
+
|
462 |
+
foreach($properties as $property) {
|
463 |
+
if(Services_JSON::isError($property)) {
|
464 |
+
return $property;
|
465 |
+
}
|
466 |
+
}
|
467 |
+
|
468 |
+
return '{' . join(',', $properties) . '}';
|
469 |
+
}
|
470 |
+
|
471 |
+
// treat it like a regular array
|
472 |
+
$elements = array_map(array($this, '_encode'), $var);
|
473 |
+
|
474 |
+
foreach($elements as $element) {
|
475 |
+
if(Services_JSON::isError($element)) {
|
476 |
+
return $element;
|
477 |
+
}
|
478 |
+
}
|
479 |
+
|
480 |
+
return '[' . join(',', $elements) . ']';
|
481 |
+
|
482 |
+
case 'object':
|
483 |
+
|
484 |
+
// support toJSON methods.
|
485 |
+
if (($this->use & SERVICES_JSON_USE_TO_JSON) && method_exists($var, 'toJSON')) {
|
486 |
+
// this may end up allowing unlimited recursion
|
487 |
+
// so we check the return value to make sure it's not got the same method.
|
488 |
+
$recode = $var->toJSON();
|
489 |
+
|
490 |
+
if (method_exists($recode, 'toJSON')) {
|
491 |
+
|
492 |
+
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
493 |
+
? 'null'
|
494 |
+
: new Services_JSON_Error(class_name($var).
|
495 |
+
" toJSON returned an object with a toJSON method.");
|
496 |
+
|
497 |
+
}
|
498 |
+
|
499 |
+
return $this->_encode( $recode );
|
500 |
+
}
|
501 |
+
|
502 |
+
$vars = get_object_vars($var);
|
503 |
+
|
504 |
+
$properties = array_map(array($this, 'name_value'),
|
505 |
+
array_keys($vars),
|
506 |
+
array_values($vars));
|
507 |
+
|
508 |
+
foreach($properties as $property) {
|
509 |
+
if(Services_JSON::isError($property)) {
|
510 |
+
return $property;
|
511 |
+
}
|
512 |
+
}
|
513 |
+
|
514 |
+
return '{' . join(',', $properties) . '}';
|
515 |
+
|
516 |
+
default:
|
517 |
+
return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
|
518 |
+
? 'null'
|
519 |
+
: new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
|
520 |
+
}
|
521 |
+
}
|
522 |
+
|
523 |
+
/**
|
524 |
+
* array-walking function for use in generating JSON-formatted name-value pairs
|
525 |
+
*
|
526 |
+
* @param string $name name of key to use
|
527 |
+
* @param mixed $value reference to an array element to be encoded
|
528 |
+
*
|
529 |
+
* @return string JSON-formatted name-value pair, like '"name":value'
|
530 |
+
* @access private
|
531 |
+
*/
|
532 |
+
function name_value($name, $value)
|
533 |
+
{
|
534 |
+
$encoded_value = $this->_encode($value);
|
535 |
+
|
536 |
+
if(Services_JSON::isError($encoded_value)) {
|
537 |
+
return $encoded_value;
|
538 |
+
}
|
539 |
+
|
540 |
+
return $this->_encode(strval($name)) . ':' . $encoded_value;
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* reduce a string by removing leading and trailing comments and whitespace
|
545 |
+
*
|
546 |
+
* @param $str string string value to strip of comments and whitespace
|
547 |
+
*
|
548 |
+
* @return string string value stripped of comments and whitespace
|
549 |
+
* @access private
|
550 |
+
*/
|
551 |
+
function reduce_string($str)
|
552 |
+
{
|
553 |
+
$str = preg_replace(array(
|
554 |
+
|
555 |
+
// eliminate single line comments in '// ...' form
|
556 |
+
'#^\s*//(.+)$#m',
|
557 |
+
|
558 |
+
// eliminate multi-line comments in '/* ... */' form, at start of string
|
559 |
+
'#^\s*/\*(.+)\*/#Us',
|
560 |
+
|
561 |
+
// eliminate multi-line comments in '/* ... */' form, at end of string
|
562 |
+
'#/\*(.+)\*/\s*$#Us'
|
563 |
+
|
564 |
+
), '', $str);
|
565 |
+
|
566 |
+
// eliminate extraneous space
|
567 |
+
return trim($str);
|
568 |
+
}
|
569 |
+
|
570 |
+
/**
|
571 |
+
* decodes a JSON string into appropriate variable
|
572 |
+
*
|
573 |
+
* @param string $str JSON-formatted string
|
574 |
+
*
|
575 |
+
* @return mixed number, boolean, string, array, or object
|
576 |
+
* corresponding to given JSON input string.
|
577 |
+
* See argument 1 to Services_JSON() above for object-output behavior.
|
578 |
+
* Note that decode() always returns strings
|
579 |
+
* in ASCII or UTF-8 format!
|
580 |
+
* @access public
|
581 |
+
*/
|
582 |
+
function decode($str)
|
583 |
+
{
|
584 |
+
$str = $this->reduce_string($str);
|
585 |
+
|
586 |
+
switch (strtolower($str)) {
|
587 |
+
case 'true':
|
588 |
+
return true;
|
589 |
+
|
590 |
+
case 'false':
|
591 |
+
return false;
|
592 |
+
|
593 |
+
case 'null':
|
594 |
+
return null;
|
595 |
+
|
596 |
+
default:
|
597 |
+
$m = array();
|
598 |
+
|
599 |
+
if (is_numeric($str)) {
|
600 |
+
// Lookie-loo, it's a number
|
601 |
+
|
602 |
+
// This would work on its own, but I'm trying to be
|
603 |
+
// good about returning integers where appropriate:
|
604 |
+
// return (float)$str;
|
605 |
+
|
606 |
+
// Return float or int, as appropriate
|
607 |
+
return ((float)$str == (integer)$str)
|
608 |
+
? (integer)$str
|
609 |
+
: (float)$str;
|
610 |
+
|
611 |
+
} elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
|
612 |
+
// STRINGS RETURNED IN UTF-8 FORMAT
|
613 |
+
$delim = $this->substr8($str, 0, 1);
|
614 |
+
$chrs = $this->substr8($str, 1, -1);
|
615 |
+
$utf8 = '';
|
616 |
+
$strlen_chrs = $this->strlen8($chrs);
|
617 |
+
|
618 |
+
for ($c = 0; $c < $strlen_chrs; ++$c) {
|
619 |
+
|
620 |
+
$substr_chrs_c_2 = $this->substr8($chrs, $c, 2);
|
621 |
+
$ord_chrs_c = ord($chrs{$c});
|
622 |
+
|
623 |
+
switch (true) {
|
624 |
+
case $substr_chrs_c_2 == '\b':
|
625 |
+
$utf8 .= chr(0x08);
|
626 |
+
++$c;
|
627 |
+
break;
|
628 |
+
case $substr_chrs_c_2 == '\t':
|
629 |
+
$utf8 .= chr(0x09);
|
630 |
+
++$c;
|
631 |
+
break;
|
632 |
+
case $substr_chrs_c_2 == '\n':
|
633 |
+
$utf8 .= chr(0x0A);
|
634 |
+
++$c;
|
635 |
+
break;
|
636 |
+
case $substr_chrs_c_2 == '\f':
|
637 |
+
$utf8 .= chr(0x0C);
|
638 |
+
++$c;
|
639 |
+
break;
|
640 |
+
case $substr_chrs_c_2 == '\r':
|
641 |
+
$utf8 .= chr(0x0D);
|
642 |
+
++$c;
|
643 |
+
break;
|
644 |
+
|
645 |
+
case $substr_chrs_c_2 == '\\"':
|
646 |
+
case $substr_chrs_c_2 == '\\\'':
|
647 |
+
case $substr_chrs_c_2 == '\\\\':
|
648 |
+
case $substr_chrs_c_2 == '\\/':
|
649 |
+
if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
|
650 |
+
($delim == "'" && $substr_chrs_c_2 != '\\"')) {
|
651 |
+
$utf8 .= $chrs{++$c};
|
652 |
+
}
|
653 |
+
break;
|
654 |
+
|
655 |
+
case preg_match('/\\\u[0-9A-F]{4}/i', $this->substr8($chrs, $c, 6)):
|
656 |
+
// single, escaped unicode character
|
657 |
+
$utf16 = chr(hexdec($this->substr8($chrs, ($c + 2), 2)))
|
658 |
+
. chr(hexdec($this->substr8($chrs, ($c + 4), 2)));
|
659 |
+
$utf8 .= $this->utf162utf8($utf16);
|
660 |
+
$c += 5;
|
661 |
+
break;
|
662 |
+
|
663 |
+
case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
|
664 |
+
$utf8 .= $chrs{$c};
|
665 |
+
break;
|
666 |
+
|
667 |
+
case ($ord_chrs_c & 0xE0) == 0xC0:
|
668 |
+
// characters U-00000080 - U-000007FF, mask 110XXXXX
|
669 |
+
//see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
670 |
+
$utf8 .= $this->substr8($chrs, $c, 2);
|
671 |
+
++$c;
|
672 |
+
break;
|
673 |
+
|
674 |
+
case ($ord_chrs_c & 0xF0) == 0xE0:
|
675 |
+
// characters U-00000800 - U-0000FFFF, mask 1110XXXX
|
676 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
677 |
+
$utf8 .= $this->substr8($chrs, $c, 3);
|
678 |
+
$c += 2;
|
679 |
+
break;
|
680 |
+
|
681 |
+
case ($ord_chrs_c & 0xF8) == 0xF0:
|
682 |
+
// characters U-00010000 - U-001FFFFF, mask 11110XXX
|
683 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
684 |
+
$utf8 .= $this->substr8($chrs, $c, 4);
|
685 |
+
$c += 3;
|
686 |
+
break;
|
687 |
+
|
688 |
+
case ($ord_chrs_c & 0xFC) == 0xF8:
|
689 |
+
// characters U-00200000 - U-03FFFFFF, mask 111110XX
|
690 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
691 |
+
$utf8 .= $this->substr8($chrs, $c, 5);
|
692 |
+
$c += 4;
|
693 |
+
break;
|
694 |
+
|
695 |
+
case ($ord_chrs_c & 0xFE) == 0xFC:
|
696 |
+
// characters U-04000000 - U-7FFFFFFF, mask 1111110X
|
697 |
+
// see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
|
698 |
+
$utf8 .= $this->substr8($chrs, $c, 6);
|
699 |
+
$c += 5;
|
700 |
+
break;
|
701 |
+
|
702 |
+
}
|
703 |
+
|
704 |
+
}
|
705 |
+
|
706 |
+
return $utf8;
|
707 |
+
|
708 |
+
} elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
|
709 |
+
// array, or object notation
|
710 |
+
|
711 |
+
if ($str{0} == '[') {
|
712 |
+
$stk = array(SERVICES_JSON_IN_ARR);
|
713 |
+
$arr = array();
|
714 |
+
} else {
|
715 |
+
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
716 |
+
$stk = array(SERVICES_JSON_IN_OBJ);
|
717 |
+
$obj = array();
|
718 |
+
} else {
|
719 |
+
$stk = array(SERVICES_JSON_IN_OBJ);
|
720 |
+
$obj = new stdClass();
|
721 |
+
}
|
722 |
+
}
|
723 |
+
|
724 |
+
array_push($stk, array('what' => SERVICES_JSON_SLICE,
|
725 |
+
'where' => 0,
|
726 |
+
'delim' => false));
|
727 |
+
|
728 |
+
$chrs = $this->substr8($str, 1, -1);
|
729 |
+
$chrs = $this->reduce_string($chrs);
|
730 |
+
|
731 |
+
if ($chrs == '') {
|
732 |
+
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
733 |
+
return $arr;
|
734 |
+
|
735 |
+
} else {
|
736 |
+
return $obj;
|
737 |
+
|
738 |
+
}
|
739 |
+
}
|
740 |
+
|
741 |
+
//print("\nparsing {$chrs}\n");
|
742 |
+
|
743 |
+
$strlen_chrs = $this->strlen8($chrs);
|
744 |
+
|
745 |
+
for ($c = 0; $c <= $strlen_chrs; ++$c) {
|
746 |
+
|
747 |
+
$top = end($stk);
|
748 |
+
$substr_chrs_c_2 = $this->substr8($chrs, $c, 2);
|
749 |
+
|
750 |
+
if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
|
751 |
+
// found a comma that is not inside a string, array, etc.,
|
752 |
+
// OR we've reached the end of the character list
|
753 |
+
$slice = $this->substr8($chrs, $top['where'], ($c - $top['where']));
|
754 |
+
array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
|
755 |
+
//print("Found split at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
756 |
+
|
757 |
+
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
758 |
+
// we are in an array, so just push an element onto the stack
|
759 |
+
array_push($arr, $this->decode($slice));
|
760 |
+
|
761 |
+
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
762 |
+
// we are in an object, so figure
|
763 |
+
// out the property name and set an
|
764 |
+
// element in an associative array,
|
765 |
+
// for now
|
766 |
+
$parts = array();
|
767 |
+
|
768 |
+
if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:/Uis', $slice, $parts)) {
|
769 |
+
// "name":value pair
|
770 |
+
$key = $this->decode($parts[1]);
|
771 |
+
$val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B"));
|
772 |
+
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
773 |
+
$obj[$key] = $val;
|
774 |
+
} else {
|
775 |
+
$obj->$key = $val;
|
776 |
+
}
|
777 |
+
} elseif (preg_match('/^\s*(\w+)\s*:/Uis', $slice, $parts)) {
|
778 |
+
// name:value pair, where name is unquoted
|
779 |
+
$key = $parts[1];
|
780 |
+
$val = $this->decode(trim(substr($slice, strlen($parts[0])), ", \t\n\r\0\x0B"));
|
781 |
+
|
782 |
+
if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
|
783 |
+
$obj[$key] = $val;
|
784 |
+
} else {
|
785 |
+
$obj->$key = $val;
|
786 |
+
}
|
787 |
+
}
|
788 |
+
|
789 |
+
}
|
790 |
+
|
791 |
+
} elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
|
792 |
+
// found a quote, and we are not inside a string
|
793 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
|
794 |
+
//print("Found start of string at {$c}\n");
|
795 |
+
|
796 |
+
} elseif (($chrs{$c} == $top['delim']) &&
|
797 |
+
($top['what'] == SERVICES_JSON_IN_STR) &&
|
798 |
+
(($this->strlen8($this->substr8($chrs, 0, $c)) - $this->strlen8(rtrim($this->substr8($chrs, 0, $c), '\\'))) % 2 != 1)) {
|
799 |
+
// found a quote, we're in a string, and it's not escaped
|
800 |
+
// we know that it's not escaped becase there is _not_ an
|
801 |
+
// odd number of backslashes at the end of the string so far
|
802 |
+
array_pop($stk);
|
803 |
+
//print("Found end of string at {$c}: ".$this->substr8($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
|
804 |
+
|
805 |
+
} elseif (($chrs{$c} == '[') &&
|
806 |
+
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
807 |
+
// found a left-bracket, and we are in an array, object, or slice
|
808 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
|
809 |
+
//print("Found start of array at {$c}\n");
|
810 |
+
|
811 |
+
} elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
|
812 |
+
// found a right-bracket, and we're in an array
|
813 |
+
array_pop($stk);
|
814 |
+
//print("Found end of array at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
815 |
+
|
816 |
+
} elseif (($chrs{$c} == '{') &&
|
817 |
+
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
818 |
+
// found a left-brace, and we are in an array, object, or slice
|
819 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
|
820 |
+
//print("Found start of object at {$c}\n");
|
821 |
+
|
822 |
+
} elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
|
823 |
+
// found a right-brace, and we're in an object
|
824 |
+
array_pop($stk);
|
825 |
+
//print("Found end of object at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
826 |
+
|
827 |
+
} elseif (($substr_chrs_c_2 == '/*') &&
|
828 |
+
in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
|
829 |
+
// found a comment start, and we are in an array, object, or slice
|
830 |
+
array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
|
831 |
+
$c++;
|
832 |
+
//print("Found start of comment at {$c}\n");
|
833 |
+
|
834 |
+
} elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
|
835 |
+
// found a comment end, and we're in one now
|
836 |
+
array_pop($stk);
|
837 |
+
$c++;
|
838 |
+
|
839 |
+
for ($i = $top['where']; $i <= $c; ++$i)
|
840 |
+
$chrs = substr_replace($chrs, ' ', $i, 1);
|
841 |
+
|
842 |
+
//print("Found end of comment at {$c}: ".$this->substr8($chrs, $top['where'], (1 + $c - $top['where']))."\n");
|
843 |
+
|
844 |
+
}
|
845 |
+
|
846 |
+
}
|
847 |
+
|
848 |
+
if (reset($stk) == SERVICES_JSON_IN_ARR) {
|
849 |
+
return $arr;
|
850 |
+
|
851 |
+
} elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
|
852 |
+
return $obj;
|
853 |
+
|
854 |
+
}
|
855 |
+
|
856 |
+
}
|
857 |
+
}
|
858 |
+
}
|
859 |
+
|
860 |
+
/**
|
861 |
+
* @todo Ultimately, this should just call PEAR::isError()
|
862 |
+
*/
|
863 |
+
function isError($data, $code = null)
|
864 |
+
{
|
865 |
+
if (class_exists('pear')) {
|
866 |
+
return PEAR::isError($data, $code);
|
867 |
+
} elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
|
868 |
+
is_subclass_of($data, 'services_json_error'))) {
|
869 |
+
return true;
|
870 |
+
}
|
871 |
+
|
872 |
+
return false;
|
873 |
+
}
|
874 |
+
|
875 |
+
/**
|
876 |
+
* Calculates length of string in bytes
|
877 |
+
* @param string
|
878 |
+
* @return integer length
|
879 |
+
*/
|
880 |
+
function strlen8( $str )
|
881 |
+
{
|
882 |
+
if ( $this->_mb_strlen ) {
|
883 |
+
return mb_strlen( $str, "8bit" );
|
884 |
+
}
|
885 |
+
return strlen( $str );
|
886 |
+
}
|
887 |
+
|
888 |
+
/**
|
889 |
+
* Returns part of a string, interpreting $start and $length as number of bytes.
|
890 |
+
* @param string
|
891 |
+
* @param integer start
|
892 |
+
* @param integer length
|
893 |
+
* @return integer length
|
894 |
+
*/
|
895 |
+
function substr8( $string, $start, $length=false )
|
896 |
+
{
|
897 |
+
if ( $length === false ) {
|
898 |
+
$length = $this->strlen8( $string ) - $start;
|
899 |
+
}
|
900 |
+
if ( $this->_mb_substr ) {
|
901 |
+
return mb_substr( $string, $start, $length, "8bit" );
|
902 |
+
}
|
903 |
+
return substr( $string, $start, $length );
|
904 |
+
}
|
905 |
+
|
906 |
+
}
|
907 |
+
|
908 |
+
if (class_exists('PEAR_Error')) {
|
909 |
+
|
910 |
+
class Services_JSON_Error extends PEAR_Error
|
911 |
+
{
|
912 |
+
function Services_JSON_Error($message = 'unknown error', $code = null,
|
913 |
+
$mode = null, $options = null, $userinfo = null)
|
914 |
+
{
|
915 |
+
parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
|
916 |
+
}
|
917 |
+
}
|
918 |
+
|
919 |
+
} else {
|
920 |
+
|
921 |
+
/**
|
922 |
+
* @todo Ultimately, this class shall be descended from PEAR_Error
|
923 |
+
*/
|
924 |
+
class Services_JSON_Error
|
925 |
+
{
|
926 |
+
function Services_JSON_Error($message = 'unknown error', $code = null,
|
927 |
+
$mode = null, $options = null, $userinfo = null)
|
928 |
+
{
|
929 |
+
|
930 |
+
}
|
931 |
+
}
|
932 |
+
|
933 |
+
}
|
trunk/models/attachment.php
ADDED
@@ -0,0 +1,64 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Attachment {
|
4 |
+
|
5 |
+
var $id; // Integer
|
6 |
+
var $url; // String
|
7 |
+
var $slug; // String
|
8 |
+
var $title; // String
|
9 |
+
var $description; // String
|
10 |
+
var $caption; // String
|
11 |
+
var $parent; // Integer
|
12 |
+
var $mime_type; // String
|
13 |
+
|
14 |
+
function JSON_API_Attachment($wp_attachment = null) {
|
15 |
+
if ($wp_attachment) {
|
16 |
+
$this->import_wp_object($wp_attachment);
|
17 |
+
if ($this->is_image()) {
|
18 |
+
$this->query_images();
|
19 |
+
}
|
20 |
+
}
|
21 |
+
}
|
22 |
+
|
23 |
+
function import_wp_object($wp_attachment) {
|
24 |
+
$this->id = (int) $wp_attachment->ID;
|
25 |
+
$this->url = $wp_attachment->guid;
|
26 |
+
$this->slug = $wp_attachment->post_name;
|
27 |
+
$this->title = $wp_attachment->post_title;
|
28 |
+
$this->description = $wp_attachment->post_content;
|
29 |
+
$this->caption = $wp_attachment->post_excerpt;
|
30 |
+
$this->parent = (int) $wp_attachment->post_parent;
|
31 |
+
$this->mime_type = $wp_attachment->post_mime_type;
|
32 |
+
}
|
33 |
+
|
34 |
+
function is_image() {
|
35 |
+
return (substr($this->mime_type, 0, 5) == 'image');
|
36 |
+
}
|
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 |
+
$home = get_bloginfo('url');
|
45 |
+
foreach ($sizes as $size) {
|
46 |
+
list($url, $width, $height) = wp_get_attachment_image_src($this->id, $size);
|
47 |
+
$filename = ABSPATH . substr($url, strlen($home) + 1);
|
48 |
+
if (file_exists($filename)) {
|
49 |
+
list($measured_width, $measured_height) = getimagesize($filename);
|
50 |
+
if ($measured_width == $width &&
|
51 |
+
$measured_height == $height) {
|
52 |
+
$this->images[$size] = (object) array(
|
53 |
+
'url' => $url,
|
54 |
+
'width' => $width,
|
55 |
+
'height' => $height
|
56 |
+
);
|
57 |
+
}
|
58 |
+
}
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
}
|
63 |
+
|
64 |
+
?>
|
trunk/models/author.php
ADDED
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Author {
|
4 |
+
|
5 |
+
var $id; // Integer
|
6 |
+
var $slug; // String
|
7 |
+
var $name; // String
|
8 |
+
var $first_name; // String
|
9 |
+
var $last_name; // String
|
10 |
+
var $nickname; // String
|
11 |
+
var $url; // String
|
12 |
+
var $description; // String
|
13 |
+
|
14 |
+
// Note:
|
15 |
+
// JSON_API_Author objects can include additional values by using the
|
16 |
+
// author_meta query var.
|
17 |
+
|
18 |
+
function JSON_API_Author($id = null) {
|
19 |
+
if ($id) {
|
20 |
+
$this->id = (int) $id;
|
21 |
+
} else {
|
22 |
+
$this->id = (int) get_the_author_meta('ID');
|
23 |
+
}
|
24 |
+
$this->set_value('slug', 'user_nicename');
|
25 |
+
$this->set_value('name', 'display_name');
|
26 |
+
$this->set_value('first_name', 'first_name');
|
27 |
+
$this->set_value('last_name', 'last_name');
|
28 |
+
$this->set_value('nickname', 'nickname');
|
29 |
+
$this->set_value('url', 'user_url');
|
30 |
+
$this->set_value('description', 'description');
|
31 |
+
$this->set_author_meta();
|
32 |
+
//$this->raw = get_userdata($this->id);
|
33 |
+
}
|
34 |
+
|
35 |
+
function set_value($key, $wp_key = false) {
|
36 |
+
if (!$wp_key) {
|
37 |
+
$wp_key = $key;
|
38 |
+
}
|
39 |
+
$this->$key = get_the_author_meta($wp_key, $this->id);
|
40 |
+
}
|
41 |
+
|
42 |
+
function set_author_meta() {
|
43 |
+
global $json_api;
|
44 |
+
if (!$json_api->query->author_meta) {
|
45 |
+
return;
|
46 |
+
}
|
47 |
+
$protected_vars = array(
|
48 |
+
'user_login',
|
49 |
+
'user_pass',
|
50 |
+
'user_email',
|
51 |
+
'user_activation_key'
|
52 |
+
);
|
53 |
+
$vars = explode(',', $json_api->query->author_meta);
|
54 |
+
$vars = array_diff($vars, $protected_vars);
|
55 |
+
foreach ($vars as $var) {
|
56 |
+
$this->set_value($var);
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
}
|
61 |
+
|
62 |
+
?>
|
trunk/models/category.php
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Category {
|
4 |
+
|
5 |
+
var $id; // Integer
|
6 |
+
var $slug; // String
|
7 |
+
var $title; // String
|
8 |
+
var $description; // String
|
9 |
+
var $parent; // Integer
|
10 |
+
var $post_count; // Integer
|
11 |
+
|
12 |
+
function JSON_API_Category($wp_category = null) {
|
13 |
+
if ($wp_category) {
|
14 |
+
$this->import_wp_object($wp_category);
|
15 |
+
}
|
16 |
+
}
|
17 |
+
|
18 |
+
function import_wp_object($wp_category) {
|
19 |
+
$this->id = (int) $wp_category->term_id;
|
20 |
+
$this->slug = $wp_category->slug;
|
21 |
+
$this->title = $wp_category->name;
|
22 |
+
$this->description = $wp_category->description;
|
23 |
+
$this->parent = (int) $wp_category->parent;
|
24 |
+
$this->post_count = (int) $wp_category->count;
|
25 |
+
}
|
26 |
+
|
27 |
+
}
|
28 |
+
|
29 |
+
?>
|
trunk/models/comment.php
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Comment {
|
4 |
+
|
5 |
+
var $id; // Integer
|
6 |
+
var $name; // String
|
7 |
+
var $url; // String
|
8 |
+
var $date; // String
|
9 |
+
var $content; // String
|
10 |
+
var $parent; // Integer
|
11 |
+
var $author; // Object (only if the user was registered & logged in)
|
12 |
+
|
13 |
+
function JSON_API_Comment($wp_comment = null) {
|
14 |
+
if ($wp_comment) {
|
15 |
+
$this->import_wp_object($wp_comment);
|
16 |
+
}
|
17 |
+
}
|
18 |
+
|
19 |
+
function import_wp_object($wp_comment) {
|
20 |
+
global $json_api;
|
21 |
+
|
22 |
+
$date_format = $json_api->query->date_format;
|
23 |
+
$content = apply_filters('comment_text', $wp_comment->comment_content);
|
24 |
+
|
25 |
+
$this->id = (int) $wp_comment->comment_ID;
|
26 |
+
$this->name = $wp_comment->comment_author;
|
27 |
+
$this->url = $wp_comment->comment_author_url;
|
28 |
+
$this->date = date($date_format, strtotime($wp_comment->comment_date));
|
29 |
+
$this->content = $content;
|
30 |
+
$this->parent = (int) $wp_comment->comment_parent;
|
31 |
+
//$this->raw = $wp_comment;
|
32 |
+
|
33 |
+
if (!empty($wp_comment->user_id)) {
|
34 |
+
$this->author = new JSON_API_Author($wp_comment->user_id);
|
35 |
+
} else {
|
36 |
+
unset($this->author);
|
37 |
+
}
|
38 |
+
}
|
39 |
+
|
40 |
+
function handle_submission() {
|
41 |
+
global $comment, $wpdb;
|
42 |
+
add_action('comment_id_not_found', array(&$this, 'comment_id_not_found'));
|
43 |
+
add_action('comment_closed', array(&$this, 'comment_closed'));
|
44 |
+
add_action('comment_on_draft', array(&$this, 'comment_on_draft'));
|
45 |
+
add_filter('comment_post_redirect', array(&$this, 'comment_post_redirect'));
|
46 |
+
$_SERVER['REQUEST_METHOD'] = 'POST';
|
47 |
+
$_POST['comment_post_ID'] = $_REQUEST['post_id'];
|
48 |
+
$_POST['author'] = $_REQUEST['name'];
|
49 |
+
$_POST['email'] = $_REQUEST['email'];
|
50 |
+
$_POST['url'] = empty($_REQUEST['url']) ? '' : $_REQUEST['url'];
|
51 |
+
$_POST['comment'] = $_REQUEST['content'];
|
52 |
+
$_POST['parent'] = $_REQUEST['parent'];
|
53 |
+
include ABSPATH . 'wp-comments-post.php';
|
54 |
+
}
|
55 |
+
|
56 |
+
function comment_id_not_found() {
|
57 |
+
global $json_api;
|
58 |
+
$json_api->error("Post ID '{$_REQUEST['post_id']}' not found.");
|
59 |
+
}
|
60 |
+
|
61 |
+
function comment_closed() {
|
62 |
+
global $json_api;
|
63 |
+
$json_api->error("Post is closed for comments.", 403);
|
64 |
+
}
|
65 |
+
|
66 |
+
function comment_on_draft() {
|
67 |
+
global $json_api;
|
68 |
+
$json_api->error("You cannot comment on unpublished posts.", 403);
|
69 |
+
}
|
70 |
+
|
71 |
+
function comment_post_redirect() {
|
72 |
+
global $comment, $json_api;
|
73 |
+
$status = ($comment->comment_approved) ? 'ok' : 'pending';
|
74 |
+
$new_comment = new JSON_API_Comment($comment);
|
75 |
+
$json_api->response->respond($new_comment, $status);
|
76 |
+
}
|
77 |
+
|
78 |
+
}
|
79 |
+
|
80 |
+
?>
|
trunk/models/post.php
ADDED
@@ -0,0 +1,319 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Post {
|
4 |
+
|
5 |
+
// Note:
|
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")
|
13 |
+
var $title; // String
|
14 |
+
var $title_plain; // String
|
15 |
+
var $content; // String (modified by read_more query var)
|
16 |
+
var $excerpt; // String
|
17 |
+
var $date; // String (modified by date_format query var)
|
18 |
+
var $modified; // String (modified by date_format query var)
|
19 |
+
var $categories; // Array of objects
|
20 |
+
var $tags; // Array of objects
|
21 |
+
var $author; // Object
|
22 |
+
var $comments; // Array of objects
|
23 |
+
var $attachments; // Array of objects
|
24 |
+
var $comment_count; // Integer
|
25 |
+
var $comment_status; // String ("open" or "closed")
|
26 |
+
var $thumbnail; // String
|
27 |
+
var $custom_fields; // Object (included by using custom_fields query var)
|
28 |
+
|
29 |
+
function JSON_API_Post($wp_post = null) {
|
30 |
+
if (!empty($wp_post)) {
|
31 |
+
$this->import_wp_object($wp_post);
|
32 |
+
}
|
33 |
+
do_action("json_api_{$this->type}_constructor", $this);
|
34 |
+
}
|
35 |
+
|
36 |
+
function create($values = null) {
|
37 |
+
unset($values['id']);
|
38 |
+
if (empty($values) || empty($values['title'])) {
|
39 |
+
$values = array(
|
40 |
+
'title' => 'Untitled',
|
41 |
+
'content' => ''
|
42 |
+
);
|
43 |
+
}
|
44 |
+
return $this->save($values);
|
45 |
+
}
|
46 |
+
|
47 |
+
function update($values) {
|
48 |
+
$values['id'] = $this->id;
|
49 |
+
return $this->save($values);
|
50 |
+
}
|
51 |
+
|
52 |
+
function save($values = null) {
|
53 |
+
global $json_api, $user_ID;
|
54 |
+
|
55 |
+
$wp_values = array();
|
56 |
+
|
57 |
+
if (!empty($values['id'])) {
|
58 |
+
$wp_values['ID'] = $values['id'];
|
59 |
+
}
|
60 |
+
|
61 |
+
if (!empty($values['type'])) {
|
62 |
+
$wp_values['post_type'] = $values['type'];
|
63 |
+
}
|
64 |
+
|
65 |
+
if (!empty($values['status'])) {
|
66 |
+
$wp_values['post_status'] = $values['status'];
|
67 |
+
}
|
68 |
+
|
69 |
+
if (!empty($values['title'])) {
|
70 |
+
$wp_values['post_title'] = $values['title'];
|
71 |
+
}
|
72 |
+
|
73 |
+
if (!empty($values['content'])) {
|
74 |
+
$wp_values['post_content'] = $values['content'];
|
75 |
+
}
|
76 |
+
|
77 |
+
if (!empty($values['author'])) {
|
78 |
+
$author = $json_api->introspector->get_author_by_login($values['author']);
|
79 |
+
$wp_values['post_author'] = $author->id;
|
80 |
+
}
|
81 |
+
|
82 |
+
if (isset($values['categories'])) {
|
83 |
+
$categories = explode(',', $values['categories']);
|
84 |
+
foreach ($categories as $category_slug) {
|
85 |
+
$category_slug = trim($category_slug);
|
86 |
+
$category = $json_api->introspector->get_category_by_slug($category_slug);
|
87 |
+
if (empty($wp_values['post_category'])) {
|
88 |
+
$wp_values['post_category'] = array($category->id);
|
89 |
+
} else {
|
90 |
+
array_push($wp_values['post_category'], $category->id);
|
91 |
+
}
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
if (isset($values['tags'])) {
|
96 |
+
$tags = explode(',', $values['tags']);
|
97 |
+
foreach ($tags as $tag_slug) {
|
98 |
+
$tag_slug = trim($tag_slug);
|
99 |
+
if (empty($wp_values['tags_input'])) {
|
100 |
+
$wp_values['tags_input'] = array($tag_slug);
|
101 |
+
} else {
|
102 |
+
array_push($wp_values['tags_input'], $tag_slug);
|
103 |
+
}
|
104 |
+
}
|
105 |
+
}
|
106 |
+
|
107 |
+
if (isset($wp_values['ID'])) {
|
108 |
+
$this->id = wp_update_post($wp_values);
|
109 |
+
} else {
|
110 |
+
$this->id = wp_insert_post($wp_values);
|
111 |
+
}
|
112 |
+
|
113 |
+
if (!empty($_FILES['attachment'])) {
|
114 |
+
include_once ABSPATH . '/wp-admin/includes/file.php';
|
115 |
+
include_once ABSPATH . '/wp-admin/includes/media.php';
|
116 |
+
include_once ABSPATH . '/wp-admin/includes/image.php';
|
117 |
+
$attachment_id = media_handle_upload('attachment', $this->id);
|
118 |
+
$this->attachments[] = new JSON_API_Attachment($attachment_id);
|
119 |
+
unset($_FILES['attachment']);
|
120 |
+
}
|
121 |
+
|
122 |
+
$wp_post = get_post($this->id);
|
123 |
+
$this->import_wp_object($wp_post);
|
124 |
+
|
125 |
+
return $this->id;
|
126 |
+
}
|
127 |
+
|
128 |
+
function import_wp_object($wp_post) {
|
129 |
+
global $json_api, $post;
|
130 |
+
$date_format = $json_api->query->date_format;
|
131 |
+
$this->id = (int) $wp_post->ID;
|
132 |
+
setup_postdata($wp_post);
|
133 |
+
$this->set_value('type', $wp_post->post_type);
|
134 |
+
$this->set_value('slug', $wp_post->post_name);
|
135 |
+
$this->set_value('url', get_permalink($this->id));
|
136 |
+
$this->set_value('status', $wp_post->post_status);
|
137 |
+
$this->set_value('title', get_the_title($this->id));
|
138 |
+
$this->set_value('title_plain', strip_tags(@$this->title));
|
139 |
+
$this->set_content_value();
|
140 |
+
$this->set_value('excerpt', apply_filters('the_excerpt', get_the_excerpt()));
|
141 |
+
$this->set_value('date', get_the_time($date_format));
|
142 |
+
$this->set_value('modified', date($date_format, strtotime($wp_post->post_modified)));
|
143 |
+
$this->set_categories_value();
|
144 |
+
$this->set_tags_value();
|
145 |
+
$this->set_author_value($wp_post->post_author);
|
146 |
+
$this->set_comments_value();
|
147 |
+
$this->set_attachments_value();
|
148 |
+
$this->set_value('comment_count', (int) $wp_post->comment_count);
|
149 |
+
$this->set_value('comment_status', $wp_post->comment_status);
|
150 |
+
$this->set_thumbnail_value();
|
151 |
+
$this->set_custom_fields_value();
|
152 |
+
$this->set_custom_taxonomies($wp_post->post_type);
|
153 |
+
do_action("json_api_import_wp_post", $this, $wp_post);
|
154 |
+
}
|
155 |
+
|
156 |
+
function set_value($key, $value) {
|
157 |
+
global $json_api;
|
158 |
+
if ($json_api->include_value($key)) {
|
159 |
+
$this->$key = $value;
|
160 |
+
} else {
|
161 |
+
unset($this->$key);
|
162 |
+
}
|
163 |
+
}
|
164 |
+
|
165 |
+
function set_content_value() {
|
166 |
+
global $json_api;
|
167 |
+
if ($json_api->include_value('content')) {
|
168 |
+
$content = get_the_content($json_api->query->read_more);
|
169 |
+
$content = apply_filters('the_content', $content);
|
170 |
+
$content = str_replace(']]>', ']]>', $content);
|
171 |
+
$this->content = $content;
|
172 |
+
} else {
|
173 |
+
unset($this->content);
|
174 |
+
}
|
175 |
+
}
|
176 |
+
|
177 |
+
function set_categories_value() {
|
178 |
+
global $json_api;
|
179 |
+
if ($json_api->include_value('categories')) {
|
180 |
+
$this->categories = array();
|
181 |
+
if ($wp_categories = get_the_category($this->id)) {
|
182 |
+
foreach ($wp_categories as $wp_category) {
|
183 |
+
$category = new JSON_API_Category($wp_category);
|
184 |
+
if ($category->id == 1 && $category->slug == 'uncategorized') {
|
185 |
+
// Skip the 'uncategorized' category
|
186 |
+
continue;
|
187 |
+
}
|
188 |
+
$this->categories[] = $category;
|
189 |
+
}
|
190 |
+
}
|
191 |
+
} else {
|
192 |
+
unset($this->categories);
|
193 |
+
}
|
194 |
+
}
|
195 |
+
|
196 |
+
function set_tags_value() {
|
197 |
+
global $json_api;
|
198 |
+
if ($json_api->include_value('tags')) {
|
199 |
+
$this->tags = array();
|
200 |
+
if ($wp_tags = get_the_tags($this->id)) {
|
201 |
+
foreach ($wp_tags as $wp_tag) {
|
202 |
+
$this->tags[] = new JSON_API_Tag($wp_tag);
|
203 |
+
}
|
204 |
+
}
|
205 |
+
} else {
|
206 |
+
unset($this->tags);
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
function set_author_value($author_id) {
|
211 |
+
global $json_api;
|
212 |
+
if ($json_api->include_value('author')) {
|
213 |
+
$this->author = new JSON_API_Author($author_id);
|
214 |
+
} else {
|
215 |
+
unset($this->author);
|
216 |
+
}
|
217 |
+
}
|
218 |
+
|
219 |
+
function set_comments_value() {
|
220 |
+
global $json_api;
|
221 |
+
if ($json_api->include_value('comments')) {
|
222 |
+
$this->comments = $json_api->introspector->get_comments($this->id);
|
223 |
+
} else {
|
224 |
+
unset($this->comments);
|
225 |
+
}
|
226 |
+
}
|
227 |
+
|
228 |
+
function set_attachments_value() {
|
229 |
+
global $json_api;
|
230 |
+
if ($json_api->include_value('attachments')) {
|
231 |
+
$this->attachments = $json_api->introspector->get_attachments($this->id);
|
232 |
+
} else {
|
233 |
+
unset($this->attachments);
|
234 |
+
}
|
235 |
+
}
|
236 |
+
|
237 |
+
function set_thumbnail_value() {
|
238 |
+
global $json_api;
|
239 |
+
if (!$json_api->include_value('thumbnail') ||
|
240 |
+
!function_exists('get_post_thumbnail_id')) {
|
241 |
+
unset($this->thumbnail);
|
242 |
+
return;
|
243 |
+
}
|
244 |
+
$attachment_id = get_post_thumbnail_id($this->id);
|
245 |
+
if (!$attachment_id) {
|
246 |
+
unset($this->thumbnail);
|
247 |
+
return;
|
248 |
+
}
|
249 |
+
$thumbnail_size = $this->get_thumbnail_size();
|
250 |
+
$this->thumbnail_size = $thumbnail_size;
|
251 |
+
$attachment = $json_api->introspector->get_attachment($attachment_id);
|
252 |
+
$image = $attachment->images[$thumbnail_size];
|
253 |
+
$this->thumbnail = $image->url;
|
254 |
+
$this->thumbnail_images = $attachment->images;
|
255 |
+
}
|
256 |
+
|
257 |
+
function set_custom_fields_value() {
|
258 |
+
global $json_api;
|
259 |
+
if ($json_api->include_value('custom_fields')) {
|
260 |
+
$wp_custom_fields = get_post_custom($this->id);
|
261 |
+
$this->custom_fields = new stdClass();
|
262 |
+
if ($json_api->query->custom_fields) {
|
263 |
+
$keys = explode(',', $json_api->query->custom_fields);
|
264 |
+
}
|
265 |
+
foreach ($wp_custom_fields as $key => $value) {
|
266 |
+
if ($json_api->query->custom_fields) {
|
267 |
+
if (in_array($key, $keys)) {
|
268 |
+
$this->custom_fields->$key = $wp_custom_fields[$key];
|
269 |
+
}
|
270 |
+
} else if (substr($key, 0, 1) != '_') {
|
271 |
+
$this->custom_fields->$key = $wp_custom_fields[$key];
|
272 |
+
}
|
273 |
+
}
|
274 |
+
} else {
|
275 |
+
unset($this->custom_fields);
|
276 |
+
}
|
277 |
+
}
|
278 |
+
|
279 |
+
function set_custom_taxonomies($type) {
|
280 |
+
global $json_api;
|
281 |
+
$taxonomies = get_taxonomies(array(
|
282 |
+
'object_type' => array($type),
|
283 |
+
'public' => true,
|
284 |
+
'_builtin' => false
|
285 |
+
), 'objects');
|
286 |
+
foreach ($taxonomies as $taxonomy_id => $taxonomy) {
|
287 |
+
$taxonomy_key = "taxonomy_$taxonomy_id";
|
288 |
+
if (!$json_api->include_value($taxonomy_key)) {
|
289 |
+
continue;
|
290 |
+
}
|
291 |
+
$taxonomy_class = $taxonomy->hierarchical ? 'JSON_API_Category' : 'JSON_API_Tag';
|
292 |
+
$terms = get_the_terms($this->id, $taxonomy_id);
|
293 |
+
$this->$taxonomy_key = array();
|
294 |
+
if (!empty($terms)) {
|
295 |
+
$taxonomy_terms = array();
|
296 |
+
foreach ($terms as $term) {
|
297 |
+
$taxonomy_terms[] = new $taxonomy_class($term);
|
298 |
+
}
|
299 |
+
$this->$taxonomy_key = $taxonomy_terms;
|
300 |
+
}
|
301 |
+
}
|
302 |
+
}
|
303 |
+
|
304 |
+
function get_thumbnail_size() {
|
305 |
+
global $json_api;
|
306 |
+
if ($json_api->query->thumbnail_size) {
|
307 |
+
return $json_api->query->thumbnail_size;
|
308 |
+
} else if (function_exists('get_intermediate_image_sizes')) {
|
309 |
+
$sizes = get_intermediate_image_sizes();
|
310 |
+
if (in_array('post-thumbnail', $sizes)) {
|
311 |
+
return 'post-thumbnail';
|
312 |
+
}
|
313 |
+
}
|
314 |
+
return 'thumbnail';
|
315 |
+
}
|
316 |
+
|
317 |
+
}
|
318 |
+
|
319 |
+
?>
|
trunk/models/tag.php
ADDED
@@ -0,0 +1,26 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Tag {
|
4 |
+
|
5 |
+
var $id; // Integer
|
6 |
+
var $slug; // String
|
7 |
+
var $title; // String
|
8 |
+
var $description; // String
|
9 |
+
|
10 |
+
function JSON_API_Tag($wp_tag = null) {
|
11 |
+
if ($wp_tag) {
|
12 |
+
$this->import_wp_object($wp_tag);
|
13 |
+
}
|
14 |
+
}
|
15 |
+
|
16 |
+
function import_wp_object($wp_tag) {
|
17 |
+
$this->id = (int) $wp_tag->term_id;
|
18 |
+
$this->slug = $wp_tag->slug;
|
19 |
+
$this->title = $wp_tag->name;
|
20 |
+
$this->description = $wp_tag->description;
|
21 |
+
$this->post_count = (int) $wp_tag->count;
|
22 |
+
}
|
23 |
+
|
24 |
+
}
|
25 |
+
|
26 |
+
?>
|
trunk/readme.txt
ADDED
@@ -0,0 +1,1241 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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: 4.3
|
7 |
+
Stable tag: 1.1.2
|
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](#1.-General-Concepts)
|
35 |
+
1.1. [Requests](#1.1.-Requests)
|
36 |
+
1.2. [Controllers](#1.2.-Controllers)
|
37 |
+
1.3. [Responses](#1.3.-Responses)
|
38 |
+
2. [Request methods](#2.-Request-methods)
|
39 |
+
2.1. [Core controller methods](#2.1.-Core-controller-methods)
|
40 |
+
2.2. [Posts controller methods](#2.2.-Pages-controller-methods)
|
41 |
+
2.3. [Respond controller methods](#2.3.-Respond-controller-methods)
|
42 |
+
2.4. [Widgets controller methods](#2.4.-Widgets-controller-methods)
|
43 |
+
3. [Request arguments](#3.-Request-arguments)
|
44 |
+
3.1. [Output-modifying arguments](#3.1.-Output-modifying-arguments)
|
45 |
+
3.2. [Content-modifying arguments](#3.2.-Content-modifying-arguments)
|
46 |
+
3.3. [Using include/exclude and redirects](#3.3.-Using-include/exclude-and-redirects)
|
47 |
+
4. [Response objects](#4.-Response-objects)
|
48 |
+
4.1. [Post response object](#4.1.-Post-response-object)
|
49 |
+
4.2. [Category response object](#4.2.-Category-response-object)
|
50 |
+
4.3. [Tag response object](#4.3.-Tag-response-object)
|
51 |
+
4.4. [Author response object](#4.4.-Author-response-object)
|
52 |
+
4.5. [Comment response object](#4.5.-Comment-response-object)
|
53 |
+
4.6. [Attachment response object](#4.6.-Attachment-response-object)
|
54 |
+
5. [Extending JSON API](#5.-Extending-JSON-API)
|
55 |
+
5.1. [Plugin hooks](#5.1.-Plugin-hooks)
|
56 |
+
5.2. [Developing JSON API controllers](#5.2.-Developing-JSON-API-controllers)
|
57 |
+
5.3. [Configuration options](#5.3.-Configuration-options)
|
58 |
+
6. [Unit tests](#6.-Unit-tests)
|
59 |
+
6.1. [Preparing a WordPress test site](#6.1.-Preparing-a-WordPress-test-site)
|
60 |
+
6.2. [Running the tests](#6.2.-Running-the-tests)
|
61 |
+
|
62 |
+
== 1. General Concepts ==
|
63 |
+
|
64 |
+
== 1.1. Requests ==
|
65 |
+
|
66 |
+
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.
|
67 |
+
|
68 |
+
JSON API operates in two modes:
|
69 |
+
|
70 |
+
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.
|
71 |
+
2. *Explicit mode* is triggered by setting `json` to a known method string. See *Section 2: Request methods* for a complete method listing.
|
72 |
+
|
73 |
+
= Implicit mode examples: =
|
74 |
+
|
75 |
+
* `http://www.example.org/?json=1`
|
76 |
+
* `http://www.example.org/?p=47&json=1`
|
77 |
+
* `http://www.example.org/tag/banana/?json=1`
|
78 |
+
|
79 |
+
= Explicit mode examples: =
|
80 |
+
|
81 |
+
* `http://www.example.org/?json=get_recent_posts`
|
82 |
+
* `http://www.example.org/?json=get_post&post_id=47`
|
83 |
+
* `http://www.example.org/?json=get_tag_posts&tag_slug=banana`
|
84 |
+
|
85 |
+
= With user-friendly permalinks configured: =
|
86 |
+
|
87 |
+
* `http://www.example.org/api/get_recent_posts/`
|
88 |
+
* `http://www.example.org/api/get_post/?post_id=47`
|
89 |
+
* `http://www.example.org/api/get_tag_posts/?tag_slug=banana`
|
90 |
+
|
91 |
+
__Further reading__
|
92 |
+
See *Section 3: Request arguments* for more information about request arguments to modify the response.
|
93 |
+
|
94 |
+
== 1.2. Controllers ==
|
95 |
+
|
96 |
+
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.
|
97 |
+
|
98 |
+
= The Core controller =
|
99 |
+
|
100 |
+
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).
|
101 |
+
|
102 |
+
= Specifying a controller =
|
103 |
+
|
104 |
+
There are a few ways of specifying a controller, depending on how you are calling the API:
|
105 |
+
|
106 |
+
* `http://www.example.org/?json=get_recent_posts` (`core` controller is implied, method is `get_recent_posts`)
|
107 |
+
* `http://www.example.org/api/info/` (`core` controller is implied)
|
108 |
+
* `http://www.example.org/api/core/get_category_posts/` (`core` controller can also be explicitly specified)
|
109 |
+
* `http://www.example.org/?json=respond.submit_comment` (`respond` controller, `submit_comment` method)
|
110 |
+
|
111 |
+
__Legacy compatibility__
|
112 |
+
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.
|
113 |
+
|
114 |
+
= Available controllers =
|
115 |
+
|
116 |
+
The current release includes three controllers: Core, Posts, and Respond. Developers are encouraged to suggest or submit additional controllers.
|
117 |
+
|
118 |
+
__Further reading__
|
119 |
+
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*.
|
120 |
+
|
121 |
+
== 1.3. Responses ==
|
122 |
+
|
123 |
+
The standard response format for JSON API is (as you may have guessed) [JSON](http://json.org/).
|
124 |
+
|
125 |
+
Here is an example response from `http://localhost/wordpress/?json=1` called on a default WordPress installation (formatted for readability):
|
126 |
+
|
127 |
+
{
|
128 |
+
"status": "ok",
|
129 |
+
"count": 1,
|
130 |
+
"count_total": 1,
|
131 |
+
"pages": 1,
|
132 |
+
"posts": [
|
133 |
+
{
|
134 |
+
"id": 1,
|
135 |
+
"type": "post",
|
136 |
+
"slug": "hello-world",
|
137 |
+
"url": "http:\/\/localhost\/wordpress\/?p=1",
|
138 |
+
"title": "Hello world!",
|
139 |
+
"title_plain": "Hello world!",
|
140 |
+
"content": "<p>Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!<\/p>\n",
|
141 |
+
"excerpt": "Welcome to WordPress. This is your first post. Edit or delete it, then start blogging!\n",
|
142 |
+
"date": "2009-11-11 12:50:19",
|
143 |
+
"modified": "2009-11-11 12:50:19",
|
144 |
+
"categories": [],
|
145 |
+
"tags": [],
|
146 |
+
"author": {
|
147 |
+
"id": 1,
|
148 |
+
"slug": "admin",
|
149 |
+
"name": "admin",
|
150 |
+
"first_name": "",
|
151 |
+
"last_name": "",
|
152 |
+
"nickname": "",
|
153 |
+
"url": "",
|
154 |
+
"description": ""
|
155 |
+
},
|
156 |
+
"comments": [
|
157 |
+
{
|
158 |
+
"id": 1,
|
159 |
+
"name": "Mr WordPress",
|
160 |
+
"url": "http:\/\/wordpress.org\/",
|
161 |
+
"date": "2009-11-11 12:50:19",
|
162 |
+
"content": "<p>Hi, this is a comment.<br \/>To delete a comment, just log in and view the post's comments. There you will have the option to edit or delete them.<\/p>\n",
|
163 |
+
"parent": 0
|
164 |
+
}
|
165 |
+
],
|
166 |
+
"comment_count": 1,
|
167 |
+
"comment_status": "open"
|
168 |
+
}
|
169 |
+
]
|
170 |
+
}
|
171 |
+
|
172 |
+
== 2. Request methods ==
|
173 |
+
|
174 |
+
Request methods are available from the following controllers:
|
175 |
+
|
176 |
+
* Core controller - basic introspection methods
|
177 |
+
* Posts controller - data manipulation methods for posts
|
178 |
+
* Respond controller - comment/trackback submission methods
|
179 |
+
* Widgets controller - retrieve sidebar widgets
|
180 |
+
|
181 |
+
== 2.1. Core controller methods ==
|
182 |
+
|
183 |
+
The Core controller offers a mostly-complete set of introspection methods for retrieving content from WordPress.
|
184 |
+
|
185 |
+
|
186 |
+
== Method: info ==
|
187 |
+
|
188 |
+
Returns information about JSON API.
|
189 |
+
|
190 |
+
= Optional arguments =
|
191 |
+
|
192 |
+
* `controller` - returns detailed information about a specific controller
|
193 |
+
|
194 |
+
= Response =
|
195 |
+
|
196 |
+
{
|
197 |
+
"status": "ok",
|
198 |
+
"json_api_version": "1.0",
|
199 |
+
"controllers": [
|
200 |
+
"core"
|
201 |
+
]
|
202 |
+
}
|
203 |
+
|
204 |
+
|
205 |
+
= Response with “controller=core” =
|
206 |
+
|
207 |
+
{
|
208 |
+
"status": "ok",
|
209 |
+
"name": "Core",
|
210 |
+
"description": "Basic introspection methods",
|
211 |
+
"methods": [
|
212 |
+
...
|
213 |
+
]
|
214 |
+
}
|
215 |
+
|
216 |
+
|
217 |
+
== Method: get_recent_posts ==
|
218 |
+
|
219 |
+
Returns an array of recent posts. You can invoke this from the WordPress home page either by setting `json` to a non-empty value (i.e., `json=1`) or from any page by setting `json=get_recent_posts`.
|
220 |
+
|
221 |
+
= Optional arguments =
|
222 |
+
|
223 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
224 |
+
* `page` - return a specific page number from the results
|
225 |
+
* `post_type` - used to retrieve custom post types
|
226 |
+
|
227 |
+
= Response =
|
228 |
+
|
229 |
+
{
|
230 |
+
"status": "ok",
|
231 |
+
"count": 10,
|
232 |
+
"count_total": 79,
|
233 |
+
"pages": 7,
|
234 |
+
"posts": [
|
235 |
+
{ ... },
|
236 |
+
{ ... },
|
237 |
+
...
|
238 |
+
]
|
239 |
+
}
|
240 |
+
|
241 |
+
|
242 |
+
== Method: get_posts ==
|
243 |
+
|
244 |
+
Returns posts according to WordPress's [`WP_Query` parameters](http://codex.wordpress.org/Class_Reference/WP_Query#Parameters). The one default parameter is `ignore_sticky_posts=1` (this can be overridden).
|
245 |
+
|
246 |
+
= Optional arguments =
|
247 |
+
|
248 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
249 |
+
* `page` - return a specific page number from the results
|
250 |
+
* `post_type` - used to retrieve custom post types
|
251 |
+
|
252 |
+
__Further reading__
|
253 |
+
See the [`WP_Query` documentation](http://codex.wordpress.org/Class_Reference/WP_Query#Parameters) for a full list of supported parameters. The `post_status` parameter is currently ignored.
|
254 |
+
|
255 |
+
= Response =
|
256 |
+
|
257 |
+
{
|
258 |
+
"status": "ok",
|
259 |
+
"count": 1,
|
260 |
+
"posts": [
|
261 |
+
{ ... }
|
262 |
+
]
|
263 |
+
}
|
264 |
+
|
265 |
+
|
266 |
+
== Method: get_post ==
|
267 |
+
|
268 |
+
Returns a single post object.
|
269 |
+
|
270 |
+
= One of the following is required =
|
271 |
+
|
272 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on a post URL
|
273 |
+
* `id` or `post_id` - set to the post's ID
|
274 |
+
* `slug` or `post_slug` - set to the post's URL slug
|
275 |
+
|
276 |
+
= Optional arguments =
|
277 |
+
|
278 |
+
* `post_type` - used to retrieve custom post types
|
279 |
+
|
280 |
+
= Response =
|
281 |
+
|
282 |
+
{
|
283 |
+
"status": "ok",
|
284 |
+
"post": { ... }
|
285 |
+
}
|
286 |
+
|
287 |
+
|
288 |
+
== Method: get_page ==
|
289 |
+
|
290 |
+
Returns a single page object.
|
291 |
+
|
292 |
+
= One of the following is required =
|
293 |
+
|
294 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on a page URL
|
295 |
+
* `id` or `page_id` - set to the page's ID
|
296 |
+
* `slug` or `page_slug` - set to the page's URL slug
|
297 |
+
|
298 |
+
= Optional arguments =
|
299 |
+
|
300 |
+
* `children` - set to a non-empty value to include a recursive hierarchy of child pages
|
301 |
+
* `post_type` - used to retrieve custom post types
|
302 |
+
|
303 |
+
= Response =
|
304 |
+
|
305 |
+
{
|
306 |
+
"status": "ok",
|
307 |
+
"page": { ... }
|
308 |
+
}
|
309 |
+
|
310 |
+
== Method: get_date_posts ==
|
311 |
+
|
312 |
+
Returns an array of posts/pages in a specific date archive (by day, month, or year).
|
313 |
+
|
314 |
+
= One of the following is required =
|
315 |
+
|
316 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on a date archive page
|
317 |
+
* `date` - set to a date in the format `YYYY` or `YYYY-MM` or `YYYY-MM-DD` (non-numeric characters are stripped from the var, so `YYYYMMDD` or `YYYY/MM/DD` are also valid)
|
318 |
+
|
319 |
+
= Optional arguments =
|
320 |
+
|
321 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
322 |
+
* `page` - return a specific page number from the results
|
323 |
+
* `post_type` - used to retrieve custom post types
|
324 |
+
|
325 |
+
= Response =
|
326 |
+
|
327 |
+
{
|
328 |
+
"status": "ok",
|
329 |
+
"count": 10,
|
330 |
+
"count_total": 79,
|
331 |
+
"pages": 7,
|
332 |
+
"posts": [
|
333 |
+
{ ... },
|
334 |
+
{ ... },
|
335 |
+
...
|
336 |
+
]
|
337 |
+
}
|
338 |
+
|
339 |
+
== Method: get_category_posts ==
|
340 |
+
|
341 |
+
Returns an array of posts/pages in a specific category.
|
342 |
+
|
343 |
+
= One of the following is required =
|
344 |
+
|
345 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on a category archive page
|
346 |
+
* `id` or `category_id` - set to the category's ID
|
347 |
+
* `slug` or `category_slug` - set to the category's URL slug
|
348 |
+
|
349 |
+
= Optional arguments =
|
350 |
+
|
351 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
352 |
+
* `page` - return a specific page number from the results
|
353 |
+
* `post_type` - used to retrieve custom post types
|
354 |
+
|
355 |
+
= Response =
|
356 |
+
|
357 |
+
{
|
358 |
+
"status": "ok",
|
359 |
+
"count": 10,
|
360 |
+
"count_total": 79,
|
361 |
+
"pages": 7,
|
362 |
+
"category": { ... }
|
363 |
+
"posts": [
|
364 |
+
{ ... },
|
365 |
+
{ ... },
|
366 |
+
...
|
367 |
+
]
|
368 |
+
}
|
369 |
+
|
370 |
+
|
371 |
+
== Method: get_tag_posts ==
|
372 |
+
|
373 |
+
Returns an array of posts/pages with a specific tag.
|
374 |
+
|
375 |
+
= One of the following is required =
|
376 |
+
|
377 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on a tag archive page
|
378 |
+
* `id` or `tag_id` - set to the tag's ID
|
379 |
+
* `slug` or `tag_slug` - set to the tag's URL slug
|
380 |
+
|
381 |
+
= Optional arguments =
|
382 |
+
|
383 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
384 |
+
* `page` - return a specific page number from the results
|
385 |
+
* `post_type` - used to retrieve custom post types
|
386 |
+
|
387 |
+
= Response =
|
388 |
+
|
389 |
+
{
|
390 |
+
"status": "ok",
|
391 |
+
"count": 10,
|
392 |
+
"count_total": 79,
|
393 |
+
"pages": 7,
|
394 |
+
"tag": { ... }
|
395 |
+
"posts": [
|
396 |
+
{ ... },
|
397 |
+
{ ... },
|
398 |
+
...
|
399 |
+
]
|
400 |
+
}
|
401 |
+
|
402 |
+
|
403 |
+
== Method: get_author_posts ==
|
404 |
+
|
405 |
+
Returns an array of posts/pages written by a specific author.
|
406 |
+
|
407 |
+
= One of the following is required =
|
408 |
+
|
409 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on an author archive page
|
410 |
+
* `id` or `author_id` - set to the author's ID
|
411 |
+
* `slug` or `author_slug` - set to the author's URL slug
|
412 |
+
|
413 |
+
= Optional arguments =
|
414 |
+
|
415 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
416 |
+
* `page` - return a specific page number from the results
|
417 |
+
* `post_type` - used to retrieve custom post types
|
418 |
+
|
419 |
+
= Response =
|
420 |
+
|
421 |
+
{
|
422 |
+
"status": "ok",
|
423 |
+
"count": 10,
|
424 |
+
"count_total": 79,
|
425 |
+
"pages": 7,
|
426 |
+
"author": { ... }
|
427 |
+
"posts": [
|
428 |
+
{ ... },
|
429 |
+
{ ... },
|
430 |
+
...
|
431 |
+
]
|
432 |
+
}
|
433 |
+
|
434 |
+
|
435 |
+
== Method: get_search_results ==
|
436 |
+
|
437 |
+
Returns an array of posts/pages in response to a search query.
|
438 |
+
|
439 |
+
= One of the following is required =
|
440 |
+
|
441 |
+
* Invoking the JSON API implicitly (i.e., `?json=1`) on a search results page
|
442 |
+
* `search` - set to the desired search query
|
443 |
+
|
444 |
+
= Optional arguments =
|
445 |
+
|
446 |
+
* `count` - determines how many posts per page are returned (default value is 10)
|
447 |
+
* `page` - return a specific page number from the results
|
448 |
+
* `post_type` - used to retrieve custom post types
|
449 |
+
|
450 |
+
= Response =
|
451 |
+
|
452 |
+
{
|
453 |
+
"status": "ok",
|
454 |
+
"count": 10,
|
455 |
+
"count_total": 79,
|
456 |
+
"pages": 7,
|
457 |
+
"posts": [
|
458 |
+
{ ... },
|
459 |
+
{ ... },
|
460 |
+
...
|
461 |
+
]
|
462 |
+
}
|
463 |
+
|
464 |
+
|
465 |
+
== Method: get_date_index ==
|
466 |
+
|
467 |
+
Returns both an array of date page permalinks and a tree structure representation of the archive.
|
468 |
+
|
469 |
+
= Response =
|
470 |
+
|
471 |
+
{
|
472 |
+
"status": "ok",
|
473 |
+
"permalinks": [
|
474 |
+
"...",
|
475 |
+
"...",
|
476 |
+
"..."
|
477 |
+
],
|
478 |
+
"tree": {
|
479 |
+
"2009": {
|
480 |
+
"09": 17,
|
481 |
+
"10": 20,
|
482 |
+
"11": 7
|
483 |
+
}
|
484 |
+
}
|
485 |
+
|
486 |
+
Note: the tree is arranged by `response.tree.[year].[month].[number of posts]`.
|
487 |
+
|
488 |
+
|
489 |
+
== Method: get_category_index ==
|
490 |
+
|
491 |
+
Returns an array of active categories.
|
492 |
+
|
493 |
+
= Optional argument =
|
494 |
+
|
495 |
+
* `parent` - returns categories that are direct children of the parent ID
|
496 |
+
|
497 |
+
= Response =
|
498 |
+
|
499 |
+
{
|
500 |
+
"status": "ok",
|
501 |
+
"count": 3,
|
502 |
+
"categories": [
|
503 |
+
{ ... },
|
504 |
+
{ ... },
|
505 |
+
{ ... }
|
506 |
+
]
|
507 |
+
}
|
508 |
+
|
509 |
+
|
510 |
+
== Method: get_tag_index ==
|
511 |
+
|
512 |
+
Returns an array of active tags.
|
513 |
+
|
514 |
+
= Response =
|
515 |
+
|
516 |
+
{
|
517 |
+
"status": "ok",
|
518 |
+
"count": 3
|
519 |
+
"tags": [
|
520 |
+
{ ... },
|
521 |
+
{ ... },
|
522 |
+
{ ... }
|
523 |
+
]
|
524 |
+
}
|
525 |
+
|
526 |
+
|
527 |
+
== Method: get_author_index ==
|
528 |
+
|
529 |
+
Returns an array of active blog authors.
|
530 |
+
|
531 |
+
= Response =
|
532 |
+
|
533 |
+
{
|
534 |
+
"status": "ok",
|
535 |
+
"count": 3,
|
536 |
+
"authors": [
|
537 |
+
{ ... },
|
538 |
+
{ ... },
|
539 |
+
{ ... }
|
540 |
+
]
|
541 |
+
}
|
542 |
+
|
543 |
+
|
544 |
+
== Method: get_page_index ==
|
545 |
+
|
546 |
+
Returns a hierarchical tree of `page` posts.
|
547 |
+
|
548 |
+
= Response =
|
549 |
+
|
550 |
+
{
|
551 |
+
"status": "ok",
|
552 |
+
"pages": [
|
553 |
+
{ ... },
|
554 |
+
{ ... },
|
555 |
+
{ ... }
|
556 |
+
]
|
557 |
+
}
|
558 |
+
|
559 |
+
== Method: get_nonce ==
|
560 |
+
|
561 |
+
Returns a WordPress nonce value, required to call some data manipulation methods.
|
562 |
+
|
563 |
+
= Required arguments =
|
564 |
+
|
565 |
+
* `controller` - the JSON API controller for the method you will use the nonce for
|
566 |
+
* `method` - the method you wish to call (currently `create_post` is the only method that requires a nonce)
|
567 |
+
|
568 |
+
= Response =
|
569 |
+
|
570 |
+
{
|
571 |
+
"status": "ok",
|
572 |
+
"controller": "posts",
|
573 |
+
"method": "create_post",
|
574 |
+
"nonce": "cefe01efd4"
|
575 |
+
}
|
576 |
+
|
577 |
+
__Further reading__
|
578 |
+
To learn more about how nonces are used in WordPress, see [Mark Jaquith's article on the subject](http://markjaquith.wordpress.com/2006/06/02/wordpress-203-nonces/).
|
579 |
+
|
580 |
+
== 2.2. Pages controller methods ==
|
581 |
+
|
582 |
+
== Method: create_post ==
|
583 |
+
|
584 |
+
Creates a new post.
|
585 |
+
|
586 |
+
= Required argument =
|
587 |
+
|
588 |
+
* `nonce` - available from the `get_nonce` method (call with vars `controller=posts` and `method=create_post`)
|
589 |
+
|
590 |
+
= Optional arguments =
|
591 |
+
|
592 |
+
* `status` - sets the post status ("draft" or "publish"), default is "draft"
|
593 |
+
* `title` - the post title
|
594 |
+
* `content` - the post content
|
595 |
+
* `author` - the post's author (login name), default is the current logged in user
|
596 |
+
* `categories` - a comma-separated list of categories (URL slugs)
|
597 |
+
* `tags` - a comma-separated list of tags (URL slugs)
|
598 |
+
|
599 |
+
Note: including a file upload field called `attachment` will cause an attachment to be stored with your new post.
|
600 |
+
|
601 |
+
== Method: update_post ==
|
602 |
+
|
603 |
+
Updates a post.
|
604 |
+
|
605 |
+
= Required argument =
|
606 |
+
|
607 |
+
* `nonce` - available from the `get_nonce` method (call with vars `controller=posts` and `method=update_post`)
|
608 |
+
|
609 |
+
= One of the following is required =
|
610 |
+
|
611 |
+
* `id` or `post_id` - set to the post's ID
|
612 |
+
* `slug` or `post_slug` - set to the post's URL slug
|
613 |
+
|
614 |
+
= Optional arguments =
|
615 |
+
|
616 |
+
* `status` - sets the post status ("draft" or "publish"), default is "draft"
|
617 |
+
* `title` - the post title
|
618 |
+
* `content` - the post content
|
619 |
+
* `author` - the post's author (login name), default is the current logged in user
|
620 |
+
* `categories` - a comma-separated list of categories (URL slugs)
|
621 |
+
* `tags` - a comma-separated list of tags (URL slugs)
|
622 |
+
|
623 |
+
Note: including a file upload field called `attachment` will cause an attachment to be stored with your post.
|
624 |
+
|
625 |
+
== Method: delete_post ==
|
626 |
+
|
627 |
+
Deletes a post.
|
628 |
+
|
629 |
+
= Required argument =
|
630 |
+
|
631 |
+
* `nonce` - available from the `get_nonce` method (call with vars `controller=posts` and `method=delete_post`)
|
632 |
+
|
633 |
+
= One of the following is required =
|
634 |
+
|
635 |
+
* `id` or `post_id` - set to the post's ID
|
636 |
+
* `slug` or `post_slug` - set to the post's URL slug
|
637 |
+
|
638 |
+
|
639 |
+
== 2.3. Respond controller methods ==
|
640 |
+
|
641 |
+
== Method: submit_comment ==
|
642 |
+
|
643 |
+
Submits a comment to a WordPress post.
|
644 |
+
|
645 |
+
= Required arguments =
|
646 |
+
|
647 |
+
* `post_id` - which post to comment on
|
648 |
+
* `name` - the commenter's name
|
649 |
+
* `email` - the commenter's email address
|
650 |
+
* `content` - the comment content
|
651 |
+
|
652 |
+
= Optional arguments =
|
653 |
+
|
654 |
+
* `redirect` - redirect instead of returning a JSON object
|
655 |
+
* `redirect_ok` - redirect to a specific URL when the status value is `ok`
|
656 |
+
* `redirect_error` - redirect to a specific URL when the status value is `error`
|
657 |
+
* `redirect_pending` - redirect to a specific URL when the status value is `pending`
|
658 |
+
|
659 |
+
= Custom status values =
|
660 |
+
|
661 |
+
* `pending` - assigned if the comment submission is pending moderation
|
662 |
+
|
663 |
+
== 2.4. Widgets controller methods ==
|
664 |
+
|
665 |
+
== Method: get_sidebar ==
|
666 |
+
|
667 |
+
Retrieves widgets assigned to a sidebar.
|
668 |
+
|
669 |
+
= Required arguments =
|
670 |
+
|
671 |
+
* `sidebar_id` - the name or number of the sidebar to retrieve
|
672 |
+
|
673 |
+
|
674 |
+
== 3. Request arguments ==
|
675 |
+
|
676 |
+
API requests can be controlled by specifying one of the following arguments as URL query vars.
|
677 |
+
|
678 |
+
= Examples =
|
679 |
+
|
680 |
+
* Debug the response: `http://www.example.org/api/get_page_index/?dev=1`
|
681 |
+
* Widget-style JSONP output: `http://www.example.org/api/get_recent_posts/?callback=show_posts_widget&read_more=More&count=3`
|
682 |
+
* Redirect on error: `http://www.example.org/api/posts/create_post/?callback_error=http%3A%2F%2Fwww.example.org%2Fhelp.html`
|
683 |
+
|
684 |
+
== 3.1. Output-modifying arguments ==
|
685 |
+
|
686 |
+
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.
|
687 |
+
|
688 |
+
* Setting `callback` to a JavaScript function name will trigger a JSONP-style callback.
|
689 |
+
* 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).
|
690 |
+
* Setting `redirect_[status]` allows you to control the resulting browser redirection depending on the `status` value.
|
691 |
+
* Setting `dev` to a non-empty value adds whitespace for readability and responds with `text/plain`
|
692 |
+
* Errors are suppressed unless `dev` is set to a non-empty value
|
693 |
+
* Setting `json_encode_options` will let you specify an integer bitmask to modify the behavior of [PHP's `json_encode`](http://php.net/manual/en/function.json-encode.php) (Note: this option is only recognized in PHP version 5.3+)
|
694 |
+
* Setting `json_unescaped_unicode` will replace unicode-escaped characters with their unescaped equivalents (e.g., `\u00e1` becomes á)
|
695 |
+
* Omitting all of the above arguments will result in a standard JSON response.
|
696 |
+
|
697 |
+
== 3.2. Content-modifying arguments ==
|
698 |
+
|
699 |
+
These arguments are available to modify all introspection methods:
|
700 |
+
|
701 |
+
* `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`.
|
702 |
+
* `read_more` - Changes the 'read more' link text in post content.
|
703 |
+
* `include` - Specifies which post data fields to include. Expects a comma-separated list of post fields. Leaving this empty includes *all* fields.
|
704 |
+
* `exclude` - Specifies which post data fields to exclude. Expects a comma-separated list of post fields.
|
705 |
+
* `custom_fields` - Includes values from posts' Custom Fields. Expects a comma-separated list of custom field keys.
|
706 |
+
* `author_meta` - Includes additional author metadata. Should be a comma-separated list of metadata fields.
|
707 |
+
* `count` - Controls the number of posts to include (defaults to the number specified by WordPress)
|
708 |
+
* `order` - Controls the order of post results ('DESC' or 'ASC'). Default value is 'DESC'.
|
709 |
+
* `order_by` - Controls which field to order results by. Expects one of the following values:
|
710 |
+
* `author`
|
711 |
+
* `date` (default value)
|
712 |
+
* `title`
|
713 |
+
* `modified`
|
714 |
+
* `menu_order` (only works with Pages)
|
715 |
+
* `parent`
|
716 |
+
* `ID`
|
717 |
+
* `rand`
|
718 |
+
* `meta_value` (`meta_key` must also be set)
|
719 |
+
* `none`
|
720 |
+
* `comment_count`
|
721 |
+
* `meta_key`, `meta_value`, `meta_compare` - Retrieve posts (or Pages) based on a custom field key or value.
|
722 |
+
|
723 |
+
== 3.3. Using include/exclude and redirects ==
|
724 |
+
|
725 |
+
__About `include`/`exclude` arguments__
|
726 |
+
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.
|
727 |
+
|
728 |
+
__About the `redirect` argument__
|
729 |
+
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.
|
730 |
+
|
731 |
+
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:
|
732 |
+
|
733 |
+
* `http://www.example.com/foo?status=ok`
|
734 |
+
* `http://www.example.com/foo?status=error`
|
735 |
+
|
736 |
+
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.
|
737 |
+
|
738 |
+
|
739 |
+
== 4. Response objects ==
|
740 |
+
|
741 |
+
This section describes data objects you can retrieve from WordPress and the optional URL redirects.
|
742 |
+
|
743 |
+
__Status values__
|
744 |
+
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.
|
745 |
+
|
746 |
+
__Naming compatibility__
|
747 |
+
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.
|
748 |
+
|
749 |
+
== 4.1. Post response object ==
|
750 |
+
|
751 |
+
* `id` - Integer
|
752 |
+
* `type` - String (e.g., `post` or `page`)
|
753 |
+
* `slug` - String
|
754 |
+
* `url` - String
|
755 |
+
* `title` - String
|
756 |
+
* `title_plain` - String
|
757 |
+
* `content` - String (modified by the `read_more` argument)
|
758 |
+
* `excerpt` - String
|
759 |
+
* `date` - String (modified by the `date_format` argument)
|
760 |
+
* `modified` - String (modified by the `date_format` argument)
|
761 |
+
* `categories` - Array of category objects
|
762 |
+
* `tags` - Array of tag objects
|
763 |
+
* `author` Author object
|
764 |
+
* `comments` - Array of comment objects
|
765 |
+
* `attachments` - Array of attachment objects
|
766 |
+
* `comment_count` - Integer
|
767 |
+
* `comment_status` - String (`"open"` or `"closed"`)
|
768 |
+
* `thumbnail` - String (only included if a post thumbnail has been specified)
|
769 |
+
* `custom_fields` - Object (included by setting the `custom_fields` argument to a comma-separated list of custom field names)
|
770 |
+
* `taxonomy_(taxonomy)` - Array of custom taxonomy objects (these resemble Category or Tag response objects, depending on whether the taxonomy is hierarchical)
|
771 |
+
|
772 |
+
__Note__
|
773 |
+
The `thumbnail` attribute returns a URL to the image size specified by the optional `thumbnail_size` request argument. By default this will use the `thumbnail` or `post-thumbnail` sizes, depending on your version of WordPress. See [Mark Jaquith's post on the topic](http://markjaquith.wordpress.com/2009/12/23/new-in-wordpress-2-9-post-thumbnail-images/) for more information.
|
774 |
+
|
775 |
+
== 4.2. Category response object ==
|
776 |
+
|
777 |
+
* `id` - Integer
|
778 |
+
* `slug` - String
|
779 |
+
* `title` - String
|
780 |
+
* `description` - String
|
781 |
+
* `parent` - Integer
|
782 |
+
* `post_count` - Integer
|
783 |
+
|
784 |
+
== 4.3. Tag response object ==
|
785 |
+
|
786 |
+
* `id` - Integer
|
787 |
+
* `slug` - String
|
788 |
+
* `title` - String
|
789 |
+
* `description` - String
|
790 |
+
* `post_count` - Integer
|
791 |
+
|
792 |
+
== 4.4. Author response object ==
|
793 |
+
|
794 |
+
* `id` - Integer
|
795 |
+
* `slug` - String
|
796 |
+
* `name` - String
|
797 |
+
* `first_name` - String
|
798 |
+
* `last_name` - String
|
799 |
+
* `nickname` - String
|
800 |
+
* `url` - String
|
801 |
+
* `description` - String
|
802 |
+
|
803 |
+
Note: You can include additional values by setting the `author_meta` argument to a comma-separated list of metadata fields.
|
804 |
+
|
805 |
+
== 4.5. Comment response object ==
|
806 |
+
|
807 |
+
* `id` - Integer
|
808 |
+
* `name` - String
|
809 |
+
* `url` - String
|
810 |
+
* `date` - String
|
811 |
+
* `content` - String
|
812 |
+
* `parent` - Integer
|
813 |
+
* `author` - Object (only set if the comment author was registered & logged in)
|
814 |
+
|
815 |
+
== 4.6. Attachment response object ==
|
816 |
+
|
817 |
+
* `id` - Integer
|
818 |
+
* `url` - String
|
819 |
+
* `slug` - String
|
820 |
+
* `title` - String
|
821 |
+
* `description` - String
|
822 |
+
* `caption` - String
|
823 |
+
* `parent` - Integer
|
824 |
+
* `mime_type` - String
|
825 |
+
* `images` - Object with values including `thumbnail`, `medium`, `large`, `full`, each of which are objects with values `url`, `width` and `height` (only set if the attachment is an image)
|
826 |
+
|
827 |
+
|
828 |
+
== 5. Extending JSON API ==
|
829 |
+
|
830 |
+
JSON API exposes several WordPress action and filter hooks as well as a modular controller system for adding new API methods.
|
831 |
+
|
832 |
+
== 5.1. Plugin hooks ==
|
833 |
+
|
834 |
+
JSON API exposes several [action and filter hooks](http://codex.wordpress.org/Plugin_API#Hooks.2C_Actions_and_Filters) to augment its behavior.
|
835 |
+
|
836 |
+
== Filter: json_api_controllers ==
|
837 |
+
|
838 |
+
This filter controls the array of controllers available to JSON API. The callback function is passed a single argument, an array of strings.
|
839 |
+
|
840 |
+
= Example =
|
841 |
+
|
842 |
+
// Add a custom controller
|
843 |
+
add_filter('json_api_controllers', 'add_my_controller');
|
844 |
+
|
845 |
+
function add_my_controller($controllers) {
|
846 |
+
// Corresponds to the class JSON_API_MyController_Controller
|
847 |
+
$controllers[] = 'MyController';
|
848 |
+
return $controllers;
|
849 |
+
}
|
850 |
+
|
851 |
+
|
852 |
+
== Filter: json_api_[controller]_controller_path ==
|
853 |
+
|
854 |
+
Specifies the PHP source file for a given controller, overriding the default location `wp-content/plugins/json_api/controllers`.
|
855 |
+
|
856 |
+
__Note__
|
857 |
+
If you your controller file in the `json-api/controllers` folder JSON API will find it automatically.
|
858 |
+
|
859 |
+
= Example =
|
860 |
+
|
861 |
+
// Register the source file for JSON_API_Widgets_Controller
|
862 |
+
add_filter('json_api_widgets_controller_path', 'widgets_controller_path');
|
863 |
+
|
864 |
+
function widgets_controller_path($default_path) {
|
865 |
+
return '/path/to/widgets.php';
|
866 |
+
}
|
867 |
+
|
868 |
+
__Capitalization__
|
869 |
+
Your filter hook must be all-lowercase to work correctly. The above example would fail with the filter `json_api_Widgets_Controller_path`, even if that's how the class is capitalized in the PHP source.
|
870 |
+
|
871 |
+
== Filter: json_api_encode ==
|
872 |
+
|
873 |
+
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.
|
874 |
+
|
875 |
+
= Example =
|
876 |
+
|
877 |
+
add_filter('json_api_encode', 'my_encode_kittens');
|
878 |
+
|
879 |
+
function my_encode_kittens($response) {
|
880 |
+
if (isset($response['posts'])) {
|
881 |
+
foreach ($response['posts'] as $post) {
|
882 |
+
my_add_kittens($post); // Add kittens to each post
|
883 |
+
}
|
884 |
+
} else if (isset($response['post'])) {
|
885 |
+
my_add_kittens($response['post']); // Add a kittens property
|
886 |
+
}
|
887 |
+
return $response;
|
888 |
+
}
|
889 |
+
|
890 |
+
function my_add_kittens(&$post) {
|
891 |
+
$post->kittens = 'Kittens!';
|
892 |
+
}
|
893 |
+
|
894 |
+
== Action: json_api-[controller]-[method] ==
|
895 |
+
|
896 |
+
Each JSON API method invokes an action when called.
|
897 |
+
|
898 |
+
= Example =
|
899 |
+
|
900 |
+
// Disable get_author_index method (e.g., for security reasons)
|
901 |
+
add_action('json_api-core-get_author_index', 'my_disable_author_index');
|
902 |
+
|
903 |
+
function my_disable_author_index() {
|
904 |
+
// Stop execution
|
905 |
+
exit;
|
906 |
+
}
|
907 |
+
|
908 |
+
== 5.2. Developing JSON API controllers ==
|
909 |
+
|
910 |
+
= Creating a controller =
|
911 |
+
|
912 |
+
To start a new JSON API controller, create a file called `hello.php` inside `wp-content/plugins/json-api/controllers`. Add the following class definition:
|
913 |
+
|
914 |
+
<?php
|
915 |
+
|
916 |
+
class JSON_API_Hello_Controller {
|
917 |
+
|
918 |
+
public function hello_world() {
|
919 |
+
return array(
|
920 |
+
"message" => "Hello, world"
|
921 |
+
);
|
922 |
+
}
|
923 |
+
|
924 |
+
}
|
925 |
+
|
926 |
+
?>
|
927 |
+
|
928 |
+
Your controller is now available as `hello`, and exposes one `hello_world` method.
|
929 |
+
|
930 |
+
Next, activate your controller from the WordPress admin interface, available from the menu under Settings > JSON API. You can either click on the link to your `hello_world` method from the admin interface or enter it manually. It should have the form: `http://www.example.org/api/hello/hello_world/?dev=1` or `http://www.example.org/?json=hello.hello_world&dev=1` (note the use of the `dev` argument to enable human-readable output). You should get the following output:
|
931 |
+
|
932 |
+
{
|
933 |
+
"status": "ok",
|
934 |
+
"message": "Hello, world"
|
935 |
+
}
|
936 |
+
|
937 |
+
= Using query vars =
|
938 |
+
|
939 |
+
To customize the behavior of your controller, you will want to make use of the global `$json_api->query` object. Add the following method to your controller:
|
940 |
+
|
941 |
+
public function hello_person() {
|
942 |
+
global $json_api;
|
943 |
+
$name = $json_api->query->name;
|
944 |
+
return array(
|
945 |
+
"message" => "Hello, $name."
|
946 |
+
);
|
947 |
+
}
|
948 |
+
|
949 |
+
Now append the `name` query var to the method call: `http://www.example.org/api/hello/hello_world/?dev=1&name=Alice` or `http://www.example.org/?json=hello.hello_world&dev=1&name=Alice`.
|
950 |
+
|
951 |
+
{
|
952 |
+
"status": "ok",
|
953 |
+
"message": "Hello, Alice"
|
954 |
+
}
|
955 |
+
|
956 |
+
= Introspector and data models =
|
957 |
+
|
958 |
+
Your controller can use any of the [existing WordPress functions](http://codex.wordpress.org/Function_Reference) to collect data, but JSON API also includes an introspector that wraps data in objects defined in the `json-api/models` directory. These are the same data models described in *Section 4: Response objects*.
|
959 |
+
|
960 |
+
Here is an example of how you might use the introspector:
|
961 |
+
|
962 |
+
// Retrieve posts based on custom field key/value pair
|
963 |
+
public function get_custom_posts() {
|
964 |
+
global $json_api;
|
965 |
+
|
966 |
+
// Make sure we have key/value query vars
|
967 |
+
if (!$json_api->query->key || !$json_api->query->value) {
|
968 |
+
$json_api->error("Include a 'key' and 'value' query var.");
|
969 |
+
}
|
970 |
+
|
971 |
+
// See also: http://codex.wordpress.org/Template_Tags/query_posts
|
972 |
+
$posts = $json_api->introspector->get_posts(array(
|
973 |
+
'meta_key' => $json_api->query->key,
|
974 |
+
'meta_value' => $json_api->query->value
|
975 |
+
));
|
976 |
+
|
977 |
+
return array(
|
978 |
+
'key' => $key,
|
979 |
+
'value' => $value,
|
980 |
+
'posts' => $posts
|
981 |
+
);
|
982 |
+
}
|
983 |
+
|
984 |
+
= External controllers =
|
985 |
+
|
986 |
+
It is recommended that custom controllers are kept outside of `json-api/controllers` in order to avoid accidental deletion during upgrades or site migrations. To make your controller visible from an external plugin or theme directory you will need to use two filters: `json_api_controllers` and `json_api_[controller]_controller_path`. Move the `hello.php` file from the steps above into your theme's directory. Then add the following to your theme's `functions.php` file (if your theme doesn't have a file called `functions.php` you can create one).
|
987 |
+
|
988 |
+
function add_hello_controller($controllers) {
|
989 |
+
$controllers[] = 'hello';
|
990 |
+
return $controllers;
|
991 |
+
}
|
992 |
+
add_filter('json_api_controllers', 'add_hello_controller');
|
993 |
+
|
994 |
+
function set_hello_controller_path() {
|
995 |
+
return "/path/to/theme/hello.php";
|
996 |
+
}
|
997 |
+
add_filter('json_api_hello_controller_path', 'set_hello_controller_path');
|
998 |
+
|
999 |
+
== 5.3. Configuration options ==
|
1000 |
+
|
1001 |
+
The following are constants you can define in your `wp-config.php` folder:
|
1002 |
+
|
1003 |
+
* `JSON_API_DIR` - set to the directory where JSON API plugin lives (in some cases this can be useful for `mu-plugins` with WordPress MU)
|
1004 |
+
* `JSON_API_CONTROLLERS` - a comma-separated list of default controllers to enable (this is overridden by the JSON API settings page)
|
1005 |
+
|
1006 |
+
== 6. Unit tests ==
|
1007 |
+
|
1008 |
+
JSON API comes with a set of tests that should make it easier to maintain and reveal incompatibilities when they might occur. This is an ongoing process, I hope to improve the test coverage going forward.
|
1009 |
+
|
1010 |
+
== 6.1. Preparing a WordPress test site ==
|
1011 |
+
|
1012 |
+
There are a few necessary steps that need to be carried out before the test suite will run properly.
|
1013 |
+
|
1014 |
+
1. WordPress should generate a new set of tables before you start, so if you're testing with a `wp_` table prefix make sure the database has no existing tables of this kind
|
1015 |
+
2. Configure and install a new copy of WordPress
|
1016 |
+
3. Delete the Hello World post and Sample Page (titled "About" in some versions of WordPress)
|
1017 |
+
4. Enable user-friendly URLs from Settings > Permalinks, use the "Day and name" format
|
1018 |
+
5. Install + Activate the JSON API plugin and enable all bundled controllers from Settings > JSON API
|
1019 |
+
6. Import the [Theme Unit Test](http://codex.wordpress.org/Theme_Unit_Test) test data XML file from Settings > Import > WordPress (you will need to install the WordPress Importer plugin)
|
1020 |
+
|
1021 |
+
== 6.2. Running the tests ==
|
1022 |
+
|
1023 |
+
From the command line, make sure you have the HTTP_Client PEAR package installed:
|
1024 |
+
|
1025 |
+
`pear install HTTP_Client`
|
1026 |
+
|
1027 |
+
Change directory to `tests` and run the following:
|
1028 |
+
|
1029 |
+
`pear run-tests`
|
1030 |
+
|
1031 |
+
You should see the test results print out culminating in a summary:
|
1032 |
+
|
1033 |
+
TOTAL TIME: 00:04
|
1034 |
+
23 PASSED TESTS
|
1035 |
+
0 SKIPPED TESTS
|
1036 |
+
|
1037 |
+
== Changelog ==
|
1038 |
+
|
1039 |
+
= 1.1.2 (2015-08-20): =
|
1040 |
+
* Don't always respond with HTTP 200
|
1041 |
+
|
1042 |
+
= 1.1.1 (2013-06-23): =
|
1043 |
+
* Added support for custom taxonomies
|
1044 |
+
* Errors are now suppressed unless you include a non-empty `dev` argument
|
1045 |
+
|
1046 |
+
= 1.1.0 (2013-06-22): =
|
1047 |
+
* Bugfix for `json_encode` compatibility with PHP < 5.3
|
1048 |
+
* Bugfix for `get_author_index` warnings in WordPress > 3.5
|
1049 |
+
|
1050 |
+
= 1.0.9 (2013-06-21): =
|
1051 |
+
* Added `update_post` and `delete_post` methods to Post controller
|
1052 |
+
* Added two JSON encoding arguments: `json_encode_options` and `json_unescaped_unicode`
|
1053 |
+
* Added a `parent` argument to `get_category_index`
|
1054 |
+
* Fixed a couple places where the code was generating PHP notifications
|
1055 |
+
* Updated bundled Services_JSON library (only used if `json_encode` is unavailable)
|
1056 |
+
|
1057 |
+
= 1.0.8 (2013-06-12): =
|
1058 |
+
* Added `widgets` controller
|
1059 |
+
* Added a generic `get_posts` method to the core controller
|
1060 |
+
* Added a `thumbnail_images` object property to complement `thumbnail` URL
|
1061 |
+
* Attachment image files are now checked to exist and match the expected width/height
|
1062 |
+
* Fixed a bug where `the_excerpt` filter wasn't being applied to the `excerpt` property
|
1063 |
+
* Fixed a bug where the number of child pages was being limited to 5
|
1064 |
+
* Fixed a bug where custom controller class names couldn't include numerics
|
1065 |
+
* Theme directory check for custom controllers
|
1066 |
+
|
1067 |
+
= 1.0.7 (2011-01-27): =
|
1068 |
+
* Created some basic unit tests
|
1069 |
+
* Fixed a bug where `get_author_posts` was unable to find users by `slug`
|
1070 |
+
* Added missing `post_type` argument to documentation for `get_post` and `get_page` (props Koshirosan)
|
1071 |
+
* Added `previous_url` and `next_url` properties to the `get_post` response object (props mlcy44)
|
1072 |
+
|
1073 |
+
= 1.0.6 (2011-01-13): =
|
1074 |
+
* Fixed a bug in `exclude` query parameter (big props to ikesyo and archon810)
|
1075 |
+
* Fix for `get_page_index` that where it only returned 5 pages -- it now responds to `count` query param (props to npavkovic and blinder)
|
1076 |
+
* Removed `Content-Disposition` header from response (props mimecine, kjwierenga)
|
1077 |
+
* Fixed an incompatibility issue with Disqus plugin (props joshcanhelp)
|
1078 |
+
* Fixed a bug where `submit_comment` was resulting in a HTTP 404 status (props @tdweston)
|
1079 |
+
* Fixed an error in the documentation, external controller example (props jli)
|
1080 |
+
|
1081 |
+
= 1.0.5 (2010-07-08): =
|
1082 |
+
* Added an check so that `json-api.php` can be moved one level above the `json-api` directory
|
1083 |
+
* Added more documentation about using nonces
|
1084 |
+
|
1085 |
+
= 1.0.4 (2010-07-07): =
|
1086 |
+
* Fixed a bug where the order of attachments didn't match the gallery
|
1087 |
+
* Added a section to the developer documentation for externalizing custom controllers
|
1088 |
+
* Moved JSON_API class to its own file: `singletons/api.php`
|
1089 |
+
* Created a new top-level function: `json_api_dir()`
|
1090 |
+
* Improvements for WordPress MU: `JSON_API_DIR` and `JSON_API_CONTROLLERS` constants (props Jim McQuillan)
|
1091 |
+
|
1092 |
+
= 1.0.3 (2010-07-07): =
|
1093 |
+
* Added request argument `thumbnail_size` to support different sizes of featured images (see also: `add_image_size` WordPress function)
|
1094 |
+
* Added request argument `post_type` to support custom post types (props Mark Harris)
|
1095 |
+
|
1096 |
+
= 1.0.2 (2010-07-02): =
|
1097 |
+
* Removed an inaccurate section from readme.txt about supporting `query_posts` arguments
|
1098 |
+
* Changed controller info block format to use "Controller name" and "Controller description"
|
1099 |
+
* Made admin page more robust about handling errors loading controllers
|
1100 |
+
* Changed `JSON_API::get_controllers` method to lowercase all entries
|
1101 |
+
* Added introspector section to developer documentation
|
1102 |
+
* Fixed incorrect example for `json_api_[controller]_controller_path`
|
1103 |
+
* Thanks to Tim Nash for early feedback on writing external controllers
|
1104 |
+
|
1105 |
+
= 1.0.1 (2010-07-01): =
|
1106 |
+
* Fixed some typos in readme.txt
|
1107 |
+
* Switched `get_tag_posts` to query on tag instead of tag_id (maybe a WordPress issue?)
|
1108 |
+
|
1109 |
+
= 1.0 (2010-06-29): =
|
1110 |
+
* JSON API officially drops support for PHP 4 (it was already broken)
|
1111 |
+
* Added JSON API Settings page to WP admin
|
1112 |
+
* Broke apart `JSON_API_Controller` into a modular controller system
|
1113 |
+
* Refactored `JSON_API_Query` to depend less on WordPress's `get_query_var` mechanism
|
1114 |
+
* Developer mode now shows response in JSON format
|
1115 |
+
* The `create_post` method now requires a nonce
|
1116 |
+
* Improved support for complex post queries (props zibitt)
|
1117 |
+
* Fixed a bug with `get_author_by_login` (props Krzysztof Sobolewski)
|
1118 |
+
* Made image attachments more robust with `get_intermediate_image_sizes` (props mimecine)
|
1119 |
+
* Improved post thumbnail support (props nyamsprod)
|
1120 |
+
|
1121 |
+
= 0.9.6 (2010-05-27): =
|
1122 |
+
* Fixed a bug introduced in 0.9.5
|
1123 |
+
|
1124 |
+
= 0.9.5 (2010-05-27): =
|
1125 |
+
* Added a `thumbnail` property to Post response objects
|
1126 |
+
|
1127 |
+
= 0.9.4 (2010-04-28): =
|
1128 |
+
* Fixed a bug where any non-authenticated user could create a draft blog post through `create_post`. Thanks to user futtta for posting about this.
|
1129 |
+
|
1130 |
+
= 0.9.3 (2010-03-19): =
|
1131 |
+
* Fixed a bug where child pages were being ignored by the API. See also: https://core.trac.wordpress.org/ticket/12647
|
1132 |
+
|
1133 |
+
= 0.9.2 (2010-03-18): =
|
1134 |
+
* Fixed a bug where the /api/ rewrite rules would be lost
|
1135 |
+
|
1136 |
+
= 0.9 (2010-02-04): =
|
1137 |
+
* Added a `create_post` method
|
1138 |
+
|
1139 |
+
= 0.8.3 (2010-01-27): =
|
1140 |
+
* Fixed the stable tag version
|
1141 |
+
|
1142 |
+
= 0.8.2 (2010-01-27): =
|
1143 |
+
* Fixed a typo in the changelog
|
1144 |
+
|
1145 |
+
= 0.8.1 (2010-01-27): =
|
1146 |
+
* Fixed a bug that was making JSONP support non-functional
|
1147 |
+
|
1148 |
+
= 0.8 (2010-01-18): =
|
1149 |
+
* Added an attachment model and instance variable for post objects
|
1150 |
+
|
1151 |
+
= 0.7.3 (2010-01-15): =
|
1152 |
+
* Added a `count` request parameter to control the number of posts returned
|
1153 |
+
|
1154 |
+
= 0.7.2 (2010-01-14): =
|
1155 |
+
* Removed the version number from the description text
|
1156 |
+
|
1157 |
+
= 0.7.1 (2010-01-14): =
|
1158 |
+
* Fixed another subtle bug with `get_author_index`
|
1159 |
+
|
1160 |
+
= 0.7 (2010-01-08): =
|
1161 |
+
* Added a `post_count` response to tag objects
|
1162 |
+
* Fixed a bug with `get_author_index`
|
1163 |
+
|
1164 |
+
= 0.6 (2009-11-30): =
|
1165 |
+
* Added `count_total` response
|
1166 |
+
* Added `json_api_encode` filter
|
1167 |
+
* Fixed bugs in the introspector's `get_current_category` and `get_current_tag`
|
1168 |
+
|
1169 |
+
= 0.5 (2009-11-17): =
|
1170 |
+
* Initial Public Release
|
1171 |
+
|
1172 |
+
== Upgrade Notice ==
|
1173 |
+
|
1174 |
+
= 1.1.2 =
|
1175 |
+
Don't always respond with HTTP 200
|
1176 |
+
|
1177 |
+
= 1.1.1 =
|
1178 |
+
Added support for custom taxonomies
|
1179 |
+
|
1180 |
+
= 1.1.0 =
|
1181 |
+
Minor bugfixes
|
1182 |
+
|
1183 |
+
= 1.0.9 =
|
1184 |
+
Update/delete post methods and some other bugfixes and improvements
|
1185 |
+
|
1186 |
+
= 1.0.8 =
|
1187 |
+
Long overdue bugfix/improvement release
|
1188 |
+
|
1189 |
+
= 1.0.7 =
|
1190 |
+
Minor bugfix/improvement release
|
1191 |
+
|
1192 |
+
= 1.0.6 =
|
1193 |
+
Minor bugfix/improvement release
|
1194 |
+
|
1195 |
+
= 1.0.5 =
|
1196 |
+
Minor improvement release
|
1197 |
+
|
1198 |
+
= 1.0.4 =
|
1199 |
+
Minor bugfix/refactor release
|
1200 |
+
|
1201 |
+
= 1.0.3 =
|
1202 |
+
Two new request arguments added: `thumbnail_size` and `post_type`
|
1203 |
+
|
1204 |
+
= 1.0.2 =
|
1205 |
+
Minor bugfix release
|
1206 |
+
|
1207 |
+
= 1.0.1 =
|
1208 |
+
Bugfix release, possibly stemming from a bug in WordPress 3.0
|
1209 |
+
|
1210 |
+
= 1.0 =
|
1211 |
+
Major release, see changelog for details.
|
1212 |
+
|
1213 |
+
= 0.9.6 =
|
1214 |
+
Bugfix release for something added in 0.9.5.
|
1215 |
+
|
1216 |
+
= 0.9.5 =
|
1217 |
+
Feature addition: post thumbnails now included in response objects.
|
1218 |
+
|
1219 |
+
= 0.9.4 =
|
1220 |
+
Security fix: all users are strongly encouraged to upgrade. (See Changelog.)
|
1221 |
+
|
1222 |
+
= 0.9.3 =
|
1223 |
+
Fixed a bug where child pages could not be introspected by the API.
|
1224 |
+
|
1225 |
+
= 0.9.2 =
|
1226 |
+
Fixed a bug where the /api/ path would stop working upon publishing new pages.
|
1227 |
+
|
1228 |
+
= 0.9 =
|
1229 |
+
Added a new data manipulation method: `create_post`.
|
1230 |
+
|
1231 |
+
= 0.8.3 =
|
1232 |
+
Oh dear, I didn't tag 0.8.2 in the stable tags thing.
|
1233 |
+
|
1234 |
+
= 0.8.2 =
|
1235 |
+
Just fixing a mislabeled 0.8.1 release in the changelog.
|
1236 |
+
|
1237 |
+
= 0.8.1 =
|
1238 |
+
This is a bug fix release for JSONP support. Thanks to Ben Wilson for reporting it!
|
1239 |
+
|
1240 |
+
= 0.8 =
|
1241 |
+
Added what may be the last introspection feature: post attachments. You can now see images and other media that have been added to posts.
|
trunk/screenshot-1.png
ADDED
Binary file
|
trunk/singletons/api.php
ADDED
@@ -0,0 +1,394 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API {
|
4 |
+
|
5 |
+
function __construct() {
|
6 |
+
$this->query = new JSON_API_Query();
|
7 |
+
$this->introspector = new JSON_API_Introspector();
|
8 |
+
$this->response = new JSON_API_Response();
|
9 |
+
add_action('template_redirect', array(&$this, 'template_redirect'));
|
10 |
+
add_action('admin_menu', array(&$this, 'admin_menu'));
|
11 |
+
add_action('update_option_json_api_base', array(&$this, 'flush_rewrite_rules'));
|
12 |
+
add_action('pre_update_option_json_api_controllers', array(&$this, 'update_controllers'));
|
13 |
+
}
|
14 |
+
|
15 |
+
function template_redirect() {
|
16 |
+
// Check to see if there's an appropriate API controller + method
|
17 |
+
$controller = strtolower($this->query->get_controller());
|
18 |
+
$available_controllers = $this->get_controllers();
|
19 |
+
$enabled_controllers = explode(',', get_option('json_api_controllers', 'core'));
|
20 |
+
$active_controllers = array_intersect($available_controllers, $enabled_controllers);
|
21 |
+
|
22 |
+
if ($controller) {
|
23 |
+
|
24 |
+
if (empty($this->query->dev)) {
|
25 |
+
error_reporting(0);
|
26 |
+
}
|
27 |
+
|
28 |
+
if (!in_array($controller, $active_controllers)) {
|
29 |
+
$this->error("Unknown controller '$controller'.");
|
30 |
+
}
|
31 |
+
|
32 |
+
$controller_path = $this->controller_path($controller);
|
33 |
+
if (file_exists($controller_path)) {
|
34 |
+
require_once $controller_path;
|
35 |
+
}
|
36 |
+
$controller_class = $this->controller_class($controller);
|
37 |
+
|
38 |
+
if (!class_exists($controller_class)) {
|
39 |
+
$this->error("Unknown controller '$controller_class'.");
|
40 |
+
}
|
41 |
+
|
42 |
+
$this->controller = new $controller_class();
|
43 |
+
$method = $this->query->get_method($controller);
|
44 |
+
|
45 |
+
if ($method) {
|
46 |
+
|
47 |
+
$this->response->setup();
|
48 |
+
|
49 |
+
// Run action hooks for method
|
50 |
+
do_action("json_api", $controller, $method);
|
51 |
+
do_action("json_api-{$controller}-$method");
|
52 |
+
|
53 |
+
// Error out if nothing is found
|
54 |
+
if ($method == '404') {
|
55 |
+
$this->error('Not found');
|
56 |
+
}
|
57 |
+
|
58 |
+
// Run the method
|
59 |
+
$result = $this->controller->$method();
|
60 |
+
|
61 |
+
// Handle the result
|
62 |
+
$this->response->respond($result);
|
63 |
+
|
64 |
+
// Done!
|
65 |
+
exit;
|
66 |
+
}
|
67 |
+
}
|
68 |
+
}
|
69 |
+
|
70 |
+
function admin_menu() {
|
71 |
+
add_options_page('JSON API Settings', 'JSON API', 'manage_options', 'json-api', array(&$this, 'admin_options'));
|
72 |
+
}
|
73 |
+
|
74 |
+
function admin_options() {
|
75 |
+
if (!current_user_can('manage_options')) {
|
76 |
+
wp_die( __('You do not have sufficient permissions to access this page.') );
|
77 |
+
}
|
78 |
+
|
79 |
+
$available_controllers = $this->get_controllers();
|
80 |
+
$active_controllers = explode(',', get_option('json_api_controllers', 'core'));
|
81 |
+
|
82 |
+
if (count($active_controllers) == 1 && empty($active_controllers[0])) {
|
83 |
+
$active_controllers = array();
|
84 |
+
}
|
85 |
+
|
86 |
+
if (!empty($_REQUEST['_wpnonce']) && wp_verify_nonce($_REQUEST['_wpnonce'], "update-options")) {
|
87 |
+
if ((!empty($_REQUEST['action']) || !empty($_REQUEST['action2'])) &&
|
88 |
+
(!empty($_REQUEST['controller']) || !empty($_REQUEST['controllers']))) {
|
89 |
+
if (!empty($_REQUEST['action'])) {
|
90 |
+
$action = $_REQUEST['action'];
|
91 |
+
} else {
|
92 |
+
$action = $_REQUEST['action2'];
|
93 |
+
}
|
94 |
+
|
95 |
+
if (!empty($_REQUEST['controllers'])) {
|
96 |
+
$controllers = $_REQUEST['controllers'];
|
97 |
+
} else {
|
98 |
+
$controllers = array($_REQUEST['controller']);
|
99 |
+
}
|
100 |
+
|
101 |
+
foreach ($controllers as $controller) {
|
102 |
+
if (in_array($controller, $available_controllers)) {
|
103 |
+
if ($action == 'activate' && !in_array($controller, $active_controllers)) {
|
104 |
+
$active_controllers[] = $controller;
|
105 |
+
} else if ($action == 'deactivate') {
|
106 |
+
$index = array_search($controller, $active_controllers);
|
107 |
+
if ($index !== false) {
|
108 |
+
unset($active_controllers[$index]);
|
109 |
+
}
|
110 |
+
}
|
111 |
+
}
|
112 |
+
}
|
113 |
+
$this->save_option('json_api_controllers', implode(',', $active_controllers));
|
114 |
+
}
|
115 |
+
if (isset($_REQUEST['json_api_base'])) {
|
116 |
+
$this->save_option('json_api_base', $_REQUEST['json_api_base']);
|
117 |
+
}
|
118 |
+
}
|
119 |
+
|
120 |
+
?>
|
121 |
+
<div class="wrap">
|
122 |
+
<div id="icon-options-general" class="icon32"><br /></div>
|
123 |
+
<h2>JSON API Settings</h2>
|
124 |
+
<form action="options-general.php?page=json-api" method="post">
|
125 |
+
<?php wp_nonce_field('update-options'); ?>
|
126 |
+
<h3>Controllers</h3>
|
127 |
+
<?php $this->print_controller_actions(); ?>
|
128 |
+
<table id="all-plugins-table" class="widefat">
|
129 |
+
<thead>
|
130 |
+
<tr>
|
131 |
+
<th class="manage-column check-column" scope="col"><input type="checkbox" /></th>
|
132 |
+
<th class="manage-column" scope="col">Controller</th>
|
133 |
+
<th class="manage-column" scope="col">Description</th>
|
134 |
+
</tr>
|
135 |
+
</thead>
|
136 |
+
<tfoot>
|
137 |
+
<tr>
|
138 |
+
<th class="manage-column check-column" scope="col"><input type="checkbox" /></th>
|
139 |
+
<th class="manage-column" scope="col">Controller</th>
|
140 |
+
<th class="manage-column" scope="col">Description</th>
|
141 |
+
</tr>
|
142 |
+
</tfoot>
|
143 |
+
<tbody class="plugins">
|
144 |
+
<?php
|
145 |
+
|
146 |
+
foreach ($available_controllers as $controller) {
|
147 |
+
|
148 |
+
$error = false;
|
149 |
+
$active = in_array($controller, $active_controllers);
|
150 |
+
$info = $this->controller_info($controller);
|
151 |
+
|
152 |
+
if (is_string($info)) {
|
153 |
+
$active = false;
|
154 |
+
$error = true;
|
155 |
+
$info = array(
|
156 |
+
'name' => $controller,
|
157 |
+
'description' => "<p><strong>Error</strong>: $info</p>",
|
158 |
+
'methods' => array(),
|
159 |
+
'url' => null
|
160 |
+
);
|
161 |
+
}
|
162 |
+
|
163 |
+
?>
|
164 |
+
<tr class="<?php echo ($active ? 'active' : 'inactive'); ?>">
|
165 |
+
<th class="check-column" scope="row">
|
166 |
+
<input type="checkbox" name="controllers[]" value="<?php echo $controller; ?>" />
|
167 |
+
</th>
|
168 |
+
<td class="plugin-title">
|
169 |
+
<strong><?php echo $info['name']; ?></strong>
|
170 |
+
<div class="row-actions-visible">
|
171 |
+
<?php
|
172 |
+
|
173 |
+
if ($active) {
|
174 |
+
echo '<a href="' . wp_nonce_url('options-general.php?page=json-api&action=deactivate&controller=' . $controller, 'update-options') . '" title="' . __('Deactivate this controller') . '" class="edit">' . __('Deactivate') . '</a>';
|
175 |
+
} else if (!$error) {
|
176 |
+
echo '<a href="' . wp_nonce_url('options-general.php?page=json-api&action=activate&controller=' . $controller, 'update-options') . '" title="' . __('Activate this controller') . '" class="edit">' . __('Activate') . '</a>';
|
177 |
+
}
|
178 |
+
|
179 |
+
if (!empty($info['url'])) {
|
180 |
+
echo ' | ';
|
181 |
+
echo '<a href="' . $info['url'] . '" target="_blank">Docs</a></div>';
|
182 |
+
}
|
183 |
+
|
184 |
+
?>
|
185 |
+
</td>
|
186 |
+
<td class="desc">
|
187 |
+
<p><?php echo $info['description']; ?></p>
|
188 |
+
<p>
|
189 |
+
<?php
|
190 |
+
|
191 |
+
foreach($info['methods'] as $method) {
|
192 |
+
$url = $this->get_method_url($controller, $method);
|
193 |
+
if ($active) {
|
194 |
+
echo "<code><a href=\"$url\">$method</a></code> ";
|
195 |
+
} else {
|
196 |
+
echo "<code>$method</code> ";
|
197 |
+
}
|
198 |
+
}
|
199 |
+
|
200 |
+
?>
|
201 |
+
</p>
|
202 |
+
</td>
|
203 |
+
</tr>
|
204 |
+
<?php } ?>
|
205 |
+
</tbody>
|
206 |
+
</table>
|
207 |
+
<?php $this->print_controller_actions('action2'); ?>
|
208 |
+
<h3>Address</h3>
|
209 |
+
<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>
|
210 |
+
<table class="form-table">
|
211 |
+
<tr valign="top">
|
212 |
+
<th scope="row">API base</th>
|
213 |
+
<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>
|
214 |
+
</tr>
|
215 |
+
</table>
|
216 |
+
<?php if (!get_option('permalink_structure', '')) { ?>
|
217 |
+
<br />
|
218 |
+
<p><strong>Note:</strong> User-friendly permalinks are not currently enabled. <a target="_blank" class="button" href="options-permalink.php">Change Permalinks</a>
|
219 |
+
<?php } ?>
|
220 |
+
<p class="submit">
|
221 |
+
<input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />
|
222 |
+
</p>
|
223 |
+
</form>
|
224 |
+
</div>
|
225 |
+
<?php
|
226 |
+
}
|
227 |
+
|
228 |
+
function print_controller_actions($name = 'action') {
|
229 |
+
?>
|
230 |
+
<div class="tablenav">
|
231 |
+
<div class="alignleft actions">
|
232 |
+
<select name="<?php echo $name; ?>">
|
233 |
+
<option selected="selected" value="-1">Bulk Actions</option>
|
234 |
+
<option value="activate">Activate</option>
|
235 |
+
<option value="deactivate">Deactivate</option>
|
236 |
+
</select>
|
237 |
+
<input type="submit" class="button-secondary action" id="doaction" name="doaction" value="Apply">
|
238 |
+
</div>
|
239 |
+
<div class="clear"></div>
|
240 |
+
</div>
|
241 |
+
<div class="clear"></div>
|
242 |
+
<?php
|
243 |
+
}
|
244 |
+
|
245 |
+
function get_method_url($controller, $method, $options = '') {
|
246 |
+
$url = get_bloginfo('url');
|
247 |
+
$base = get_option('json_api_base', 'api');
|
248 |
+
$permalink_structure = get_option('permalink_structure', '');
|
249 |
+
if (!empty($options) && is_array($options)) {
|
250 |
+
$args = array();
|
251 |
+
foreach ($options as $key => $value) {
|
252 |
+
$args[] = urlencode($key) . '=' . urlencode($value);
|
253 |
+
}
|
254 |
+
$args = implode('&', $args);
|
255 |
+
} else {
|
256 |
+
$args = $options;
|
257 |
+
}
|
258 |
+
if ($controller != 'core') {
|
259 |
+
$method = "$controller/$method";
|
260 |
+
}
|
261 |
+
if (!empty($base) && !empty($permalink_structure)) {
|
262 |
+
if (!empty($args)) {
|
263 |
+
$args = "?$args";
|
264 |
+
}
|
265 |
+
return "$url/$base/$method/$args";
|
266 |
+
} else {
|
267 |
+
return "$url?json=$method&$args";
|
268 |
+
}
|
269 |
+
}
|
270 |
+
|
271 |
+
function save_option($id, $value) {
|
272 |
+
$option_exists = (get_option($id, null) !== null);
|
273 |
+
if ($option_exists) {
|
274 |
+
update_option($id, $value);
|
275 |
+
} else {
|
276 |
+
add_option($id, $value);
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
function get_controllers() {
|
281 |
+
$controllers = array();
|
282 |
+
$dir = json_api_dir();
|
283 |
+
$this->check_directory_for_controllers("$dir/controllers", $controllers);
|
284 |
+
$this->check_directory_for_controllers(get_stylesheet_directory(), $controllers);
|
285 |
+
$controllers = apply_filters('json_api_controllers', $controllers);
|
286 |
+
return array_map('strtolower', $controllers);
|
287 |
+
}
|
288 |
+
|
289 |
+
function check_directory_for_controllers($dir, &$controllers) {
|
290 |
+
$dh = opendir($dir);
|
291 |
+
while ($file = readdir($dh)) {
|
292 |
+
if (preg_match('/(.+)\.php$/i', $file, $matches)) {
|
293 |
+
$src = file_get_contents("$dir/$file");
|
294 |
+
if (preg_match("/class\s+JSON_API_{$matches[1]}_Controller/i", $src)) {
|
295 |
+
$controllers[] = $matches[1];
|
296 |
+
}
|
297 |
+
}
|
298 |
+
}
|
299 |
+
}
|
300 |
+
|
301 |
+
function controller_is_active($controller) {
|
302 |
+
if (defined('JSON_API_CONTROLLERS')) {
|
303 |
+
$default = JSON_API_CONTROLLERS;
|
304 |
+
} else {
|
305 |
+
$default = 'core';
|
306 |
+
}
|
307 |
+
$active_controllers = explode(',', get_option('json_api_controllers', $default));
|
308 |
+
return (in_array($controller, $active_controllers));
|
309 |
+
}
|
310 |
+
|
311 |
+
function update_controllers($controllers) {
|
312 |
+
if (is_array($controllers)) {
|
313 |
+
return implode(',', $controllers);
|
314 |
+
} else {
|
315 |
+
return $controllers;
|
316 |
+
}
|
317 |
+
}
|
318 |
+
|
319 |
+
function controller_info($controller) {
|
320 |
+
$path = $this->controller_path($controller);
|
321 |
+
$class = $this->controller_class($controller);
|
322 |
+
$response = array(
|
323 |
+
'name' => $controller,
|
324 |
+
'description' => '(No description available)',
|
325 |
+
'methods' => array()
|
326 |
+
);
|
327 |
+
if (file_exists($path)) {
|
328 |
+
$source = file_get_contents($path);
|
329 |
+
if (preg_match('/^\s*Controller name:(.+)$/im', $source, $matches)) {
|
330 |
+
$response['name'] = trim($matches[1]);
|
331 |
+
}
|
332 |
+
if (preg_match('/^\s*Controller description:(.+)$/im', $source, $matches)) {
|
333 |
+
$response['description'] = trim($matches[1]);
|
334 |
+
}
|
335 |
+
if (preg_match('/^\s*Controller URI:(.+)$/im', $source, $matches)) {
|
336 |
+
$response['docs'] = trim($matches[1]);
|
337 |
+
}
|
338 |
+
if (!class_exists($class)) {
|
339 |
+
require_once($path);
|
340 |
+
}
|
341 |
+
$response['methods'] = get_class_methods($class);
|
342 |
+
return $response;
|
343 |
+
} else if (is_admin()) {
|
344 |
+
return "Cannot find controller class '$class' (filtered path: $path).";
|
345 |
+
} else {
|
346 |
+
$this->error("Unknown controller '$controller'.");
|
347 |
+
}
|
348 |
+
return $response;
|
349 |
+
}
|
350 |
+
|
351 |
+
function controller_class($controller) {
|
352 |
+
return "json_api_{$controller}_controller";
|
353 |
+
}
|
354 |
+
|
355 |
+
function controller_path($controller) {
|
356 |
+
$json_api_dir = json_api_dir();
|
357 |
+
$json_api_path = "$json_api_dir/controllers/$controller.php";
|
358 |
+
$theme_dir = get_stylesheet_directory();
|
359 |
+
$theme_path = "$theme_dir/$controller.php";
|
360 |
+
if (file_exists($theme_path)) {
|
361 |
+
$path = $theme_path;
|
362 |
+
} else if (file_exists($json_api_path)) {
|
363 |
+
$path = $json_api_path;
|
364 |
+
} else {
|
365 |
+
$path = null;
|
366 |
+
}
|
367 |
+
$controller_class = $this->controller_class($controller);
|
368 |
+
return apply_filters("{$controller_class}_path", $path);
|
369 |
+
}
|
370 |
+
|
371 |
+
function get_nonce_id($controller, $method) {
|
372 |
+
$controller = strtolower($controller);
|
373 |
+
$method = strtolower($method);
|
374 |
+
return "json_api-$controller-$method";
|
375 |
+
}
|
376 |
+
|
377 |
+
function flush_rewrite_rules() {
|
378 |
+
global $wp_rewrite;
|
379 |
+
$wp_rewrite->flush_rules();
|
380 |
+
}
|
381 |
+
|
382 |
+
function error($message = 'Unknown error', $http_status = 404) {
|
383 |
+
$this->response->respond(array(
|
384 |
+
'error' => $message
|
385 |
+
), 'error', $http_status);
|
386 |
+
}
|
387 |
+
|
388 |
+
function include_value($key) {
|
389 |
+
return $this->response->is_value_included($key);
|
390 |
+
}
|
391 |
+
|
392 |
+
}
|
393 |
+
|
394 |
+
?>
|
trunk/singletons/introspector.php
ADDED
@@ -0,0 +1,345 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Introspector {
|
4 |
+
|
5 |
+
public function get_posts($query = false, $wp_posts = false) {
|
6 |
+
global $post, $wp_query;
|
7 |
+
$this->set_posts_query($query);
|
8 |
+
$output = array();
|
9 |
+
while (have_posts()) {
|
10 |
+
the_post();
|
11 |
+
if ($wp_posts) {
|
12 |
+
$new_post = $post;
|
13 |
+
} else {
|
14 |
+
$new_post = new JSON_API_Post($post);
|
15 |
+
}
|
16 |
+
$output[] = $new_post;
|
17 |
+
}
|
18 |
+
return $output;
|
19 |
+
}
|
20 |
+
|
21 |
+
public function get_date_archive_permalinks() {
|
22 |
+
$archives = wp_get_archives('echo=0');
|
23 |
+
preg_match_all("/href='([^']+)'/", $archives, $matches);
|
24 |
+
return $matches[1];
|
25 |
+
}
|
26 |
+
|
27 |
+
public function get_date_archive_tree($permalinks) {
|
28 |
+
$tree = array();
|
29 |
+
foreach ($permalinks as $url) {
|
30 |
+
if (preg_match('#(\d{4})/(\d{2})#', $url, $date)) {
|
31 |
+
$year = $date[1];
|
32 |
+
$month = $date[2];
|
33 |
+
} else if (preg_match('/(\d{4})(\d{2})/', $url, $date)) {
|
34 |
+
$year = $date[1];
|
35 |
+
$month = $date[2];
|
36 |
+
} else {
|
37 |
+
continue;
|
38 |
+
}
|
39 |
+
$count = $this->get_date_archive_count($year, $month);
|
40 |
+
if (empty($tree[$year])) {
|
41 |
+
$tree[$year] = array(
|
42 |
+
$month => $count
|
43 |
+
);
|
44 |
+
} else {
|
45 |
+
$tree[$year][$month] = $count;
|
46 |
+
}
|
47 |
+
}
|
48 |
+
return $tree;
|
49 |
+
}
|
50 |
+
|
51 |
+
public function get_date_archive_count($year, $month) {
|
52 |
+
if (!isset($this->month_archives)) {
|
53 |
+
global $wpdb;
|
54 |
+
$post_counts = $wpdb->get_results("
|
55 |
+
SELECT DATE_FORMAT(post_date, '%Y%m') AS month,
|
56 |
+
COUNT(ID) AS post_count
|
57 |
+
FROM $wpdb->posts
|
58 |
+
WHERE post_status = 'publish'
|
59 |
+
AND post_type = 'post'
|
60 |
+
GROUP BY month
|
61 |
+
");
|
62 |
+
$this->month_archives = array();
|
63 |
+
foreach ($post_counts as $post_count) {
|
64 |
+
$this->month_archives[$post_count->month] = $post_count->post_count;
|
65 |
+
}
|
66 |
+
}
|
67 |
+
return $this->month_archives["$year$month"];
|
68 |
+
}
|
69 |
+
|
70 |
+
public function get_categories($args = null) {
|
71 |
+
$wp_categories = get_categories($args);
|
72 |
+
$categories = array();
|
73 |
+
foreach ($wp_categories as $wp_category) {
|
74 |
+
if ($wp_category->term_id == 1 && $wp_category->slug == 'uncategorized') {
|
75 |
+
continue;
|
76 |
+
}
|
77 |
+
$categories[] = $this->get_category_object($wp_category);
|
78 |
+
}
|
79 |
+
return $categories;
|
80 |
+
}
|
81 |
+
|
82 |
+
public function get_current_post() {
|
83 |
+
global $json_api;
|
84 |
+
extract($json_api->query->get(array('id', 'slug', 'post_id', 'post_slug')));
|
85 |
+
if ($id || $post_id) {
|
86 |
+
if (!$id) {
|
87 |
+
$id = $post_id;
|
88 |
+
}
|
89 |
+
$posts = $this->get_posts(array(
|
90 |
+
'p' => $id
|
91 |
+
), true);
|
92 |
+
} else if ($slug || $post_slug) {
|
93 |
+
if (!$slug) {
|
94 |
+
$slug = $post_slug;
|
95 |
+
}
|
96 |
+
$posts = $this->get_posts(array(
|
97 |
+
'name' => $slug
|
98 |
+
), true);
|
99 |
+
} else {
|
100 |
+
$json_api->error("Include 'id' or 'slug' var in your request.");
|
101 |
+
}
|
102 |
+
if (!empty($posts)) {
|
103 |
+
return $posts[0];
|
104 |
+
} else {
|
105 |
+
return null;
|
106 |
+
}
|
107 |
+
}
|
108 |
+
|
109 |
+
public function get_current_category() {
|
110 |
+
global $json_api;
|
111 |
+
extract($json_api->query->get(array('id', 'slug', 'category_id', 'category_slug')));
|
112 |
+
if ($id || $category_id) {
|
113 |
+
if (!$id) {
|
114 |
+
$id = $category_id;
|
115 |
+
}
|
116 |
+
return $this->get_category_by_id($id);
|
117 |
+
} else if ($slug || $category_slug) {
|
118 |
+
if (!$slug) {
|
119 |
+
$slug = $category_slug;
|
120 |
+
}
|
121 |
+
return $this->get_category_by_slug($slug);
|
122 |
+
} else {
|
123 |
+
$json_api->error("Include 'id' or 'slug' var in your request.");
|
124 |
+
}
|
125 |
+
return null;
|
126 |
+
}
|
127 |
+
|
128 |
+
public function get_category_by_id($category_id) {
|
129 |
+
$wp_category = get_term_by('id', $category_id, 'category');
|
130 |
+
return $this->get_category_object($wp_category);
|
131 |
+
}
|
132 |
+
|
133 |
+
public function get_category_by_slug($category_slug) {
|
134 |
+
$wp_category = get_term_by('slug', $category_slug, 'category');
|
135 |
+
return $this->get_category_object($wp_category);
|
136 |
+
}
|
137 |
+
|
138 |
+
public function get_tags() {
|
139 |
+
$wp_tags = get_tags();
|
140 |
+
return array_map(array(&$this, 'get_tag_object'), $wp_tags);
|
141 |
+
}
|
142 |
+
|
143 |
+
public function get_current_tag() {
|
144 |
+
global $json_api;
|
145 |
+
extract($json_api->query->get(array('id', 'slug', 'tag_id', 'tag_slug')));
|
146 |
+
if ($id || $tag_id) {
|
147 |
+
if (!$id) {
|
148 |
+
$id = $tag_id;
|
149 |
+
}
|
150 |
+
return $this->get_tag_by_id($id);
|
151 |
+
} else if ($slug || $tag_slug) {
|
152 |
+
if (!$slug) {
|
153 |
+
$slug = $tag_slug;
|
154 |
+
}
|
155 |
+
return $this->get_tag_by_slug($slug);
|
156 |
+
} else {
|
157 |
+
$json_api->error("Include 'id' or 'slug' var in your request.");
|
158 |
+
}
|
159 |
+
return null;
|
160 |
+
}
|
161 |
+
|
162 |
+
public function get_tag_by_id($tag_id) {
|
163 |
+
$wp_tag = get_term_by('id', $tag_id, 'post_tag');
|
164 |
+
return $this->get_tag_object($wp_tag);
|
165 |
+
}
|
166 |
+
|
167 |
+
public function get_tag_by_slug($tag_slug) {
|
168 |
+
$wp_tag = get_term_by('slug', $tag_slug, 'post_tag');
|
169 |
+
return $this->get_tag_object($wp_tag);
|
170 |
+
}
|
171 |
+
|
172 |
+
public function get_authors() {
|
173 |
+
global $wpdb;
|
174 |
+
$author_ids = $wpdb->get_col("
|
175 |
+
SELECT u.ID, m.meta_value AS last_name
|
176 |
+
FROM $wpdb->users AS u,
|
177 |
+
$wpdb->usermeta AS m
|
178 |
+
WHERE m.user_id = u.ID
|
179 |
+
AND m.meta_key = 'last_name'
|
180 |
+
ORDER BY last_name
|
181 |
+
");
|
182 |
+
$all_authors = array_map(array(&$this, 'get_author_by_id'), $author_ids);
|
183 |
+
$active_authors = array_filter($all_authors, array(&$this, 'is_active_author'));
|
184 |
+
return $active_authors;
|
185 |
+
}
|
186 |
+
|
187 |
+
public function get_current_author() {
|
188 |
+
global $json_api;
|
189 |
+
extract($json_api->query->get(array('id', 'slug', 'author_id', 'author_slug')));
|
190 |
+
if ($id || $author_id) {
|
191 |
+
if (!$id) {
|
192 |
+
$id = $author_id;
|
193 |
+
}
|
194 |
+
return $this->get_author_by_id($id);
|
195 |
+
} else if ($slug || $author_slug) {
|
196 |
+
if (!$slug) {
|
197 |
+
$slug = $author_slug;
|
198 |
+
}
|
199 |
+
return $this->get_author_by_login($slug);
|
200 |
+
} else {
|
201 |
+
$json_api->error("Include 'id' or 'slug' var in your request.");
|
202 |
+
}
|
203 |
+
return null;
|
204 |
+
}
|
205 |
+
|
206 |
+
public function get_author_by_id($id) {
|
207 |
+
$id = get_the_author_meta('ID', $id);
|
208 |
+
if (!$id) {
|
209 |
+
return null;
|
210 |
+
}
|
211 |
+
return new JSON_API_Author($id);
|
212 |
+
}
|
213 |
+
|
214 |
+
public function get_author_by_login($login) {
|
215 |
+
global $wpdb;
|
216 |
+
$id = $wpdb->get_var($wpdb->prepare("
|
217 |
+
SELECT ID
|
218 |
+
FROM $wpdb->users
|
219 |
+
WHERE user_nicename = %s
|
220 |
+
", $login));
|
221 |
+
return $this->get_author_by_id($id);
|
222 |
+
}
|
223 |
+
|
224 |
+
public function get_comments($post_id) {
|
225 |
+
global $wpdb;
|
226 |
+
$wp_comments = $wpdb->get_results($wpdb->prepare("
|
227 |
+
SELECT *
|
228 |
+
FROM $wpdb->comments
|
229 |
+
WHERE comment_post_ID = %d
|
230 |
+
AND comment_approved = 1
|
231 |
+
AND comment_type = ''
|
232 |
+
ORDER BY comment_date
|
233 |
+
", $post_id));
|
234 |
+
$comments = array();
|
235 |
+
foreach ($wp_comments as $wp_comment) {
|
236 |
+
$comments[] = new JSON_API_Comment($wp_comment);
|
237 |
+
}
|
238 |
+
return $comments;
|
239 |
+
}
|
240 |
+
|
241 |
+
public function get_attachments($post_id) {
|
242 |
+
$wp_attachments = get_children(array(
|
243 |
+
'post_type' => 'attachment',
|
244 |
+
'post_parent' => $post_id,
|
245 |
+
'orderby' => 'menu_order',
|
246 |
+
'order' => 'ASC',
|
247 |
+
'suppress_filters' => false
|
248 |
+
));
|
249 |
+
$attachments = array();
|
250 |
+
if (!empty($wp_attachments)) {
|
251 |
+
foreach ($wp_attachments as $wp_attachment) {
|
252 |
+
$attachments[] = new JSON_API_Attachment($wp_attachment);
|
253 |
+
}
|
254 |
+
}
|
255 |
+
return $attachments;
|
256 |
+
}
|
257 |
+
|
258 |
+
public function get_attachment($attachment_id) {
|
259 |
+
global $wpdb;
|
260 |
+
$wp_attachment = $wpdb->get_row(
|
261 |
+
$wpdb->prepare("
|
262 |
+
SELECT *
|
263 |
+
FROM $wpdb->posts
|
264 |
+
WHERE ID = %d
|
265 |
+
", $attachment_id)
|
266 |
+
);
|
267 |
+
return new JSON_API_Attachment($wp_attachment);
|
268 |
+
}
|
269 |
+
|
270 |
+
public function attach_child_posts(&$post) {
|
271 |
+
$post->children = array();
|
272 |
+
$wp_children = get_posts(array(
|
273 |
+
'post_type' => $post->type,
|
274 |
+
'post_parent' => $post->id,
|
275 |
+
'order' => 'ASC',
|
276 |
+
'orderby' => 'menu_order',
|
277 |
+
'numberposts' => -1,
|
278 |
+
'suppress_filters' => false
|
279 |
+
));
|
280 |
+
foreach ($wp_children as $wp_post) {
|
281 |
+
$new_post = new JSON_API_Post($wp_post);
|
282 |
+
$new_post->parent = $post->id;
|
283 |
+
$post->children[] = $new_post;
|
284 |
+
}
|
285 |
+
foreach ($post->children as $child) {
|
286 |
+
$this->attach_child_posts($child);
|
287 |
+
}
|
288 |
+
}
|
289 |
+
|
290 |
+
protected function get_category_object($wp_category) {
|
291 |
+
if (!$wp_category) {
|
292 |
+
return null;
|
293 |
+
}
|
294 |
+
return new JSON_API_Category($wp_category);
|
295 |
+
}
|
296 |
+
|
297 |
+
protected function get_tag_object($wp_tag) {
|
298 |
+
if (!$wp_tag) {
|
299 |
+
return null;
|
300 |
+
}
|
301 |
+
return new JSON_API_Tag($wp_tag);
|
302 |
+
}
|
303 |
+
|
304 |
+
protected function is_active_author($author) {
|
305 |
+
if (!isset($this->active_authors)) {
|
306 |
+
$this->active_authors = explode(',', wp_list_authors(array(
|
307 |
+
'html' => false,
|
308 |
+
'echo' => false,
|
309 |
+
'exclude_admin' => false
|
310 |
+
)));
|
311 |
+
$this->active_authors = array_map('trim', $this->active_authors);
|
312 |
+
}
|
313 |
+
return in_array($author->name, $this->active_authors);
|
314 |
+
}
|
315 |
+
|
316 |
+
protected function set_posts_query($query = false) {
|
317 |
+
global $json_api, $wp_query;
|
318 |
+
|
319 |
+
if (!$query) {
|
320 |
+
$query = array();
|
321 |
+
}
|
322 |
+
|
323 |
+
$query = array_merge($query, $wp_query->query);
|
324 |
+
|
325 |
+
if ($json_api->query->page) {
|
326 |
+
$query['paged'] = $json_api->query->page;
|
327 |
+
}
|
328 |
+
|
329 |
+
if ($json_api->query->count) {
|
330 |
+
$query['posts_per_page'] = $json_api->query->count;
|
331 |
+
}
|
332 |
+
|
333 |
+
if ($json_api->query->post_type) {
|
334 |
+
$query['post_type'] = $json_api->query->post_type;
|
335 |
+
}
|
336 |
+
|
337 |
+
if (!empty($query)) {
|
338 |
+
query_posts($query);
|
339 |
+
do_action('json_api_query', $wp_query);
|
340 |
+
}
|
341 |
+
}
|
342 |
+
|
343 |
+
}
|
344 |
+
|
345 |
+
?>
|
trunk/singletons/query.php
ADDED
@@ -0,0 +1,194 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Query {
|
4 |
+
|
5 |
+
// Default values
|
6 |
+
protected $defaults = array(
|
7 |
+
'date_format' => 'Y-m-d H:i:s',
|
8 |
+
'read_more' => 'Read more'
|
9 |
+
);
|
10 |
+
|
11 |
+
function __construct() {
|
12 |
+
// Register JSON API query vars
|
13 |
+
add_filter('query_vars', array(&$this, 'query_vars'));
|
14 |
+
}
|
15 |
+
|
16 |
+
function get($key) {
|
17 |
+
if (is_array($key)) {
|
18 |
+
$result = array();
|
19 |
+
foreach ($key as $k) {
|
20 |
+
$result[$k] = $this->get($k);
|
21 |
+
}
|
22 |
+
return $result;
|
23 |
+
}
|
24 |
+
$query_var = (isset($_REQUEST[$key])) ? $_REQUEST[$key] : null;
|
25 |
+
$wp_query_var = $this->wp_query_var($key);
|
26 |
+
if ($wp_query_var) {
|
27 |
+
return $wp_query_var;
|
28 |
+
} else if ($query_var) {
|
29 |
+
return $this->strip_magic_quotes($query_var);
|
30 |
+
} else if (isset($this->defaults[$key])) {
|
31 |
+
return $this->defaults[$key];
|
32 |
+
} else {
|
33 |
+
return null;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
|
37 |
+
function __get($key) {
|
38 |
+
return $this->get($key);
|
39 |
+
}
|
40 |
+
|
41 |
+
function __isset($key) {
|
42 |
+
return ($this->get($key) !== null);
|
43 |
+
}
|
44 |
+
|
45 |
+
function wp_query_var($key) {
|
46 |
+
$wp_translation = array(
|
47 |
+
'json' => 'json',
|
48 |
+
'post_id' => 'p',
|
49 |
+
'post_slug' => 'name',
|
50 |
+
'page_id' => 'page_id',
|
51 |
+
'page_slug' => 'name',
|
52 |
+
'category_id' => 'cat',
|
53 |
+
'category_slug' => 'category_name',
|
54 |
+
'tag_id' => 'tag_id',
|
55 |
+
'tag_slug' => 'tag',
|
56 |
+
'author_id' => 'author',
|
57 |
+
'author_slug' => 'author_name',
|
58 |
+
'search' => 's',
|
59 |
+
'order' => 'order',
|
60 |
+
'order_by' => 'orderby'
|
61 |
+
);
|
62 |
+
if ($key == 'date') {
|
63 |
+
$date = null;
|
64 |
+
if (get_query_var('year')) {
|
65 |
+
$date = get_query_var('year');
|
66 |
+
}
|
67 |
+
if (get_query_var('monthnum')) {
|
68 |
+
$month = get_query_var('monthnum');
|
69 |
+
if ($month < 10) {
|
70 |
+
$month = "0$month";
|
71 |
+
}
|
72 |
+
$date .= $month;
|
73 |
+
}
|
74 |
+
if (get_query_var('day')) {
|
75 |
+
$day = get_query_var('day');
|
76 |
+
if ($day < 10) {
|
77 |
+
$day = "0$day";
|
78 |
+
}
|
79 |
+
$date .= $day;
|
80 |
+
}
|
81 |
+
return $date;
|
82 |
+
} else if (isset($wp_translation[$key])) {
|
83 |
+
return get_query_var($wp_translation[$key]);
|
84 |
+
} else {
|
85 |
+
return null;
|
86 |
+
}
|
87 |
+
}
|
88 |
+
|
89 |
+
function strip_magic_quotes($value) {
|
90 |
+
if (get_magic_quotes_gpc()) {
|
91 |
+
return stripslashes($value);
|
92 |
+
} else {
|
93 |
+
return $value;
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
function query_vars($wp_vars) {
|
98 |
+
$wp_vars[] = 'json';
|
99 |
+
return $wp_vars;
|
100 |
+
}
|
101 |
+
|
102 |
+
function get_controller() {
|
103 |
+
$json = $this->get('json');
|
104 |
+
if (empty($json)) {
|
105 |
+
return false;
|
106 |
+
}
|
107 |
+
if (preg_match('/^[a-zA-Z_]+$/', $json)) {
|
108 |
+
return $this->get_legacy_controller($json);
|
109 |
+
} else if (preg_match('/^([a-zA-Z0-9_]+)(\/|\.)[a-zA-Z0-9_]+$/', $json, $matches)) {
|
110 |
+
return $matches[1];
|
111 |
+
} else {
|
112 |
+
return 'core';
|
113 |
+
}
|
114 |
+
}
|
115 |
+
|
116 |
+
function get_legacy_controller($json) {
|
117 |
+
global $json_api;
|
118 |
+
if ($json == 'submit_comment') {
|
119 |
+
if ($json_api->controller_is_active('respond')) {
|
120 |
+
return 'respond';
|
121 |
+
} else {
|
122 |
+
$json_api->error("The 'submit_comment' method has been removed from the Core controller. To use this method you must enable the Respond controller from WP Admin > Settings > JSON API.");
|
123 |
+
}
|
124 |
+
} else if ($json == 'create_post') {
|
125 |
+
if ($json_api->controller_is_active('posts')) {
|
126 |
+
return 'posts';
|
127 |
+
} else {
|
128 |
+
$json_api->error("The 'create_post' method has been removed from the Core controller. To use this method you must enable the Posts controller from WP Admin > Settings > JSON API.");
|
129 |
+
}
|
130 |
+
} else {
|
131 |
+
return 'core';
|
132 |
+
}
|
133 |
+
}
|
134 |
+
|
135 |
+
function get_method($controller) {
|
136 |
+
|
137 |
+
global $json_api;
|
138 |
+
|
139 |
+
// Returns an appropriate API method name or false. Four possible outcomes:
|
140 |
+
// 1. API isn't being invoked at all (return false)
|
141 |
+
// 2. A specific API method was requested (return method name)
|
142 |
+
// 3. A method is chosen implicitly on a given WordPress page
|
143 |
+
// 4. API invoked incorrectly (return "error" method)
|
144 |
+
//
|
145 |
+
// Note:
|
146 |
+
// The implicit outcome (3) is invoked by setting the json query var to a
|
147 |
+
// non-empty value on any WordPress page:
|
148 |
+
// * http://example.org/2009/11/10/hello-world/?json=1 (get_post)
|
149 |
+
// * http://example.org/2009/11/?json=1 (get_date_posts)
|
150 |
+
// * http://example.org/category/foo?json=1 (get_category_posts)
|
151 |
+
|
152 |
+
$method = $this->get('json');
|
153 |
+
if (strpos($method, '/') !== false) {
|
154 |
+
$method = substr($method, strpos($method, '/') + 1);
|
155 |
+
} else if (strpos($method, '.') !== false) {
|
156 |
+
$method = substr($method, strpos($method, '.') + 1);
|
157 |
+
}
|
158 |
+
|
159 |
+
if (empty($method)) {
|
160 |
+
// Case 1: we're not being invoked (done!)
|
161 |
+
return false;
|
162 |
+
} else if (method_exists("JSON_API_{$controller}_Controller", $method)) {
|
163 |
+
// Case 2: an explicit method was specified
|
164 |
+
return $method;
|
165 |
+
} else if ($controller == 'core') {
|
166 |
+
// Case 3: choose the method implicitly based on which page we're on...
|
167 |
+
if (is_search()) {
|
168 |
+
return 'get_search_results';
|
169 |
+
} else if (is_home()) {
|
170 |
+
if (empty($_GET['json'])) {
|
171 |
+
$json_api->error("Unknown method '$method'.");
|
172 |
+
}
|
173 |
+
return 'get_recent_posts';
|
174 |
+
} else if (is_page()) {
|
175 |
+
return 'get_page';
|
176 |
+
} else if (is_single()) {
|
177 |
+
return 'get_post';
|
178 |
+
} else if (is_category()) {
|
179 |
+
return 'get_category_posts';
|
180 |
+
} else if (is_tag()) {
|
181 |
+
return 'get_tag_posts';
|
182 |
+
} else if (is_author()) {
|
183 |
+
return 'get_author_posts';
|
184 |
+
} else if (is_date()) {
|
185 |
+
return 'get_date_posts';
|
186 |
+
} else if (is_404()) {
|
187 |
+
return '404';
|
188 |
+
}
|
189 |
+
}
|
190 |
+
// Case 4: either the method doesn't exist or we don't support the page implicitly
|
191 |
+
return 'error';
|
192 |
+
}
|
193 |
+
|
194 |
+
}
|
trunk/singletons/response.php
ADDED
@@ -0,0 +1,205 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
class JSON_API_Response {
|
4 |
+
|
5 |
+
function setup() {
|
6 |
+
global $json_api;
|
7 |
+
$this->include_values = array();
|
8 |
+
$this->exclude_values = array();
|
9 |
+
if ($json_api->query->include) {
|
10 |
+
$this->include_values = explode(',', $json_api->query->include);
|
11 |
+
}
|
12 |
+
// Props to ikesyo for submitting a fix!
|
13 |
+
if ($json_api->query->exclude) {
|
14 |
+
$this->exclude_values = explode(',', $json_api->query->exclude);
|
15 |
+
$this->include_values = array_diff($this->include_values, $this->exclude_values);
|
16 |
+
}
|
17 |
+
|
18 |
+
// Compatibility with Disqus plugin
|
19 |
+
remove_action('loop_end', 'dsq_loop_end');
|
20 |
+
}
|
21 |
+
|
22 |
+
function get_json($data, $status = 'ok') {
|
23 |
+
global $json_api;
|
24 |
+
// Include a status value with the response
|
25 |
+
if (is_array($data)) {
|
26 |
+
$data = array_merge(array('status' => $status), $data);
|
27 |
+
} else if (is_object($data)) {
|
28 |
+
$data = get_object_vars($data);
|
29 |
+
$data = array_merge(array('status' => $status), $data);
|
30 |
+
}
|
31 |
+
|
32 |
+
$data = apply_filters('json_api_encode', $data);
|
33 |
+
|
34 |
+
if (function_exists('json_encode')) {
|
35 |
+
// Use the built-in json_encode function if it's available
|
36 |
+
if (version_compare(PHP_VERSION, '5.3') < 0) {
|
37 |
+
$json = json_encode($data);
|
38 |
+
} else {
|
39 |
+
$json_encode_options = 0;
|
40 |
+
if ($json_api->query->json_encode_options) {
|
41 |
+
$json_encode_options = $json_api->query->json_encode_options;
|
42 |
+
}
|
43 |
+
$json = json_encode($data, $json_encode_options);
|
44 |
+
}
|
45 |
+
} else {
|
46 |
+
// Use PEAR's Services_JSON encoder otherwise
|
47 |
+
if (!class_exists('Services_JSON')) {
|
48 |
+
$dir = json_api_dir();
|
49 |
+
require_once "$dir/library/JSON.php";
|
50 |
+
}
|
51 |
+
$json_service = new Services_JSON();
|
52 |
+
$json = $json_service->encode($data);
|
53 |
+
}
|
54 |
+
|
55 |
+
// Thanks to Stack Overflow user Gumbo stackoverflow.com/questions/2934563
|
56 |
+
if ($json_api->query->json_unescaped_unicode) {
|
57 |
+
$callback = array($this, 'replace_unicode_escape_sequence');
|
58 |
+
$json = preg_replace_callback('/\\\\u([0-9a-f]{4})/i', $callback, $json);
|
59 |
+
}
|
60 |
+
|
61 |
+
return $json;
|
62 |
+
}
|
63 |
+
|
64 |
+
function is_value_included($key) {
|
65 |
+
// Props to ikesyo for submitting a fix!
|
66 |
+
if (empty($this->include_values) && empty($this->exclude_values)) {
|
67 |
+
return true;
|
68 |
+
} else {
|
69 |
+
if (empty($this->exclude_values)) {
|
70 |
+
return in_array($key, $this->include_values);
|
71 |
+
} else {
|
72 |
+
return !in_array($key, $this->exclude_values);
|
73 |
+
}
|
74 |
+
}
|
75 |
+
}
|
76 |
+
|
77 |
+
function respond($result, $status = 'ok', $http_status = 200) {
|
78 |
+
global $json_api;
|
79 |
+
$json = $this->get_json($result, $status);
|
80 |
+
$status_redirect = "redirect_$status";
|
81 |
+
if ($json_api->query->dev || !empty($_REQUEST['dev'])) {
|
82 |
+
// Output the result in a human-redable format
|
83 |
+
if (!headers_sent()) {
|
84 |
+
header('HTTP/1.1 200 OK');
|
85 |
+
header('Content-Type: text/plain; charset: UTF-8', true);
|
86 |
+
} else {
|
87 |
+
echo '<pre>';
|
88 |
+
}
|
89 |
+
echo $this->prettify($json);
|
90 |
+
} else if (!empty($_REQUEST[$status_redirect])) {
|
91 |
+
wp_redirect($_REQUEST[$status_redirect]);
|
92 |
+
} else if ($json_api->query->redirect) {
|
93 |
+
$url = $this->add_status_query_var($json_api->query->redirect, $status);
|
94 |
+
wp_redirect($url);
|
95 |
+
} else if ($json_api->query->callback) {
|
96 |
+
// Run a JSONP-style callback with the result
|
97 |
+
$this->callback($json_api->query->callback, $json);
|
98 |
+
} else {
|
99 |
+
// Output the result
|
100 |
+
$this->output($json, $http_status);
|
101 |
+
}
|
102 |
+
exit;
|
103 |
+
}
|
104 |
+
|
105 |
+
function output($result, $http_status = 200) {
|
106 |
+
$charset = get_option('blog_charset');
|
107 |
+
if (!headers_sent()) {
|
108 |
+
status_header($http_status);
|
109 |
+
header("Content-Type: application/json; charset=$charset", true);
|
110 |
+
}
|
111 |
+
echo $result;
|
112 |
+
}
|
113 |
+
|
114 |
+
function callback($callback, $result) {
|
115 |
+
$charset = get_option('blog_charset');
|
116 |
+
if (!headers_sent()) {
|
117 |
+
status_header(200);
|
118 |
+
header("Content-Type: application/javascript; charset=$charset", true);
|
119 |
+
}
|
120 |
+
echo "$callback($result)";
|
121 |
+
}
|
122 |
+
|
123 |
+
function add_status_query_var($url, $status) {
|
124 |
+
if (strpos($url, '#')) {
|
125 |
+
// Remove the anchor hash for now
|
126 |
+
$pos = strpos($url, '#');
|
127 |
+
$anchor = substr($url, $pos);
|
128 |
+
$url = substr($url, 0, $pos);
|
129 |
+
}
|
130 |
+
if (strpos($url, '?')) {
|
131 |
+
$url .= "&status=$status";
|
132 |
+
} else {
|
133 |
+
$url .= "?status=$status";
|
134 |
+
}
|
135 |
+
if (!empty($anchor)) {
|
136 |
+
// Add the anchor hash back in
|
137 |
+
$url .= $anchor;
|
138 |
+
}
|
139 |
+
return $url;
|
140 |
+
}
|
141 |
+
|
142 |
+
function prettify($ugly) {
|
143 |
+
$pretty = "";
|
144 |
+
$indent = "";
|
145 |
+
$last = '';
|
146 |
+
$pos = 0;
|
147 |
+
$level = 0;
|
148 |
+
$string = false;
|
149 |
+
while ($pos < strlen($ugly)) {
|
150 |
+
$char = substr($ugly, $pos++, 1);
|
151 |
+
if (!$string) {
|
152 |
+
if ($char == '{' || $char == '[') {
|
153 |
+
if ($char == '[' && substr($ugly, $pos, 1) == ']') {
|
154 |
+
$pretty .= "[]";
|
155 |
+
$pos++;
|
156 |
+
} else if ($char == '{' && substr($ugly, $pos, 1) == '}') {
|
157 |
+
$pretty .= "{}";
|
158 |
+
$pos++;
|
159 |
+
} else {
|
160 |
+
$pretty .= "$char\n";
|
161 |
+
$indent = str_repeat(' ', ++$level);
|
162 |
+
$pretty .= "$indent";
|
163 |
+
}
|
164 |
+
} else if ($char == '}' || $char == ']') {
|
165 |
+
$indent = str_repeat(' ', --$level);
|
166 |
+
if ($last != '}' && $last != ']') {
|
167 |
+
$pretty .= "\n$indent";
|
168 |
+
} else if (substr($pretty, -2, 2) == ' ') {
|
169 |
+
$pretty = substr($pretty, 0, -2);
|
170 |
+
}
|
171 |
+
$pretty .= $char;
|
172 |
+
if (substr($ugly, $pos, 1) == ',') {
|
173 |
+
$pretty .= ",";
|
174 |
+
$last = ',';
|
175 |
+
$pos++;
|
176 |
+
}
|
177 |
+
$pretty .= "\n$indent";
|
178 |
+
} else if ($char == ':') {
|
179 |
+
$pretty .= ": ";
|
180 |
+
} else if ($char == ',') {
|
181 |
+
$pretty .= ",\n$indent";
|
182 |
+
} else if ($char == '"') {
|
183 |
+
$pretty .= '"';
|
184 |
+
$string = true;
|
185 |
+
} else {
|
186 |
+
$pretty .= $char;
|
187 |
+
}
|
188 |
+
} else {
|
189 |
+
if ($last != '\\' && $char == '"') {
|
190 |
+
$string = false;
|
191 |
+
}
|
192 |
+
$pretty .= $char;
|
193 |
+
}
|
194 |
+
$last = $char;
|
195 |
+
}
|
196 |
+
return $pretty;
|
197 |
+
}
|
198 |
+
|
199 |
+
function replace_unicode_escape_sequence($match) {
|
200 |
+
return mb_convert_encoding(pack('H*', $match[1]), 'UTF-8', 'UCS-2BE');
|
201 |
+
}
|
202 |
+
|
203 |
+
}
|
204 |
+
|
205 |
+
?>
|
trunk/tests/core.get_author_index-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_author_index
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_author_index&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$author = $response->authors[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Author count: $response->count\n";
|
15 |
+
echo "Author name: $author->name\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Author count: 1
|
21 |
+
Author name: themedemos
|
trunk/tests/core.get_author_posts-01.phpt
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_author_posts by slug
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_author_posts&slug=themedemos&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$author = $response->author;
|
12 |
+
$post = $response->posts[0];
|
13 |
+
|
14 |
+
echo "Response status: $response->status\n";
|
15 |
+
echo "Post count: $response->count\n";
|
16 |
+
echo "First post title: $post->title\n";
|
17 |
+
|
18 |
+
?>
|
19 |
+
--EXPECT--
|
20 |
+
Response status: ok
|
21 |
+
Post count: 10
|
22 |
+
First post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_author_posts-02.phpt
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_author_posts by author_slug
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_author_posts&author_slug=themedemos&page=2&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$author = $response->author;
|
12 |
+
$post = $response->posts[0];
|
13 |
+
|
14 |
+
echo "Response status: $response->status\n";
|
15 |
+
echo "Post count: $response->count\n";
|
16 |
+
echo "First post title: $post->title\n";
|
17 |
+
|
18 |
+
?>
|
19 |
+
--EXPECT--
|
20 |
+
Response status: ok
|
21 |
+
Post count: 10
|
22 |
+
First post title: Template: Paginated
|
trunk/tests/core.get_author_posts-03.phpt
ADDED
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_author_posts by id
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_author_posts&id=2&count=20&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$author = $response->author;
|
12 |
+
$post = $response->posts[0];
|
13 |
+
|
14 |
+
echo "Response status: $response->status\n";
|
15 |
+
echo "Post count: $response->count\n";
|
16 |
+
echo "First post title: $post->title\n";
|
17 |
+
|
18 |
+
?>
|
19 |
+
--EXPECT--
|
20 |
+
Response status: ok
|
21 |
+
Post count: 20
|
22 |
+
First post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_category_index-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_category_index
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_category_index&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$category = $response->categories[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Category count: $response->count\n";
|
15 |
+
echo "Category name: $category->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Category count: 63
|
21 |
+
Category name: aciform
|
trunk/tests/core.get_category_posts-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_category_posts default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_category_posts&slug=markup&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 6
|
21 |
+
Post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_date_index-01.phpt
ADDED
@@ -0,0 +1,80 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_search_posts default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_date_index&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$count = count($response->permalinks);
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Permalink count: $count\n";
|
15 |
+
echo "Tree:\n";
|
16 |
+
var_dump($response->tree);
|
17 |
+
|
18 |
+
|
19 |
+
?>
|
20 |
+
--EXPECT--
|
21 |
+
Response status: ok
|
22 |
+
Permalink count: 20
|
23 |
+
Tree:
|
24 |
+
object(stdClass)#5 (5) {
|
25 |
+
["2013"]=>
|
26 |
+
object(stdClass)#6 (1) {
|
27 |
+
["01"]=>
|
28 |
+
string(1) "5"
|
29 |
+
}
|
30 |
+
["2012"]=>
|
31 |
+
object(stdClass)#4 (2) {
|
32 |
+
["03"]=>
|
33 |
+
string(1) "5"
|
34 |
+
["01"]=>
|
35 |
+
string(1) "6"
|
36 |
+
}
|
37 |
+
["2011"]=>
|
38 |
+
object(stdClass)#7 (1) {
|
39 |
+
["03"]=>
|
40 |
+
string(1) "1"
|
41 |
+
}
|
42 |
+
["2010"]=>
|
43 |
+
object(stdClass)#8 (10) {
|
44 |
+
["10"]=>
|
45 |
+
string(1) "1"
|
46 |
+
["09"]=>
|
47 |
+
string(1) "2"
|
48 |
+
["08"]=>
|
49 |
+
string(1) "3"
|
50 |
+
["07"]=>
|
51 |
+
string(1) "1"
|
52 |
+
["06"]=>
|
53 |
+
string(1) "3"
|
54 |
+
["05"]=>
|
55 |
+
string(1) "1"
|
56 |
+
["04"]=>
|
57 |
+
string(1) "1"
|
58 |
+
["03"]=>
|
59 |
+
string(1) "1"
|
60 |
+
["02"]=>
|
61 |
+
string(1) "1"
|
62 |
+
["01"]=>
|
63 |
+
string(1) "1"
|
64 |
+
}
|
65 |
+
["2009"]=>
|
66 |
+
object(stdClass)#9 (6) {
|
67 |
+
["10"]=>
|
68 |
+
string(1) "1"
|
69 |
+
["09"]=>
|
70 |
+
string(1) "1"
|
71 |
+
["08"]=>
|
72 |
+
string(1) "1"
|
73 |
+
["07"]=>
|
74 |
+
string(1) "1"
|
75 |
+
["06"]=>
|
76 |
+
string(1) "1"
|
77 |
+
["05"]=>
|
78 |
+
string(1) "1"
|
79 |
+
}
|
80 |
+
}
|
trunk/tests/core.get_date_posts-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_date_posts by day
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_date_posts&date=2013-01&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 5
|
21 |
+
Post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_date_posts-02.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_date_posts by month
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_date_posts&date=2013-01&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 5
|
21 |
+
Post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_date_posts-03.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_date_posts by year
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_date_posts&date=2012&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 10
|
21 |
+
Post title: Template: Featured Image (Vertical)
|
trunk/tests/core.get_page-01.phpt
ADDED
@@ -0,0 +1,19 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_page default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_page&slug=about&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
|
12 |
+
echo "Response status: $response->status\n";
|
13 |
+
echo "Page title: {$response->page->title}\n";
|
14 |
+
|
15 |
+
|
16 |
+
?>
|
17 |
+
--EXPECT--
|
18 |
+
Response status: ok
|
19 |
+
Page title: About The Tests
|
trunk/tests/core.get_page-02.phpt
ADDED
@@ -0,0 +1,25 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_page children argument
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_page&slug=level-1&children=1&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$page = $response->page;
|
12 |
+
$child = $page->children[0];
|
13 |
+
$grandchild = $child->children[0];
|
14 |
+
|
15 |
+
echo "Response status: $response->status\n";
|
16 |
+
echo "Page title: $page->title\n";
|
17 |
+
echo "Child title: $child->title\n";
|
18 |
+
echo "Grandchild title: $grandchild->title\n";
|
19 |
+
|
20 |
+
?>
|
21 |
+
--EXPECT--
|
22 |
+
Response status: ok
|
23 |
+
Page title: Level 1
|
24 |
+
Child title: Level 2
|
25 |
+
Grandchild title: Level 3
|
trunk/tests/core.get_post-01.phpt
ADDED
@@ -0,0 +1,18 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_post default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_post&slug=markup-html-tags-and-formatting&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
|
12 |
+
echo "Response status: $response->status\n";
|
13 |
+
echo "post title: {$response->post->title}\n";
|
14 |
+
|
15 |
+
?>
|
16 |
+
--EXPECT--
|
17 |
+
Response status: ok
|
18 |
+
post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_posts-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_posts default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_posts&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 10
|
21 |
+
Post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.get_posts-02.phpt
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_posts by meta key
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_posts&meta_key=enclosure&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
$attachment = $post->attachments[0];
|
13 |
+
|
14 |
+
echo "Response status: $response->status\n";
|
15 |
+
echo "Post count: $response->count\n";
|
16 |
+
echo "Post title: $post->title\n";
|
17 |
+
echo "Attachment title: $attachment->title\n";
|
18 |
+
|
19 |
+
?>
|
20 |
+
--EXPECT--
|
21 |
+
Response status: ok
|
22 |
+
Post count: 1
|
23 |
+
Post title: Post Format: Audio
|
24 |
+
Attachment title: St. Louis Blues
|
trunk/tests/core.get_posts-03.phpt
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_posts by meta value
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_posts&meta_key=_wp_old_slug&meta_value=excerpt&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
echo "Post slug: $post->slug\n";
|
17 |
+
|
18 |
+
?>
|
19 |
+
--EXPECT--
|
20 |
+
Response status: ok
|
21 |
+
Post count: 1
|
22 |
+
Post title: Template: Excerpt (Defined)
|
23 |
+
Post slug: template-excerpt-defined
|
trunk/tests/core.get_recent_posts-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_recent_posts default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_recent_posts&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 11
|
21 |
+
Post title: Template: Sticky
|
trunk/tests/core.get_recent_posts-02.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_recent_posts count argument
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_recent_posts&count=3&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[3];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 4
|
21 |
+
Post title: Markup: Text Alignment
|
trunk/tests/core.get_recent_posts-03.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_recent_posts page argument
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_recent_posts&page=2&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 10
|
21 |
+
Post title: Template: Paginated
|
trunk/tests/core.get_search_posts-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_search_posts default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_search_results&search=foolish&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 2
|
21 |
+
Post title: Page Markup And Formatting
|
trunk/tests/core.get_tag_index-01.phpt
ADDED
@@ -0,0 +1,803 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_tag_index
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_tag_index&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
|
12 |
+
echo "Response status: $response->status\n";
|
13 |
+
echo "Tag count: $response->count\n";
|
14 |
+
echo "Tags:\n";
|
15 |
+
var_dump($response->tags);
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Tag count: 60
|
21 |
+
Tags:
|
22 |
+
array(60) {
|
23 |
+
[0]=>
|
24 |
+
object(stdClass)#5 (5) {
|
25 |
+
["id"]=>
|
26 |
+
int(66)
|
27 |
+
["slug"]=>
|
28 |
+
string(4) "8bit"
|
29 |
+
["title"]=>
|
30 |
+
string(4) "8BIT"
|
31 |
+
["description"]=>
|
32 |
+
string(22) "Tags posts about 8BIT."
|
33 |
+
["post_count"]=>
|
34 |
+
int(1)
|
35 |
+
}
|
36 |
+
[1]=>
|
37 |
+
object(stdClass)#6 (5) {
|
38 |
+
["id"]=>
|
39 |
+
int(67)
|
40 |
+
["slug"]=>
|
41 |
+
string(11) "alignment-2"
|
42 |
+
["title"]=>
|
43 |
+
string(9) "alignment"
|
44 |
+
["description"]=>
|
45 |
+
string(0) ""
|
46 |
+
["post_count"]=>
|
47 |
+
int(3)
|
48 |
+
}
|
49 |
+
[2]=>
|
50 |
+
object(stdClass)#4 (5) {
|
51 |
+
["id"]=>
|
52 |
+
int(68)
|
53 |
+
["slug"]=>
|
54 |
+
string(8) "articles"
|
55 |
+
["title"]=>
|
56 |
+
string(8) "Articles"
|
57 |
+
["description"]=>
|
58 |
+
string(26) "Tags posts about Articles."
|
59 |
+
["post_count"]=>
|
60 |
+
int(1)
|
61 |
+
}
|
62 |
+
[3]=>
|
63 |
+
object(stdClass)#7 (5) {
|
64 |
+
["id"]=>
|
65 |
+
int(69)
|
66 |
+
["slug"]=>
|
67 |
+
string(5) "aside"
|
68 |
+
["title"]=>
|
69 |
+
string(5) "aside"
|
70 |
+
["description"]=>
|
71 |
+
string(0) ""
|
72 |
+
["post_count"]=>
|
73 |
+
int(1)
|
74 |
+
}
|
75 |
+
[4]=>
|
76 |
+
object(stdClass)#8 (5) {
|
77 |
+
["id"]=>
|
78 |
+
int(70)
|
79 |
+
["slug"]=>
|
80 |
+
string(5) "audio"
|
81 |
+
["title"]=>
|
82 |
+
string(5) "audio"
|
83 |
+
["description"]=>
|
84 |
+
string(0) ""
|
85 |
+
["post_count"]=>
|
86 |
+
int(1)
|
87 |
+
}
|
88 |
+
[5]=>
|
89 |
+
object(stdClass)#9 (5) {
|
90 |
+
["id"]=>
|
91 |
+
int(71)
|
92 |
+
["slug"]=>
|
93 |
+
string(10) "captions-2"
|
94 |
+
["title"]=>
|
95 |
+
string(8) "captions"
|
96 |
+
["description"]=>
|
97 |
+
string(0) ""
|
98 |
+
["post_count"]=>
|
99 |
+
int(2)
|
100 |
+
}
|
101 |
+
[6]=>
|
102 |
+
object(stdClass)#10 (5) {
|
103 |
+
["id"]=>
|
104 |
+
int(72)
|
105 |
+
["slug"]=>
|
106 |
+
string(10) "categories"
|
107 |
+
["title"]=>
|
108 |
+
string(10) "categories"
|
109 |
+
["description"]=>
|
110 |
+
string(0) ""
|
111 |
+
["post_count"]=>
|
112 |
+
int(2)
|
113 |
+
}
|
114 |
+
[7]=>
|
115 |
+
object(stdClass)#11 (5) {
|
116 |
+
["id"]=>
|
117 |
+
int(73)
|
118 |
+
["slug"]=>
|
119 |
+
string(4) "chat"
|
120 |
+
["title"]=>
|
121 |
+
string(4) "chat"
|
122 |
+
["description"]=>
|
123 |
+
string(0) ""
|
124 |
+
["post_count"]=>
|
125 |
+
int(2)
|
126 |
+
}
|
127 |
+
[8]=>
|
128 |
+
object(stdClass)#12 (5) {
|
129 |
+
["id"]=>
|
130 |
+
int(77)
|
131 |
+
["slug"]=>
|
132 |
+
string(5) "codex"
|
133 |
+
["title"]=>
|
134 |
+
string(5) "Codex"
|
135 |
+
["description"]=>
|
136 |
+
string(0) ""
|
137 |
+
["post_count"]=>
|
138 |
+
int(3)
|
139 |
+
}
|
140 |
+
[9]=>
|
141 |
+
object(stdClass)#13 (5) {
|
142 |
+
["id"]=>
|
143 |
+
int(78)
|
144 |
+
["slug"]=>
|
145 |
+
string(10) "comments-2"
|
146 |
+
["title"]=>
|
147 |
+
string(8) "comments"
|
148 |
+
["description"]=>
|
149 |
+
string(0) ""
|
150 |
+
["post_count"]=>
|
151 |
+
int(4)
|
152 |
+
}
|
153 |
+
[10]=>
|
154 |
+
object(stdClass)#14 (5) {
|
155 |
+
["id"]=>
|
156 |
+
int(79)
|
157 |
+
["slug"]=>
|
158 |
+
string(9) "content-2"
|
159 |
+
["title"]=>
|
160 |
+
string(7) "content"
|
161 |
+
["description"]=>
|
162 |
+
string(0) ""
|
163 |
+
["post_count"]=>
|
164 |
+
int(12)
|
165 |
+
}
|
166 |
+
[11]=>
|
167 |
+
object(stdClass)#15 (5) {
|
168 |
+
["id"]=>
|
169 |
+
int(81)
|
170 |
+
["slug"]=>
|
171 |
+
string(3) "css"
|
172 |
+
["title"]=>
|
173 |
+
string(3) "css"
|
174 |
+
["description"]=>
|
175 |
+
string(0) ""
|
176 |
+
["post_count"]=>
|
177 |
+
int(7)
|
178 |
+
}
|
179 |
+
[12]=>
|
180 |
+
object(stdClass)#16 (5) {
|
181 |
+
["id"]=>
|
182 |
+
int(85)
|
183 |
+
["slug"]=>
|
184 |
+
string(6) "dowork"
|
185 |
+
["title"]=>
|
186 |
+
string(6) "dowork"
|
187 |
+
["description"]=>
|
188 |
+
string(25) "Tags posts about #dowork."
|
189 |
+
["post_count"]=>
|
190 |
+
int(1)
|
191 |
+
}
|
192 |
+
[13]=>
|
193 |
+
object(stdClass)#17 (5) {
|
194 |
+
["id"]=>
|
195 |
+
int(86)
|
196 |
+
["slug"]=>
|
197 |
+
string(9) "edge-case"
|
198 |
+
["title"]=>
|
199 |
+
string(9) "edge case"
|
200 |
+
["description"]=>
|
201 |
+
string(0) ""
|
202 |
+
["post_count"]=>
|
203 |
+
int(8)
|
204 |
+
}
|
205 |
+
[14]=>
|
206 |
+
object(stdClass)#18 (5) {
|
207 |
+
["id"]=>
|
208 |
+
int(87)
|
209 |
+
["slug"]=>
|
210 |
+
string(8) "embeds-2"
|
211 |
+
["title"]=>
|
212 |
+
string(6) "embeds"
|
213 |
+
["description"]=>
|
214 |
+
string(0) ""
|
215 |
+
["post_count"]=>
|
216 |
+
int(4)
|
217 |
+
}
|
218 |
+
[15]=>
|
219 |
+
object(stdClass)#19 (5) {
|
220 |
+
["id"]=>
|
221 |
+
int(91)
|
222 |
+
["slug"]=>
|
223 |
+
string(9) "excerpt-2"
|
224 |
+
["title"]=>
|
225 |
+
string(7) "excerpt"
|
226 |
+
["description"]=>
|
227 |
+
string(0) ""
|
228 |
+
["post_count"]=>
|
229 |
+
int(3)
|
230 |
+
}
|
231 |
+
[16]=>
|
232 |
+
object(stdClass)#20 (5) {
|
233 |
+
["id"]=>
|
234 |
+
int(92)
|
235 |
+
["slug"]=>
|
236 |
+
string(4) "fail"
|
237 |
+
["title"]=>
|
238 |
+
string(4) "Fail"
|
239 |
+
["description"]=>
|
240 |
+
string(22) "Tags posts about fail."
|
241 |
+
["post_count"]=>
|
242 |
+
int(1)
|
243 |
+
}
|
244 |
+
[17]=>
|
245 |
+
object(stdClass)#21 (5) {
|
246 |
+
["id"]=>
|
247 |
+
int(93)
|
248 |
+
["slug"]=>
|
249 |
+
string(14) "featured-image"
|
250 |
+
["title"]=>
|
251 |
+
string(14) "featured image"
|
252 |
+
["description"]=>
|
253 |
+
string(0) ""
|
254 |
+
["post_count"]=>
|
255 |
+
int(3)
|
256 |
+
}
|
257 |
+
[18]=>
|
258 |
+
object(stdClass)#22 (5) {
|
259 |
+
["id"]=>
|
260 |
+
int(96)
|
261 |
+
["slug"]=>
|
262 |
+
string(12) "formatting-2"
|
263 |
+
["title"]=>
|
264 |
+
string(10) "formatting"
|
265 |
+
["description"]=>
|
266 |
+
string(0) ""
|
267 |
+
["post_count"]=>
|
268 |
+
int(1)
|
269 |
+
}
|
270 |
+
[19]=>
|
271 |
+
object(stdClass)#23 (5) {
|
272 |
+
["id"]=>
|
273 |
+
int(97)
|
274 |
+
["slug"]=>
|
275 |
+
string(3) "ftw"
|
276 |
+
["title"]=>
|
277 |
+
string(3) "FTW"
|
278 |
+
["description"]=>
|
279 |
+
string(0) ""
|
280 |
+
["post_count"]=>
|
281 |
+
int(1)
|
282 |
+
}
|
283 |
+
[20]=>
|
284 |
+
object(stdClass)#24 (5) {
|
285 |
+
["id"]=>
|
286 |
+
int(98)
|
287 |
+
["slug"]=>
|
288 |
+
string(3) "fun"
|
289 |
+
["title"]=>
|
290 |
+
string(3) "Fun"
|
291 |
+
["description"]=>
|
292 |
+
string(21) "Tags posts about fun."
|
293 |
+
["post_count"]=>
|
294 |
+
int(1)
|
295 |
+
}
|
296 |
+
[21]=>
|
297 |
+
object(stdClass)#25 (5) {
|
298 |
+
["id"]=>
|
299 |
+
int(99)
|
300 |
+
["slug"]=>
|
301 |
+
string(7) "gallery"
|
302 |
+
["title"]=>
|
303 |
+
string(7) "gallery"
|
304 |
+
["description"]=>
|
305 |
+
string(0) ""
|
306 |
+
["post_count"]=>
|
307 |
+
int(3)
|
308 |
+
}
|
309 |
+
[22]=>
|
310 |
+
object(stdClass)#26 (5) {
|
311 |
+
["id"]=>
|
312 |
+
int(105)
|
313 |
+
["slug"]=>
|
314 |
+
string(4) "html"
|
315 |
+
["title"]=>
|
316 |
+
string(4) "html"
|
317 |
+
["description"]=>
|
318 |
+
string(0) ""
|
319 |
+
["post_count"]=>
|
320 |
+
int(5)
|
321 |
+
}
|
322 |
+
[23]=>
|
323 |
+
object(stdClass)#27 (5) {
|
324 |
+
["id"]=>
|
325 |
+
int(106)
|
326 |
+
["slug"]=>
|
327 |
+
string(5) "image"
|
328 |
+
["title"]=>
|
329 |
+
string(5) "image"
|
330 |
+
["description"]=>
|
331 |
+
string(0) ""
|
332 |
+
["post_count"]=>
|
333 |
+
int(7)
|
334 |
+
}
|
335 |
+
[24]=>
|
336 |
+
object(stdClass)#28 (5) {
|
337 |
+
["id"]=>
|
338 |
+
int(109)
|
339 |
+
["slug"]=>
|
340 |
+
string(9) "jetpack-2"
|
341 |
+
["title"]=>
|
342 |
+
string(7) "jetpack"
|
343 |
+
["description"]=>
|
344 |
+
string(0) ""
|
345 |
+
["post_count"]=>
|
346 |
+
int(3)
|
347 |
+
}
|
348 |
+
[25]=>
|
349 |
+
object(stdClass)#29 (5) {
|
350 |
+
["id"]=>
|
351 |
+
int(111)
|
352 |
+
["slug"]=>
|
353 |
+
string(6) "layout"
|
354 |
+
["title"]=>
|
355 |
+
string(6) "layout"
|
356 |
+
["description"]=>
|
357 |
+
string(0) ""
|
358 |
+
["post_count"]=>
|
359 |
+
int(4)
|
360 |
+
}
|
361 |
+
[26]=>
|
362 |
+
object(stdClass)#30 (5) {
|
363 |
+
["id"]=>
|
364 |
+
int(112)
|
365 |
+
["slug"]=>
|
366 |
+
string(4) "link"
|
367 |
+
["title"]=>
|
368 |
+
string(4) "link"
|
369 |
+
["description"]=>
|
370 |
+
string(0) ""
|
371 |
+
["post_count"]=>
|
372 |
+
int(2)
|
373 |
+
}
|
374 |
+
[27]=>
|
375 |
+
object(stdClass)#31 (5) {
|
376 |
+
["id"]=>
|
377 |
+
int(113)
|
378 |
+
["slug"]=>
|
379 |
+
string(7) "lists-2"
|
380 |
+
["title"]=>
|
381 |
+
string(5) "lists"
|
382 |
+
["description"]=>
|
383 |
+
string(0) ""
|
384 |
+
["post_count"]=>
|
385 |
+
int(1)
|
386 |
+
}
|
387 |
+
[28]=>
|
388 |
+
object(stdClass)#32 (5) {
|
389 |
+
["id"]=>
|
390 |
+
int(115)
|
391 |
+
["slug"]=>
|
392 |
+
string(4) "love"
|
393 |
+
["title"]=>
|
394 |
+
string(4) "Love"
|
395 |
+
["description"]=>
|
396 |
+
string(22) "Tags posts about love."
|
397 |
+
["post_count"]=>
|
398 |
+
int(1)
|
399 |
+
}
|
400 |
+
[29]=>
|
401 |
+
object(stdClass)#33 (5) {
|
402 |
+
["id"]=>
|
403 |
+
int(116)
|
404 |
+
["slug"]=>
|
405 |
+
string(8) "markup-2"
|
406 |
+
["title"]=>
|
407 |
+
string(6) "markup"
|
408 |
+
["description"]=>
|
409 |
+
string(0) ""
|
410 |
+
["post_count"]=>
|
411 |
+
int(6)
|
412 |
+
}
|
413 |
+
[30]=>
|
414 |
+
object(stdClass)#34 (5) {
|
415 |
+
["id"]=>
|
416 |
+
int(117)
|
417 |
+
["slug"]=>
|
418 |
+
string(5) "media"
|
419 |
+
["title"]=>
|
420 |
+
string(5) "media"
|
421 |
+
["description"]=>
|
422 |
+
string(0) ""
|
423 |
+
["post_count"]=>
|
424 |
+
int(1)
|
425 |
+
}
|
426 |
+
[31]=>
|
427 |
+
object(stdClass)#35 (5) {
|
428 |
+
["id"]=>
|
429 |
+
int(122)
|
430 |
+
["slug"]=>
|
431 |
+
string(10) "mothership"
|
432 |
+
["title"]=>
|
433 |
+
string(10) "Mothership"
|
434 |
+
["description"]=>
|
435 |
+
string(29) "Tags posts about motherships."
|
436 |
+
["post_count"]=>
|
437 |
+
int(1)
|
438 |
+
}
|
439 |
+
[32]=>
|
440 |
+
object(stdClass)#36 (5) {
|
441 |
+
["id"]=>
|
442 |
+
int(123)
|
443 |
+
["slug"]=>
|
444 |
+
string(8) "mustread"
|
445 |
+
["title"]=>
|
446 |
+
string(9) "Must Read"
|
447 |
+
["description"]=>
|
448 |
+
string(40) "Tags posts about articles you must read."
|
449 |
+
["post_count"]=>
|
450 |
+
int(1)
|
451 |
+
}
|
452 |
+
[33]=>
|
453 |
+
object(stdClass)#37 (5) {
|
454 |
+
["id"]=>
|
455 |
+
int(124)
|
456 |
+
["slug"]=>
|
457 |
+
string(8) "nailedit"
|
458 |
+
["title"]=>
|
459 |
+
string(9) "Nailed It"
|
460 |
+
["description"]=>
|
461 |
+
string(32) "Tags posts about that nailed it."
|
462 |
+
["post_count"]=>
|
463 |
+
int(1)
|
464 |
+
}
|
465 |
+
[34]=>
|
466 |
+
object(stdClass)#38 (5) {
|
467 |
+
["id"]=>
|
468 |
+
int(126)
|
469 |
+
["slug"]=>
|
470 |
+
string(10) "pagination"
|
471 |
+
["title"]=>
|
472 |
+
string(10) "pagination"
|
473 |
+
["description"]=>
|
474 |
+
string(0) ""
|
475 |
+
["post_count"]=>
|
476 |
+
int(1)
|
477 |
+
}
|
478 |
+
[35]=>
|
479 |
+
object(stdClass)#39 (5) {
|
480 |
+
["id"]=>
|
481 |
+
int(128)
|
482 |
+
["slug"]=>
|
483 |
+
string(10) "password-2"
|
484 |
+
["title"]=>
|
485 |
+
string(8) "password"
|
486 |
+
["description"]=>
|
487 |
+
string(0) ""
|
488 |
+
["post_count"]=>
|
489 |
+
int(1)
|
490 |
+
}
|
491 |
+
[36]=>
|
492 |
+
object(stdClass)#40 (5) {
|
493 |
+
["id"]=>
|
494 |
+
int(129)
|
495 |
+
["slug"]=>
|
496 |
+
string(8) "pictures"
|
497 |
+
["title"]=>
|
498 |
+
string(8) "Pictures"
|
499 |
+
["description"]=>
|
500 |
+
string(0) ""
|
501 |
+
["post_count"]=>
|
502 |
+
int(1)
|
503 |
+
}
|
504 |
+
[37]=>
|
505 |
+
object(stdClass)#41 (5) {
|
506 |
+
["id"]=>
|
507 |
+
int(130)
|
508 |
+
["slug"]=>
|
509 |
+
string(11) "pingbacks-2"
|
510 |
+
["title"]=>
|
511 |
+
string(9) "pingbacks"
|
512 |
+
["description"]=>
|
513 |
+
string(0) ""
|
514 |
+
["post_count"]=>
|
515 |
+
int(1)
|
516 |
+
}
|
517 |
+
[38]=>
|
518 |
+
object(stdClass)#42 (5) {
|
519 |
+
["id"]=>
|
520 |
+
int(133)
|
521 |
+
["slug"]=>
|
522 |
+
string(4) "post"
|
523 |
+
["title"]=>
|
524 |
+
string(4) "post"
|
525 |
+
["description"]=>
|
526 |
+
string(0) ""
|
527 |
+
["post_count"]=>
|
528 |
+
int(1)
|
529 |
+
}
|
530 |
+
[39]=>
|
531 |
+
object(stdClass)#43 (5) {
|
532 |
+
["id"]=>
|
533 |
+
int(38)
|
534 |
+
["slug"]=>
|
535 |
+
string(12) "post-formats"
|
536 |
+
["title"]=>
|
537 |
+
string(12) "Post Formats"
|
538 |
+
["description"]=>
|
539 |
+
string(0) ""
|
540 |
+
["post_count"]=>
|
541 |
+
int(16)
|
542 |
+
}
|
543 |
+
[40]=>
|
544 |
+
object(stdClass)#44 (5) {
|
545 |
+
["id"]=>
|
546 |
+
int(139)
|
547 |
+
["slug"]=>
|
548 |
+
string(5) "quote"
|
549 |
+
["title"]=>
|
550 |
+
string(5) "quote"
|
551 |
+
["description"]=>
|
552 |
+
string(0) ""
|
553 |
+
["post_count"]=>
|
554 |
+
int(2)
|
555 |
+
}
|
556 |
+
[41]=>
|
557 |
+
object(stdClass)#45 (5) {
|
558 |
+
["id"]=>
|
559 |
+
int(141)
|
560 |
+
["slug"]=>
|
561 |
+
string(9) "read-more"
|
562 |
+
["title"]=>
|
563 |
+
string(9) "read more"
|
564 |
+
["description"]=>
|
565 |
+
string(0) ""
|
566 |
+
["post_count"]=>
|
567 |
+
int(1)
|
568 |
+
}
|
569 |
+
[42]=>
|
570 |
+
object(stdClass)#46 (5) {
|
571 |
+
["id"]=>
|
572 |
+
int(142)
|
573 |
+
["slug"]=>
|
574 |
+
string(11) "readability"
|
575 |
+
["title"]=>
|
576 |
+
string(11) "readability"
|
577 |
+
["description"]=>
|
578 |
+
string(0) ""
|
579 |
+
["post_count"]=>
|
580 |
+
int(1)
|
581 |
+
}
|
582 |
+
[43]=>
|
583 |
+
object(stdClass)#47 (5) {
|
584 |
+
["id"]=>
|
585 |
+
int(145)
|
586 |
+
["slug"]=>
|
587 |
+
string(9) "shortcode"
|
588 |
+
["title"]=>
|
589 |
+
string(9) "shortcode"
|
590 |
+
["description"]=>
|
591 |
+
string(0) ""
|
592 |
+
["post_count"]=>
|
593 |
+
int(6)
|
594 |
+
}
|
595 |
+
[44]=>
|
596 |
+
object(stdClass)#48 (5) {
|
597 |
+
["id"]=>
|
598 |
+
int(147)
|
599 |
+
["slug"]=>
|
600 |
+
string(10) "standard-2"
|
601 |
+
["title"]=>
|
602 |
+
string(8) "standard"
|
603 |
+
["description"]=>
|
604 |
+
string(0) ""
|
605 |
+
["post_count"]=>
|
606 |
+
int(2)
|
607 |
+
}
|
608 |
+
[45]=>
|
609 |
+
object(stdClass)#49 (5) {
|
610 |
+
["id"]=>
|
611 |
+
int(148)
|
612 |
+
["slug"]=>
|
613 |
+
string(6) "status"
|
614 |
+
["title"]=>
|
615 |
+
string(6) "status"
|
616 |
+
["description"]=>
|
617 |
+
string(0) ""
|
618 |
+
["post_count"]=>
|
619 |
+
int(1)
|
620 |
+
}
|
621 |
+
[46]=>
|
622 |
+
object(stdClass)#50 (5) {
|
623 |
+
["id"]=>
|
624 |
+
int(149)
|
625 |
+
["slug"]=>
|
626 |
+
string(8) "sticky-2"
|
627 |
+
["title"]=>
|
628 |
+
string(6) "sticky"
|
629 |
+
["description"]=>
|
630 |
+
string(0) ""
|
631 |
+
["post_count"]=>
|
632 |
+
int(1)
|
633 |
+
}
|
634 |
+
[47]=>
|
635 |
+
object(stdClass)#51 (5) {
|
636 |
+
["id"]=>
|
637 |
+
int(150)
|
638 |
+
["slug"]=>
|
639 |
+
string(7) "success"
|
640 |
+
["title"]=>
|
641 |
+
string(7) "Success"
|
642 |
+
["description"]=>
|
643 |
+
string(25) "Tags posts about success."
|
644 |
+
["post_count"]=>
|
645 |
+
int(1)
|
646 |
+
}
|
647 |
+
[48]=>
|
648 |
+
object(stdClass)#52 (5) {
|
649 |
+
["id"]=>
|
650 |
+
int(151)
|
651 |
+
["slug"]=>
|
652 |
+
string(7) "swagger"
|
653 |
+
["title"]=>
|
654 |
+
string(7) "Swagger"
|
655 |
+
["description"]=>
|
656 |
+
string(25) "Tags posts about swagger."
|
657 |
+
["post_count"]=>
|
658 |
+
int(1)
|
659 |
+
}
|
660 |
+
[49]=>
|
661 |
+
object(stdClass)#53 (5) {
|
662 |
+
["id"]=>
|
663 |
+
int(158)
|
664 |
+
["slug"]=>
|
665 |
+
string(4) "tags"
|
666 |
+
["title"]=>
|
667 |
+
string(4) "Tags"
|
668 |
+
["description"]=>
|
669 |
+
string(33) "Tags posts about tags. #inception"
|
670 |
+
["post_count"]=>
|
671 |
+
int(1)
|
672 |
+
}
|
673 |
+
[50]=>
|
674 |
+
object(stdClass)#54 (5) {
|
675 |
+
["id"]=>
|
676 |
+
int(159)
|
677 |
+
["slug"]=>
|
678 |
+
string(8) "template"
|
679 |
+
["title"]=>
|
680 |
+
string(8) "template"
|
681 |
+
["description"]=>
|
682 |
+
string(0) ""
|
683 |
+
["post_count"]=>
|
684 |
+
int(12)
|
685 |
+
}
|
686 |
+
[51]=>
|
687 |
+
object(stdClass)#55 (5) {
|
688 |
+
["id"]=>
|
689 |
+
int(163)
|
690 |
+
["slug"]=>
|
691 |
+
string(5) "tiled"
|
692 |
+
["title"]=>
|
693 |
+
string(5) "tiled"
|
694 |
+
["description"]=>
|
695 |
+
string(0) ""
|
696 |
+
["post_count"]=>
|
697 |
+
int(1)
|
698 |
+
}
|
699 |
+
[52]=>
|
700 |
+
object(stdClass)#56 (5) {
|
701 |
+
["id"]=>
|
702 |
+
int(164)
|
703 |
+
["slug"]=>
|
704 |
+
string(5) "title"
|
705 |
+
["title"]=>
|
706 |
+
string(5) "title"
|
707 |
+
["description"]=>
|
708 |
+
string(0) ""
|
709 |
+
["post_count"]=>
|
710 |
+
int(5)
|
711 |
+
}
|
712 |
+
[53]=>
|
713 |
+
object(stdClass)#57 (5) {
|
714 |
+
["id"]=>
|
715 |
+
int(165)
|
716 |
+
["slug"]=>
|
717 |
+
string(12) "trackbacks-2"
|
718 |
+
["title"]=>
|
719 |
+
string(10) "trackbacks"
|
720 |
+
["description"]=>
|
721 |
+
string(0) ""
|
722 |
+
["post_count"]=>
|
723 |
+
int(1)
|
724 |
+
}
|
725 |
+
[54]=>
|
726 |
+
object(stdClass)#58 (5) {
|
727 |
+
["id"]=>
|
728 |
+
int(166)
|
729 |
+
["slug"]=>
|
730 |
+
string(9) "twitter-2"
|
731 |
+
["title"]=>
|
732 |
+
string(7) "twitter"
|
733 |
+
["description"]=>
|
734 |
+
string(0) ""
|
735 |
+
["post_count"]=>
|
736 |
+
int(2)
|
737 |
+
}
|
738 |
+
[55]=>
|
739 |
+
object(stdClass)#59 (5) {
|
740 |
+
["id"]=>
|
741 |
+
int(168)
|
742 |
+
["slug"]=>
|
743 |
+
string(6) "unseen"
|
744 |
+
["title"]=>
|
745 |
+
string(6) "Unseen"
|
746 |
+
["description"]=>
|
747 |
+
string(46) "Tags posts about things that cannot be unseen."
|
748 |
+
["post_count"]=>
|
749 |
+
int(1)
|
750 |
+
}
|
751 |
+
[56]=>
|
752 |
+
object(stdClass)#60 (5) {
|
753 |
+
["id"]=>
|
754 |
+
int(169)
|
755 |
+
["slug"]=>
|
756 |
+
string(5) "video"
|
757 |
+
["title"]=>
|
758 |
+
string(5) "video"
|
759 |
+
["description"]=>
|
760 |
+
string(0) ""
|
761 |
+
["post_count"]=>
|
762 |
+
int(3)
|
763 |
+
}
|
764 |
+
[57]=>
|
765 |
+
object(stdClass)#61 (5) {
|
766 |
+
["id"]=>
|
767 |
+
int(170)
|
768 |
+
["slug"]=>
|
769 |
+
string(10) "videopress"
|
770 |
+
["title"]=>
|
771 |
+
string(10) "videopress"
|
772 |
+
["description"]=>
|
773 |
+
string(0) ""
|
774 |
+
["post_count"]=>
|
775 |
+
int(2)
|
776 |
+
}
|
777 |
+
[58]=>
|
778 |
+
object(stdClass)#62 (5) {
|
779 |
+
["id"]=>
|
780 |
+
int(172)
|
781 |
+
["slug"]=>
|
782 |
+
string(9) "wordpress"
|
783 |
+
["title"]=>
|
784 |
+
string(9) "WordPress"
|
785 |
+
["description"]=>
|
786 |
+
string(27) "Tags posts about WordPress."
|
787 |
+
["post_count"]=>
|
788 |
+
int(1)
|
789 |
+
}
|
790 |
+
[59]=>
|
791 |
+
object(stdClass)#63 (5) {
|
792 |
+
["id"]=>
|
793 |
+
int(173)
|
794 |
+
["slug"]=>
|
795 |
+
string(12) "wordpress-tv"
|
796 |
+
["title"]=>
|
797 |
+
string(12) "wordpress.tv"
|
798 |
+
["description"]=>
|
799 |
+
string(0) ""
|
800 |
+
["post_count"]=>
|
801 |
+
int(2)
|
802 |
+
}
|
803 |
+
}
|
trunk/tests/core.get_tag_posts-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_tag_posts default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.get_tag_posts&slug=css&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$post = $response->posts[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Post count: $response->count\n";
|
15 |
+
echo "Post title: $post->title\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Post count: 7
|
21 |
+
Post title: Markup: HTML Tags and Formatting
|
trunk/tests/core.info-01.phpt
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.info default
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.info&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
|
12 |
+
echo "Response status: $response->status\n";
|
13 |
+
echo "Controllers:\n";
|
14 |
+
var_dump($response->controllers);
|
15 |
+
|
16 |
+
?>
|
17 |
+
--EXPECT--
|
18 |
+
Response status: ok
|
19 |
+
Controllers:
|
20 |
+
array(4) {
|
21 |
+
[0]=>
|
22 |
+
string(4) "core"
|
23 |
+
[1]=>
|
24 |
+
string(5) "posts"
|
25 |
+
[2]=>
|
26 |
+
string(7) "respond"
|
27 |
+
[3]=>
|
28 |
+
string(7) "widgets"
|
29 |
+
}
|
trunk/tests/core.info-02.phpt
ADDED
@@ -0,0 +1,57 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.info controller detail
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/?json=core.info&controller=core&dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
|
12 |
+
echo "Response status: $response->status\n";
|
13 |
+
echo "Name: $response->name\n";
|
14 |
+
echo "Description: $response->description\n";
|
15 |
+
echo "Methods:\n";
|
16 |
+
var_dump($response->methods);
|
17 |
+
|
18 |
+
?>
|
19 |
+
--EXPECT--
|
20 |
+
Response status: ok
|
21 |
+
Name: Core
|
22 |
+
Description: Basic introspection methods
|
23 |
+
Methods:
|
24 |
+
array(16) {
|
25 |
+
[0]=>
|
26 |
+
string(4) "info"
|
27 |
+
[1]=>
|
28 |
+
string(16) "get_recent_posts"
|
29 |
+
[2]=>
|
30 |
+
string(9) "get_posts"
|
31 |
+
[3]=>
|
32 |
+
string(8) "get_post"
|
33 |
+
[4]=>
|
34 |
+
string(8) "get_page"
|
35 |
+
[5]=>
|
36 |
+
string(14) "get_date_posts"
|
37 |
+
[6]=>
|
38 |
+
string(18) "get_category_posts"
|
39 |
+
[7]=>
|
40 |
+
string(13) "get_tag_posts"
|
41 |
+
[8]=>
|
42 |
+
string(16) "get_author_posts"
|
43 |
+
[9]=>
|
44 |
+
string(18) "get_search_results"
|
45 |
+
[10]=>
|
46 |
+
string(14) "get_date_index"
|
47 |
+
[11]=>
|
48 |
+
string(18) "get_category_index"
|
49 |
+
[12]=>
|
50 |
+
string(13) "get_tag_index"
|
51 |
+
[13]=>
|
52 |
+
string(16) "get_author_index"
|
53 |
+
[14]=>
|
54 |
+
string(14) "get_page_index"
|
55 |
+
[15]=>
|
56 |
+
string(9) "get_nonce"
|
57 |
+
}
|
trunk/tests/query-01.phpt
ADDED
@@ -0,0 +1,21 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
--TEST--
|
2 |
+
core.get_author_index with user-friendly URLs
|
3 |
+
--FILE--
|
4 |
+
<?php
|
5 |
+
|
6 |
+
require_once 'HTTP/Client.php';
|
7 |
+
$http = new HTTP_Client();
|
8 |
+
$http->get('http://wordpress.test/api/core/get_author_index?dev=1');
|
9 |
+
$response = $http->currentResponse();
|
10 |
+
$response = json_decode($response['body']);
|
11 |
+
$author = $response->authors[0];
|
12 |
+
|
13 |
+
echo "Response status: $response->status\n";
|
14 |
+
echo "Author count: $response->count\n";
|
15 |
+
echo "Author name: $author->name\n";
|
16 |
+
|
17 |
+
?>
|
18 |
+
--EXPECT--
|
19 |
+
Response status: ok
|
20 |
+
Author count: 1
|
21 |
+
Author name: themedemos
|