JSON API - Version 0.6

Version Description

(2009-11-30): = * Added count_total response * Added json_api_encode filter * Fixed bugs in the introspector's get_current_category and get_current_tag

Download this release

Release Info

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

Version 0.6

json-api.php ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ Plugin Name: JSON API
4
+ Plugin URI: http://wordpress.org/extend/plugins/json-api/
5
+ Description: A RESTful API for WordPress
6
+ Version: 0.5
7
+ Author: Dan Phiffer
8
+ Author URI: http://phiffer.org/
9
+ */
10
+
11
+ global $json_api_dir;
12
+ $json_api_dir = WP_PLUGIN_DIR . '/json-api';
13
+
14
+ function json_api_init() {
15
+ // Initialize the controller and query inspector
16
+ global $json_api, $json_api_dir;
17
+ require_once "$json_api_dir/singletons/controller.php";
18
+ require_once "$json_api_dir/singletons/query.php";
19
+ $json_api = new JSON_API_Controller();
20
+ }
21
+
22
+ function json_api_activation() {
23
+ // Add the rewrite rule on activation
24
+ global $wp_rewrite;
25
+ add_filter('rewrite_rules_array', 'json_api_rewrites');
26
+ $wp_rewrite->flush_rules();
27
+ }
28
+
29
+ function json_api_deactivation() {
30
+ // Remove the rewrite rule on deactivation
31
+ global $wp_rewrite;
32
+ $wp_rewrite->flush_rules();
33
+ }
34
+
35
+ function json_api_rewrites($wp_rules) {
36
+ // Register the rewrite rule /api/[method] => ?json=[method]
37
+ $json_api_rules = array(
38
+ 'api/(.+)$' => 'index.php?json=$matches[1]'
39
+ );
40
+ return array_merge($json_api_rules, $wp_rules);
41
+ }
42
+
43
+ // Add initialization and activation hooks
44
+ add_action('init', 'json_api_init');
45
+ register_activation_hook("$json_api_dir/json-api.php", 'json_api_activation');
46
+ register_deactivation_hook("$json_api_dir/json-api.php", 'json_api_deactivation');
47
+
48
+ ?>
library/JSON.php ADDED
@@ -0,0 +1,861 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 288200 2009-09-09 15:41:29Z 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
+ * Converts to and from JSON format.
95
+ *
96
+ * Brief example of use:
97
+ *
98
+ * <code>
99
+ * // create a new instance of Services_JSON
100
+ * $json = new Services_JSON();
101
+ *
102
+ * // convert a complexe value to JSON notation, and send it to the browser
103
+ * $value = array('foo', 'bar', array(1, 2, 'baz'), array(3, array(4)));
104
+ * $output = $json->encode($value);
105
+ *
106
+ * print($output);
107
+ * // prints: ["foo","bar",[1,2,"baz"],[3,[4]]]
108
+ *
109
+ * // accept incoming POST data, assumed to be in JSON notation
110
+ * $input = file_get_contents('php://input', 1000000);
111
+ * $value = $json->decode($input);
112
+ * </code>
113
+ */
114
+ class Services_JSON
115
+ {
116
+ /**
117
+ * constructs a new JSON instance
118
+ *
119
+ * @param int $use object behavior flags; combine with boolean-OR
120
+ *
121
+ * possible values:
122
+ * - SERVICES_JSON_LOOSE_TYPE: loose typing.
123
+ * "{...}" syntax creates associative arrays
124
+ * instead of objects in decode().
125
+ * - SERVICES_JSON_SUPPRESS_ERRORS: error suppression.
126
+ * Values which can't be encoded (e.g. resources)
127
+ * appear as NULL instead of throwing errors.
128
+ * By default, a deeply-nested resource will
129
+ * bubble up with an error, so all return values
130
+ * from encode() should be checked with isError()
131
+ */
132
+ function Services_JSON($use = 0)
133
+ {
134
+ $this->use = $use;
135
+ }
136
+
137
+ /**
138
+ * convert a string from one UTF-16 char to one UTF-8 char
139
+ *
140
+ * Normally should be handled by mb_convert_encoding, but
141
+ * provides a slower PHP-only method for installations
142
+ * that lack the multibye string extension.
143
+ *
144
+ * @param string $utf16 UTF-16 character
145
+ * @return string UTF-8 character
146
+ * @access private
147
+ */
148
+ function utf162utf8($utf16)
149
+ {
150
+ // oh please oh please oh please oh please oh please
151
+ if(function_exists('mb_convert_encoding')) {
152
+ return mb_convert_encoding($utf16, 'UTF-8', 'UTF-16');
153
+ }
154
+
155
+ $bytes = (ord($utf16{0}) << 8) | ord($utf16{1});
156
+
157
+ switch(true) {
158
+ case ((0x7F & $bytes) == $bytes):
159
+ // this case should never be reached, because we are in ASCII range
160
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
161
+ return chr(0x7F & $bytes);
162
+
163
+ case (0x07FF & $bytes) == $bytes:
164
+ // return a 2-byte UTF-8 character
165
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
166
+ return chr(0xC0 | (($bytes >> 6) & 0x1F))
167
+ . chr(0x80 | ($bytes & 0x3F));
168
+
169
+ case (0xFFFF & $bytes) == $bytes:
170
+ // return a 3-byte UTF-8 character
171
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
172
+ return chr(0xE0 | (($bytes >> 12) & 0x0F))
173
+ . chr(0x80 | (($bytes >> 6) & 0x3F))
174
+ . chr(0x80 | ($bytes & 0x3F));
175
+ }
176
+
177
+ // ignoring UTF-32 for now, sorry
178
+ return '';
179
+ }
180
+
181
+ /**
182
+ * convert a string from one UTF-8 char to one UTF-16 char
183
+ *
184
+ * Normally should be handled by mb_convert_encoding, but
185
+ * provides a slower PHP-only method for installations
186
+ * that lack the multibye string extension.
187
+ *
188
+ * @param string $utf8 UTF-8 character
189
+ * @return string UTF-16 character
190
+ * @access private
191
+ */
192
+ function utf82utf16($utf8)
193
+ {
194
+ // oh please oh please oh please oh please oh please
195
+ if(function_exists('mb_convert_encoding')) {
196
+ return mb_convert_encoding($utf8, 'UTF-16', 'UTF-8');
197
+ }
198
+
199
+ switch(strlen($utf8)) {
200
+ case 1:
201
+ // this case should never be reached, because we are in ASCII range
202
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
203
+ return $utf8;
204
+
205
+ case 2:
206
+ // return a UTF-16 character from a 2-byte UTF-8 char
207
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
208
+ return chr(0x07 & (ord($utf8{0}) >> 2))
209
+ . chr((0xC0 & (ord($utf8{0}) << 6))
210
+ | (0x3F & ord($utf8{1})));
211
+
212
+ case 3:
213
+ // return a UTF-16 character from a 3-byte UTF-8 char
214
+ // see: http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
215
+ return chr((0xF0 & (ord($utf8{0}) << 4))
216
+ | (0x0F & (ord($utf8{1}) >> 2)))
217
+ . chr((0xC0 & (ord($utf8{1}) << 6))
218
+ | (0x7F & ord($utf8{2})));
219
+ }
220
+
221
+ // ignoring UTF-32 for now, sorry
222
+ return '';
223
+ }
224
+
225
+ /**
226
+ * encodes an arbitrary variable into JSON format (and sends JSON Header)
227
+ *
228
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
229
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
230
+ * if var is a strng, note that encode() always expects it
231
+ * to be in ASCII or UTF-8 format!
232
+ *
233
+ * @return mixed JSON string representation of input var or an error if a problem occurs
234
+ * @access public
235
+ */
236
+ function encode($var)
237
+ {
238
+ header('Content-type: application/json');
239
+ return $this->_encode($var);
240
+ }
241
+ /**
242
+ * encodes an arbitrary variable into JSON format without JSON Header - warning - may allow CSS!!!!)
243
+ *
244
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
245
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
246
+ * if var is a strng, note that encode() always expects it
247
+ * to be in ASCII or UTF-8 format!
248
+ *
249
+ * @return mixed JSON string representation of input var or an error if a problem occurs
250
+ * @access public
251
+ */
252
+ function encodeUnsafe($var)
253
+ {
254
+ return $this->_encode($var);
255
+ }
256
+ /**
257
+ * PRIVATE CODE that does the work of encodes an arbitrary variable into JSON format
258
+ *
259
+ * @param mixed $var any number, boolean, string, array, or object to be encoded.
260
+ * see argument 1 to Services_JSON() above for array-parsing behavior.
261
+ * if var is a strng, note that encode() always expects it
262
+ * to be in ASCII or UTF-8 format!
263
+ *
264
+ * @return mixed JSON string representation of input var or an error if a problem occurs
265
+ * @access public
266
+ */
267
+ function _encode($var)
268
+ {
269
+
270
+ switch (gettype($var)) {
271
+ case 'boolean':
272
+ return $var ? 'true' : 'false';
273
+
274
+ case 'NULL':
275
+ return 'null';
276
+
277
+ case 'integer':
278
+ return (int) $var;
279
+
280
+ case 'double':
281
+ case 'float':
282
+ return (float) $var;
283
+
284
+ case 'string':
285
+ // STRINGS ARE EXPECTED TO BE IN ASCII OR UTF-8 FORMAT
286
+ $ascii = '';
287
+ $strlen_var = strlen($var);
288
+
289
+ /*
290
+ * Iterate over every character in the string,
291
+ * escaping with a slash or encoding to UTF-8 where necessary
292
+ */
293
+ for ($c = 0; $c < $strlen_var; ++$c) {
294
+
295
+ $ord_var_c = ord($var{$c});
296
+
297
+ switch (true) {
298
+ case $ord_var_c == 0x08:
299
+ $ascii .= '\b';
300
+ break;
301
+ case $ord_var_c == 0x09:
302
+ $ascii .= '\t';
303
+ break;
304
+ case $ord_var_c == 0x0A:
305
+ $ascii .= '\n';
306
+ break;
307
+ case $ord_var_c == 0x0C:
308
+ $ascii .= '\f';
309
+ break;
310
+ case $ord_var_c == 0x0D:
311
+ $ascii .= '\r';
312
+ break;
313
+
314
+ case $ord_var_c == 0x22:
315
+ case $ord_var_c == 0x2F:
316
+ case $ord_var_c == 0x5C:
317
+ // double quote, slash, slosh
318
+ $ascii .= '\\'.$var{$c};
319
+ break;
320
+
321
+ case (($ord_var_c >= 0x20) && ($ord_var_c <= 0x7F)):
322
+ // characters U-00000000 - U-0000007F (same as ASCII)
323
+ $ascii .= $var{$c};
324
+ break;
325
+
326
+ case (($ord_var_c & 0xE0) == 0xC0):
327
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
328
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
329
+ if ($c+1 >= $strlen_var) {
330
+ $c += 1;
331
+ $ascii .= '?';
332
+ break;
333
+ }
334
+
335
+ $char = pack('C*', $ord_var_c, ord($var{$c + 1}));
336
+ $c += 1;
337
+ $utf16 = $this->utf82utf16($char);
338
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
339
+ break;
340
+
341
+ case (($ord_var_c & 0xF0) == 0xE0):
342
+ if ($c+2 >= $strlen_var) {
343
+ $c += 2;
344
+ $ascii .= '?';
345
+ break;
346
+ }
347
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
348
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
349
+ $char = pack('C*', $ord_var_c,
350
+ @ord($var{$c + 1}),
351
+ @ord($var{$c + 2}));
352
+ $c += 2;
353
+ $utf16 = $this->utf82utf16($char);
354
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
355
+ break;
356
+
357
+ case (($ord_var_c & 0xF8) == 0xF0):
358
+ if ($c+3 >= $strlen_var) {
359
+ $c += 3;
360
+ $ascii .= '?';
361
+ break;
362
+ }
363
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
364
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
365
+ $char = pack('C*', $ord_var_c,
366
+ ord($var{$c + 1}),
367
+ ord($var{$c + 2}),
368
+ ord($var{$c + 3}));
369
+ $c += 3;
370
+ $utf16 = $this->utf82utf16($char);
371
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
372
+ break;
373
+
374
+ case (($ord_var_c & 0xFC) == 0xF8):
375
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
376
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
377
+ if ($c+4 >= $strlen_var) {
378
+ $c += 4;
379
+ $ascii .= '?';
380
+ break;
381
+ }
382
+ $char = pack('C*', $ord_var_c,
383
+ ord($var{$c + 1}),
384
+ ord($var{$c + 2}),
385
+ ord($var{$c + 3}),
386
+ ord($var{$c + 4}));
387
+ $c += 4;
388
+ $utf16 = $this->utf82utf16($char);
389
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
390
+ break;
391
+
392
+ case (($ord_var_c & 0xFE) == 0xFC):
393
+ if ($c+5 >= $strlen_var) {
394
+ $c += 5;
395
+ $ascii .= '?';
396
+ break;
397
+ }
398
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
399
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
400
+ $char = pack('C*', $ord_var_c,
401
+ ord($var{$c + 1}),
402
+ ord($var{$c + 2}),
403
+ ord($var{$c + 3}),
404
+ ord($var{$c + 4}),
405
+ ord($var{$c + 5}));
406
+ $c += 5;
407
+ $utf16 = $this->utf82utf16($char);
408
+ $ascii .= sprintf('\u%04s', bin2hex($utf16));
409
+ break;
410
+ }
411
+ }
412
+ return '"'.$ascii.'"';
413
+
414
+ case 'array':
415
+ /*
416
+ * As per JSON spec if any array key is not an integer
417
+ * we must treat the the whole array as an object. We
418
+ * also try to catch a sparsely populated associative
419
+ * array with numeric keys here because some JS engines
420
+ * will create an array with empty indexes up to
421
+ * max_index which can cause memory issues and because
422
+ * the keys, which may be relevant, will be remapped
423
+ * otherwise.
424
+ *
425
+ * As per the ECMA and JSON specification an object may
426
+ * have any string as a property. Unfortunately due to
427
+ * a hole in the ECMA specification if the key is a
428
+ * ECMA reserved word or starts with a digit the
429
+ * parameter is only accessible using ECMAScript's
430
+ * bracket notation.
431
+ */
432
+
433
+ // treat as a JSON object
434
+ if (is_array($var) && count($var) && (array_keys($var) !== range(0, sizeof($var) - 1))) {
435
+ $properties = array_map(array($this, 'name_value'),
436
+ array_keys($var),
437
+ array_values($var));
438
+
439
+ foreach($properties as $property) {
440
+ if(Services_JSON::isError($property)) {
441
+ return $property;
442
+ }
443
+ }
444
+
445
+ return '{' . join(',', $properties) . '}';
446
+ }
447
+
448
+ // treat it like a regular array
449
+ $elements = array_map(array($this, '_encode'), $var);
450
+
451
+ foreach($elements as $element) {
452
+ if(Services_JSON::isError($element)) {
453
+ return $element;
454
+ }
455
+ }
456
+
457
+ return '[' . join(',', $elements) . ']';
458
+
459
+ case 'object':
460
+ $vars = get_object_vars($var);
461
+
462
+ $properties = array_map(array($this, 'name_value'),
463
+ array_keys($vars),
464
+ array_values($vars));
465
+
466
+ foreach($properties as $property) {
467
+ if(Services_JSON::isError($property)) {
468
+ return $property;
469
+ }
470
+ }
471
+
472
+ return '{' . join(',', $properties) . '}';
473
+
474
+ default:
475
+ return ($this->use & SERVICES_JSON_SUPPRESS_ERRORS)
476
+ ? 'null'
477
+ : new Services_JSON_Error(gettype($var)." can not be encoded as JSON string");
478
+ }
479
+ }
480
+
481
+ /**
482
+ * array-walking function for use in generating JSON-formatted name-value pairs
483
+ *
484
+ * @param string $name name of key to use
485
+ * @param mixed $value reference to an array element to be encoded
486
+ *
487
+ * @return string JSON-formatted name-value pair, like '"name":value'
488
+ * @access private
489
+ */
490
+ function name_value($name, $value)
491
+ {
492
+ $encoded_value = $this->_encode($value);
493
+
494
+ if(Services_JSON::isError($encoded_value)) {
495
+ return $encoded_value;
496
+ }
497
+
498
+ return $this->_encode(strval($name)) . ':' . $encoded_value;
499
+ }
500
+
501
+ /**
502
+ * reduce a string by removing leading and trailing comments and whitespace
503
+ *
504
+ * @param $str string string value to strip of comments and whitespace
505
+ *
506
+ * @return string string value stripped of comments and whitespace
507
+ * @access private
508
+ */
509
+ function reduce_string($str)
510
+ {
511
+ $str = preg_replace(array(
512
+
513
+ // eliminate single line comments in '// ...' form
514
+ '#^\s*//(.+)$#m',
515
+
516
+ // eliminate multi-line comments in '/* ... */' form, at start of string
517
+ '#^\s*/\*(.+)\*/#Us',
518
+
519
+ // eliminate multi-line comments in '/* ... */' form, at end of string
520
+ '#/\*(.+)\*/\s*$#Us'
521
+
522
+ ), '', $str);
523
+
524
+ // eliminate extraneous space
525
+ return trim($str);
526
+ }
527
+
528
+ /**
529
+ * decodes a JSON string into appropriate variable
530
+ *
531
+ * @param string $str JSON-formatted string
532
+ *
533
+ * @return mixed number, boolean, string, array, or object
534
+ * corresponding to given JSON input string.
535
+ * See argument 1 to Services_JSON() above for object-output behavior.
536
+ * Note that decode() always returns strings
537
+ * in ASCII or UTF-8 format!
538
+ * @access public
539
+ */
540
+ function decode($str)
541
+ {
542
+ $str = $this->reduce_string($str);
543
+
544
+ switch (strtolower($str)) {
545
+ case 'true':
546
+ return true;
547
+
548
+ case 'false':
549
+ return false;
550
+
551
+ case 'null':
552
+ return null;
553
+
554
+ default:
555
+ $m = array();
556
+
557
+ if (is_numeric($str)) {
558
+ // Lookie-loo, it's a number
559
+
560
+ // This would work on its own, but I'm trying to be
561
+ // good about returning integers where appropriate:
562
+ // return (float)$str;
563
+
564
+ // Return float or int, as appropriate
565
+ return ((float)$str == (integer)$str)
566
+ ? (integer)$str
567
+ : (float)$str;
568
+
569
+ } elseif (preg_match('/^("|\').*(\1)$/s', $str, $m) && $m[1] == $m[2]) {
570
+ // STRINGS RETURNED IN UTF-8 FORMAT
571
+ $delim = substr($str, 0, 1);
572
+ $chrs = substr($str, 1, -1);
573
+ $utf8 = '';
574
+ $strlen_chrs = strlen($chrs);
575
+
576
+ for ($c = 0; $c < $strlen_chrs; ++$c) {
577
+
578
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
579
+ $ord_chrs_c = ord($chrs{$c});
580
+
581
+ switch (true) {
582
+ case $substr_chrs_c_2 == '\b':
583
+ $utf8 .= chr(0x08);
584
+ ++$c;
585
+ break;
586
+ case $substr_chrs_c_2 == '\t':
587
+ $utf8 .= chr(0x09);
588
+ ++$c;
589
+ break;
590
+ case $substr_chrs_c_2 == '\n':
591
+ $utf8 .= chr(0x0A);
592
+ ++$c;
593
+ break;
594
+ case $substr_chrs_c_2 == '\f':
595
+ $utf8 .= chr(0x0C);
596
+ ++$c;
597
+ break;
598
+ case $substr_chrs_c_2 == '\r':
599
+ $utf8 .= chr(0x0D);
600
+ ++$c;
601
+ break;
602
+
603
+ case $substr_chrs_c_2 == '\\"':
604
+ case $substr_chrs_c_2 == '\\\'':
605
+ case $substr_chrs_c_2 == '\\\\':
606
+ case $substr_chrs_c_2 == '\\/':
607
+ if (($delim == '"' && $substr_chrs_c_2 != '\\\'') ||
608
+ ($delim == "'" && $substr_chrs_c_2 != '\\"')) {
609
+ $utf8 .= $chrs{++$c};
610
+ }
611
+ break;
612
+
613
+ case preg_match('/\\\u[0-9A-F]{4}/i', substr($chrs, $c, 6)):
614
+ // single, escaped unicode character
615
+ $utf16 = chr(hexdec(substr($chrs, ($c + 2), 2)))
616
+ . chr(hexdec(substr($chrs, ($c + 4), 2)));
617
+ $utf8 .= $this->utf162utf8($utf16);
618
+ $c += 5;
619
+ break;
620
+
621
+ case ($ord_chrs_c >= 0x20) && ($ord_chrs_c <= 0x7F):
622
+ $utf8 .= $chrs{$c};
623
+ break;
624
+
625
+ case ($ord_chrs_c & 0xE0) == 0xC0:
626
+ // characters U-00000080 - U-000007FF, mask 110XXXXX
627
+ //see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
628
+ $utf8 .= substr($chrs, $c, 2);
629
+ ++$c;
630
+ break;
631
+
632
+ case ($ord_chrs_c & 0xF0) == 0xE0:
633
+ // characters U-00000800 - U-0000FFFF, mask 1110XXXX
634
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
635
+ $utf8 .= substr($chrs, $c, 3);
636
+ $c += 2;
637
+ break;
638
+
639
+ case ($ord_chrs_c & 0xF8) == 0xF0:
640
+ // characters U-00010000 - U-001FFFFF, mask 11110XXX
641
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
642
+ $utf8 .= substr($chrs, $c, 4);
643
+ $c += 3;
644
+ break;
645
+
646
+ case ($ord_chrs_c & 0xFC) == 0xF8:
647
+ // characters U-00200000 - U-03FFFFFF, mask 111110XX
648
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
649
+ $utf8 .= substr($chrs, $c, 5);
650
+ $c += 4;
651
+ break;
652
+
653
+ case ($ord_chrs_c & 0xFE) == 0xFC:
654
+ // characters U-04000000 - U-7FFFFFFF, mask 1111110X
655
+ // see http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8
656
+ $utf8 .= substr($chrs, $c, 6);
657
+ $c += 5;
658
+ break;
659
+
660
+ }
661
+
662
+ }
663
+
664
+ return $utf8;
665
+
666
+ } elseif (preg_match('/^\[.*\]$/s', $str) || preg_match('/^\{.*\}$/s', $str)) {
667
+ // array, or object notation
668
+
669
+ if ($str{0} == '[') {
670
+ $stk = array(SERVICES_JSON_IN_ARR);
671
+ $arr = array();
672
+ } else {
673
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
674
+ $stk = array(SERVICES_JSON_IN_OBJ);
675
+ $obj = array();
676
+ } else {
677
+ $stk = array(SERVICES_JSON_IN_OBJ);
678
+ $obj = new stdClass();
679
+ }
680
+ }
681
+
682
+ array_push($stk, array('what' => SERVICES_JSON_SLICE,
683
+ 'where' => 0,
684
+ 'delim' => false));
685
+
686
+ $chrs = substr($str, 1, -1);
687
+ $chrs = $this->reduce_string($chrs);
688
+
689
+ if ($chrs == '') {
690
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
691
+ return $arr;
692
+
693
+ } else {
694
+ return $obj;
695
+
696
+ }
697
+ }
698
+
699
+ //print("\nparsing {$chrs}\n");
700
+
701
+ $strlen_chrs = strlen($chrs);
702
+
703
+ for ($c = 0; $c <= $strlen_chrs; ++$c) {
704
+
705
+ $top = end($stk);
706
+ $substr_chrs_c_2 = substr($chrs, $c, 2);
707
+
708
+ if (($c == $strlen_chrs) || (($chrs{$c} == ',') && ($top['what'] == SERVICES_JSON_SLICE))) {
709
+ // found a comma that is not inside a string, array, etc.,
710
+ // OR we've reached the end of the character list
711
+ $slice = substr($chrs, $top['where'], ($c - $top['where']));
712
+ array_push($stk, array('what' => SERVICES_JSON_SLICE, 'where' => ($c + 1), 'delim' => false));
713
+ //print("Found split at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
714
+
715
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
716
+ // we are in an array, so just push an element onto the stack
717
+ array_push($arr, $this->decode($slice));
718
+
719
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
720
+ // we are in an object, so figure
721
+ // out the property name and set an
722
+ // element in an associative array,
723
+ // for now
724
+ $parts = array();
725
+
726
+ if (preg_match('/^\s*(["\'].*[^\\\]["\'])\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
727
+ // "name":value pair
728
+ $key = $this->decode($parts[1]);
729
+ $val = $this->decode($parts[2]);
730
+
731
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
732
+ $obj[$key] = $val;
733
+ } else {
734
+ $obj->$key = $val;
735
+ }
736
+ } elseif (preg_match('/^\s*(\w+)\s*:\s*(\S.*),?$/Uis', $slice, $parts)) {
737
+ // name:value pair, where name is unquoted
738
+ $key = $parts[1];
739
+ $val = $this->decode($parts[2]);
740
+
741
+ if ($this->use & SERVICES_JSON_LOOSE_TYPE) {
742
+ $obj[$key] = $val;
743
+ } else {
744
+ $obj->$key = $val;
745
+ }
746
+ }
747
+
748
+ }
749
+
750
+ } elseif ((($chrs{$c} == '"') || ($chrs{$c} == "'")) && ($top['what'] != SERVICES_JSON_IN_STR)) {
751
+ // found a quote, and we are not inside a string
752
+ array_push($stk, array('what' => SERVICES_JSON_IN_STR, 'where' => $c, 'delim' => $chrs{$c}));
753
+ //print("Found start of string at {$c}\n");
754
+
755
+ } elseif (($chrs{$c} == $top['delim']) &&
756
+ ($top['what'] == SERVICES_JSON_IN_STR) &&
757
+ ((strlen(substr($chrs, 0, $c)) - strlen(rtrim(substr($chrs, 0, $c), '\\'))) % 2 != 1)) {
758
+ // found a quote, we're in a string, and it's not escaped
759
+ // we know that it's not escaped becase there is _not_ an
760
+ // odd number of backslashes at the end of the string so far
761
+ array_pop($stk);
762
+ //print("Found end of string at {$c}: ".substr($chrs, $top['where'], (1 + 1 + $c - $top['where']))."\n");
763
+
764
+ } elseif (($chrs{$c} == '[') &&
765
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
766
+ // found a left-bracket, and we are in an array, object, or slice
767
+ array_push($stk, array('what' => SERVICES_JSON_IN_ARR, 'where' => $c, 'delim' => false));
768
+ //print("Found start of array at {$c}\n");
769
+
770
+ } elseif (($chrs{$c} == ']') && ($top['what'] == SERVICES_JSON_IN_ARR)) {
771
+ // found a right-bracket, and we're in an array
772
+ array_pop($stk);
773
+ //print("Found end of array at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
774
+
775
+ } elseif (($chrs{$c} == '{') &&
776
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
777
+ // found a left-brace, and we are in an array, object, or slice
778
+ array_push($stk, array('what' => SERVICES_JSON_IN_OBJ, 'where' => $c, 'delim' => false));
779
+ //print("Found start of object at {$c}\n");
780
+
781
+ } elseif (($chrs{$c} == '}') && ($top['what'] == SERVICES_JSON_IN_OBJ)) {
782
+ // found a right-brace, and we're in an object
783
+ array_pop($stk);
784
+ //print("Found end of object at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
785
+
786
+ } elseif (($substr_chrs_c_2 == '/*') &&
787
+ in_array($top['what'], array(SERVICES_JSON_SLICE, SERVICES_JSON_IN_ARR, SERVICES_JSON_IN_OBJ))) {
788
+ // found a comment start, and we are in an array, object, or slice
789
+ array_push($stk, array('what' => SERVICES_JSON_IN_CMT, 'where' => $c, 'delim' => false));
790
+ $c++;
791
+ //print("Found start of comment at {$c}\n");
792
+
793
+ } elseif (($substr_chrs_c_2 == '*/') && ($top['what'] == SERVICES_JSON_IN_CMT)) {
794
+ // found a comment end, and we're in one now
795
+ array_pop($stk);
796
+ $c++;
797
+
798
+ for ($i = $top['where']; $i <= $c; ++$i)
799
+ $chrs = substr_replace($chrs, ' ', $i, 1);
800
+
801
+ //print("Found end of comment at {$c}: ".substr($chrs, $top['where'], (1 + $c - $top['where']))."\n");
802
+
803
+ }
804
+
805
+ }
806
+
807
+ if (reset($stk) == SERVICES_JSON_IN_ARR) {
808
+ return $arr;
809
+
810
+ } elseif (reset($stk) == SERVICES_JSON_IN_OBJ) {
811
+ return $obj;
812
+
813
+ }
814
+
815
+ }
816
+ }
817
+ }
818
+
819
+ /**
820
+ * @todo Ultimately, this should just call PEAR::isError()
821
+ */
822
+ function isError($data, $code = null)
823
+ {
824
+ if (class_exists('pear')) {
825
+ return PEAR::isError($data, $code);
826
+ } elseif (is_object($data) && (get_class($data) == 'services_json_error' ||
827
+ is_subclass_of($data, 'services_json_error'))) {
828
+ return true;
829
+ }
830
+
831
+ return false;
832
+ }
833
+ }
834
+
835
+ if (class_exists('PEAR_Error')) {
836
+
837
+ class Services_JSON_Error extends PEAR_Error
838
+ {
839
+ function Services_JSON_Error($message = 'unknown error', $code = null,
840
+ $mode = null, $options = null, $userinfo = null)
841
+ {
842
+ parent::PEAR_Error($message, $code, $mode, $options, $userinfo);
843
+ }
844
+ }
845
+
846
+ } else {
847
+
848
+ /**
849
+ * @todo Ultimately, this class shall be descended from PEAR_Error
850
+ */
851
+ class Services_JSON_Error
852
+ {
853
+ function Services_JSON_Error($message = 'unknown error', $code = null,
854
+ $mode = null, $options = null, $userinfo = null)
855
+ {
856
+
857
+ }
858
+ }
859
+
860
+ }
861
+
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
+ ?>
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
+ ?>
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.");
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() {
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
+ ?>
models/post.php ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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 $slug; // String
10
+ var $url; // String
11
+ var $title; // String
12
+ var $title_plain; // String
13
+ var $content; // String (modified by read_more query var)
14
+ var $excerpt; // String
15
+ var $date; // String (modified by date_format query var)
16
+ var $modified; // String (modified by date_format query var)
17
+ var $categories; // Array of objects
18
+ var $tags; // Array of objects
19
+ var $author; // Object
20
+ var $comments; // Array of objects
21
+ var $comment_count; // Integer
22
+ var $comment_status; // String ("open" or "closed")
23
+ var $custom_fields; // Object (included by using custom_fields query var)
24
+
25
+ function JSON_API_Post() {
26
+ global $json_api, $post;
27
+ $date_format = $json_api->query->date_format;
28
+ $this->id = (int) get_the_ID();
29
+ $this->set_value('slug', $post->post_name);
30
+ $this->set_value('url', get_permalink());
31
+ $this->set_value('title', get_the_title());
32
+ $this->set_value('title_plain', strip_tags(get_the_title()));
33
+ $this->set_content_value();
34
+ $this->set_value('excerpt', get_the_excerpt());
35
+ $this->set_value('date', get_the_time($date_format));
36
+ $this->set_value('modified', date($date_format, strtotime($post->post_modified)));
37
+ $this->set_categories_value();
38
+ $this->set_tags_value();
39
+ $this->set_author_value();
40
+ $this->set_comments_value();
41
+ $this->set_value('comment_count', (int) $post->comment_count);
42
+ $this->set_value('comment_status', $post->comment_status);
43
+ $this->set_custom_fields_value();
44
+ }
45
+
46
+ function set_value($key, $value) {
47
+ global $json_api;
48
+ if ($json_api->include_value($key)) {
49
+ $this->$key = $value;
50
+ } else {
51
+ unset($this->$key);
52
+ }
53
+ }
54
+
55
+ function set_content_value() {
56
+ global $json_api;
57
+ if ($json_api->include_value('content')) {
58
+ $content = get_the_content($json_api->query->read_more);
59
+ $content = apply_filters('the_content', $content);
60
+ $content = str_replace(']]>', ']]&gt;', $content);
61
+ $this->content = $content;
62
+ }
63
+ }
64
+
65
+ function set_categories_value() {
66
+ global $json_api;
67
+ if ($json_api->include_value('categories')) {
68
+ $this->categories = array();
69
+ if ($wp_categories = get_the_category()) {
70
+ foreach ($wp_categories as $wp_category) {
71
+ $category = new JSON_API_Category($wp_category);
72
+ if ($category->id == 1 && $category->slug == 'uncategorized') {
73
+ // Skip the 'uncategorized' category
74
+ continue;
75
+ }
76
+ $this->categories[] = $category;
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ function set_tags_value() {
83
+ global $json_api;
84
+ if ($json_api->include_value('tags')) {
85
+ $this->tags = array();
86
+ if ($wp_tags = get_the_tags()) {
87
+ foreach ($wp_tags as $wp_tag) {
88
+ $this->tags[] = new JSON_API_Tag($wp_tag);
89
+ }
90
+ }
91
+ }
92
+ }
93
+
94
+ function set_author_value() {
95
+ global $json_api;
96
+ if ($json_api->include_value('author')) {
97
+ $this->author = new JSON_API_Author();
98
+ }
99
+ }
100
+
101
+ function set_comments_value() {
102
+ global $json_api;
103
+ if ($json_api->include_value('comments')) {
104
+ $this->comments = $json_api->introspector->get_comments($this->id);
105
+ }
106
+ }
107
+
108
+ function set_custom_fields_value() {
109
+ global $json_api;
110
+ if ($json_api->include_value('custom_fields') &&
111
+ $json_api->query->custom_fields) {
112
+ $keys = explode(',', $json_api->query->custom_fields);
113
+ $wp_custom_fields = get_post_custom($this->id);
114
+ $this->custom_fields = new stdClass();
115
+ foreach ($keys as $key) {
116
+ if (isset($wp_custom_fields[$key])) {
117
+ $this->custom_fields->$key = $wp_custom_fields[$key];
118
+ }
119
+ }
120
+ } else {
121
+ unset($this->custom_fields);
122
+ }
123
+ }
124
+
125
+ }
126
+
127
+ ?>
models/tag.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
+ }
22
+
23
+ }
24
+
25
+ ?>
readme.txt ADDED
@@ -0,0 +1,566 @@