├── README.markdown └── system └── expressionengine └── third_party └── json ├── libraries ├── Json_Template.php └── Jsonp.php └── pi.json.php /README.markdown: -------------------------------------------------------------------------------- 1 | # JSON # 2 | 3 | Output ExpressionEngine data in JSON format. 4 | 5 | ## Requirements 6 | 7 | - ExpressionEngine 2.6+ 8 | 9 | For older versions of EE use JSON version [1.0.3](https://github.com/rsanchez/json/tree/v1.0.3). 10 | 11 | ## Installation 12 | 13 | * Copy the /system/expressionengine/third_party/json/ folder to your /system/expressionengine/third_party/ folder 14 | 15 | ## Global Parameters 16 | 17 | ### `xhr="yes"` 18 | 19 | Set xhr to yes to only output data when an XMLHttpRequest is detected. Do not set this to yes if you are using JSONP, as JSONP requests are not true XHMLHttpRequests. 20 | 21 | ### `terminate="yes"` 22 | 23 | Set terminate to yes to terminate the template and output your json immediately, with Content-Type headers. 24 | 25 | ### `fields="title|url_title"` 26 | 27 | Specify which fields you wish to have in the array. Separate multiple fields by a pipe character. If you do not specify fields, you will get all of the default fields' data. The primary key (`entry_id` for entries, `member_id` for members) will always be present and cannot be suppressed by this parameter. 28 | 29 | ### `content_type="text/javascript"` 30 | 31 | Set a custom Content-Type header. The default is "application/json", or "application/javascript" if using JSONP. Headers are only sent when terminate is set to "yes". 32 | 33 | ### `jsonp="yes"` 34 | 35 | Set jsonp to yes to enable a JSONP response. You must also specify a valid callback. You are encouraged to set terminate to yes when using JSONP. 36 | 37 | ### `callback="yourCallbackFunction"` 38 | 39 | Set a callback function for your JSONP request. Since query strings do not work out-of-the-box in EE, you may want to consider using a URL segment to specify your callback, ie. callback="{segment_3}", rather than the standard ?callback=foo method. 40 | 41 | ### `date_format="U"` 42 | 43 | Use a different date format. Note: always returns dates as string. 44 | 45 | ### `root_node="items"` 46 | 47 | By default, JSON will output a simple array of items. Use this parameter to make the response into a JSON object whose specified property is the array of items. 48 | 49 | Using this parameter will turn this: 50 | 51 | ``` 52 | [ 53 | { 54 | "title": "Foo", 55 | "entry_id": 1 56 | }, 57 | { 58 | "title": "Bar", 59 | "entry_id": 2 60 | } 61 | ] 62 | ``` 63 | 64 | Into this: 65 | 66 | ``` 67 | { 68 | "items": [ 69 | { 70 | "title": "Foo", 71 | "entry_id": 1 72 | }, 73 | { 74 | "title": "Bar", 75 | "entry_id": 2 76 | } 77 | ] 78 | } 79 | ``` 80 | 81 | ### `item_root_node="item"` 82 | 83 | By default, each item in the response array is a simple object. Using this parameter turns each item into a JSON object whose specified property is the item object. 84 | 85 | Using this parameter will turn this: 86 | 87 | ``` 88 | [ 89 | { 90 | "title": "Foo", 91 | "entry_id": 1 92 | }, 93 | { 94 | "title": "Bar", 95 | "entry_id": 2 96 | }, 97 | ] 98 | ``` 99 | 100 | Into this: 101 | 102 | ``` 103 | [ 104 | { 105 | "item": { 106 | "title": "Foo", 107 | "entry_id": 1 108 | } 109 | }, 110 | { 111 | "item": { 112 | "title": "Bar", 113 | "entry_id": 2 114 | } 115 | } 116 | ] 117 | ``` 118 | 119 | ## Dates 120 | 121 | By default, the date fields are in unix timestamp format, accurate to milliseconds. Use the Javascript Date object in combination with date field data: 122 | 123 | ``` 124 | for (i in data) { 125 | var entryDate = new Date(data[i].entry_date); 126 | } 127 | ``` 128 | 129 | If you require a different output format for the date fields, set the date_format= parameter. This uses the php date() function. common formats include "U" (unix timestamp in seconds), "c" (ISO 8601) or "Y-m-d H:i" (2011-12-24 19:06). 130 | 131 | ## json:entries 132 | 133 | ``` 134 | {exp:json:entries channel="news"} 135 | ``` 136 | 137 | json:entries is a single tag, not a tag pair. Use channel:entries parameters to filter your entries. 138 | 139 | #### json:entries Default Fields 140 | 141 | ``` 142 | title 143 | url_title 144 | entry_id 145 | channel_id 146 | author_id 147 | status 148 | entry_date 149 | edit_date 150 | expiration_date 151 | Plus all of the custom fields associated with that channel 152 | ``` 153 | 154 | #### json:entries Parameters 155 | 156 | See [channel:entries parameters](http://expressionengine.com/user_guide/modules/channel/parameters.html). 157 | 158 | ##### `show_categories="yes"` 159 | 160 | This will add categories to the entries response 161 | 162 | ##### `show_category_group="1|2"` 163 | 164 | When paired with show_categories="yes", this will display only categories from the specified groups. 165 | 166 | #### json:entries Custom Fields 167 | 168 | Most custom fields will just return the raw column data from the `exp_channel_data` database table. The following fieldtypes will provide custom data. You *must* specify the `channel` parameter to get custom fields. 169 | 170 | ##### Matrix 171 | 172 | The data will include an array of Matrix rows, including the row_id and the column names: 173 | 174 | ``` 175 | your_matrix_field: [ 176 | { 177 | row_id: 1, 178 | my_col_name: "foo", 179 | other_col_name: "bar" 180 | }, 181 | { 182 | row_id: 2, 183 | my_col_name: "baz", 184 | other_col_name: "qux" 185 | } 186 | ] 187 | ``` 188 | 189 | ##### Grid 190 | 191 | The data will include an array of Grid rows, including the row_id and the column names: 192 | 193 | ``` 194 | your_grid_field: [ 195 | { 196 | row_id: 1, 197 | my_col_name: "foo", 198 | other_col_name: "bar" 199 | }, 200 | { 201 | row_id: 2, 202 | my_col_name: "baz", 203 | other_col_name: "qux" 204 | } 205 | ] 206 | ``` 207 | 208 | ##### Relationships 209 | 210 | The data will include an array of related entry IDs: 211 | 212 | ``` 213 | your_relationships_field: [1, 2] 214 | ``` 215 | 216 | ##### Playa 217 | 218 | The data will include an array of related entry IDs: 219 | 220 | ``` 221 | your_playa_field: [1, 2] 222 | ``` 223 | 224 | ##### Assets 225 | 226 | ``` 227 | your_assets_field: [ 228 | { 229 | "file_id": 1, 230 | "url": "http://yoursite.com/uploads/flower.jpg", 231 | "subfolder": "", 232 | "filename": "flower", 233 | "extension": "jpg", 234 | "date_modified": 1389459034000, 235 | "kind": "image", 236 | "width": "300", 237 | "height": "300", 238 | "size": "65 KB", 239 | "title": null, 240 | "date": 1389459034000, 241 | "alt_text": null, 242 | "caption": null, 243 | "author": null, 244 | "desc": null, 245 | "location": null, 246 | "manipulations": { 247 | "medium": "http://yoursite.com/uploads/_medium/flower.jpg", 248 | "large": "http://yoursite.com/uploads/_large/flower.jpg" 249 | } 250 | }, 251 | { 252 | "file_id": 2, 253 | "url": "http://yoursite.com/uploads/dog.jpg", 254 | "subfolder": "", 255 | "filename": "dog", 256 | "extension": "jpg", 257 | "date_modified": 1389466147000, 258 | "kind": "image", 259 | "width": "300", 260 | "height": "300", 261 | "size": "75 KB", 262 | "title": null, 263 | "date": 1389466147000, 264 | "alt_text": null, 265 | "caption": null, 266 | "author": null, 267 | "desc": null, 268 | "location": null, 269 | "manipulations": { 270 | "medium": "http://yoursite.com/uploads/_medium/dog.jpg", 271 | "large": "http://yoursite.com/uploads/_large/dog.jpg" 272 | } 273 | } 274 | ] 275 | ``` 276 | 277 | *NOTE: image manipulation urls are only available to Assets files store locally, not on Amazon S3 or Google Storage.* 278 | 279 | ##### Channel Files 280 | 281 | ``` 282 | your_channel_files_field: [ 283 | { 284 | "file_id": 1, 285 | "url": "http://yoursite.com/uploads/flower.jpg", 286 | "filename": "flower.jpg", 287 | "extension": "jpg", 288 | "kind": "image\/jpeg", 289 | "size": "65 KB", 290 | "title": "flower", 291 | "date": 1389459034000, 292 | "author": 1, 293 | "desc": "Lorem ipsum", 294 | "primary": true, 295 | "downloads": 10, 296 | "custom1": null, 297 | "custom2": null, 298 | "custom3": null, 299 | "custom4": null, 300 | "custom5": null 301 | }, 302 | { 303 | "file_id": 2, 304 | "url": "http://yoursite.com/uploads/dog.jpg", 305 | "filename": "dog.jpg", 306 | "extension": "jpg", 307 | "kind": "image\/jpeg", 308 | "size": "75 KB", 309 | "title": "dog", 310 | "date": 1389466147000, 311 | "author": 1, 312 | "desc": "Lorem ipsum", 313 | "primary": false, 314 | "downloads": 0, 315 | "custom1": null, 316 | "custom2": null, 317 | "custom3": null, 318 | "custom4": null, 319 | "custom5": null 320 | } 321 | ] 322 | ``` 323 | 324 | ##### Date 325 | 326 | The data will be the Unix timestamp, accurate to milliseconds. This is because the native JavaScript Date object accepts a millisecond-based timestamp in its constructor. 327 | 328 | ``` 329 | your_date_field: 1385661660000 330 | ``` 331 | 332 | ## json:search 333 | 334 | ``` 335 | {exp:json:search search_id="{segment_3}"} 336 | ``` 337 | 338 | json:search must be paired with {exp:search:simple_form} or {exp:search:advanced_form}. 339 | 340 | #### json:search Parameters 341 | 342 | See [channel:entries parameters](http://expressionengine.com/user_guide/modules/channel/parameters.html). 343 | 344 | ##### `search_id="{segment_3}"` 345 | 346 | The native search forms will append a search_id automatically to the result_page when you submit a form. 347 | 348 | #### json:search Example 349 | 350 | ``` 351 | {exp:search:simple_form channel="site" form_id="search" return_page="site/json"} 352 | 353 | 354 | {/exp:search:simple_form} 355 | 356 | 371 | ``` 372 | 373 | ## json:members 374 | 375 | ``` 376 | {exp:json:members member_id="1|2"} 377 | ``` 378 | 379 | json:members is a single tag, not a tag pair. 380 | 381 | #### json:members Parameters 382 | 383 | ##### `member_id="1"` 384 | 385 | Specify which members, by member_id, to output. Separate multiple member_id's with a pipe character. Use `member_id="CURRENT_USER"` to get member data for just the current user. 386 | 387 | ##### `username="admin"` 388 | 389 | Specify which members, by username, to output. Separate multiple usernames with a pipe character. 390 | 391 | ##### `group_id="1"` 392 | 393 | Specify which members, by group_id, to output. Separate multiple group_id's 394 | 395 | ##### `limit="1"` 396 | 397 | Set a limit for records to retrieve. 398 | 399 | 400 | ## Advanced Examples 401 | 402 | ### JSONP 403 | 404 | If you're doing cross-domain AJAX, you will probably want to use JSONP. 405 | 406 | This is the JSON template: 407 | 408 | ``` 409 | {exp:json:entries channel="site" jsonp="yes" callback="{segment_3}"} 410 | ``` 411 | 412 | And the request itself: 413 | 414 | ``` 415 | $.ajax({ 416 | url: "http://yoursite.com/group/template/yourCallbackFunction", 417 | dataType: "jsonp", 418 | jsonp: false 419 | }); 420 | function yourCallbackFunction(data) { 421 | console.log(data); 422 | } 423 | ``` 424 | 425 | You'll see here that we appended the callback function to the url as a segment, rather than use the traditional ?callback=function syntax. This is because query strings do not work out of the box with EE. If you have gotten query strings to work with EE you can use the traditional approach: 426 | 427 | ``` 428 | {exp:json:entries channel="site" jsonp="yes" callback=""} 429 | ``` 430 | 431 | The request: 432 | 433 | ``` 434 | $.ajax({ 435 | url: "http://yoursite.com/group/template", 436 | dataType: "jsonp", 437 | jsonpCallback: "yourCallbackFunction" 438 | }); 439 | function yourCallbackFunction(data) { 440 | console.log(data); 441 | } 442 | ``` 443 | 444 | ## Changelog 445 | 446 | ### v1.1.8 447 | 448 | - Added `json_plugin_entries_end` and `json_plugin_members_end` hooks 449 | - Improved Wygwam support 450 | - Fixed intermittent disappearing `ee()->TMPL` object 451 | 452 | ### v1.1.7 453 | 454 | - Added `offset` support for members 455 | 456 | ### v1.1.6 457 | 458 | - Add Channel Files support. 459 | 460 | ### v1.1.5 461 | 462 | - Add `root_node` and `item_root_node` parameters. 463 | 464 | ### v1.1.4 465 | 466 | - Add manipulations to Assets fields 467 | 468 | ### v1.1.3 469 | 470 | - Fix bug where show_categories parameter did not work 471 | 472 | ### v1.1.2 473 | 474 | - Fix bug where `fields` parameter was not being honored 475 | - Fix bug causing fatal MySQL error when using the `fixed_order` parameter 476 | 477 | ### v1.1.1 478 | 479 | - Fix WSOD on Plugins page 480 | - Fix PHP errors when an Assests field has no selection(s) 481 | 482 | ### v1.1.0 483 | 484 | - Added support for the following fieldtypes: Assets, Grid, Playa, Relationships 485 | - Change IDs (entry_id, author_id, etc.) and Dates to integers 486 | - Added `show_categories` and `show_category_group` parameters to `{exp:json:entries}` 487 | - Added `{exp:json:search}` 488 | - Added JSONP support 489 | - Added `date_format` parameter 490 | - Added `content_type` parameter 491 | 492 | ## Upgrading from 1.0.x 493 | 494 | - IDs (entry_id, author_id, etc.) and Dates are returned as integers 495 | - The following fieldtypes have different output: Playa, Assets. Please see docs above for an example of their output. 496 | -------------------------------------------------------------------------------- /system/expressionengine/third_party/json/libraries/Json_Template.php: -------------------------------------------------------------------------------- 1 | TMPL =& ee()->TMPL; 22 | 23 | // Override the "real" TMPL object 24 | ee()->TMPL =& $this; 25 | } 26 | 27 | public function __destruct() 28 | { 29 | // Restore the "real" TMPL object 30 | ee()->TMPL =& $this->TMPL; 31 | } 32 | 33 | public function parse_variables($tagdata, $variables, $enable_backspace = TRUE) 34 | { 35 | $output = parent::parse_variables($tagdata, $variables, $enable_backspace); 36 | $this->variables = $variables; 37 | return $output; 38 | } 39 | 40 | public function parse_variables_row($tagdata, $variables, $solo = TRUE) 41 | { 42 | $this->variables = $variables; 43 | return parent::parse_variables_row($tagdata, $variables, $solo); 44 | } 45 | } -------------------------------------------------------------------------------- /system/expressionengine/third_party/json/libraries/Jsonp.php: -------------------------------------------------------------------------------- 1 | false, 33 | 'hello' => true, 34 | 'alert()' => false, 35 | 'test()' => false, 36 | 'a-b' => false, 37 | '23foo' => false, 38 | 'foo23' => true, 39 | '$210' => true, 40 | '_bar' => true, 41 | 'some_var' => true, 42 | '$' => true, 43 | 'somevar' => true, 44 | 'function' => false, 45 | ' somevar' => false, 46 | '$.ajaxHandler' => true, 47 | '$.23' => false, 48 | 'array_of_functions[42]' => true, 49 | 'array_of_functions[42][1]' => true, 50 | '$.ajaxHandler[42][1].foo' => true, 51 | 'array_of_functions[42]foo[1]' => false, 52 | 'array_of_functions[]' => false, 53 | 'array_of_functions["key"]' => true, 54 | 'myFunction[123].false' => false, 55 | 'myFunction .tester' => false, 56 | '_function' => true, 57 | 'petersCallback1412331422[12]' => true, 58 | ':myFunction' => false 59 | ); 60 | 61 | /** 62 | * Is valid callback 63 | * 64 | * @param string $callback 65 | * 66 | * @return boolean 67 | */ 68 | function isValidCallback($callback) 69 | { 70 | $reserved = array( 71 | 'break', 72 | 'do', 73 | 'instanceof', 74 | 'typeof', 75 | 'case', 76 | 'else', 77 | 'new', 78 | 'var', 79 | 'catch', 80 | 'finally', 81 | 'return', 82 | 'void', 83 | 'continue', 84 | 'for', 85 | 'switch', 86 | 'while', 87 | 'debugger', 88 | 'function', 89 | 'this', 90 | 'with', 91 | 'default', 92 | 'if', 93 | 'throw', 94 | 'delete', 95 | 'in', 96 | 'try', 97 | 'class', 98 | 'enum', 99 | 'extends', 100 | 'super', 101 | 'const', 102 | 'export', 103 | 'import', 104 | 'implements', 105 | 'let', 106 | 'private', 107 | 'public', 108 | 'yield', 109 | 'interface', 110 | 'package', 111 | 'protected', 112 | 'static', 113 | 'null', 114 | 'true', 115 | 'false' 116 | ); 117 | 118 | foreach(explode('.', $callback) as $identifier) { 119 | if(!preg_match('/^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|\'.+\'|\d+)\])*?$/', $identifier)) { 120 | return false; 121 | } 122 | if(in_array($identifier, $reserved)) { 123 | return false; 124 | } 125 | } 126 | 127 | return true; 128 | } 129 | 130 | /** 131 | * Test callback strings 132 | * 133 | * @param string $callback 134 | * 135 | * @return void 136 | * 137 | * @access private 138 | */ 139 | private function _test($callback, $valid) 140 | { 141 | $vocal = $valid ? 'valid' : 'invalid'; 142 | if($this->isValidCallback($callback) === $valid) { 143 | echo '"'.$callback.'" passed as '.$vocal.'.', "\n"; 144 | return true; 145 | } 146 | else { 147 | echo '"'.$callback.'" failed as '.$vocal.'.', "\n"; 148 | return false; 149 | } 150 | } 151 | 152 | /** 153 | * Run all tests 154 | * 155 | * @return void 156 | * 157 | * @access public 158 | */ 159 | function runTests() 160 | { 161 | echo 'Testing ', count($this->_tests), ' callback methods:', "\n\n"; 162 | $passed = 0; 163 | foreach($this->_tests as $callback => $valid) { 164 | $passed = self::_test($callback, $valid) ? $passed+1 : $passed; 165 | } 166 | echo "\n", $passed, ' of ', count($this->_tests), ' tests passed.'; 167 | } 168 | } -------------------------------------------------------------------------------- /system/expressionengine/third_party/json/pi.json.php: -------------------------------------------------------------------------------- 1 | 'JSON', 5 | 'pi_version' => '1.1.8', 6 | 'pi_author' => 'Rob Sanchez', 7 | 'pi_author_url' => 'https://github.com/rsanchez', 8 | 'pi_description' => 'Output ExpressionEngine data in JSON format.', 9 | 'pi_usage' => ' 10 | {exp:json:entries channel="news"} 11 | 12 | {exp:json:entries channel="products" search:product_size="10"} 13 | 14 | {exp:json:members member_id="1"}', 15 | ); 16 | 17 | class Json 18 | { 19 | /* settings */ 20 | protected $content_type = 'application/json'; 21 | protected $terminate = FALSE; 22 | protected $xhr = FALSE; 23 | protected $fields = array(); 24 | protected $date_format = FALSE; 25 | protected $jsonp = FALSE; 26 | protected $callback; 27 | 28 | /* caches */ 29 | public $entries; 30 | public $entries_entry_ids; 31 | public $entries_custom_fields; 32 | protected $entries_matrix_rows; 33 | protected $entries_matrix_cols; 34 | protected $entries_grid_rows; 35 | protected $entries_grid_cols; 36 | protected $entries_rel_data; 37 | protected $entries_relationship_data; 38 | protected $entries_playa_data; 39 | protected $entries_channel_files_data; 40 | protected $image_manipulations = array(); 41 | 42 | public function entries($entry_ids = null) 43 | { 44 | $this->initialize('entries'); 45 | 46 | //exit if ajax request is required and not found 47 | if ($this->check_xhr_required()) 48 | { 49 | return ''; 50 | } 51 | 52 | //instantiate channel module object 53 | if (empty($this->channel)) 54 | { 55 | require_once PATH_MOD.'channel/mod.channel'.EXT; 56 | 57 | $this->channel = new Channel; 58 | } 59 | 60 | $this->channel->initialize(); 61 | 62 | $order_by_string = ''; 63 | 64 | if (is_array($entry_ids)) 65 | { 66 | $this->entries_entry_ids = $entry_ids; 67 | $order_by_string = 'FIELD(t.entry_id,'.implode(',', $entry_ids).')'; 68 | } 69 | else 70 | { 71 | //run through the channel module process to grab the entries 72 | $this->channel->uri = ($this->channel->query_string != '') ? $this->channel->query_string : 'index.php'; 73 | 74 | if ($this->channel->enable['custom_fields'] === TRUE) 75 | { 76 | $this->channel->fetch_custom_channel_fields(); 77 | } 78 | 79 | $save_cache = FALSE; 80 | 81 | if (ee()->config->item('enable_sql_caching') == 'y') 82 | { 83 | if (FALSE == ($this->channel->sql = $this->channel->fetch_cache())) 84 | { 85 | $save_cache = TRUE; 86 | } 87 | else 88 | { 89 | if (ee()->TMPL->fetch_param('dynamic') != 'no') 90 | { 91 | if (preg_match("#(^|\/)C(\d+)#", $this->channel->query_string, $match) OR in_array($this->channel->reserved_cat_segment, explode("/", $this->channel->query_string))) 92 | { 93 | $this->channel->cat_request = TRUE; 94 | } 95 | } 96 | } 97 | } 98 | 99 | if ( ! $this->channel->sql) 100 | { 101 | $this->channel->build_sql_query(); 102 | } 103 | 104 | if (preg_match('/t\.entry_id IN \(([\d,]+)\)/', $this->channel->sql, $match)) 105 | { 106 | $this->entries_entry_ids = explode(',', $match[1]); 107 | } 108 | 109 | if (preg_match('/ORDER BY (.*)?/', $this->channel->sql, $match)) 110 | { 111 | $order_by_string = $match[1]; 112 | } 113 | } 114 | 115 | if ($this->entries_entry_ids) 116 | { 117 | $this->entries_custom_fields = ee()->db->select('channel_fields.*, channels.channel_id') 118 | ->from('channel_fields') 119 | ->join('channels', 'channel_fields.group_id = channels.field_group') 120 | ->where('channels.site_id', ee()->config->item('site_id')) 121 | ->where_in('channels.channel_name', explode('|', ee()->TMPL->fetch_param('channel'))) 122 | ->get() 123 | ->result_array(); 124 | 125 | $default_fields = array( 126 | 't.title', 127 | 't.url_title', 128 | 't.entry_id', 129 | 't.channel_id', 130 | 't.author_id', 131 | 't.status', 132 | 't.entry_date', 133 | 't.edit_date', 134 | 't.expiration_date', 135 | ); 136 | 137 | $select = array(); 138 | 139 | if ( ! empty($this->fields)) 140 | { 141 | foreach ($default_fields as $field) 142 | { 143 | $key = substr($field, 2); 144 | 145 | if (in_array($key, $this->fields)) 146 | { 147 | $select[] = $field; 148 | } 149 | } 150 | } 151 | else 152 | { 153 | $select = $default_fields; 154 | } 155 | 156 | foreach ($this->entries_custom_fields as &$field) 157 | { 158 | if (empty($this->fields) || in_array($field['field_name'], $this->fields)) 159 | { 160 | $select[] = 'wd.'.ee()->db->protect_identifiers('field_id_'.$field['field_id']).' AS '.ee()->db->protect_identifiers($field['field_name']); 161 | } 162 | } 163 | 164 | //we need entry_id, always grab it 165 | if ( ! in_array('t.entry_id', $select)) 166 | { 167 | $select[] = 't.entry_id'; 168 | } 169 | 170 | ee()->db->select(implode(', ', $select), FALSE) 171 | ->from('channel_titles t') 172 | ->join('channel_data wd', 't.entry_id = wd.entry_id') 173 | ->where_in('t.entry_id', $this->entries_entry_ids); 174 | 175 | if ($order_by_string) 176 | { 177 | if (strpos($order_by_string, 'w.') !== FALSE) 178 | { 179 | ee()->db->join('channels w', 't.channel_id = w.channel_id'); 180 | } 181 | 182 | if (strpos($order_by_string, 'm.') !== FALSE) 183 | { 184 | ee()->db->join('members m', 'm.member_id = t.author_id'); 185 | } 186 | 187 | if (strpos($order_by_string, 'md.') !== FALSE) 188 | { 189 | ee()->db->join('member_data md', 'm.member_id = md.member_id'); 190 | } 191 | 192 | if (ee()->TMPL->fetch_param('display_by') === 'week' && strpos($order_by_string, 'yearweek') !== FALSE) 193 | { 194 | $yearweek = TRUE; 195 | 196 | $offset = ee()->localize->zones[ee()->config->item('server_timezone')] * 3600; 197 | 198 | $format = (ee()->TMPL->fetch_param('start_day') === 'Monday') ? '%x%v' : '%X%V'; 199 | 200 | ee()->db->select("DATE_FORMAT(FROM_UNIXTIME(entry_date + $offset), '$format') AS yearweek", FALSE); 201 | } 202 | 203 | ee()->db->order_by($order_by_string, '', FALSE); 204 | } 205 | 206 | $query = $this->channel->query = ee()->db->get(); 207 | 208 | $show_categories = ee()->TMPL->fetch_param('show_categories') === 'yes'; 209 | 210 | if ($show_categories) 211 | { 212 | $this->channel->fetch_categories(); 213 | 214 | if (ee()->TMPL->fetch_param('show_category_group')) 215 | { 216 | $show_category_group = explode('|', ee()->TMPL->fetch_param('show_category_group')); 217 | } 218 | } 219 | 220 | $this->entries = $query->result_array(); 221 | 222 | $query->free_result(); 223 | 224 | foreach ($this->entries as &$entry) 225 | { 226 | if (isset($yearweek)) 227 | { 228 | unset($entry['yearweek']); 229 | } 230 | 231 | //format dates as javascript unix time (in microseconds!) 232 | if (isset($entry['entry_date'])) 233 | { 234 | $entry['entry_date'] = $this->date_format($entry['entry_date']); 235 | } 236 | 237 | if (isset($entry['edit_date'])) 238 | { 239 | $entry['edit_date'] = $this->date_format(strtotime($entry['edit_date'])); 240 | } 241 | 242 | if (isset($entry['expiration_date'])) 243 | { 244 | $entry['expiration_date'] = $this->date_format($entry['expiration_date']); 245 | } 246 | 247 | foreach ($this->entries_custom_fields as &$field) 248 | { 249 | //call our custom callback for this fieldtype if it exists 250 | if (isset($entry[$field['field_name']]) && is_callable(array($this, 'entries_'.$field['field_type']))) 251 | { 252 | $entry[$field['field_name']] = call_user_func(array($this, 'entries_'.$field['field_type']), $entry['entry_id'], $field, $entry[$field['field_name']], $entry); 253 | } 254 | } 255 | 256 | if ($show_categories) 257 | { 258 | $entry['categories'] = array(); 259 | 260 | if (isset($this->channel->categories[$entry['entry_id']])) 261 | { 262 | foreach ($this->channel->categories[$entry['entry_id']] as $raw_category) 263 | { 264 | if ( ! empty($show_category_group) && ! in_array($raw_category[5], $show_category_group)) 265 | { 266 | continue; 267 | } 268 | 269 | $category = array( 270 | 'category_id' => (int) $raw_category[0], 271 | 'parent_id' => (int) $raw_category[1], 272 | 'category_name' => $raw_category[2], 273 | 'category_image' => $raw_category[3], 274 | 'category_description' => $raw_category[4], 275 | 'category_group' => $raw_category[5], 276 | 'category_url_title' => $raw_category[6], 277 | ); 278 | 279 | foreach ($this->channel->catfields as $cat_field) 280 | { 281 | $category[$cat_field['field_name']] = (isset($raw_category['field_id_'.$cat_field['field_id']])) ? $raw_category['field_id_'.$cat_field['field_id']] : ''; 282 | } 283 | 284 | $entry['categories'][] = $category; 285 | } 286 | } 287 | } 288 | 289 | $entry['entry_id'] = (int) $entry['entry_id']; 290 | 291 | if (isset($entry['channel_id'])) 292 | { 293 | $entry['channel_id'] = (int) $entry['channel_id']; 294 | } 295 | 296 | if (isset($entry['author_id'])) 297 | { 298 | $entry['author_id'] = (int) $entry['author_id']; 299 | } 300 | } 301 | } 302 | 303 | ee()->load->library('javascript'); 304 | 305 | ee()->load->library('typography'); 306 | 307 | // ---------------------------------------- 308 | // 'json_plugin_entries_end' hook. 309 | // - Enables additional manipulation of entry data 310 | // ---------------------------------------- 311 | 312 | if (ee()->extensions->active_hook('json_plugin_entries_end') === TRUE) 313 | { 314 | ee()->extensions->call('json_plugin_entries_end', $this); 315 | if (ee()->extensions->end_script === TRUE) return; 316 | } 317 | // ---------------------------------------- 318 | 319 | return $this->respond($this->entries, array(ee()->typography, 'parse_file_paths')); 320 | } 321 | 322 | protected function entries_matrix($entry_id, $field, $field_data) 323 | { 324 | if (is_null($this->entries_matrix_rows)) 325 | { 326 | $query = ee()->db->where_in('entry_id', $this->entries_entry_ids) 327 | ->order_by('row_order') 328 | ->get('matrix_data'); 329 | 330 | foreach ($query->result_array() as $row) 331 | { 332 | if ( ! isset($this->entries_matrix_rows[$row['entry_id']])) 333 | { 334 | $this->entries_matrix_rows[$row['entry_id']] = array(); 335 | } 336 | 337 | if ( ! isset($this->entries_matrix_rows[$row['entry_id']][$row['field_id']])) 338 | { 339 | $this->entries_matrix_rows[$row['entry_id']][$row['field_id']] = array(); 340 | } 341 | 342 | $this->entries_matrix_rows[$row['entry_id']][$row['field_id']][] = $row; 343 | } 344 | 345 | $query->free_result(); 346 | } 347 | 348 | if (is_null($this->entries_matrix_cols)) 349 | { 350 | $query = ee()->db->get('matrix_cols'); 351 | 352 | foreach ($query->result_array() as $row) 353 | { 354 | $this->entries_matrix_cols[$row['col_id']] = $row; 355 | } 356 | 357 | $query->free_result(); 358 | } 359 | 360 | $data = array(); 361 | 362 | if (isset($this->entries_matrix_rows[$entry_id][$field['field_id']])) 363 | { 364 | $field_settings = unserialize(base64_decode($field['field_settings'])); 365 | 366 | foreach ($this->entries_matrix_rows[$entry_id][$field['field_id']] as $matrix_row) 367 | { 368 | $row = array('row_id' => (int) $matrix_row['row_id']); 369 | 370 | foreach ($field_settings['col_ids'] as $col_id) 371 | { 372 | if (isset($this->entries_matrix_cols[$col_id])) 373 | { 374 | $row[$this->entries_matrix_cols[$col_id]['col_name']] = $matrix_row['col_id_'.$col_id]; 375 | } 376 | } 377 | 378 | $data[] = $row; 379 | } 380 | } 381 | 382 | return $data; 383 | } 384 | 385 | protected function entries_grid($entry_id, $field, $field_data) 386 | { 387 | if ( ! isset($this->entries_grid_rows[$field['field_id']])) 388 | { 389 | $query = ee()->db->where_in('entry_id', $this->entries_entry_ids) 390 | ->order_by('row_order') 391 | ->get('channel_grid_field_'.$field['field_id']); 392 | 393 | foreach ($query->result_array() as $row) 394 | { 395 | if ( ! isset($this->entries_grid_rows[$field['field_id']][$row['entry_id']])) 396 | { 397 | $this->entries_grid_rows[$field['field_id']][$row['entry_id']] = array(); 398 | } 399 | 400 | $this->entries_grid_rows[$field['field_id']][$row['entry_id']][] = $row; 401 | } 402 | 403 | $query->free_result(); 404 | } 405 | 406 | if (is_null($this->entries_grid_cols)) 407 | { 408 | $query = ee()->db->order_by('col_order', 'ASC') 409 | ->get('grid_columns'); 410 | 411 | foreach ($query->result_array() as $row) 412 | { 413 | if ( ! isset($this->entries_grid_cols[$row['field_id']])) 414 | { 415 | $this->entries_grid_cols[$row['field_id']] = array(); 416 | } 417 | 418 | $this->entries_grid_cols[$row['field_id']][$row['col_id']] = $row; 419 | } 420 | 421 | $query->free_result(); 422 | } 423 | 424 | $data = array(); 425 | 426 | if (isset($this->entries_grid_rows[$field['field_id']][$entry_id]) && isset($this->entries_grid_cols[$field['field_id']])) 427 | { 428 | foreach ($this->entries_grid_rows[$field['field_id']][$entry_id] as $grid_row) 429 | { 430 | $row = array('row_id' => (int) $grid_row['row_id']); 431 | 432 | foreach ($this->entries_grid_cols[$field['field_id']] as $col_id => $col) 433 | { 434 | $row[$col['col_name']] = $grid_row['col_id_'.$col_id]; 435 | } 436 | 437 | $data[] = $row; 438 | } 439 | } 440 | 441 | return $data; 442 | } 443 | 444 | protected function entries_rel($entry_id, $field, $field_data) 445 | { 446 | if (is_null($this->entries_rel_data)) 447 | { 448 | $query = ee()->db->select('rel_child_id, rel_id') 449 | ->where('rel_parent_id', $entry_id) 450 | ->get('relationships'); 451 | 452 | $this->entries_rel_data = array(); 453 | 454 | foreach ($query->result() as $row) 455 | { 456 | $this->entries_rel_data[$row->rel_id] = (int) $row->rel_child_id; 457 | } 458 | 459 | $query->free_result(); 460 | } 461 | 462 | if ( ! isset($this->entries_rel_data[$field_data])) 463 | { 464 | return NULL; 465 | } 466 | 467 | return $this->entries_rel_data[$field_data]; 468 | } 469 | 470 | protected function entries_relationship($entry_id, $field, $field_data) 471 | { 472 | if (is_null($this->entries_relationship_data)) 473 | { 474 | $query = ee()->db->select('parent_id, child_id, field_id') 475 | ->where_in('parent_id', $this->entries_entry_ids) 476 | ->order_by('order', 'asc') 477 | ->get('relationships'); 478 | 479 | foreach ($query->result_array() as $row) 480 | { 481 | if ( ! isset($this->entries_relationship_data[$row['parent_id']])) 482 | { 483 | $this->entries_relationship_data[$row['parent_id']] = array(); 484 | } 485 | 486 | if ( ! isset($this->entries_relationship_data[$row['parent_id']][$row['field_id']])) 487 | { 488 | $this->entries_relationship_data[$row['parent_id']][$row['field_id']] = array(); 489 | } 490 | 491 | $this->entries_relationship_data[$row['parent_id']][$row['field_id']][] = (int) $row['child_id']; 492 | } 493 | 494 | $query->free_result(); 495 | } 496 | 497 | if (isset($this->entries_relationship_data[$entry_id][$field['field_id']])) 498 | { 499 | return $this->entries_relationship_data[$entry_id][$field['field_id']]; 500 | } 501 | 502 | return array(); 503 | } 504 | 505 | protected function entries_playa($entry_id, $field, $field_data) 506 | { 507 | if (is_null($this->entries_playa_data)) 508 | { 509 | $query = ee()->db->select('parent_entry_id, child_entry_id, parent_field_id') 510 | ->where_in('parent_entry_id', $this->entries_entry_ids) 511 | ->order_by('rel_order', 'asc') 512 | ->get('playa_relationships'); 513 | 514 | foreach ($query->result_array() as $row) 515 | { 516 | if ( ! isset($this->entries_playa_data[$row['parent_entry_id']])) 517 | { 518 | $this->entries_playa_data[$row['parent_entry_id']] = array(); 519 | } 520 | 521 | if ( ! isset($this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']])) 522 | { 523 | $this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']] = array(); 524 | } 525 | 526 | $this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']][] = (int) $row['child_entry_id']; 527 | } 528 | 529 | $query->free_result(); 530 | } 531 | 532 | if (isset($this->entries_playa_data[$entry_id][$field['field_id']])) 533 | { 534 | return $this->entries_playa_data[$entry_id][$field['field_id']]; 535 | } 536 | 537 | return array(); 538 | } 539 | 540 | protected function entries_channel_files($entry_id, $field, $field_data, $entry) 541 | { 542 | $this->entries_channel_files_data = array(); 543 | 544 | $field_settings = unserialize(base64_decode($field['field_settings'])); 545 | $field_settings = $field_settings['channel_files']; 546 | 547 | $query = ee()->db->select() 548 | ->where('entry_id', $entry_id) 549 | ->where('field_id', $field['field_id']) 550 | ->order_by('file_order', 'asc') 551 | ->get('channel_files'); 552 | 553 | foreach ($query->result_array() as $row) 554 | { 555 | $field_data = array( 556 | 'file_id' => (int) $row['file_id'], 557 | 'url' => $row['filename'], 558 | 'filename' => $row['filename'], 559 | 'extension' => $row['extension'], 560 | 'kind' => $row['mime'], 561 | 'size' => $row['filesize'], 562 | 'title' => $row['title'], 563 | 'date' => $this->date_format($row['date']), 564 | 'author' => (int)$row['member_id'], 565 | 'desc' => $row['description'], 566 | 'primary' => (bool)$row['file_primary'], 567 | 'downloads' => (int)$row['downloads'], 568 | 'custom1' => (isset($row['cffield1']) ? $row['cffield1'] : null), 569 | 'custom2' => (isset($row['cffield2']) ? $row['cffield2'] : null), 570 | 'custom3' => (isset($row['cffield3']) ? $row['cffield3'] : null), 571 | 'custom4' => (isset($row['cffield4']) ? $row['cffield4'] : null), 572 | 'custom5' => (isset($row['cffield5']) ? $row['cffield5'] : null) 573 | ); 574 | 575 | $fieldtype_specific_settings = $field_settings['locations'][$row['upload_service']]; 576 | 577 | switch ($row['upload_service']) 578 | { 579 | case 'local': 580 | // get upload folder details from EE 581 | $query = ee()->db->select('url') 582 | ->where('id', $fieldtype_specific_settings['location']) 583 | ->get('exp_upload_prefs'); 584 | 585 | $result = $query->row_array(); 586 | $query->free_result(); 587 | 588 | $base_url = $result['url'] . ($field_settings['entry_id_folder'] == 'yes' ? $entry_id . '/' : ''); 589 | $field_data['url'] = $base_url . $field_data['url']; 590 | break; 591 | case 's3': 592 | if ($fieldtype_specific_settings['cloudfront_domain'] != '') 593 | { 594 | $domain = rtrim($fieldtype_specific_settings['cloudfront_domain'], '/'); 595 | $domain = 'http://' . preg_replace('#https?://#', '', $domain); 596 | } 597 | else 598 | { 599 | $domain = "http://{$fieldtype_specific_settings['bucket']}.s3.amazonaws.com"; 600 | } 601 | 602 | 603 | $dir = ($fieldtype_specific_settings['directory'] != '' ? rtrim($fieldtype_specific_settings['directory'], '/') . '/' : ''); 604 | 605 | $base_url = "{$domain}/{$dir}{$entry_id}/"; 606 | $field_data['url'] = $base_url . $field_data['url']; 607 | break; 608 | case 'cloudfiles': 609 | case 'ftp': 610 | case 'sftp': 611 | require_once PATH_THIRD.'channel_files/locations/cfile_location.php'; 612 | require_once PATH_THIRD."channel_files/locations/{$row['upload_service']}/{$row['upload_service']}.php"; 613 | 614 | $class_name = "CF_Location_{$row['upload_service']}"; 615 | $cf = new $class_name($fieldtype_specific_settings); 616 | $dir = $entry_id; 617 | $entry_id_folder = (isset($fieldtype_specific_settings['entry_id_folder']) ? $fieldtype_specific_settings['entry_id_folder'] : null);; 618 | if (isset($entry_id_folder) && $fieldtype_specific_settings['entry_id_folder'] == 'no') 619 | { 620 | $dir = FALSE; 621 | } 622 | 623 | $field_data['url'] = $cf->parse_file_url($dir, $field_data['url']); 624 | break; 625 | default: 626 | break; 627 | } 628 | 629 | // make file size relevant 630 | $units = array('B', 'KB', 'MB', 'GB'); 631 | $units_index = 0; 632 | while ($field_data['size'] >= 1024) 633 | { 634 | $field_data['size'] /= 1024; 635 | $units_index++; 636 | } 637 | $field_data['size'] = round($field_data['size']) . ' ' . $units[$units_index]; 638 | 639 | $this->entries_channel_files_data[$row['field_id']][] = $field_data; 640 | } 641 | 642 | $query->free_result(); 643 | 644 | if (isset($row['field_id'], $this->entries_channel_files_data[$row['field_id']])) 645 | { 646 | return $this->entries_channel_files_data[$row['field_id']]; 647 | } 648 | 649 | return array(); 650 | } 651 | 652 | protected function entries_date($entry_id, $field, $field_data) 653 | { 654 | return $this->date_format($field_data); 655 | } 656 | 657 | protected function entries_text($entry_id, $field, $field_data) 658 | { 659 | $field_settings = ee()->api_channel_fields->get_settings($field['field_id']); 660 | 661 | if ($field_settings['field_content_type'] === 'numeric' || $field_settings['field_content_type'] === 'decimal') 662 | { 663 | return floatval($field_data); 664 | } 665 | 666 | if ($field_settings['field_content_type'] === 'integer') 667 | { 668 | return intval($field_data); 669 | } 670 | 671 | return $field_data; 672 | } 673 | 674 | protected function entries_custom_field($entry_id, $field, $field_data, $entry, $tagdata = ' ') 675 | { 676 | ee()->load->add_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']], FALSE); 677 | 678 | ee()->api_channel_fields->setup_handler($field['field_id']); 679 | 680 | ee()->api_channel_fields->apply('_init', array(array( 681 | 'row' => $entry, 682 | 'content_id' => $entry['entry_id'], 683 | 'content_type' => 'channel', 684 | ))); 685 | 686 | $field_data = ee()->api_channel_fields->apply('pre_process', array($field_data)); 687 | 688 | if (ee()->api_channel_fields->check_method_exists('replace_tag')) 689 | { 690 | require_once PATH_THIRD.'json/libraries/Json_Template.php'; 691 | 692 | $ee_tmpl = ee()->TMPL; 693 | $template = new Json_Template(); 694 | 695 | $field_data = ee()->api_channel_fields->apply('replace_tag', array($field_data, array(), $tagdata)); 696 | 697 | if ($template->variables) 698 | { 699 | $field_data = $template->variables; 700 | } 701 | 702 | unset($template); 703 | ee()->TMPL = $ee_tmpl; 704 | } 705 | 706 | ee()->load->remove_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']]); 707 | 708 | return $field_data; 709 | } 710 | 711 | protected function entries_wygwam($entry_id, $field, $field_data, $entry) { 712 | return $this->entries_custom_field($entry_id, $field, $field_data, $entry); 713 | } 714 | 715 | protected function entries_assets($entry_id, $field, $field_data, $entry) 716 | { 717 | $field_data = $this->entries_custom_field($entry_id, $field, $field_data, $entry); 718 | 719 | if ( ! is_array($field_data)) 720 | { 721 | $field_data = array(); 722 | } 723 | 724 | if (isset($field_data['absolute_total_files']) && $field_data['absolute_total_files'] === 0) 725 | { 726 | return array(); 727 | } 728 | 729 | $fields = array( 730 | 'file_id', 731 | 'url', 732 | 'subfolder', 733 | 'filename', 734 | 'extension', 735 | 'date_modified', 736 | 'kind', 737 | 'width', 738 | 'height', 739 | 'size', 740 | 'title', 741 | 'date', 742 | 'alt_text', 743 | 'caption', 744 | 'author', 745 | 'desc', 746 | 'location', 747 | ); 748 | 749 | foreach ($field_data as &$row) 750 | { 751 | $source_type = $row['source_type']; 752 | $filedir_id = $row['filedir_id']; 753 | //excise any other fields from this row 754 | $row = array_intersect_key($row, array_flip($fields)); 755 | $row['file_id'] = (int) $row['file_id']; 756 | $row['date'] = $this->date_format($row['date']); 757 | $row['date_modified'] = $this->date_format($row['date_modified']); 758 | 759 | $row['manipulations'] = array(); 760 | 761 | if ($source_type === 'ee') 762 | { 763 | if ( ! isset($this->image_manipulations[$filedir_id])) 764 | { 765 | ee()->load->model('file_model'); 766 | 767 | $query = ee()->file_model->get_dimensions_by_dir_id($filedir_id); 768 | 769 | $this->image_manipulations[$filedir_id] = $query->result(); 770 | 771 | $query->free_result(); 772 | } 773 | 774 | foreach ($this->image_manipulations[$filedir_id] as $manipulation) 775 | { 776 | $row['manipulations'][$manipulation->short_name] = pathinfo($row['url'], PATHINFO_DIRNAME).'/_'.$manipulation->short_name.'/'.basename($row['url']); 777 | } 778 | } 779 | } 780 | 781 | return $field_data; 782 | } 783 | 784 | public function search() 785 | { 786 | $search_id = ee()->TMPL->fetch_param('search_id'); 787 | 788 | if ( ! $search_id) 789 | { 790 | $search_id = end(ee()->uri->segment_array()); 791 | } 792 | 793 | if ($search_id) 794 | { 795 | $query = ee()->db->where('search_id', $search_id) 796 | ->limit(1) 797 | ->get('exp_search'); 798 | 799 | if ($query->num_rows() > 0) 800 | { 801 | $search = $query->row_array(); 802 | 803 | $query->free_result(); 804 | 805 | if (preg_match('/IN \(([\d,]+)\)/', $query->row('query'), $match)) 806 | { 807 | ee()->TMPL->tagparams['entry_id'] = (strpos($match[1], ',') !== FALSE) ? str_replace(',', '|', $match[1]) : $match[1]; 808 | 809 | return $this->entries(); 810 | } 811 | } 812 | } 813 | 814 | $this->initialize(); 815 | 816 | return $this->respond(array()); 817 | } 818 | 819 | /** 820 | * Categories 821 | * 822 | * @TODO a work in progress, does not work yet 823 | * 824 | * @param array|null $params 825 | * 826 | * @return string 827 | */ 828 | public function categories($params = NULL) 829 | { 830 | $this->initialize(); 831 | 832 | if (is_null($params)) 833 | { 834 | $params = ee()->TMPL->tagparams; 835 | } 836 | 837 | ee()->load->helper('array'); 838 | 839 | $channel = element('channel', $params); 840 | $group_id = element('group_id', $params, element('category_group', $params)); 841 | $cat_id = element('cat_id', $params, element('category_id', $params, element('show', $params))); 842 | $status = element('status', $params); 843 | $parent_only = element('parent_only', $params); 844 | $show_empty = element('show_empty', $params, TRUE); 845 | $joins = array(); 846 | 847 | if ($channel) 848 | { 849 | ee()->db->join('channel_titles', 'channel_titles.entry_id = category_posts.entry_id'); 850 | ee()->db->join('channels', 'channels.channel_id = channel_titles.channel_id'); 851 | ee()->db->where_in('channels.channel_name', explode('|', $channel)); 852 | $joins[] = 'channels'; 853 | $joins[] = 'channel_titles'; 854 | } 855 | 856 | if ($group_id) 857 | { 858 | ee()->db->where_in('categories.group_id', explode('|', $group_id)); 859 | } 860 | 861 | if ($cat_id) 862 | { 863 | ee()->db->where_in('categories.cat_id', explode('|', $cat_id)); 864 | } 865 | 866 | if ($status) 867 | { 868 | if ( ! in_array('channel_titles', $joins)) 869 | { 870 | ee()->db->join('channel_titles', 'channel_titles.entry_id = category_posts.entry_id'); 871 | } 872 | 873 | ee()->db->where_in('channel_titles.status', explode('|', $status)); 874 | } 875 | 876 | if ($parent_only) 877 | { 878 | ee()->db->where('categories.parent_id', 0); 879 | } 880 | 881 | if ($show_empty) 882 | { 883 | ee()->db->where('count >', 0); 884 | } 885 | } 886 | 887 | /** 888 | * Members 889 | * 890 | * @return string 891 | */ 892 | public function members() 893 | { 894 | $this->initialize(); 895 | 896 | if ($this->check_xhr_required()) 897 | { 898 | return ''; 899 | } 900 | 901 | $default_fields = array( 902 | 'm.member_id', 903 | 'm.group_id', 904 | 'm.username', 905 | 'm.screen_name', 906 | 'm.email', 907 | 'm.signature', 908 | 'm.avatar_filename', 909 | 'm.avatar_width', 910 | 'm.avatar_height', 911 | 'm.photo_filename', 912 | 'm.photo_width', 913 | 'm.photo_height', 914 | 'm.url', 915 | 'm.location', 916 | 'm.occupation', 917 | 'm.interests', 918 | 'm.bio', 919 | 'm.join_date', 920 | 'm.last_visit', 921 | 'm.last_activity', 922 | 'm.last_entry_date', 923 | 'm.last_comment_date', 924 | 'm.last_forum_post_date', 925 | 'm.total_entries', 926 | 'm.total_comments', 927 | 'm.total_forum_topics', 928 | 'm.total_forum_posts', 929 | 'm.language', 930 | 'm.timezone', 931 | 'm.bday_d', 932 | 'm.bday_m', 933 | 'm.bday_y', 934 | ); 935 | 936 | if (version_compare(APP_VER, '2.6', '<')) 937 | { 938 | $default_fields[] = 'm.daylight_savings'; 939 | } 940 | 941 | $query = ee()->db->select('m_field_id, m_field_name') 942 | ->get('member_fields'); 943 | 944 | $custom_fields = $query->result_array(); 945 | 946 | $query->free_result(); 947 | 948 | $select = array(); 949 | 950 | if ( ! empty($this->fields)) 951 | { 952 | foreach ($default_fields as $field) 953 | { 954 | $key = substr($field, 2); 955 | 956 | if (in_array($key, $this->fields)) 957 | { 958 | $select[] = $field; 959 | } 960 | } 961 | } 962 | else 963 | { 964 | $select = $default_fields; 965 | } 966 | 967 | foreach ($custom_fields as &$field) 968 | { 969 | if (empty($this->fields) || in_array($field['m_field_name'], $this->fields)) 970 | { 971 | $select[] = 'd.'.ee()->db->protect_identifiers('m_field_id_'.$field['m_field_id']).' AS '.ee()->db->protect_identifiers($field['m_field_name']); 972 | } 973 | } 974 | 975 | ee()->db->select(implode(', ', $select), FALSE) 976 | ->from('members m') 977 | ->join('member_data d', 'm.member_id = d.member_id'); 978 | 979 | if ($member_ids = ee()->TMPL->fetch_param('member_id')) 980 | { 981 | if ($member_ids === 'CURRENT_USER') 982 | { 983 | $member_ids = ee()->session->userdata('member_id'); 984 | } 985 | 986 | ee()->db->where_in('m.member_id', explode('|', $member_ids)); 987 | } 988 | else if (ee()->TMPL->fetch_param('username')) 989 | { 990 | ee()->db->where_in('m.member_id', explode('|', ee()->TMPL->fetch_param('member_id'))); 991 | } 992 | 993 | if (ee()->TMPL->fetch_param('group_id')) 994 | { 995 | ee()->db->where_in('m.group_id', explode('|', ee()->TMPL->fetch_param('group_id'))); 996 | } 997 | 998 | if (ee()->TMPL->fetch_param('limit')) 999 | { 1000 | ee()->db->limit(ee()->TMPL->fetch_param('limit')); 1001 | } 1002 | 1003 | if (ee()->TMPL->fetch_param('offset')) 1004 | { 1005 | ee()->db->offset(ee()->TMPL->fetch_param('offset')); 1006 | } 1007 | 1008 | $query = ee()->db->get(); 1009 | 1010 | $members = $query->result_array(); 1011 | 1012 | $query->free_result(); 1013 | 1014 | $date_fields = array( 1015 | 'join_date', 1016 | 'last_visit', 1017 | 'last_activity', 1018 | 'last_entry_date', 1019 | 'last_comment_date', 1020 | 'last_forum_post_date' 1021 | ); 1022 | 1023 | foreach ($members as &$member) 1024 | { 1025 | foreach ($date_fields as $field) 1026 | { 1027 | if (isset($member[$field])) 1028 | { 1029 | $member[$field] = $this->date_format($member[$field]); 1030 | } 1031 | } 1032 | } 1033 | 1034 | // ---------------------------------------- 1035 | // 'json_plugin_members_end' hook. 1036 | // - Enables additional manipulation of entry data 1037 | // ---------------------------------------- 1038 | 1039 | if (ee()->extensions->active_hook('json_plugin_members_end') === TRUE) 1040 | { 1041 | $members = ee()->extensions->call('json_plugin_members_end', $members, $this); 1042 | if (ee()->extensions->end_script === TRUE) return; 1043 | } 1044 | // ---------------------------------------- 1045 | 1046 | return $this->respond($members); 1047 | } 1048 | 1049 | protected function initialize($which = NULL) 1050 | { 1051 | switch($which) 1052 | { 1053 | case 'entries': 1054 | //initialize caches 1055 | $this->entries = array(); 1056 | $this->entries_entry_ids = array(); 1057 | $this->entries_custom_fields = array(); 1058 | $this->entries_matrix_rows = NULL; 1059 | $this->entries_rel_data = NULL; 1060 | $this->entries_relationship_data = NULL; 1061 | $this->entries_playa_data = NULL; 1062 | $this->entries_channel_files_data = NULL; 1063 | break; 1064 | } 1065 | 1066 | $this->xhr = ee()->TMPL->fetch_param('xhr') === 'yes'; 1067 | 1068 | $this->terminate = ee()->TMPL->fetch_param('terminate') === 'yes'; 1069 | 1070 | $this->fields = (ee()->TMPL->fetch_param('fields')) ? explode('|', ee()->TMPL->fetch_param('fields')) : array(); 1071 | 1072 | $this->date_format = ee()->TMPL->fetch_param('date_format'); 1073 | 1074 | // get rid of EE formatted dates 1075 | if ($this->date_format && strstr($this->date_format, '%')) 1076 | { 1077 | $this->date_format = str_replace('%', '', $this->date_format); 1078 | } 1079 | 1080 | $this->jsonp = ee()->TMPL->fetch_param('jsonp') === 'yes'; 1081 | 1082 | ee()->load->library('jsonp'); 1083 | 1084 | $this->callback = (ee()->TMPL->fetch_param('callback') && ee()->jsonp->isValidCallback(ee()->TMPL->fetch_param('callback'))) 1085 | ? ee()->TMPL->fetch_param('callback') : NULL; 1086 | 1087 | $this->content_type = ee()->TMPL->fetch_param('content_type', ($this->jsonp && $this->callback) ? 'application/javascript' : 'application/json'); 1088 | } 1089 | 1090 | protected function check_xhr_required() 1091 | { 1092 | return $this->xhr && ! ee()->input->is_ajax_request(); 1093 | } 1094 | 1095 | protected function date_format($date) 1096 | { 1097 | if ( ! $date) 1098 | { 1099 | return NULL; 1100 | } 1101 | 1102 | return ($this->date_format) ? date($this->date_format, $date) : $date * 1000; 1103 | } 1104 | 1105 | protected function respond(array $response, $callback = NULL) 1106 | { 1107 | ee()->load->library('javascript'); 1108 | 1109 | if ($item_root_node = ee()->TMPL->fetch_param('item_root_node')) 1110 | { 1111 | $response_with_nodes = array(); 1112 | 1113 | foreach($response as $item) 1114 | { 1115 | $response_with_nodes[] = array($item_root_node => $item); 1116 | } 1117 | 1118 | $response = $response_with_nodes; 1119 | } 1120 | 1121 | if ($root_node = ee()->TMPL->fetch_param('root_node')) 1122 | { 1123 | $response = array($root_node => $response); 1124 | } 1125 | 1126 | $response = function_exists('json_encode') 1127 | ? json_encode($response) 1128 | : ee()->javascript->generate_json($response, TRUE); 1129 | 1130 | if ( ! is_null($callback)) 1131 | { 1132 | $response = call_user_func($callback, $response); 1133 | } 1134 | 1135 | if ($this->check_xhr_required()) 1136 | { 1137 | $response = ''; 1138 | } 1139 | else if ($this->jsonp && $this->callback) 1140 | { 1141 | $response = sprintf('%s(%s)', $this->callback, $response); 1142 | } 1143 | 1144 | if ($this->terminate) 1145 | { 1146 | @header('Content-Type: '.$this->content_type); 1147 | 1148 | exit($response); 1149 | } 1150 | 1151 | return $response; 1152 | } 1153 | } 1154 | 1155 | /* End of file pi.json.php */ 1156 | /* Location: ./system/expressionengine/third_party/json/pi.json.php */ 1157 | --------------------------------------------------------------------------------