From 94d285f3fc0fe1aaa9053d07f3d37ada6121bf13 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:13:04 +0200 Subject: [PATCH 01/17] Create addon.setup.php --- .../user/addons/json_output/addon.setup.php | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 system/user/addons/json_output/addon.setup.php diff --git a/system/user/addons/json_output/addon.setup.php b/system/user/addons/json_output/addon.setup.php new file mode 100644 index 0000000..98e4583 --- /dev/null +++ b/system/user/addons/json_output/addon.setup.php @@ -0,0 +1,19 @@ + 'Zignature', + 'author_url' => 'https://github.com/Zignature/ee-json-output', + 'description' => 'Output ExpressionEngine channel entries in JSON format.', + 'docs_url' => 'https://github.com/Zignature/ee-json-output', + 'name' => 'EE JSON Output', + 'settings_exist' => false, + 'version' => '1.0.0', + 'namespace' => 'json_output/json_output' +); From 87edf1110cdb6810c705b111a30f7e7005837af7 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:16:04 +0200 Subject: [PATCH 02/17] Create pi.json_output.php --- .../addons/json_output/pi.json_output.php | 1114 +++++++++++++++++ 1 file changed, 1114 insertions(+) create mode 100644 system/user/addons/json_output/pi.json_output.php diff --git a/system/user/addons/json_output/pi.json_output.php b/system/user/addons/json_output/pi.json_output.php new file mode 100644 index 0000000..d395fb8 --- /dev/null +++ b/system/user/addons/json_output/pi.json_output.php @@ -0,0 +1,1114 @@ +initialize('entries'); + + //exit if ajax request is required and not found + if ($this->check_xhr_required()) + { + return ''; + } + + //instantiate channel module object + if (empty($this->channel)) + { + require_once PATH_MOD.'channel/mod.channel.php'; + + $this->channel = new Channel; + } + + $this->channel->initialize(); + + $order_by_string = ''; + + if (is_array($entry_ids)) + { + $this->entries_entry_ids = $entry_ids; + $order_by_string = 'FIELD(t.entry_id,'.implode(',', $entry_ids).')'; + } + else + { + //run through the channel module process to grab the entries + $this->channel->uri = ($this->channel->query_string != '') ? $this->channel->query_string : 'index.php'; + + if ($this->channel->enable['custom_fields'] === TRUE) + { + $this->channel->fetch_custom_channel_fields(); + } + + $save_cache = FALSE; + + if (ee()->config->item('enable_sql_caching') == 'y') + { + if (FALSE == ($this->channel->sql = $this->channel->fetch_cache())) + { + $save_cache = TRUE; + } + else + { + if (ee()->TMPL->fetch_param('dynamic') != 'no') + { + if (preg_match("#(^|\/)C(\d+)#", $this->channel->query_string, $match) OR in_array($this->channel->reserved_cat_segment, explode("/", $this->channel->query_string))) + { + $this->channel->cat_request = TRUE; + } + } + } + } + + if ( ! $this->channel->sql) + { + $this->channel->build_sql_query(); + } + + if (preg_match('/t\.entry_id IN \(([\d,]+)\)/', $this->channel->sql, $match)) + { + $this->entries_entry_ids = explode(',', $match[1]); + } + + if (preg_match('/ORDER BY (.*)?/', $this->channel->sql, $match)) + { + $order_by_string = $match[1]; + } + } + + if ($this->entries_entry_ids) + { + $this->entries_custom_fields = ee()->db->select('channel_fields.*') + ->from('channel_fields') + ->join('channel_field_groups_fields', 'channel_fields.field_id = channel_field_groups_fields.field_id') + ->join('channels_channel_field_groups', 'channel_field_groups_fields.group_id = channels_channel_field_groups.group_id') + ->join('channels', 'channels_channel_field_groups.channel_id = channels.channel_id') + ->where('channels.site_id', ee()->config->item('site_id')) + ->where_in('channels.channel_name', explode('|', ee()->TMPL->fetch_param('channel'))) + ->get() + ->result_array(); + + $default_fields = array( + 't.title', + 't.url_title', + 't.entry_id', + 't.channel_id', + 't.author_id', + 't.status', + 't.entry_date', + 't.edit_date', + 't.expiration_date', + ); + + $select = array(); + + if ( ! empty($this->fields)) + { + foreach ($default_fields as $field) + { + $key = substr($field, 2); + + if (in_array($key, $this->fields)) + { + $select[] = $field; + } + } + } + else + { + $select = $default_fields; + } + + foreach ($this->entries_custom_fields as &$field) + { + if (empty($this->fields) || in_array($field['field_name'], $this->fields)) + { + $select[] = 'wd.'.ee()->db->protect_identifiers('field_id_'.$field['field_id']).' AS '.ee()->db->protect_identifiers($field['field_name']); + } + } + + //we need entry_id, always grab it + if ( ! in_array('t.entry_id', $select)) + { + $select[] = 't.entry_id'; + } + + ee()->db->select(implode(', ', $select), FALSE) + ->from('channel_titles t') + ->join('channel_data wd', 't.entry_id = wd.entry_id') + ->where_in('t.entry_id', $this->entries_entry_ids); + + if ($order_by_string) + { + if (strpos($order_by_string, 'w.') !== FALSE) + { + ee()->db->join('channels w', 't.channel_id = w.channel_id'); + } + + if (strpos($order_by_string, 'm.') !== FALSE) + { + ee()->db->join('members m', 'm.member_id = t.author_id'); + } + + if (strpos($order_by_string, 'md.') !== FALSE) + { + ee()->db->join('member_data md', 'm.member_id = md.member_id'); + } + + if (ee()->TMPL->fetch_param('display_by') === 'week' && strpos($order_by_string, 'yearweek') !== FALSE) + { + $yearweek = TRUE; + + $offset = ee()->localize->zones[ee()->config->item('server_timezone')] * 3600; + + $format = (ee()->TMPL->fetch_param('start_day') === 'Monday') ? '%x%v' : '%X%V'; + + ee()->db->select("DATE_FORMAT(FROM_UNIXTIME(entry_date + $offset), '$format') AS yearweek", FALSE); + } + + ee()->db->order_by($order_by_string, '', FALSE); + } + + $query = $this->channel->query = ee()->db->get(); + + $show_categories = ee()->TMPL->fetch_param('show_categories') === 'yes'; + + if ($show_categories) + { + $this->channel->fetch_categories(); + + if (ee()->TMPL->fetch_param('show_category_group')) + { + $show_category_group = explode('|', ee()->TMPL->fetch_param('show_category_group')); + } + } + + $this->entries = $query->result_array(); + + $query->free_result(); + + foreach ($this->entries as &$entry) + { + if (isset($yearweek)) + { + unset($entry['yearweek']); + } + + //format dates as javascript unix time (in microseconds!) + if (isset($entry['entry_date'])) + { + $entry['entry_date'] = $this->date_format($entry['entry_date']); + } + + if (isset($entry['edit_date'])) + { + $entry['edit_date'] = $this->date_format(strtotime($entry['edit_date'])); + } + + if (isset($entry['expiration_date'])) + { + $entry['expiration_date'] = $this->date_format($entry['expiration_date']); + } + + foreach ($this->entries_custom_fields as &$field) + { + //call our custom callback for this fieldtype if it exists + if (isset($entry[$field['field_name']]) && is_callable(array($this, 'entries_'.$field['field_type']))) + { + $entry[$field['field_name']] = call_user_func(array($this, 'entries_'.$field['field_type']), $entry['entry_id'], $field, $entry[$field['field_name']], $entry); + } + } + + if ($show_categories) + { + $entry['categories'] = array(); + + if (isset($this->channel->categories[$entry['entry_id']])) + { + foreach ($this->channel->categories[$entry['entry_id']] as $raw_category) + { + if ( ! empty($show_category_group) && ! in_array($raw_category[5], $show_category_group)) + { + continue; + } + + $category = array( + 'category_id' => (int) $raw_category[0], + 'parent_id' => (int) $raw_category[1], + 'category_name' => $raw_category[2], + 'category_image' => $raw_category[3], + 'category_description' => $raw_category[4], + 'category_group' => $raw_category[5], + 'category_url_title' => $raw_category[6], + ); + + foreach ($this->channel->catfields as $cat_field) + { + $category[$cat_field['field_name']] = (isset($raw_category['field_id_'.$cat_field['field_id']])) ? $raw_category['field_id_'.$cat_field['field_id']] : ''; + } + + $entry['categories'][] = $category; + } + } + } + + $entry['entry_id'] = (int) $entry['entry_id']; + + if (isset($entry['channel_id'])) + { + $entry['channel_id'] = (int) $entry['channel_id']; + } + + if (isset($entry['author_id'])) + { + $entry['author_id'] = (int) $entry['author_id']; + } + } + } + + ee()->load->library('javascript'); + + ee()->load->library('typography'); + + return $this->respond($this->entries, array(ee()->typography, 'parse_file_paths')); + } + + protected function entries_matrix($entry_id, $field, $field_data) + { + if (is_null($this->entries_matrix_rows)) + { + $query = ee()->db->where_in('entry_id', $this->entries_entry_ids) + ->order_by('row_order') + ->get('matrix_data'); + + foreach ($query->result_array() as $row) + { + if ( ! isset($this->entries_matrix_rows[$row['entry_id']])) + { + $this->entries_matrix_rows[$row['entry_id']] = array(); + } + + if ( ! isset($this->entries_matrix_rows[$row['entry_id']][$row['field_id']])) + { + $this->entries_matrix_rows[$row['entry_id']][$row['field_id']] = array(); + } + + $this->entries_matrix_rows[$row['entry_id']][$row['field_id']][] = $row; + } + + $query->free_result(); + } + + if (is_null($this->entries_matrix_cols)) + { + $query = ee()->db->get('matrix_cols'); + + foreach ($query->result_array() as $row) + { + $this->entries_matrix_cols[$row['col_id']] = $row; + } + + $query->free_result(); + } + + $data = array(); + + if (isset($this->entries_matrix_rows[$entry_id][$field['field_id']])) + { + $field_settings = unserialize(base64_decode($field['field_settings'])); + + foreach ($this->entries_matrix_rows[$entry_id][$field['field_id']] as $matrix_row) + { + $row = array('row_id' => (int) $matrix_row['row_id']); + + foreach ($field_settings['col_ids'] as $col_id) + { + if (isset($this->entries_matrix_cols[$col_id])) + { + $row[$this->entries_matrix_cols[$col_id]['col_name']] = $matrix_row['col_id_'.$col_id]; + } + } + + $data[] = $row; + } + } + + return $data; + } + + protected function entries_grid($entry_id, $field, $field_data) + { + if ( ! isset($this->entries_grid_rows[$field['field_id']])) + { + $query = ee()->db->where_in('entry_id', $this->entries_entry_ids) + ->order_by('row_order') + ->get('channel_grid_field_'.$field['field_id']); + + foreach ($query->result_array() as $row) + { + if ( ! isset($this->entries_grid_rows[$field['field_id']][$row['entry_id']])) + { + $this->entries_grid_rows[$field['field_id']][$row['entry_id']] = array(); + } + + $this->entries_grid_rows[$field['field_id']][$row['entry_id']][] = $row; + } + + $query->free_result(); + } + + if (is_null($this->entries_grid_cols)) + { + $query = ee()->db->order_by('col_order', 'ASC') + ->get('grid_columns'); + + foreach ($query->result_array() as $row) + { + if ( ! isset($this->entries_grid_cols[$row['field_id']])) + { + $this->entries_grid_cols[$row['field_id']] = array(); + } + + $this->entries_grid_cols[$row['field_id']][$row['col_id']] = $row; + } + + $query->free_result(); + } + + $data = array(); + + if (isset($this->entries_grid_rows[$field['field_id']][$entry_id]) && isset($this->entries_grid_cols[$field['field_id']])) + { + foreach ($this->entries_grid_rows[$field['field_id']][$entry_id] as $grid_row) + { + $row = array('row_id' => (int) $grid_row['row_id']); + + foreach ($this->entries_grid_cols[$field['field_id']] as $col_id => $col) + { + $row[$col['col_name']] = $grid_row['col_id_'.$col_id]; + } + + $data[] = $row; + } + } + + return $data; + } + + protected function entries_rel($entry_id, $field, $field_data) + { + if (is_null($this->entries_rel_data)) + { + $query = ee()->db->select('rel_child_id, rel_id') + ->where('rel_parent_id', $entry_id) + ->get('relationships'); + + $this->entries_rel_data = array(); + + foreach ($query->result() as $row) + { + $this->entries_rel_data[$row->rel_id] = (int) $row->rel_child_id; + } + + $query->free_result(); + } + + if ( ! isset($this->entries_rel_data[$field_data])) + { + return NULL; + } + + return $this->entries_rel_data[$field_data]; + } + + protected function entries_relationship($entry_id, $field, $field_data) + { + if (is_null($this->entries_relationship_data)) + { + $query = ee()->db->select('parent_id, child_id, field_id') + ->where_in('parent_id', $this->entries_entry_ids) + ->order_by('order', 'asc') + ->get('relationships'); + + foreach ($query->result_array() as $row) + { + if ( ! isset($this->entries_relationship_data[$row['parent_id']])) + { + $this->entries_relationship_data[$row['parent_id']] = array(); + } + + if ( ! isset($this->entries_relationship_data[$row['parent_id']][$row['field_id']])) + { + $this->entries_relationship_data[$row['parent_id']][$row['field_id']] = array(); + } + + $this->entries_relationship_data[$row['parent_id']][$row['field_id']][] = (int) $row['child_id']; + } + + $query->free_result(); + } + + if (isset($this->entries_relationship_data[$entry_id][$field['field_id']])) + { + return $this->entries_relationship_data[$entry_id][$field['field_id']]; + } + + return array(); + } + + protected function entries_playa($entry_id, $field, $field_data) + { + if (is_null($this->entries_playa_data)) + { + $query = ee()->db->select('parent_entry_id, child_entry_id, parent_field_id') + ->where_in('parent_entry_id', $this->entries_entry_ids) + ->order_by('rel_order', 'asc') + ->get('playa_relationships'); + + foreach ($query->result_array() as $row) + { + if ( ! isset($this->entries_playa_data[$row['parent_entry_id']])) + { + $this->entries_playa_data[$row['parent_entry_id']] = array(); + } + + if ( ! isset($this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']])) + { + $this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']] = array(); + } + + $this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']][] = (int) $row['child_entry_id']; + } + + $query->free_result(); + } + + if (isset($this->entries_playa_data[$entry_id][$field['field_id']])) + { + return $this->entries_playa_data[$entry_id][$field['field_id']]; + } + + return array(); + } + + protected function entries_channel_files($entry_id, $field, $field_data, $entry) + { + $this->entries_channel_files_data = array(); + + $field_settings = unserialize(base64_decode($field['field_settings'])); + $field_settings = $field_settings['channel_files']; + + $query = ee()->db->select() + ->where('entry_id', $entry_id) + ->where('field_id', $field['field_id']) + ->order_by('file_order', 'asc') + ->get('channel_files'); + + foreach ($query->result_array() as $row) + { + $field_data = array( + 'file_id' => (int) $row['file_id'], + 'url' => $row['filename'], + 'filename' => $row['filename'], + 'extension' => $row['extension'], + 'kind' => $row['mime'], + 'size' => $row['filesize'], + 'title' => $row['title'], + 'date' => $this->date_format($row['date']), + 'author' => (int)$row['member_id'], + 'desc' => $row['description'], + 'primary' => (bool)$row['file_primary'], + 'downloads' => (int)$row['downloads'], + 'custom1' => (isset($row['cffield1']) ? $row['cffield1'] : null), + 'custom2' => (isset($row['cffield2']) ? $row['cffield2'] : null), + 'custom3' => (isset($row['cffield3']) ? $row['cffield3'] : null), + 'custom4' => (isset($row['cffield4']) ? $row['cffield4'] : null), + 'custom5' => (isset($row['cffield5']) ? $row['cffield5'] : null) + ); + + $fieldtype_specific_settings = $field_settings['locations'][$row['upload_service']]; + + switch ($row['upload_service']) + { + case 'local': + // get upload folder details from EE + $query = ee()->db->select('url') + ->where('id', $fieldtype_specific_settings['location']) + ->get('exp_upload_prefs'); + + $result = $query->row_array(); + $query->free_result(); + + $base_url = $result['url'] . ($field_settings['entry_id_folder'] == 'yes' ? $entry_id . '/' : ''); + $field_data['url'] = $base_url . $field_data['url']; + break; + case 's3': + if ($fieldtype_specific_settings['cloudfront_domain'] != '') + { + $domain = rtrim($fieldtype_specific_settings['cloudfront_domain'], '/'); + $domain = 'http://' . preg_replace('#https?://#', '', $domain); + } + else + { + $domain = "http://{$fieldtype_specific_settings['bucket']}.s3.amazonaws.com"; + } + + + $dir = ($fieldtype_specific_settings['directory'] != '' ? rtrim($fieldtype_specific_settings['directory'], '/') . '/' : ''); + + $base_url = "{$domain}/{$dir}{$entry_id}/"; + $field_data['url'] = $base_url . $field_data['url']; + break; + case 'cloudfiles': + case 'ftp': + case 'sftp': + require_once PATH_THIRD.'channel_files/locations/cfile_location.php'; + require_once PATH_THIRD."channel_files/locations/{$row['upload_service']}/{$row['upload_service']}.php"; + + $class_name = "CF_Location_{$row['upload_service']}"; + $cf = new $class_name($fieldtype_specific_settings); + $dir = $entry_id; + $entry_id_folder = (isset($fieldtype_specific_settings['entry_id_folder']) ? $fieldtype_specific_settings['entry_id_folder'] : null);; + if (isset($entry_id_folder) && $fieldtype_specific_settings['entry_id_folder'] == 'no') + { + $dir = FALSE; + } + + $field_data['url'] = $cf->parse_file_url($dir, $field_data['url']); + break; + default: + break; + } + + // make file size relevant + $units = array('B', 'KB', 'MB', 'GB'); + $units_index = 0; + while ($field_data['size'] >= 1024) + { + $field_data['size'] /= 1024; + $units_index++; + } + $field_data['size'] = round($field_data['size']) . ' ' . $units[$units_index]; + + $this->entries_channel_files_data[$row['field_id']][] = $field_data; + } + + $query->free_result(); + + if (isset($row['field_id'], $this->entries_channel_files_data[$row['field_id']])) + { + return $this->entries_channel_files_data[$row['field_id']]; + } + + return array(); + } + + protected function entries_date($entry_id, $field, $field_data) + { + return $this->date_format($field_data); + } + + protected function entries_text($entry_id, $field, $field_data) + { + $field_settings = ee()->api_channel_fields->get_settings($field['field_id']); + + if ($field_settings['field_content_type'] === 'numeric' || $field_settings['field_content_type'] === 'decimal') + { + return floatval($field_data); + } + + if ($field_settings['field_content_type'] === 'integer') + { + return intval($field_data); + } + + return $field_data; + } + + protected function entries_custom_field($entry_id, $field, $field_data, $entry, $tagdata = ' ') + { + ee()->load->add_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']], FALSE); + + ee()->api_channel_fields->setup_handler($field['field_id']); + + ee()->api_channel_fields->apply('_init', array(array( + 'row' => $entry, + 'content_id' => $entry['entry_id'], + 'content_type' => 'channel', + ))); + + $field_data = ee()->api_channel_fields->apply('pre_process', array($field_data)); + + if (ee()->api_channel_fields->check_method_exists('replace_tag')) + { + require_once PATH_THIRD.'json/libraries/Json_Template.php'; + + $template = new Json_Template(); + + $field_data = ee()->api_channel_fields->apply('replace_tag', array($field_data, array(), $tagdata)); + + if ($template->variables) + { + $field_data = $template->variables; + } + + unset($template); + } + + ee()->load->remove_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']]); + + return $field_data; + } + + protected function entries_assets($entry_id, $field, $field_data, $entry) + { + $field_data = $this->entries_custom_field($entry_id, $field, $field_data, $entry); + + if ( ! is_array($field_data)) + { + $field_data = array(); + } + + if (isset($field_data['absolute_total_files']) && $field_data['absolute_total_files'] === 0) + { + return array(); + } + + $fields = array( + 'file_id', + 'url', + 'subfolder', + 'filename', + 'extension', + 'date_modified', + 'kind', + 'width', + 'height', + 'size', + 'title', + 'date', + 'alt_text', + 'caption', + 'author', + 'desc', + 'location', + ); + + foreach ($field_data as &$row) + { + $source_type = $row['source_type']; + $filedir_id = $row['filedir_id']; + //excise any other fields from this row + $row = array_intersect_key($row, array_flip($fields)); + $row['file_id'] = (int) $row['file_id']; + $row['date'] = $this->date_format($row['date']); + $row['date_modified'] = $this->date_format($row['date_modified']); + + $row['manipulations'] = array(); + + if ($source_type === 'ee') + { + if ( ! isset($this->image_manipulations[$filedir_id])) + { + ee()->load->model('file_model'); + + $query = ee()->file_model->get_dimensions_by_dir_id($filedir_id); + + $this->image_manipulations[$filedir_id] = $query->result(); + + $query->free_result(); + } + + foreach ($this->image_manipulations[$filedir_id] as $manipulation) + { + $row['manipulations'][$manipulation->short_name] = pathinfo($row['url'], PATHINFO_DIRNAME).'/_'.$manipulation->short_name.'/'.basename($row['url']); + } + } + } + + return $field_data; + } + + public function search() + { + $search_id = ee()->TMPL->fetch_param('search_id'); + + if ( ! $search_id) + { + $search_id = end(ee()->uri->segment_array()); + } + + if ($search_id) + { + $query = ee()->db->where('search_id', $search_id) + ->limit(1) + ->get('exp_search'); + + if ($query->num_rows() > 0) + { + $search = $query->row_array(); + + $query->free_result(); + + if (preg_match('/IN \(([\d,]+)\)/', $query->row('query'), $match)) + { + ee()->TMPL->tagparams['entry_id'] = (strpos($match[1], ',') !== FALSE) ? str_replace(',', '|', $match[1]) : $match[1]; + + return $this->entries(); + } + } + } + + $this->initialize(); + + return $this->respond(array()); + } + + /** + * Categories + * + * @TODO a work in progress, does not work yet + * + * @param array|null $params + * + * @return string + */ + public function categories($params = NULL) + { + $this->initialize(); + + if (is_null($params)) + { + $params = ee()->TMPL->tagparams; + } + + ee()->load->helper('array'); + + $channel = element('channel', $params); + $group_id = element('group_id', $params, element('category_group', $params)); + $cat_id = element('cat_id', $params, element('category_id', $params, element('show', $params))); + $status = element('status', $params); + $parent_only = element('parent_only', $params); + $show_empty = element('show_empty', $params, TRUE); + $joins = array(); + + if ($channel) + { + ee()->db->join('channel_titles', 'channel_titles.entry_id = category_posts.entry_id'); + ee()->db->join('channels', 'channels.channel_id = channel_titles.channel_id'); + ee()->db->where_in('channels.channel_name', explode('|', $channel)); + $joins[] = 'channels'; + $joins[] = 'channel_titles'; + } + + if ($group_id) + { + ee()->db->where_in('categories.group_id', explode('|', $group_id)); + } + + if ($cat_id) + { + ee()->db->where_in('categories.cat_id', explode('|', $cat_id)); + } + + if ($status) + { + if ( ! in_array('channel_titles', $joins)) + { + ee()->db->join('channel_titles', 'channel_titles.entry_id = category_posts.entry_id'); + } + + ee()->db->where_in('channel_titles.status', explode('|', $status)); + } + + if ($parent_only) + { + ee()->db->where('categories.parent_id', 0); + } + + if ($show_empty) + { + ee()->db->where('count >', 0); + } + } + + /** + * Members + * + * @return string + */ + public function members() + { + $this->initialize(); + + if ($this->check_xhr_required()) + { + return ''; + } + + $default_fields = array( + 'm.member_id', + 'm.group_id', + 'm.username', + 'm.screen_name', + 'm.email', + 'm.signature', + 'm.avatar_filename', + 'm.avatar_width', + 'm.avatar_height', + 'm.photo_filename', + 'm.photo_width', + 'm.photo_height', + 'm.url', + 'm.location', + 'm.occupation', + 'm.interests', + 'm.bio', + 'm.join_date', + 'm.last_visit', + 'm.last_activity', + 'm.last_entry_date', + 'm.last_comment_date', + 'm.last_forum_post_date', + 'm.total_entries', + 'm.total_comments', + 'm.total_forum_topics', + 'm.total_forum_posts', + 'm.language', + 'm.timezone', + 'm.bday_d', + 'm.bday_m', + 'm.bday_y', + ); + + if (version_compare(APP_VER, '2.6', '<')) + { + $default_fields[] = 'm.daylight_savings'; + } + + $query = ee()->db->select('m_field_id, m_field_name') + ->get('member_fields'); + + $custom_fields = $query->result_array(); + + $query->free_result(); + + $select = array(); + + if ( ! empty($this->fields)) + { + foreach ($default_fields as $field) + { + $key = substr($field, 2); + + if (in_array($key, $this->fields)) + { + $select[] = $field; + } + } + } + else + { + $select = $default_fields; + } + + foreach ($custom_fields as &$field) + { + if (empty($this->fields) || in_array($field['m_field_name'], $this->fields)) + { + $select[] = 'd.'.ee()->db->protect_identifiers('m_field_id_'.$field['m_field_id']).' AS '.ee()->db->protect_identifiers($field['m_field_name']); + } + } + + ee()->db->select(implode(', ', $select), FALSE) + ->from('members m') + ->join('member_data d', 'm.member_id = d.member_id'); + + if ($member_ids = ee()->TMPL->fetch_param('member_id')) + { + if ($member_ids === 'CURRENT_USER') + { + $member_ids = ee()->session->userdata('member_id'); + } + + ee()->db->where_in('m.member_id', explode('|', $member_ids)); + } + else if (ee()->TMPL->fetch_param('username')) + { + ee()->db->where_in('m.member_id', explode('|', ee()->TMPL->fetch_param('member_id'))); + } + + if (ee()->TMPL->fetch_param('group_id')) + { + ee()->db->where_in('m.group_id', explode('|', ee()->TMPL->fetch_param('group_id'))); + } + + if (ee()->TMPL->fetch_param('limit')) + { + ee()->db->limit(ee()->TMPL->fetch_param('limit')); + } + + if (ee()->TMPL->fetch_param('offset')) + { + ee()->db->offset(ee()->TMPL->fetch_param('offset')); + } + + $query = ee()->db->get(); + + $members = $query->result_array(); + + $query->free_result(); + + $date_fields = array( + 'join_date', + 'last_visit', + 'last_activity', + 'last_entry_date', + 'last_comment_date', + 'last_forum_post_date' + ); + + foreach ($members as &$member) + { + foreach ($date_fields as $field) + { + if (isset($member[$field])) + { + $member[$field] = $this->date_format($member[$field]); + } + } + } + + return $this->respond($members); + } + + protected function initialize($which = NULL) + { + switch($which) + { + case 'entries': + //initialize caches + $this->entries = array(); + $this->entries_entry_ids = array(); + $this->entries_custom_fields = array(); + $this->entries_matrix_rows = NULL; + $this->entries_rel_data = NULL; + $this->entries_relationship_data = NULL; + $this->entries_playa_data = NULL; + $this->entries_channel_files_data = NULL; + break; + } + + $this->xhr = ee()->TMPL->fetch_param('xhr') === 'yes'; + + $this->terminate = ee()->TMPL->fetch_param('terminate') === 'yes'; + + $this->fields = (ee()->TMPL->fetch_param('fields')) ? explode('|', ee()->TMPL->fetch_param('fields')) : array(); + + $this->date_format = ee()->TMPL->fetch_param('date_format'); + + // get rid of EE formatted dates + if ($this->date_format && strstr($this->date_format, '%')) + { + $this->date_format = str_replace('%', '', $this->date_format); + } + + $this->jsonp = ee()->TMPL->fetch_param('jsonp') === 'yes'; + + ee()->load->library('jsonp'); + + $this->callback = (ee()->TMPL->fetch_param('callback') && ee()->jsonp->isValidCallback(ee()->TMPL->fetch_param('callback'))) + ? ee()->TMPL->fetch_param('callback') : NULL; + + $this->content_type = ee()->TMPL->fetch_param('content_type', ($this->jsonp && $this->callback) ? 'application/javascript' : 'application/json'); + } + + protected function check_xhr_required() + { + return $this->xhr && ! ee()->input->is_ajax_request(); + } + + protected function date_format($date) + { + if ( ! $date) + { + return NULL; + } + + return ($this->date_format) ? date($this->date_format, $date) : $date * 1000; + } + + protected function respond(array $response, $callback = NULL) + { + ee()->load->library('javascript'); + + if ($item_root_node = ee()->TMPL->fetch_param('item_root_node')) + { + $response_with_nodes = array(); + + foreach($response as $item) + { + $response_with_nodes[] = array($item_root_node => $item); + } + + $response = $response_with_nodes; + } + + if ($root_node = ee()->TMPL->fetch_param('root_node')) + { + $response = array($root_node => $response); + } + + $response = function_exists('json_encode') + ? json_encode($response) + : ee()->javascript->generate_json($response, TRUE); + + if ( ! is_null($callback)) + { + $response = call_user_func($callback, $response); + } + + if ($this->check_xhr_required()) + { + $response = ''; + } + else if ($this->jsonp && $this->callback) + { + $response = sprintf('%s(%s)', $this->callback, $response); + } + + if ($this->terminate) + { + @header('Content-Type: '.$this->content_type); + + exit($response); + } + + return $response; + } +} + +/* End of file pi.json_output.php */ +/* Location: ./system/user/addons/json/pi.json_output.php */ From 7cdb267199da98b59c17743b642ca57761a31f49 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:24:41 +0200 Subject: [PATCH 03/17] Create Json_Template.php --- .../json_output/libraries/Json_Template.php | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 system/user/addons/json_output/libraries/Json_Template.php diff --git a/system/user/addons/json_output/libraries/Json_Template.php b/system/user/addons/json_output/libraries/Json_Template.php new file mode 100644 index 0000000..abd197b --- /dev/null +++ b/system/user/addons/json_output/libraries/Json_Template.php @@ -0,0 +1,45 @@ +TMPL =& ee()->TMPL; + + // Override the "real" TMPL object + ee()->TMPL =& $this; + } + + public function __destruct() + { + // Restore the "real" TMPL object + ee()->TMPL =& $this->TMPL; + } + + public function parse_variables($tagdata, $variables, $enable_backspace = TRUE) + { + $output = parent::parse_variables($tagdata, $variables, $enable_backspace); + $this->variables = $variables; + return $output; + } + + public function parse_variables_row($tagdata, $variables, $solo = TRUE) + { + $this->variables = $variables; + return parent::parse_variables_row($tagdata, $variables, $solo); + } +} From c2d74742f416cb357a589f931207c18c72d5601b Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:25:07 +0200 Subject: [PATCH 04/17] Create Jsonp.php --- .../addons/json_output/libraries/Jsonp.php | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 system/user/addons/json_output/libraries/Jsonp.php diff --git a/system/user/addons/json_output/libraries/Jsonp.php b/system/user/addons/json_output/libraries/Jsonp.php new file mode 100644 index 0000000..ccf98eb --- /dev/null +++ b/system/user/addons/json_output/libraries/Jsonp.php @@ -0,0 +1,168 @@ + false, + 'hello' => true, + 'alert()' => false, + 'test()' => false, + 'a-b' => false, + '23foo' => false, + 'foo23' => true, + '$210' => true, + '_bar' => true, + 'some_var' => true, + '$' => true, + 'somevar' => true, + 'function' => false, + ' somevar' => false, + '$.ajaxHandler' => true, + '$.23' => false, + 'array_of_functions[42]' => true, + 'array_of_functions[42][1]' => true, + '$.ajaxHandler[42][1].foo' => true, + 'array_of_functions[42]foo[1]' => false, + 'array_of_functions[]' => false, + 'array_of_functions["key"]' => true, + 'myFunction[123].false' => false, + 'myFunction .tester' => false, + '_function' => true, + 'petersCallback1412331422[12]' => true, + ':myFunction' => false + ); + + /** + * Is valid callback + * + * @param string $callback + * + * @return boolean + */ + function isValidCallback($callback) + { + $reserved = array( + 'break', + 'do', + 'instanceof', + 'typeof', + 'case', + 'else', + 'new', + 'var', + 'catch', + 'finally', + 'return', + 'void', + 'continue', + 'for', + 'switch', + 'while', + 'debugger', + 'function', + 'this', + 'with', + 'default', + 'if', + 'throw', + 'delete', + 'in', + 'try', + 'class', + 'enum', + 'extends', + 'super', + 'const', + 'export', + 'import', + 'implements', + 'let', + 'private', + 'public', + 'yield', + 'interface', + 'package', + 'protected', + 'static', + 'null', + 'true', + 'false' + ); + + foreach(explode('.', $callback) as $identifier) { + if(!preg_match('/^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|\'.+\'|\d+)\])*?$/', $identifier)) { + return false; + } + if(in_array($identifier, $reserved)) { + return false; + } + } + + return true; + } + + /** + * Test callback strings + * + * @param string $callback + * + * @return void + * + * @access private + */ + private function _test($callback, $valid) + { + $vocal = $valid ? 'valid' : 'invalid'; + if($this->isValidCallback($callback) === $valid) { + echo '"'.$callback.'" passed as '.$vocal.'.', "\n"; + return true; + } + else { + echo '"'.$callback.'" failed as '.$vocal.'.', "\n"; + return false; + } + } + + /** + * Run all tests + * + * @return void + * + * @access public + */ + function runTests() + { + echo 'Testing ', count($this->_tests), ' callback methods:', "\n\n"; + $passed = 0; + foreach($this->_tests as $callback => $valid) { + $passed = self::_test($callback, $valid) ? $passed+1 : $passed; + } + echo "\n", $passed, ' of ', count($this->_tests), ' tests passed.'; + } +} From 74c9a06765cfeef27576293efd8cc8293d9b96dc Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:26:21 +0200 Subject: [PATCH 05/17] Delete pi.json.php --- .../third_party/json/pi.json.php | 1156 ----------------- 1 file changed, 1156 deletions(-) delete mode 100644 system/expressionengine/third_party/json/pi.json.php diff --git a/system/expressionengine/third_party/json/pi.json.php b/system/expressionengine/third_party/json/pi.json.php deleted file mode 100644 index dbae472..0000000 --- a/system/expressionengine/third_party/json/pi.json.php +++ /dev/null @@ -1,1156 +0,0 @@ - 'JSON', - 'pi_version' => '1.1.8', - 'pi_author' => 'Rob Sanchez', - 'pi_author_url' => 'https://github.com/rsanchez', - 'pi_description' => 'Output ExpressionEngine data in JSON format.', - 'pi_usage' => ' -{exp:json:entries channel="news"} - -{exp:json:entries channel="products" search:product_size="10"} - -{exp:json:members member_id="1"}', -); - -class Json -{ - /* settings */ - protected $content_type = 'application/json'; - protected $terminate = FALSE; - protected $xhr = FALSE; - protected $fields = array(); - protected $date_format = FALSE; - protected $jsonp = FALSE; - protected $callback; - - /* caches */ - public $entries; - public $entries_entry_ids; - public $entries_custom_fields; - protected $entries_matrix_rows; - protected $entries_matrix_cols; - protected $entries_grid_rows; - protected $entries_grid_cols; - protected $entries_rel_data; - protected $entries_relationship_data; - protected $entries_playa_data; - protected $entries_channel_files_data; - protected $image_manipulations = array(); - - public function entries($entry_ids = null) - { - $this->initialize('entries'); - - //exit if ajax request is required and not found - if ($this->check_xhr_required()) - { - return ''; - } - - //instantiate channel module object - if (empty($this->channel)) - { - require_once PATH_MOD.'channel/mod.channel'.EXT; - - $this->channel = new Channel; - } - - $this->channel->initialize(); - - $order_by_string = ''; - - if (is_array($entry_ids)) - { - $this->entries_entry_ids = $entry_ids; - $order_by_string = 'FIELD(t.entry_id,'.implode(',', $entry_ids).')'; - } - else - { - //run through the channel module process to grab the entries - $this->channel->uri = ($this->channel->query_string != '') ? $this->channel->query_string : 'index.php'; - - if ($this->channel->enable['custom_fields'] === TRUE) - { - $this->channel->fetch_custom_channel_fields(); - } - - $save_cache = FALSE; - - if (ee()->config->item('enable_sql_caching') == 'y') - { - if (FALSE == ($this->channel->sql = $this->channel->fetch_cache())) - { - $save_cache = TRUE; - } - else - { - if (ee()->TMPL->fetch_param('dynamic') != 'no') - { - if (preg_match("#(^|\/)C(\d+)#", $this->channel->query_string, $match) OR in_array($this->channel->reserved_cat_segment, explode("/", $this->channel->query_string))) - { - $this->channel->cat_request = TRUE; - } - } - } - } - - if ( ! $this->channel->sql) - { - $this->channel->build_sql_query(); - } - - if (preg_match('/t\.entry_id IN \(([\d,]+)\)/', $this->channel->sql, $match)) - { - $this->entries_entry_ids = explode(',', $match[1]); - } - - if (preg_match('/ORDER BY (.*)?/', $this->channel->sql, $match)) - { - $order_by_string = $match[1]; - } - } - - if ($this->entries_entry_ids) - { - $this->entries_custom_fields = ee()->db->select('channel_fields.*, channels.channel_id') - ->from('channel_fields') - ->join('channels', 'channel_fields.group_id = channels.field_group') - ->where('channels.site_id', ee()->config->item('site_id')) - ->where_in('channels.channel_name', explode('|', ee()->TMPL->fetch_param('channel'))) - ->get() - ->result_array(); - - $default_fields = array( - 't.title', - 't.url_title', - 't.entry_id', - 't.channel_id', - 't.author_id', - 't.status', - 't.entry_date', - 't.edit_date', - 't.expiration_date', - ); - - $select = array(); - - if ( ! empty($this->fields)) - { - foreach ($default_fields as $field) - { - $key = substr($field, 2); - - if (in_array($key, $this->fields)) - { - $select[] = $field; - } - } - } - else - { - $select = $default_fields; - } - - foreach ($this->entries_custom_fields as &$field) - { - if (empty($this->fields) || in_array($field['field_name'], $this->fields)) - { - $select[] = 'wd.'.ee()->db->protect_identifiers('field_id_'.$field['field_id']).' AS '.ee()->db->protect_identifiers($field['field_name']); - } - } - - //we need entry_id, always grab it - if ( ! in_array('t.entry_id', $select)) - { - $select[] = 't.entry_id'; - } - - ee()->db->select(implode(', ', $select), FALSE) - ->from('channel_titles t') - ->join('channel_data wd', 't.entry_id = wd.entry_id') - ->where_in('t.entry_id', $this->entries_entry_ids); - - if ($order_by_string) - { - if (strpos($order_by_string, 'w.') !== FALSE) - { - ee()->db->join('channels w', 't.channel_id = w.channel_id'); - } - - if (strpos($order_by_string, 'm.') !== FALSE) - { - ee()->db->join('members m', 'm.member_id = t.author_id'); - } - - if (strpos($order_by_string, 'md.') !== FALSE) - { - ee()->db->join('member_data md', 'm.member_id = md.member_id'); - } - - if (ee()->TMPL->fetch_param('display_by') === 'week' && strpos($order_by_string, 'yearweek') !== FALSE) - { - $yearweek = TRUE; - - $offset = ee()->localize->zones[ee()->config->item('server_timezone')] * 3600; - - $format = (ee()->TMPL->fetch_param('start_day') === 'Monday') ? '%x%v' : '%X%V'; - - ee()->db->select("DATE_FORMAT(FROM_UNIXTIME(entry_date + $offset), '$format') AS yearweek", FALSE); - } - - ee()->db->order_by($order_by_string, '', FALSE); - } - - $query = $this->channel->query = ee()->db->get(); - - $show_categories = ee()->TMPL->fetch_param('show_categories') === 'yes'; - - if ($show_categories) - { - $this->channel->fetch_categories(); - - if (ee()->TMPL->fetch_param('show_category_group')) - { - $show_category_group = explode('|', ee()->TMPL->fetch_param('show_category_group')); - } - } - - $this->entries = $query->result_array(); - - $query->free_result(); - - foreach ($this->entries as &$entry) - { - if (isset($yearweek)) - { - unset($entry['yearweek']); - } - - //format dates as javascript unix time (in microseconds!) - if (isset($entry['entry_date'])) - { - $entry['entry_date'] = $this->date_format($entry['entry_date']); - } - - if (isset($entry['edit_date'])) - { - $entry['edit_date'] = $this->date_format(strtotime($entry['edit_date'])); - } - - if (isset($entry['expiration_date'])) - { - $entry['expiration_date'] = $this->date_format($entry['expiration_date']); - } - - foreach ($this->entries_custom_fields as &$field) - { - //call our custom callback for this fieldtype if it exists - if (isset($entry[$field['field_name']]) && is_callable(array($this, 'entries_'.$field['field_type']))) - { - $entry[$field['field_name']] = call_user_func(array($this, 'entries_'.$field['field_type']), $entry['entry_id'], $field, $entry[$field['field_name']], $entry); - } - } - - if ($show_categories) - { - $entry['categories'] = array(); - - if (isset($this->channel->categories[$entry['entry_id']])) - { - foreach ($this->channel->categories[$entry['entry_id']] as $raw_category) - { - if ( ! empty($show_category_group) && ! in_array($raw_category[5], $show_category_group)) - { - continue; - } - - $category = array( - 'category_id' => (int) $raw_category[0], - 'parent_id' => (int) $raw_category[1], - 'category_name' => $raw_category[2], - 'category_image' => $raw_category[3], - 'category_description' => $raw_category[4], - 'category_group' => $raw_category[5], - 'category_url_title' => $raw_category[6], - ); - - foreach ($this->channel->catfields as $cat_field) - { - $category[$cat_field['field_name']] = (isset($raw_category['field_id_'.$cat_field['field_id']])) ? $raw_category['field_id_'.$cat_field['field_id']] : ''; - } - - $entry['categories'][] = $category; - } - } - } - - $entry['entry_id'] = (int) $entry['entry_id']; - - if (isset($entry['channel_id'])) - { - $entry['channel_id'] = (int) $entry['channel_id']; - } - - if (isset($entry['author_id'])) - { - $entry['author_id'] = (int) $entry['author_id']; - } - } - } - - ee()->load->library('javascript'); - - ee()->load->library('typography'); - - // ---------------------------------------- - // 'json_plugin_entries_end' hook. - // - Enables additional manipulation of entry data - // ---------------------------------------- - - if (ee()->extensions->active_hook('json_plugin_entries_end') === TRUE) - { - ee()->extensions->call('json_plugin_entries_end', $this); - if (ee()->extensions->end_script === TRUE) return; - } - // ---------------------------------------- - - return $this->respond($this->entries, array(ee()->typography, 'parse_file_paths')); - } - - protected function entries_matrix($entry_id, $field, $field_data) - { - if (is_null($this->entries_matrix_rows)) - { - $query = ee()->db->where_in('entry_id', $this->entries_entry_ids) - ->order_by('row_order') - ->get('matrix_data'); - - foreach ($query->result_array() as $row) - { - if ( ! isset($this->entries_matrix_rows[$row['entry_id']])) - { - $this->entries_matrix_rows[$row['entry_id']] = array(); - } - - if ( ! isset($this->entries_matrix_rows[$row['entry_id']][$row['field_id']])) - { - $this->entries_matrix_rows[$row['entry_id']][$row['field_id']] = array(); - } - - $this->entries_matrix_rows[$row['entry_id']][$row['field_id']][] = $row; - } - - $query->free_result(); - } - - if (is_null($this->entries_matrix_cols)) - { - $query = ee()->db->get('matrix_cols'); - - foreach ($query->result_array() as $row) - { - $this->entries_matrix_cols[$row['col_id']] = $row; - } - - $query->free_result(); - } - - $data = array(); - - if (isset($this->entries_matrix_rows[$entry_id][$field['field_id']])) - { - $field_settings = unserialize(base64_decode($field['field_settings'])); - - foreach ($this->entries_matrix_rows[$entry_id][$field['field_id']] as $matrix_row) - { - $row = array('row_id' => (int) $matrix_row['row_id']); - - foreach ($field_settings['col_ids'] as $col_id) - { - if (isset($this->entries_matrix_cols[$col_id])) - { - $row[$this->entries_matrix_cols[$col_id]['col_name']] = $matrix_row['col_id_'.$col_id]; - } - } - - $data[] = $row; - } - } - - return $data; - } - - protected function entries_grid($entry_id, $field, $field_data) - { - if ( ! isset($this->entries_grid_rows[$field['field_id']])) - { - $query = ee()->db->where_in('entry_id', $this->entries_entry_ids) - ->order_by('row_order') - ->get('channel_grid_field_'.$field['field_id']); - - foreach ($query->result_array() as $row) - { - if ( ! isset($this->entries_grid_rows[$field['field_id']][$row['entry_id']])) - { - $this->entries_grid_rows[$field['field_id']][$row['entry_id']] = array(); - } - - $this->entries_grid_rows[$field['field_id']][$row['entry_id']][] = $row; - } - - $query->free_result(); - } - - if (is_null($this->entries_grid_cols)) - { - $query = ee()->db->order_by('col_order', 'ASC') - ->get('grid_columns'); - - foreach ($query->result_array() as $row) - { - if ( ! isset($this->entries_grid_cols[$row['field_id']])) - { - $this->entries_grid_cols[$row['field_id']] = array(); - } - - $this->entries_grid_cols[$row['field_id']][$row['col_id']] = $row; - } - - $query->free_result(); - } - - $data = array(); - - if (isset($this->entries_grid_rows[$field['field_id']][$entry_id]) && isset($this->entries_grid_cols[$field['field_id']])) - { - foreach ($this->entries_grid_rows[$field['field_id']][$entry_id] as $grid_row) - { - $row = array('row_id' => (int) $grid_row['row_id']); - - foreach ($this->entries_grid_cols[$field['field_id']] as $col_id => $col) - { - $row[$col['col_name']] = $grid_row['col_id_'.$col_id]; - } - - $data[] = $row; - } - } - - return $data; - } - - protected function entries_rel($entry_id, $field, $field_data) - { - if (is_null($this->entries_rel_data)) - { - $query = ee()->db->select('rel_child_id, rel_id') - ->where('rel_parent_id', $entry_id) - ->get('relationships'); - - $this->entries_rel_data = array(); - - foreach ($query->result() as $row) - { - $this->entries_rel_data[$row->rel_id] = (int) $row->rel_child_id; - } - - $query->free_result(); - } - - if ( ! isset($this->entries_rel_data[$field_data])) - { - return NULL; - } - - return $this->entries_rel_data[$field_data]; - } - - protected function entries_relationship($entry_id, $field, $field_data) - { - if (is_null($this->entries_relationship_data)) - { - $query = ee()->db->select('parent_id, child_id, field_id') - ->where_in('parent_id', $this->entries_entry_ids) - ->order_by('order', 'asc') - ->get('relationships'); - - foreach ($query->result_array() as $row) - { - if ( ! isset($this->entries_relationship_data[$row['parent_id']])) - { - $this->entries_relationship_data[$row['parent_id']] = array(); - } - - if ( ! isset($this->entries_relationship_data[$row['parent_id']][$row['field_id']])) - { - $this->entries_relationship_data[$row['parent_id']][$row['field_id']] = array(); - } - - $this->entries_relationship_data[$row['parent_id']][$row['field_id']][] = (int) $row['child_id']; - } - - $query->free_result(); - } - - if (isset($this->entries_relationship_data[$entry_id][$field['field_id']])) - { - return $this->entries_relationship_data[$entry_id][$field['field_id']]; - } - - return array(); - } - - protected function entries_playa($entry_id, $field, $field_data) - { - if (is_null($this->entries_playa_data)) - { - $query = ee()->db->select('parent_entry_id, child_entry_id, parent_field_id') - ->where_in('parent_entry_id', $this->entries_entry_ids) - ->order_by('rel_order', 'asc') - ->get('playa_relationships'); - - foreach ($query->result_array() as $row) - { - if ( ! isset($this->entries_playa_data[$row['parent_entry_id']])) - { - $this->entries_playa_data[$row['parent_entry_id']] = array(); - } - - if ( ! isset($this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']])) - { - $this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']] = array(); - } - - $this->entries_playa_data[$row['parent_entry_id']][$row['parent_field_id']][] = (int) $row['child_entry_id']; - } - - $query->free_result(); - } - - if (isset($this->entries_playa_data[$entry_id][$field['field_id']])) - { - return $this->entries_playa_data[$entry_id][$field['field_id']]; - } - - return array(); - } - - protected function entries_channel_files($entry_id, $field, $field_data, $entry) - { - $this->entries_channel_files_data = array(); - - $field_settings = unserialize(base64_decode($field['field_settings'])); - $field_settings = $field_settings['channel_files']; - - $query = ee()->db->select() - ->where('entry_id', $entry_id) - ->where('field_id', $field['field_id']) - ->order_by('file_order', 'asc') - ->get('channel_files'); - - foreach ($query->result_array() as $row) - { - $field_data = array( - 'file_id' => (int) $row['file_id'], - 'url' => $row['filename'], - 'filename' => $row['filename'], - 'extension' => $row['extension'], - 'kind' => $row['mime'], - 'size' => $row['filesize'], - 'title' => $row['title'], - 'date' => $this->date_format($row['date']), - 'author' => (int)$row['member_id'], - 'desc' => $row['description'], - 'primary' => (bool)$row['file_primary'], - 'downloads' => (int)$row['downloads'], - 'custom1' => (isset($row['cffield1']) ? $row['cffield1'] : null), - 'custom2' => (isset($row['cffield2']) ? $row['cffield2'] : null), - 'custom3' => (isset($row['cffield3']) ? $row['cffield3'] : null), - 'custom4' => (isset($row['cffield4']) ? $row['cffield4'] : null), - 'custom5' => (isset($row['cffield5']) ? $row['cffield5'] : null) - ); - - $fieldtype_specific_settings = $field_settings['locations'][$row['upload_service']]; - - switch ($row['upload_service']) - { - case 'local': - // get upload folder details from EE - $query = ee()->db->select('url') - ->where('id', $fieldtype_specific_settings['location']) - ->get('exp_upload_prefs'); - - $result = $query->row_array(); - $query->free_result(); - - $base_url = $result['url'] . ($field_settings['entry_id_folder'] == 'yes' ? $entry_id . '/' : ''); - $field_data['url'] = $base_url . $field_data['url']; - break; - case 's3': - if ($fieldtype_specific_settings['cloudfront_domain'] != '') - { - $domain = rtrim($fieldtype_specific_settings['cloudfront_domain'], '/'); - $domain = 'http://' . preg_replace('#https?://#', '', $domain); - } - else - { - $domain = "http://{$fieldtype_specific_settings['bucket']}.s3.amazonaws.com"; - } - - - $dir = ($fieldtype_specific_settings['directory'] != '' ? rtrim($fieldtype_specific_settings['directory'], '/') . '/' : ''); - - $base_url = "{$domain}/{$dir}{$entry_id}/"; - $field_data['url'] = $base_url . $field_data['url']; - break; - case 'cloudfiles': - case 'ftp': - case 'sftp': - require_once PATH_THIRD.'channel_files/locations/cfile_location.php'; - require_once PATH_THIRD."channel_files/locations/{$row['upload_service']}/{$row['upload_service']}.php"; - - $class_name = "CF_Location_{$row['upload_service']}"; - $cf = new $class_name($fieldtype_specific_settings); - $dir = $entry_id; - $entry_id_folder = (isset($fieldtype_specific_settings['entry_id_folder']) ? $fieldtype_specific_settings['entry_id_folder'] : null);; - if (isset($entry_id_folder) && $fieldtype_specific_settings['entry_id_folder'] == 'no') - { - $dir = FALSE; - } - - $field_data['url'] = $cf->parse_file_url($dir, $field_data['url']); - break; - default: - break; - } - - // make file size relevant - $units = array('B', 'KB', 'MB', 'GB'); - $units_index = 0; - while ($field_data['size'] >= 1024) - { - $field_data['size'] /= 1024; - $units_index++; - } - $field_data['size'] = round($field_data['size']) . ' ' . $units[$units_index]; - - $this->entries_channel_files_data[$row['field_id']][] = $field_data; - } - - $query->free_result(); - - if (isset($row['field_id'], $this->entries_channel_files_data[$row['field_id']])) - { - return $this->entries_channel_files_data[$row['field_id']]; - } - - return array(); - } - - protected function entries_date($entry_id, $field, $field_data) - { - return $this->date_format($field_data); - } - - protected function entries_text($entry_id, $field, $field_data) - { - $field_settings = ee()->api_channel_fields->get_settings($field['field_id']); - - if ($field_settings['field_content_type'] === 'numeric' || $field_settings['field_content_type'] === 'decimal') - { - return floatval($field_data); - } - - if ($field_settings['field_content_type'] === 'integer') - { - return intval($field_data); - } - - return $field_data; - } - - protected function entries_custom_field($entry_id, $field, $field_data, $entry, $tagdata = ' ') - { - ee()->load->add_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']], FALSE); - - ee()->api_channel_fields->setup_handler($field['field_id']); - - ee()->api_channel_fields->apply('_init', array(array( - 'row' => $entry, - 'content_id' => $entry['entry_id'], - 'content_type' => 'channel', - ))); - - $field_data = ee()->api_channel_fields->apply('pre_process', array($field_data)); - - if (ee()->api_channel_fields->check_method_exists('replace_tag')) - { - require_once PATH_THIRD.'json/libraries/Json_Template.php'; - - $ee_tmpl = ee()->TMPL; - $template = new Json_Template(); - - $field_data = ee()->api_channel_fields->apply('replace_tag', array($field_data, array(), $tagdata)); - - if ($template->variables) - { - $field_data = $template->variables; - } - - unset($template); - ee()->TMPL = $ee_tmpl; - } - - ee()->load->remove_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']]); - - return $field_data; - } - - protected function entries_wygwam($entry_id, $field, $field_data, $entry) { - return $this->entries_custom_field($entry_id, $field, $field_data, $entry); - } - - protected function entries_assets($entry_id, $field, $field_data, $entry) - { - $field_data = $this->entries_custom_field($entry_id, $field, $field_data, $entry); - - if ( ! is_array($field_data)) - { - $field_data = array(); - } - - if (isset($field_data['absolute_total_files']) && $field_data['absolute_total_files'] === 0) - { - return array(); - } - - $fields = array( - 'file_id', - 'url', - 'subfolder', - 'filename', - 'extension', - 'date_modified', - 'kind', - 'width', - 'height', - 'size', - 'title', - 'date', - 'alt_text', - 'caption', - 'author', - 'desc', - 'location', - ); - - foreach ($field_data as &$row) - { - $source_type = $row['source_type']; - $filedir_id = $row['filedir_id']; - //excise any other fields from this row - $row = array_intersect_key($row, array_flip($fields)); - $row['file_id'] = (int) $row['file_id']; - $row['date'] = $this->date_format($row['date']); - $row['date_modified'] = $this->date_format($row['date_modified']); - - $row['manipulations'] = array(); - - if ($source_type === 'ee') - { - if ( ! isset($this->image_manipulations[$filedir_id])) - { - ee()->load->model('file_model'); - - $query = ee()->file_model->get_dimensions_by_dir_id($filedir_id); - - $this->image_manipulations[$filedir_id] = $query->result(); - - $query->free_result(); - } - - foreach ($this->image_manipulations[$filedir_id] as $manipulation) - { - $row['manipulations'][$manipulation->short_name] = pathinfo($row['url'], PATHINFO_DIRNAME).'/_'.$manipulation->short_name.'/'.basename($row['url']); - } - } - } - - return $field_data; - } - - public function search() - { - $search_id = ee()->TMPL->fetch_param('search_id'); - - if ( ! $search_id) - { - $search_id = end(ee()->uri->segment_array()); - } - - if ($search_id) - { - $query = ee()->db->where('search_id', $search_id) - ->limit(1) - ->get('exp_search'); - - if ($query->num_rows() > 0) - { - $search = $query->row_array(); - - $query->free_result(); - - if (preg_match('/IN \(([\d,]+)\)/', $query->row('query'), $match)) - { - ee()->TMPL->tagparams['entry_id'] = (strpos($match[1], ',') !== FALSE) ? str_replace(',', '|', $match[1]) : $match[1]; - - return $this->entries(); - } - } - } - - $this->initialize(); - - return $this->respond(array()); - } - - /** - * Categories - * - * @TODO a work in progress, does not work yet - * - * @param array|null $params - * - * @return string - */ - public function categories($params = NULL) - { - $this->initialize(); - - if (is_null($params)) - { - $params = ee()->TMPL->tagparams; - } - - ee()->load->helper('array'); - - $channel = element('channel', $params); - $group_id = element('group_id', $params, element('category_group', $params)); - $cat_id = element('cat_id', $params, element('category_id', $params, element('show', $params))); - $status = element('status', $params); - $parent_only = element('parent_only', $params); - $show_empty = element('show_empty', $params, TRUE); - $joins = array(); - - if ($channel) - { - ee()->db->join('channel_titles', 'channel_titles.entry_id = category_posts.entry_id'); - ee()->db->join('channels', 'channels.channel_id = channel_titles.channel_id'); - ee()->db->where_in('channels.channel_name', explode('|', $channel)); - $joins[] = 'channels'; - $joins[] = 'channel_titles'; - } - - if ($group_id) - { - ee()->db->where_in('categories.group_id', explode('|', $group_id)); - } - - if ($cat_id) - { - ee()->db->where_in('categories.cat_id', explode('|', $cat_id)); - } - - if ($status) - { - if ( ! in_array('channel_titles', $joins)) - { - ee()->db->join('channel_titles', 'channel_titles.entry_id = category_posts.entry_id'); - } - - ee()->db->where_in('channel_titles.status', explode('|', $status)); - } - - if ($parent_only) - { - ee()->db->where('categories.parent_id', 0); - } - - if ($show_empty) - { - ee()->db->where('count >', 0); - } - } - - /** - * Members - * - * @return string - */ - public function members() - { - $this->initialize(); - - if ($this->check_xhr_required()) - { - return ''; - } - - $default_fields = array( - 'm.member_id', - 'm.group_id', - 'm.username', - 'm.screen_name', - 'm.email', - 'm.signature', - 'm.avatar_filename', - 'm.avatar_width', - 'm.avatar_height', - 'm.photo_filename', - 'm.photo_width', - 'm.photo_height', - 'm.url', - 'm.location', - 'm.occupation', - 'm.interests', - 'm.bio', - 'm.join_date', - 'm.last_visit', - 'm.last_activity', - 'm.last_entry_date', - 'm.last_comment_date', - 'm.last_forum_post_date', - 'm.total_entries', - 'm.total_comments', - 'm.total_forum_topics', - 'm.total_forum_posts', - 'm.language', - 'm.timezone', - 'm.bday_d', - 'm.bday_m', - 'm.bday_y', - ); - - if (version_compare(APP_VER, '2.6', '<')) - { - $default_fields[] = 'm.daylight_savings'; - } - - $query = ee()->db->select('m_field_id, m_field_name') - ->get('member_fields'); - - $custom_fields = $query->result_array(); - - $query->free_result(); - - $select = array(); - - if ( ! empty($this->fields)) - { - foreach ($default_fields as $field) - { - $key = substr($field, 2); - - if (in_array($key, $this->fields)) - { - $select[] = $field; - } - } - } - else - { - $select = $default_fields; - } - - foreach ($custom_fields as &$field) - { - if (empty($this->fields) || in_array($field['m_field_name'], $this->fields)) - { - $select[] = 'd.'.ee()->db->protect_identifiers('m_field_id_'.$field['m_field_id']).' AS '.ee()->db->protect_identifiers($field['m_field_name']); - } - } - - ee()->db->select(implode(', ', $select), FALSE) - ->from('members m') - ->join('member_data d', 'm.member_id = d.member_id'); - - if ($member_ids = ee()->TMPL->fetch_param('member_id')) - { - if ($member_ids === 'CURRENT_USER') - { - $member_ids = ee()->session->userdata('member_id'); - } - - ee()->db->where_in('m.member_id', explode('|', $member_ids)); - } - else if (ee()->TMPL->fetch_param('username')) - { - ee()->db->where_in('m.member_id', explode('|', ee()->TMPL->fetch_param('member_id'))); - } - - if (ee()->TMPL->fetch_param('group_id')) - { - ee()->db->where_in('m.group_id', explode('|', ee()->TMPL->fetch_param('group_id'))); - } - - if (ee()->TMPL->fetch_param('limit')) - { - ee()->db->limit(ee()->TMPL->fetch_param('limit')); - } - - if (ee()->TMPL->fetch_param('offset')) - { - ee()->db->offset(ee()->TMPL->fetch_param('offset')); - } - - $query = ee()->db->get(); - - $members = $query->result_array(); - - $query->free_result(); - - $date_fields = array( - 'join_date', - 'last_visit', - 'last_activity', - 'last_entry_date', - 'last_comment_date', - 'last_forum_post_date' - ); - - foreach ($members as &$member) - { - foreach ($date_fields as $field) - { - if (isset($member[$field])) - { - $member[$field] = $this->date_format($member[$field]); - } - } - } - - // ---------------------------------------- - // 'json_plugin_members_end' hook. - // - Enables additional manipulation of entry data - // ---------------------------------------- - - if (ee()->extensions->active_hook('json_plugin_members_end') === TRUE) - { - $members = ee()->extensions->call('json_plugin_members_end', $members, $this); - if (ee()->extensions->end_script === TRUE) return; - } - // ---------------------------------------- - - return $this->respond($members); - } - - protected function initialize($which = NULL) - { - switch($which) - { - case 'entries': - //initialize caches - $this->entries = array(); - $this->entries_entry_ids = array(); - $this->entries_custom_fields = array(); - $this->entries_matrix_rows = NULL; - $this->entries_rel_data = NULL; - $this->entries_relationship_data = NULL; - $this->entries_playa_data = NULL; - $this->entries_channel_files_data = NULL; - break; - } - - $this->xhr = ee()->TMPL->fetch_param('xhr') === 'yes'; - - $this->terminate = ee()->TMPL->fetch_param('terminate') === 'yes'; - - $this->fields = (ee()->TMPL->fetch_param('fields')) ? explode('|', ee()->TMPL->fetch_param('fields')) : array(); - - $this->date_format = ee()->TMPL->fetch_param('date_format'); - - // get rid of EE formatted dates - if ($this->date_format && strstr($this->date_format, '%')) - { - $this->date_format = str_replace('%', '', $this->date_format); - } - - $this->jsonp = ee()->TMPL->fetch_param('jsonp') === 'yes'; - - ee()->load->library('jsonp'); - - $this->callback = (ee()->TMPL->fetch_param('callback') && ee()->jsonp->isValidCallback(ee()->TMPL->fetch_param('callback'))) - ? ee()->TMPL->fetch_param('callback') : NULL; - - $this->content_type = ee()->TMPL->fetch_param('content_type', ($this->jsonp && $this->callback) ? 'application/javascript' : 'application/json'); - } - - protected function check_xhr_required() - { - return $this->xhr && ! ee()->input->is_ajax_request(); - } - - protected function date_format($date) - { - if ( ! $date) - { - return NULL; - } - - return ($this->date_format) ? date($this->date_format, $date) : $date * 1000; - } - - protected function respond(array $response, $callback = NULL) - { - ee()->load->library('javascript'); - - if ($item_root_node = ee()->TMPL->fetch_param('item_root_node')) - { - $response_with_nodes = array(); - - foreach($response as $item) - { - $response_with_nodes[] = array($item_root_node => $item); - } - - $response = $response_with_nodes; - } - - if ($root_node = ee()->TMPL->fetch_param('root_node')) - { - $response = array($root_node => $response); - } - - $response = function_exists('json_encode') - ? json_encode($response) - : ee()->javascript->generate_json($response, TRUE); - - if ( ! is_null($callback)) - { - $response = call_user_func($callback, $response); - } - - if ($this->check_xhr_required()) - { - $response = ''; - } - else if ($this->jsonp && $this->callback) - { - $response = sprintf('%s(%s)', $this->callback, $response); - } - - if ($this->terminate) - { - @header('Content-Type: '.$this->content_type); - - exit($response); - } - - return $response; - } -} - -/* End of file pi.json.php */ -/* Location: ./system/expressionengine/third_party/json/pi.json.php */ From 73ca22123189f144643028c636042af00e35ab77 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:26:33 +0200 Subject: [PATCH 06/17] Delete Json_Template.php --- .../json/libraries/Json_Template.php | 45 ------------------- 1 file changed, 45 deletions(-) delete mode 100644 system/expressionengine/third_party/json/libraries/Json_Template.php diff --git a/system/expressionengine/third_party/json/libraries/Json_Template.php b/system/expressionengine/third_party/json/libraries/Json_Template.php deleted file mode 100644 index be9c123..0000000 --- a/system/expressionengine/third_party/json/libraries/Json_Template.php +++ /dev/null @@ -1,45 +0,0 @@ -TMPL =& ee()->TMPL; - - // Override the "real" TMPL object - ee()->TMPL =& $this; - } - - public function __destruct() - { - // Restore the "real" TMPL object - ee()->TMPL =& $this->TMPL; - } - - public function parse_variables($tagdata, $variables, $enable_backspace = TRUE) - { - $output = parent::parse_variables($tagdata, $variables, $enable_backspace); - $this->variables = $variables; - return $output; - } - - public function parse_variables_row($tagdata, $variables, $solo = TRUE) - { - $this->variables = $variables; - return parent::parse_variables_row($tagdata, $variables, $solo); - } -} \ No newline at end of file From 2e867183848bc2edff66797eccf2637185274955 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:26:43 +0200 Subject: [PATCH 07/17] Delete Jsonp.php --- .../third_party/json/libraries/Jsonp.php | 168 ------------------ 1 file changed, 168 deletions(-) delete mode 100644 system/expressionengine/third_party/json/libraries/Jsonp.php diff --git a/system/expressionengine/third_party/json/libraries/Jsonp.php b/system/expressionengine/third_party/json/libraries/Jsonp.php deleted file mode 100644 index f7df27b..0000000 --- a/system/expressionengine/third_party/json/libraries/Jsonp.php +++ /dev/null @@ -1,168 +0,0 @@ - false, - 'hello' => true, - 'alert()' => false, - 'test()' => false, - 'a-b' => false, - '23foo' => false, - 'foo23' => true, - '$210' => true, - '_bar' => true, - 'some_var' => true, - '$' => true, - 'somevar' => true, - 'function' => false, - ' somevar' => false, - '$.ajaxHandler' => true, - '$.23' => false, - 'array_of_functions[42]' => true, - 'array_of_functions[42][1]' => true, - '$.ajaxHandler[42][1].foo' => true, - 'array_of_functions[42]foo[1]' => false, - 'array_of_functions[]' => false, - 'array_of_functions["key"]' => true, - 'myFunction[123].false' => false, - 'myFunction .tester' => false, - '_function' => true, - 'petersCallback1412331422[12]' => true, - ':myFunction' => false - ); - - /** - * Is valid callback - * - * @param string $callback - * - * @return boolean - */ - function isValidCallback($callback) - { - $reserved = array( - 'break', - 'do', - 'instanceof', - 'typeof', - 'case', - 'else', - 'new', - 'var', - 'catch', - 'finally', - 'return', - 'void', - 'continue', - 'for', - 'switch', - 'while', - 'debugger', - 'function', - 'this', - 'with', - 'default', - 'if', - 'throw', - 'delete', - 'in', - 'try', - 'class', - 'enum', - 'extends', - 'super', - 'const', - 'export', - 'import', - 'implements', - 'let', - 'private', - 'public', - 'yield', - 'interface', - 'package', - 'protected', - 'static', - 'null', - 'true', - 'false' - ); - - foreach(explode('.', $callback) as $identifier) { - if(!preg_match('/^[a-zA-Z_$][0-9a-zA-Z_$]*(?:\[(?:".+"|\'.+\'|\d+)\])*?$/', $identifier)) { - return false; - } - if(in_array($identifier, $reserved)) { - return false; - } - } - - return true; - } - - /** - * Test callback strings - * - * @param string $callback - * - * @return void - * - * @access private - */ - private function _test($callback, $valid) - { - $vocal = $valid ? 'valid' : 'invalid'; - if($this->isValidCallback($callback) === $valid) { - echo '"'.$callback.'" passed as '.$vocal.'.', "\n"; - return true; - } - else { - echo '"'.$callback.'" failed as '.$vocal.'.', "\n"; - return false; - } - } - - /** - * Run all tests - * - * @return void - * - * @access public - */ - function runTests() - { - echo 'Testing ', count($this->_tests), ' callback methods:', "\n\n"; - $passed = 0; - foreach($this->_tests as $callback => $valid) { - $passed = self::_test($callback, $valid) ? $passed+1 : $passed; - } - echo "\n", $passed, ' of ', count($this->_tests), ' tests passed.'; - } -} \ No newline at end of file From 27efed2170b8056d752a30e10943648340c4c0d0 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 02:29:43 +0200 Subject: [PATCH 08/17] Update README.markdown --- README.markdown | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index 5ae8afe..a45cd94 100644 --- a/README.markdown +++ b/README.markdown @@ -4,13 +4,13 @@ Output ExpressionEngine data in JSON format. ## Requirements -- ExpressionEngine 2.6+ +- ExpressionEngine 3+ -For older versions of EE use JSON version [1.0.3](https://github.com/rsanchez/json/tree/v1.0.3). +For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/json). ## Installation -* Copy the /system/expressionengine/third_party/json/ folder to your /system/expressionengine/third_party/ folder +* Copy the /system/user/addons/json_output/ folder to your /system/user/addons/ folder ## Global Parameters From 5cfd8e0c4895f96d93a14ae8b9dda97e5c1ba229 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 10:57:00 +0200 Subject: [PATCH 09/17] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index a45cd94..68583ae 100644 --- a/README.markdown +++ b/README.markdown @@ -6,7 +6,7 @@ Output ExpressionEngine data in JSON format. - ExpressionEngine 3+ -For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/json). +For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/json) by Rob Sanchez. ## Installation From fc4fef32b9aafdbf5cb1344621afc6f7bec9fbc0 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 11:00:32 +0200 Subject: [PATCH 10/17] Update README.markdown --- README.markdown | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.markdown b/README.markdown index 68583ae..4b74c44 100644 --- a/README.markdown +++ b/README.markdown @@ -8,6 +8,11 @@ Output ExpressionEngine data in JSON format. For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/json) by Rob Sanchez. +## Warning + +Do thoroughly test this plugin on a local or development server before using it on a production/live server! +Since this plugin only outputs data I don't expect any damage but I will not accept any liability for any problems risen from using this plugin. + ## Installation * Copy the /system/user/addons/json_output/ folder to your /system/user/addons/ folder From af1e39966d9551955f41b93c7f395d13320cd6f4 Mon Sep 17 00:00:00 2001 From: Zignature Date: Fri, 8 May 2020 11:02:34 +0200 Subject: [PATCH 11/17] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 4b74c44..11aaee4 100644 --- a/README.markdown +++ b/README.markdown @@ -10,7 +10,7 @@ For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/js ## Warning -Do thoroughly test this plugin on a local or development server before using it on a production/live server! +Do thoroughly test this plugin on a local or development server before using it on a production/live server! Since this plugin only outputs data I don't expect any damage but I will not accept any liability for any problems risen from using this plugin. ## Installation From 348e20e572839147ad29c9454a30e611cc0b3a49 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sat, 9 May 2020 23:33:32 +0200 Subject: [PATCH 12/17] Update README.markdown --- README.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.markdown b/README.markdown index 11aaee4..5098e4b 100644 --- a/README.markdown +++ b/README.markdown @@ -15,7 +15,7 @@ Since this plugin only outputs data I don't expect any damage but I will not acc ## Installation -* Copy the /system/user/addons/json_output/ folder to your /system/user/addons/ folder +* Copy the `/system/user/addons/json_output/` folder to your `/system/user/addons/` folder ## Global Parameters From 47a56c5eca580c1a752ca8d3767798ff32074c9d Mon Sep 17 00:00:00 2001 From: Zignature Date: Sun, 10 May 2020 13:17:09 +0200 Subject: [PATCH 13/17] Update README.markdown --- README.markdown | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.markdown b/README.markdown index 5098e4b..0146de0 100644 --- a/README.markdown +++ b/README.markdown @@ -10,6 +10,8 @@ For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/js ## Warning +Not tested with categories, Matrix and Playa yet. + Do thoroughly test this plugin on a local or development server before using it on a production/live server! Since this plugin only outputs data I don't expect any damage but I will not accept any liability for any problems risen from using this plugin. From 3b3ee3ac111cb7e7f0d4e9c1df51dd5c75e1aa72 Mon Sep 17 00:00:00 2001 From: Zignature Date: Sun, 10 May 2020 14:00:16 +0200 Subject: [PATCH 14/17] Update README.markdown --- README.markdown | 52 +++---------------------------------------------- 1 file changed, 3 insertions(+), 49 deletions(-) diff --git a/README.markdown b/README.markdown index 0146de0..1bf2b73 100644 --- a/README.markdown +++ b/README.markdown @@ -10,7 +10,7 @@ For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/js ## Warning -Not tested with categories, Matrix and Playa yet. +Not tested with categories, Matrix and Playa yet! Do thoroughly test this plugin on a local or development server before using it on a production/live server! Since this plugin only outputs data I don't expect any damage but I will not accept any liability for any problems risen from using this plugin. @@ -450,53 +450,7 @@ function yourCallbackFunction(data) { ## Changelog -### v1.1.8 +### v1.0.0 -- Added `json_plugin_entries_end` and `json_plugin_members_end` hooks -- Improved Wygwam support -- Fixed intermittent disappearing `ee()->TMPL` object +- Changed the SQL statement to be compatible with EE3+ -### v1.1.7 - -- Added `offset` support for members - -### v1.1.6 - -- Add Channel Files support. - -### v1.1.5 - -- Add `root_node` and `item_root_node` parameters. - -### v1.1.4 - -- Add manipulations to Assets fields - -### v1.1.3 - -- Fix bug where show_categories parameter did not work - -### v1.1.2 - -- Fix bug where `fields` parameter was not being honored -- Fix bug causing fatal MySQL error when using the `fixed_order` parameter - -### v1.1.1 - -- Fix WSOD on Plugins page -- Fix PHP errors when an Assests field has no selection(s) - -### v1.1.0 - -- Added support for the following fieldtypes: Assets, Grid, Playa, Relationships -- Change IDs (entry_id, author_id, etc.) and Dates to integers -- Added `show_categories` and `show_category_group` parameters to `{exp:json:entries}` -- Added `{exp:json:search}` -- Added JSONP support -- Added `date_format` parameter -- Added `content_type` parameter - -## Upgrading from 1.0.x - -- IDs (entry_id, author_id, etc.) and Dates are returned as integers -- The following fieldtypes have different output: Playa, Assets. Please see docs above for an example of their output. From 08d7be18b9e0d81adc9bf2bd2e5fa707bb2ff6d7 Mon Sep 17 00:00:00 2001 From: Zignature Date: Mon, 18 Jan 2021 10:44:43 +0100 Subject: [PATCH 15/17] Reworked EE3 compatibility --- system/user/addons/json/README.md | 514 ++++++++++++++++++ system/user/addons/json/addon.setup.php | 17 + .../libraries/Json_Template.php | 0 .../{json_output => json}/libraries/Jsonp.php | 0 .../pi.json_output.php => json/pi.json.php} | 64 ++- .../user/addons/json_output/addon.setup.php | 19 - 6 files changed, 584 insertions(+), 30 deletions(-) create mode 100644 system/user/addons/json/README.md create mode 100644 system/user/addons/json/addon.setup.php rename system/user/addons/{json_output => json}/libraries/Json_Template.php (100%) rename system/user/addons/{json_output => json}/libraries/Jsonp.php (100%) rename system/user/addons/{json_output/pi.json_output.php => json/pi.json.php} (94%) delete mode 100644 system/user/addons/json_output/addon.setup.php diff --git a/system/user/addons/json/README.md b/system/user/addons/json/README.md new file mode 100644 index 0000000..5710dba --- /dev/null +++ b/system/user/addons/json/README.md @@ -0,0 +1,514 @@ +# JSON # + +Output ExpressionEngine data in JSON format. + +## Requirements + +- ExpressionEngine 3 +- EE2 no longer supported + +For older versions of EE use JSON version [1.1.8](https://github.com/rsanchez/json/releases/tag/v1.1.8) by Rob Sanchez. + +## Warning + +***Not tested with categories, Assets, Matrix and Playa!*** + +Do thoroughly test this plugin on a local or development server before using it on a production/live server! +Since this plugin only outputs data I don't expect any damage but I will not accept any liability for any problems risen from using this plugin. + +## Installation + +* Copy the `/system/user/addons/json/` folder to your `/system/user/addons/` folder + +## Global Parameters + +### `xhr="yes"` + +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. + +### `terminate="yes"` + +Set terminate to yes to terminate the template and output your json immediately, with Content-Type headers. + +### `fields="title|url_title"` + +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. + +### `content_type="text/javascript"` + +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". + +### `jsonp="yes"` + +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. + +### `callback="yourCallbackFunction"` + +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. + +### `date_format="U"` + +Use a different date format. Note: always returns dates as string. + +### `root_node="items"` + +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. + +Using this parameter will turn this: + +``` +[ + { + "title": "Foo", + "entry_id": 1 + }, + { + "title": "Bar", + "entry_id": 2 + } +] +``` + +Into this: + +``` +{ + "items": [ + { + "title": "Foo", + "entry_id": 1 + }, + { + "title": "Bar", + "entry_id": 2 + } + ] +} +``` + +### `item_root_node="item"` + +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. + +Using this parameter will turn this: + +``` +[ + { + "title": "Foo", + "entry_id": 1 + }, + { + "title": "Bar", + "entry_id": 2 + }, +] +``` + +Into this: + +``` +[ + { + "item": { + "title": "Foo", + "entry_id": 1 + } + }, + { + "item": { + "title": "Bar", + "entry_id": 2 + } + } +] +``` + +## Dates + +By default, the date fields are in unix timestamp format, accurate to milliseconds. Use the Javascript Date object in combination with date field data: + +``` +for (i in data) { + var entryDate = new Date(data[i].entry_date); +} +``` + +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). + +## json:entries + +``` +{exp:json:entries channel="news"} +``` + +json:entries is a single tag, not a tag pair. Use channel:entries parameters to filter your entries. + +#### json:entries Default Fields + +``` +title +url_title +entry_id +channel_id +author_id +status +entry_date +edit_date +expiration_date +Plus all of the custom fields associated with that channel +``` + +#### json:entries Parameters + +See [channel:entries parameters](http://expressionengine.com/user_guide/modules/channel/parameters.html). + +##### `show_categories="yes"` + +This will add categories to the entries response + +##### `show_category_group="1|2"` + +When paired with show_categories="yes", this will display only categories from the specified groups. + +#### json:entries Custom Fields + +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. + +##### Matrix + +The data will include an array of Matrix rows, including the row_id and the column names: + +``` +your_matrix_field: [ + { + row_id: 1, + my_col_name: "foo", + other_col_name: "bar" + }, + { + row_id: 2, + my_col_name: "baz", + other_col_name: "qux" + } +] +``` + +##### Grid + +The data will include an array of Grid rows, including the row_id and the column names: + +``` +your_grid_field: [ + { + row_id: 1, + my_col_name: "foo", + other_col_name: "bar" + }, + { + row_id: 2, + my_col_name: "baz", + other_col_name: "qux" + } +] +``` + +##### Relationships + +The data will include an array of related entry IDs: + +``` +your_relationships_field: [1, 2] +``` + +##### Playa + +The data will include an array of related entry IDs: + +``` +your_playa_field: [1, 2] +``` + +##### Assets + +``` +your_assets_field: [ + { + "file_id": 1, + "url": "http://yoursite.com/uploads/flower.jpg", + "subfolder": "", + "filename": "flower", + "extension": "jpg", + "date_modified": 1389459034000, + "kind": "image", + "width": "300", + "height": "300", + "size": "65 KB", + "title": null, + "date": 1389459034000, + "alt_text": null, + "caption": null, + "author": null, + "desc": null, + "location": null, + "manipulations": { + "medium": "http://yoursite.com/uploads/_medium/flower.jpg", + "large": "http://yoursite.com/uploads/_large/flower.jpg" + } + }, + { + "file_id": 2, + "url": "http://yoursite.com/uploads/dog.jpg", + "subfolder": "", + "filename": "dog", + "extension": "jpg", + "date_modified": 1389466147000, + "kind": "image", + "width": "300", + "height": "300", + "size": "75 KB", + "title": null, + "date": 1389466147000, + "alt_text": null, + "caption": null, + "author": null, + "desc": null, + "location": null, + "manipulations": { + "medium": "http://yoursite.com/uploads/_medium/dog.jpg", + "large": "http://yoursite.com/uploads/_large/dog.jpg" + } + } +] +``` + +*NOTE: image manipulation urls are only available to Assets files store locally, not on Amazon S3 or Google Storage.* + +##### Channel Files + +``` +your_channel_files_field: [ + { + "file_id": 1, + "url": "http://yoursite.com/uploads/flower.jpg", + "filename": "flower.jpg", + "extension": "jpg", + "kind": "image\/jpeg", + "size": "65 KB", + "title": "flower", + "date": 1389459034000, + "author": 1, + "desc": "Lorem ipsum", + "primary": true, + "downloads": 10, + "custom1": null, + "custom2": null, + "custom3": null, + "custom4": null, + "custom5": null + }, + { + "file_id": 2, + "url": "http://yoursite.com/uploads/dog.jpg", + "filename": "dog.jpg", + "extension": "jpg", + "kind": "image\/jpeg", + "size": "75 KB", + "title": "dog", + "date": 1389466147000, + "author": 1, + "desc": "Lorem ipsum", + "primary": false, + "downloads": 0, + "custom1": null, + "custom2": null, + "custom3": null, + "custom4": null, + "custom5": null + } +] +``` + +##### Date + +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. + +``` +your_date_field: 1385661660000 +``` + +## json:search + +``` +{exp:json:search search_id="{segment_3}"} +``` + +json:search must be paired with {exp:search:simple_form} or {exp:search:advanced_form}. + +#### json:search Parameters + +See [channel:entries parameters](http://expressionengine.com/user_guide/modules/channel/parameters.html). + +##### `search_id="{segment_3}"` + +The native search forms will append a search_id automatically to the result_page when you submit a form. + +#### json:search Example + +``` +{exp:search:simple_form channel="site" form_id="search" return_page="site/json"} + + +{/exp:search:simple_form} + + +``` + +## json:members + +``` +{exp:json:members member_id="1|2"} +``` + +json:members is a single tag, not a tag pair. + +#### json:members Parameters + +##### `member_id="1"` + +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. + +##### `username="admin"` + +Specify which members, by username, to output. Separate multiple usernames with a pipe character. + +##### `group_id="1"` + +Specify which members, by group_id, to output. Separate multiple group_id's + +##### `limit="1"` + +Set a limit for records to retrieve. + + +## Advanced Examples + +### JSONP + +If you're doing cross-domain AJAX, you will probably want to use JSONP. + +This is the JSON template: + +``` +{exp:json:entries channel="site" jsonp="yes" callback="{segment_3}"} +``` + +And the request itself: + +``` +$.ajax({ + url: "http://yoursite.com/group/template/yourCallbackFunction", + dataType: "jsonp", + jsonp: false +}); +function yourCallbackFunction(data) { + console.log(data); +} +``` + +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: + +``` +{exp:json:entries channel="site" jsonp="yes" callback=""} +``` + +The request: + +``` +$.ajax({ + url: "http://yoursite.com/group/template", + dataType: "jsonp", + jsonpCallback: "yourCallbackFunction" +}); +function yourCallbackFunction(data) { + console.log(data); +} +``` + +## Changelog + +### v1.1.9 + +- EE3 compatibility +- Added relationships support for grids by [ahebrank](https://github.com/ahebrank) +- Added `addon.setup.php` for EE3 +- Added `README.md` for the add-on manual in the control panel (as of EE3) +- Fluid fieldtype not supported +- **Note:** not tested with Playa, Assets and Matrix + +### v1.1.8 + +- Added `json_plugin_entries_end` and `json_plugin_members_end` hooks +- Improved Wygwam support +- Fixed intermittent disappearing `ee()->TMPL` object + +### v1.1.7 + +- Added `offset` support for members + +### v1.1.6 + +- Add Channel Files support. + +### v1.1.5 + +- Add `root_node` and `item_root_node` parameters. + +### v1.1.4 + +- Add manipulations to Assets fields + +### v1.1.3 + +- Fix bug where show_categories parameter did not work + +### v1.1.2 + +- Fix bug where `fields` parameter was not being honored +- Fix bug causing fatal MySQL error when using the `fixed_order` parameter + +### v1.1.1 + +- Fix WSOD on Plugins page +- Fix PHP errors when an Assests field has no selection(s) + +### v1.1.0 + +- Added support for the following fieldtypes: Assets, Grid, Playa, Relationships +- Change IDs (entry_id, author_id, etc.) and Dates to integers +- Added `show_categories` and `show_category_group` parameters to `{exp:json:entries}` +- Added `{exp:json:search}` +- Added JSONP support +- Added `date_format` parameter +- Added `content_type` parameter + +## Upgrading from 1.0.x + +- IDs (entry_id, author_id, etc.) and Dates are returned as integers +- The following fieldtypes have different output: Playa, Assets. Please see docs above for an example of their output. + + diff --git a/system/user/addons/json/addon.setup.php b/system/user/addons/json/addon.setup.php new file mode 100644 index 0000000..ca206b6 --- /dev/null +++ b/system/user/addons/json/addon.setup.php @@ -0,0 +1,17 @@ + 'Rob Sanchez', + 'author_url' => 'https://github.com/rsanchez', + 'description' => 'Output ExpressionEngine channel entries in JSON format.', + 'docs_url' => 'https://github.com/rsanchez/json', + 'name' => 'JSON', + 'settings_exist' => FALSE, + 'version' => '1.1.9', + 'namespace' => 'rsanchez/json' +); diff --git a/system/user/addons/json_output/libraries/Json_Template.php b/system/user/addons/json/libraries/Json_Template.php similarity index 100% rename from system/user/addons/json_output/libraries/Json_Template.php rename to system/user/addons/json/libraries/Json_Template.php diff --git a/system/user/addons/json_output/libraries/Jsonp.php b/system/user/addons/json/libraries/Jsonp.php similarity index 100% rename from system/user/addons/json_output/libraries/Jsonp.php rename to system/user/addons/json/libraries/Jsonp.php diff --git a/system/user/addons/json_output/pi.json_output.php b/system/user/addons/json/pi.json.php similarity index 94% rename from system/user/addons/json_output/pi.json_output.php rename to system/user/addons/json/pi.json.php index d395fb8..8443fb6 100644 --- a/system/user/addons/json_output/pi.json_output.php +++ b/system/user/addons/json/pi.json.php @@ -1,6 +1,21 @@ 'JSON', + 'pi_version' => '1.1.9', + 'pi_author' => 'Rob Sanchez', + 'pi_author_url' => 'https://github.com/rsanchez', + 'pi_description' => 'Output ExpressionEngine data in JSON format.', + 'pi_usage' => ' +{exp:json:entries channel="news"} + +{exp:json:entries channel="products" search:product_size="10"} + +{exp:json:members member_id="1"}', +); + +class Json { /* settings */ protected $content_type = 'application/json'; @@ -100,11 +115,9 @@ public function entries($entry_ids = null) if ($this->entries_entry_ids) { - $this->entries_custom_fields = ee()->db->select('channel_fields.*') + $this->entries_custom_fields = ee()->db->select('channel_fields.*, channels.channel_id') ->from('channel_fields') - ->join('channel_field_groups_fields', 'channel_fields.field_id = channel_field_groups_fields.field_id') - ->join('channels_channel_field_groups', 'channel_field_groups_fields.group_id = channels_channel_field_groups.group_id') - ->join('channels', 'channels_channel_field_groups.channel_id = channels.channel_id') + ->join('channels', 'channel_fields.group_id = channels.field_group') ->where('channels.site_id', ee()->config->item('site_id')) ->where_in('channels.channel_name', explode('|', ee()->TMPL->fetch_param('channel'))) ->get() @@ -235,7 +248,7 @@ public function entries($entry_ids = null) foreach ($this->entries_custom_fields as &$field) { //call our custom callback for this fieldtype if it exists - if (isset($entry[$field['field_name']]) && is_callable(array($this, 'entries_'.$field['field_type']))) + if (is_callable(array($this, 'entries_'.$field['field_type']))) { $entry[$field['field_name']] = call_user_func(array($this, 'entries_'.$field['field_type']), $entry['entry_id'], $field, $entry[$field['field_name']], $entry); } @@ -292,6 +305,18 @@ public function entries($entry_ids = null) ee()->load->library('typography'); + // ---------------------------------------- + // 'json_plugin_entries_end' hook. + // - Enables additional manipulation of entry data + // ---------------------------------------- + + if (ee()->extensions->active_hook('json_plugin_entries_end') === TRUE) + { + ee()->extensions->call('json_plugin_entries_end', $this); + if (ee()->extensions->end_script === TRUE) return; + } + // ---------------------------------------- + return $this->respond($this->entries, array(ee()->typography, 'parse_file_paths')); } @@ -665,6 +690,7 @@ protected function entries_custom_field($entry_id, $field, $field_data, $entry, { require_once PATH_THIRD.'json/libraries/Json_Template.php'; + $ee_tmpl = ee()->TMPL; $template = new Json_Template(); $field_data = ee()->api_channel_fields->apply('replace_tag', array($field_data, array(), $tagdata)); @@ -675,12 +701,17 @@ protected function entries_custom_field($entry_id, $field, $field_data, $entry, } unset($template); + ee()->TMPL = $ee_tmpl; } ee()->load->remove_package_path(ee()->api_channel_fields->ft_paths[$field['field_type']]); return $field_data; } + + protected function entries_wygwam($entry_id, $field, $field_data, $entry) { + return $this->entries_custom_field($entry_id, $field, $field_data, $entry); + } protected function entries_assets($entry_id, $field, $field_data, $entry) { @@ -904,15 +935,15 @@ public function members() ); if (version_compare(APP_VER, '2.6', '<')) - { + { $default_fields[] = 'm.daylight_savings'; } - + $query = ee()->db->select('m_field_id, m_field_name') ->get('member_fields'); $custom_fields = $query->result_array(); - + $query->free_result(); $select = array(); @@ -999,7 +1030,18 @@ public function members() $member[$field] = $this->date_format($member[$field]); } } + } + // ---------------------------------------- + // 'json_plugin_members_end' hook. + // - Enables additional manipulation of entry data + // ---------------------------------------- + + if (ee()->extensions->active_hook('json_plugin_members_end') === TRUE) + { + $members = ee()->extensions->call('json_plugin_members_end', $members, $this); + if (ee()->extensions->end_script === TRUE) return; } + // ---------------------------------------- return $this->respond($members); } @@ -1110,5 +1152,5 @@ protected function respond(array $response, $callback = NULL) } } -/* End of file pi.json_output.php */ -/* Location: ./system/user/addons/json/pi.json_output.php */ +/* End of file pi.json.php */ +/* Location: ./system/user/addons/json/pi.json.php */ diff --git a/system/user/addons/json_output/addon.setup.php b/system/user/addons/json_output/addon.setup.php deleted file mode 100644 index 98e4583..0000000 --- a/system/user/addons/json_output/addon.setup.php +++ /dev/null @@ -1,19 +0,0 @@ - 'Zignature', - 'author_url' => 'https://github.com/Zignature/ee-json-output', - 'description' => 'Output ExpressionEngine channel entries in JSON format.', - 'docs_url' => 'https://github.com/Zignature/ee-json-output', - 'name' => 'EE JSON Output', - 'settings_exist' => false, - 'version' => '1.0.0', - 'namespace' => 'json_output/json_output' -); From 51a2631dcaf7e3f58bfd14ce978b9f522c465fe0 Mon Sep 17 00:00:00 2001 From: Zignature Date: Mon, 18 Jan 2021 10:48:20 +0100 Subject: [PATCH 16/17] Update README.markdown --- README.markdown | 68 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 62 insertions(+), 6 deletions(-) diff --git a/README.markdown b/README.markdown index 1bf2b73..da76bab 100644 --- a/README.markdown +++ b/README.markdown @@ -4,20 +4,21 @@ Output ExpressionEngine data in JSON format. ## Requirements -- ExpressionEngine 3+ +- ExpressionEngine 3 +- EE2 no longer supported -For older versions of EE use JSON version [1.1.7](https://github.com/rsanchez/json) by Rob Sanchez. +For older versions of EE use JSON version [1.1.8](https://github.com/rsanchez/json/releases/tag/v1.1.8) by Rob Sanchez. ## Warning -Not tested with categories, Matrix and Playa yet! +***Not tested with categories, Assets, Matrix and Playa!*** Do thoroughly test this plugin on a local or development server before using it on a production/live server! Since this plugin only outputs data I don't expect any damage but I will not accept any liability for any problems risen from using this plugin. ## Installation -* Copy the `/system/user/addons/json_output/` folder to your `/system/user/addons/` folder +* Copy the `/system/user/addons/json/` folder to your `/system/user/addons/` folder ## Global Parameters @@ -450,7 +451,62 @@ function yourCallbackFunction(data) { ## Changelog -### v1.0.0 +### v1.1.9 -- Changed the SQL statement to be compatible with EE3+ +- EE3 compatibility +- Added relationships support for grids by [ahebrank](https://github.com/ahebrank) +- Added `addon.setup.php` for EE3 +- Added `README.md` for the add-on manual in the control panel (as of EE3) +- Fluid fieldtype not supported +- **Note:** not tested with Playa, Assets and Matrix +### v1.1.8 + +- Added `json_plugin_entries_end` and `json_plugin_members_end` hooks +- Improved Wygwam support +- Fixed intermittent disappearing `ee()->TMPL` object + +### v1.1.7 + +- Added `offset` support for members + +### v1.1.6 + +- Add Channel Files support. + +### v1.1.5 + +- Add `root_node` and `item_root_node` parameters. + +### v1.1.4 + +- Add manipulations to Assets fields + +### v1.1.3 + +- Fix bug where show_categories parameter did not work + +### v1.1.2 + +- Fix bug where `fields` parameter was not being honored +- Fix bug causing fatal MySQL error when using the `fixed_order` parameter + +### v1.1.1 + +- Fix WSOD on Plugins page +- Fix PHP errors when an Assests field has no selection(s) + +### v1.1.0 + +- Added support for the following fieldtypes: Assets, Grid, Playa, Relationships +- Change IDs (entry_id, author_id, etc.) and Dates to integers +- Added `show_categories` and `show_category_group` parameters to `{exp:json:entries}` +- Added `{exp:json:search}` +- Added JSONP support +- Added `date_format` parameter +- Added `content_type` parameter + +## Upgrading from 1.0.x + +- IDs (entry_id, author_id, etc.) and Dates are returned as integers +- The following fieldtypes have different output: Playa, Assets. Please see docs above for an example of their output. From 94287e1d5927beed373ecf3e0c75bdf66a314722 Mon Sep 17 00:00:00 2001 From: Zignature Date: Mon, 18 Jan 2021 10:49:22 +0100 Subject: [PATCH 17/17] Update README.markdown --- README.markdown | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/README.markdown b/README.markdown index da76bab..805ed28 100644 --- a/README.markdown +++ b/README.markdown @@ -4,10 +4,9 @@ Output ExpressionEngine data in JSON format. ## Requirements -- ExpressionEngine 3 -- EE2 no longer supported +- ExpressionEngine 2.6+ -For older versions of EE use JSON version [1.1.8](https://github.com/rsanchez/json/releases/tag/v1.1.8) by Rob Sanchez. +For older versions of EE use JSON version [1.0.3](https://github.com/rsanchez/json/releases/tag/v1.0.3). ## Warning