/system/expressionengine/modules/channel/mod.channel.php
PHP | 7660 lines | 5352 code | 1374 blank | 934 comment | 1189 complexity | 4559c0dcc7800d56d939ac7cfa181d00 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
- /**
- * ExpressionEngine - by EllisLab
- *
- * @package ExpressionEngine
- * @author EllisLab Dev Team
- * @copyright Copyright (c) 2003 - 2012, EllisLab, Inc.
- * @license http://expressionengine.com/user_guide/license.html
- * @link http://expressionengine.com
- * @since Version 2.0
- * @filesource
- */
- // --------------------------------------------------------------------
- /**
- * ExpressionEngine Channel Module
- *
- * @package ExpressionEngine
- * @subpackage Modules
- * @category Modules
- * @author EllisLab Dev Team
- * @link http://expressionengine.com
- */
- class Channel {
- public $limit = '100'; // Default maximum query results if not specified.
- // These variable are all set dynamically
- public $query;
- public $TYPE;
- public $entry_id = '';
- public $uri = '';
- public $uristr = '';
- public $return_data = ''; // Final data
- public $hit_tracking_id = FALSE;
- public $sql = FALSE;
- public $cfields = array();
- public $dfields = array();
- public $rfields = array();
- public $mfields = array();
- public $pfields = array();
- public $categories = array();
- public $catfields = array();
- public $channel_name = array();
- public $channels_array = array();
- public $related_entries = array();
- public $reverse_related_entries = array();
- public $reserved_cat_segment = '';
- public $use_category_names = FALSE;
- public $cat_request = FALSE;
- public $enable = array(); // modified by various tags with disable= parameter
- public $absolute_results = NULL; // absolute total results returned by the tag, useful when paginating
- public $display_by = '';
- // These are used with the nested category trees
- public $category_list = array();
- public $cat_full_array = array();
- public $cat_array = array();
- public $temp_array = array();
- public $category_count = 0;
- public $pagination;
- public $pager_sql = '';
- // SQL Caching
- public $sql_cache_dir = 'sql_cache/';
- // Misc. - Class variable usable by extensions
- public $misc = FALSE;
- /**
- * Constructor
- */
- public function Channel()
- {
- // Make a local reference to the ExpressionEngine super object
- $this->EE =& get_instance();
- $this->EE->load->library('pagination');
- $this->pagination = new Pagination_object(__CLASS__);
- // $this->pagination->per_page = $this->limit;
-
- // Used by pagination to determine whether we're coming from the cache
- $this->pagination->dynamic_sql = FALSE;
- $this->query_string = ($this->EE->uri->page_query_string != '') ? $this->EE->uri->page_query_string : $this->EE->uri->query_string;
- if ($this->EE->config->item("use_category_name") == 'y' && $this->EE->config->item("reserved_category_word") != '')
- {
- $this->use_category_names = $this->EE->config->item("use_category_name");
- $this->reserved_cat_segment = $this->EE->config->item("reserved_category_word");
- }
- // a number of tags utilize the disable= parameter, set it here
- if (isset($this->EE->TMPL) && is_object($this->EE->TMPL))
- {
- $this->_fetch_disable_param();
- }
- }
- // ------------------------------------------------------------------------
- /**
- * Initialize values
- */
- public function initialize()
- {
- $this->sql = '';
- $this->return_data = '';
- }
- // ------------------------------------------------------------------------
- /**
- * Fetch Cache
- */
- public function fetch_cache($identifier = '')
- {
- $tag = ($identifier == '') ? $this->EE->TMPL->tagproper : $this->EE->TMPL->tagproper.$identifier;
- if ($this->EE->TMPL->fetch_param('dynamic_parameters') !== FALSE && isset($_POST) && count($_POST) > 0)
- {
- foreach (explode('|', $this->EE->TMPL->fetch_param('dynamic_parameters')) as $var)
- {
- if (isset($_POST[$var]) && in_array($var, array('channel', 'entry_id', 'category', 'orderby', 'sort', 'sticky', 'show_future_entries', 'show_expired', 'entry_id_from', 'entry_id_to', 'not_entry_id', 'start_on', 'stop_before', 'year', 'month', 'day', 'display_by', 'limit', 'username', 'status', 'group_id', 'cat_limit', 'month_limit', 'offset', 'author_id')))
- {
- $tag .= $var.'="'.$_POST[$var].'"';
- }
- if (isset($_POST[$var]) && strncmp($var, 'search:', 7) == 0)
- {
- $tag .= $var.'="'.substr($_POST[$var], 7).'"';
- }
- }
- }
- $cache_file = APPPATH.'cache/'.$this->sql_cache_dir.md5($tag.$this->uri);
- if ( ! $fp = @fopen($cache_file, FOPEN_READ))
- {
- return FALSE;
- }
- flock($fp, LOCK_SH);
- $sql = @fread($fp, filesize($cache_file));
- flock($fp, LOCK_UN);
- fclose($fp);
- return $sql;
- }
- // ------------------------------------------------------------------------
- /**
- * Save Cache
- */
- public function save_cache($sql, $identifier = '')
- {
- $tag = ($identifier == '') ? $this->EE->TMPL->tagproper : $this->EE->TMPL->tagproper.$identifier;
- $cache_dir = APPPATH.'cache/'.$this->sql_cache_dir;
- $cache_file = $cache_dir.md5($tag.$this->uri);
- if ( ! @is_dir($cache_dir))
- {
- if ( ! @mkdir($cache_dir, DIR_WRITE_MODE))
- {
- return FALSE;
- }
- if ($fp = @fopen($cache_dir.'/index.html', FOPEN_WRITE_CREATE_DESTRUCTIVE))
- {
- fclose($fp);
- }
- @chmod($cache_dir, DIR_WRITE_MODE);
- }
- if ( ! $fp = @fopen($cache_file, FOPEN_WRITE_CREATE_DESTRUCTIVE))
- {
- return FALSE;
- }
- flock($fp, LOCK_EX);
- fwrite($fp, $sql);
- flock($fp, LOCK_UN);
- fclose($fp);
- @chmod($cache_file, FILE_WRITE_MODE);
- return TRUE;
- }
- // ------------------------------------------------------------------------
- /**
- * Channel entries
- */
- public function entries()
- {
- // If the "related_categories" mode is enabled
- // we'll call the "related_categories" function
- // and bail out.
- if ($this->EE->TMPL->fetch_param('related_categories_mode') == 'yes')
- {
- return $this->related_entries();
- }
- // Onward...
- $this->initialize();
- $this->uri = ($this->query_string != '') ? $this->query_string : 'index.php';
- if ($this->enable['custom_fields'] == TRUE)
- {
- $this->fetch_custom_channel_fields();
- }
- if ($this->enable['member_data'] == TRUE)
- {
- $this->fetch_custom_member_fields();
- }
- if ($this->enable['pagination'] == TRUE)
- {
- $this->pagination->get_template();
- }
- $save_cache = FALSE;
-
- if ($this->EE->config->item('enable_sql_caching') == 'y' && $this->EE->TMPL->fetch_param('author_id') != 'CURRENT_USER')
- {
- if (FALSE == ($this->sql = $this->fetch_cache()))
- {
- $save_cache = TRUE;
- }
- else
- {
- if ($this->EE->TMPL->fetch_param('dynamic') != 'no')
- {
- if (preg_match("#(^|\/)C(\d+)#", $this->query_string, $match) OR in_array($this->reserved_cat_segment, explode("/", $this->query_string)))
- {
- $this->cat_request = TRUE;
- }
- }
- }
- if (FALSE !== ($cache = $this->fetch_cache('pagination_count')))
- {
- if (FALSE !== ($this->fetch_cache('field_pagination')))
- {
- if (FALSE !== ($pg_query = $this->fetch_cache('pagination_query')))
- {
- $this->pagination->paginate = TRUE;
- $this->pagination->field_pagination = TRUE;
- $this->pagination->cfields = $this->cfields;
- $this->pagination->build(trim($cache), $this->sql, $this->EE->db->query(trim($pg_query)));
- }
- }
- else
- {
- $this->pagination->cfields = $this->cfields;
- $this->pagination->build(trim($cache), $this->sql);
- }
- }
- }
- if ($this->sql == '')
- {
- $this->build_sql_query();
- }
- if ($this->sql == '')
- {
- return $this->EE->TMPL->no_results();
- }
- if ($save_cache == TRUE)
- {
- $this->save_cache($this->sql);
- }
- $this->query = $this->EE->db->query($this->sql);
- if ($this->query->num_rows() == 0)
- {
- return $this->EE->TMPL->no_results();
- }
- // -------------------------------------
- // "Relaxed" View Tracking
- //
- // Some people have tags that are used to mimic a single-entry
- // page without it being dynamic. This allows Entry View Tracking
- // to work for ANY combination that results in only one entry
- // being returned by the tag, including channel query caching.
- //
- // Hidden Configuration Variable
- // - relaxed_track_views => Allow view tracking on non-dynamic
- // single entries (y/n)
- // -------------------------------------
- if ($this->EE->config->item('relaxed_track_views') === 'y' && $this->query->num_rows() == 1)
- {
- $this->hit_tracking_id = $this->query->row('entry_id') ;
- }
- $this->track_views();
- $this->EE->load->library('typography');
- $this->EE->typography->initialize(array(
- 'convert_curly' => FALSE
- ));
- if ($this->enable['categories'] == TRUE)
- {
- $this->fetch_categories();
- }
- $this->parse_channel_entries();
- if ($this->enable['pagination'] == TRUE)
- {
- $this->return_data = $this->pagination->render($this->return_data);
- }
- // Does the tag contain "related entries" that we need to parse out?
- if (count($this->EE->TMPL->related_data) > 0 && count($this->related_entries) > 0)
- {
- $this->parse_related_entries();
- }
- if (count($this->EE->TMPL->reverse_related_data) > 0 && count($this->reverse_related_entries) > 0)
- {
- $this->parse_reverse_related_entries();
- }
- return $this->return_data;
- }
- // ------------------------------------------------------------------------
- /**
- * Process related entries
- */
- public function parse_related_entries()
- {
- $sql = "SELECT rel_id, rel_parent_id, rel_child_id, rel_type, rel_data
- FROM exp_relationships
- WHERE rel_id IN (";
- $templates = array();
- foreach ($this->related_entries as $val)
- {
- $x = explode('_', $val);
- $sql .= "'".$x[0]."',";
- $templates[] = array($x[0], $x[1], $this->EE->TMPL->related_data[$x[1]]);
- }
- $sql = substr($sql, 0, -1).')';
- $query = $this->EE->db->query($sql);
- if ($query->num_rows() == 0)
- return;
- // --------------------------------
- // Without this the Related Entries were inheriting the parameters of
- // the enclosing Channel Entries tag. Sometime in the future we will
- // likely allow Related Entries to have their own parameters
- // --------------------------------
- $return_data = $this->return_data;
- foreach ($templates as $temp)
- {
- foreach ($query->result_array() as $row)
- {
- if ($row['rel_id'] != $temp[0])
- continue;
- // --------------------------------------
- // If the data is emptied (cache cleared), then we
- // rebuild it with fresh data so processing can continue.
- // --------------------------------------
- if (trim($row['rel_data']) == '')
- {
- $rewrite = array(
- 'type' => $row['rel_type'],
- 'parent_id' => $row['rel_parent_id'],
- 'child_id' => $row['rel_child_id'],
- 'related_id' => $row['rel_id']
- );
- $this->EE->functions->compile_relationship($rewrite, FALSE);
- $results = $this->EE->db->query("SELECT rel_data FROM exp_relationships WHERE rel_id = '".$row['rel_id']."'");
- $row['rel_data'] = $results->row('rel_data') ;
- }
- // Begin Processing
- $this->initialize();
- if ($reldata = @unserialize($row['rel_data']))
- {
- $this->EE->TMPL->var_single = $temp[2]['var_single'];
- $this->EE->TMPL->var_pair = $temp[2]['var_pair'];
- $this->EE->TMPL->var_cond = $temp[2]['var_cond'];
- $this->EE->TMPL->tagdata = $temp[2]['tagdata'];
- if ($row['rel_type'] == 'channel')
- {
- // Bug fix for when categories were not being inserted
- // correctly for related channel entries. Bummer.
- if (count($reldata['categories'] == 0) && ! isset($reldata['cats_fixed']))
- {
- $fixdata = array(
- 'type' => $row['rel_type'],
- 'parent_id' => $row['rel_parent_id'],
- 'child_id' => $row['rel_child_id'],
- 'related_id' => $row['rel_id']
- );
- $this->EE->functions->compile_relationship($fixdata, FALSE);
- $reldata['categories'] = $this->EE->functions->cat_array;
- $reldata['category_fields'] = $this->EE->functions->catfields;
- }
- $this->query = $reldata['query'];
-
- if ($this->query->num_rows != 0)
- {
- $this->categories = array($this->query->row('entry_id') => $reldata['categories']);
- if (isset($reldata['category_fields']))
- {
- $this->catfields = array($this->query->row('entry_id') => $reldata['category_fields']);
- }
- }
- $this->parse_channel_entries();
- $marker = LD."REL[".$row['rel_id']."][".$temp[2]['field_name']."]".$temp[1]."REL".RD;
- $return_data = str_replace($marker, $this->return_data, $return_data);
- }
- }
- }
- }
- $this->return_data = $return_data;
- }
- // ------------------------------------------------------------------------
- /**
- * Process reverse related entries
- */
- public function parse_reverse_related_entries()
- {
- $this->EE->db->select('rel_id, rel_parent_id, rel_child_id, rel_type, reverse_rel_data');
- $this->EE->db->where_in('rel_child_id', array_keys($this->reverse_related_entries));
- $this->EE->db->where('rel_type', 'channel');
- $query = $this->EE->db->get('relationships');
-
- if ($query->num_rows() == 0)
- {
- // remove Reverse Related tags for these entries
- foreach ($this->reverse_related_entries as $entry_id => $templates)
- {
- foreach($templates as $tkey => $template)
- {
- $this->return_data = str_replace(LD."REV_REL[".$this->EE->TMPL->reverse_related_data[$template]['marker']."][".$entry_id."]REV_REL".RD, $this->EE->TMPL->reverse_related_data[$template]['no_rev_content'], $this->return_data);
- }
- }
- return;
- }
- // Data Processing Time
- $entry_data = array();
- for ($i = 0, $total = count($query->result_array()); $i < $total; $i++)
- {
- $row = array_shift($query->result_array);
- // If the data is emptied (cache cleared or first process), then we
- // rebuild it with fresh data so processing can continue.
- if (trim($row['reverse_rel_data']) == '')
- {
- $rewrite = array(
- 'type' => $row['rel_type'],
- 'parent_id' => $row['rel_parent_id'],
- 'child_id' => $row['rel_child_id'],
- 'related_id' => $row['rel_id']
- );
- $this->EE->functions->compile_relationship($rewrite, FALSE, TRUE);
- $this->EE->db->select('reverse_rel_data');
- $this->EE->db->where('rel_parent_id', $row['rel_parent_id']);
- $results = $this->EE->db->get('relationships');
- $row['reverse_rel_data'] = $results->row('reverse_rel_data');
- }
- // Unserialize the entries data, please
- if ($revreldata = @unserialize($row['reverse_rel_data']))
- {
- $entry_data[$row['rel_child_id']][$row['rel_parent_id']] = $revreldata;
- }
- }
-
- // Without this the Reverse Related Entries were inheriting the parameters of
- // the enclosing Channel Entries tag, which is not appropriate.
- $return_data = $this->return_data;
- foreach ($this->reverse_related_entries as $entry_id => $templates)
- {
- // No Entries? Remove Reverse Related Tags and Continue to Next Entry
- if ( ! isset($entry_data[$entry_id]))
- {
- foreach($templates as $tkey => $template)
- {
- $return_data = str_replace(LD."REV_REL[".$this->EE->TMPL->reverse_related_data[$template]['marker']."][".$entry_id."]REV_REL".RD, $this->EE->TMPL->reverse_related_data[$template]['no_rev_content'], $return_data);
- }
- continue;
- }
- // Process Our Reverse Related Templates
- foreach($templates as $tkey => $template)
- {
- $i = 0;
- $cats = array();
- $params = $this->EE->TMPL->reverse_related_data[$template]['params'];
- if ( ! is_array($params))
- {
- $params = array('status' => 'open');
- }
- elseif ( ! isset($params['status']))
- {
- $params['status'] = 'open';
- }
- else
- {
- $params['status'] = trim($params['status'], " |\t\n\r");
- }
- // Entries have to be ordered, sorted and other stuff
- $new = array();
- $order = ( ! isset($params['orderby'])) ? 'date' : $params['orderby'];
- $offset = ( ! isset($params['offset']) OR ! is_numeric($params['offset'])) ? 0 : $params['offset'];
- $limit = ( ! isset($params['limit']) OR ! is_numeric($params['limit'])) ? 100 : $params['limit'];
- $sort = ( ! isset($params['sort'])) ? 'asc' : $params['sort'];
- $random = ($order == 'random') ? TRUE : FALSE;
- $base_orders = array('random', 'date', 'title', 'url_title', 'edit_date', 'comment_total', 'username', 'screen_name', 'most_recent_comment', 'expiration_date', 'entry_id',
- 'view_count_one', 'view_count_two', 'view_count_three', 'view_count_four');
- $str_sort = array('title', 'url_title', 'username', 'screen_name');
-
- if ( ! in_array($order, $base_orders))
- {
- $set = 'n';
- foreach($this->cfields as $site_id => $cfields)
- {
- if ( isset($cfields[$order]))
- {
- $multi_order[] = 'field_id_'.$cfields[$order];
- $set = 'y';
- $str_sort[] = 'field_id_'.$cfields[$order];
- //break;
- }
- }
- if ( $set == 'n' )
- {
- $order = 'date';
- }
- }
- if ($order == 'date' OR $order == 'random')
- {
- $order = 'entry_date';
- }
- if (isset($params['channel']) && trim($params['channel']) != '')
- {
- if (count($this->channels_array) == 0)
- {
- $this->EE->db->select('channel_id, channel_name');
- $this->EE->db->where_in('site_id', $this->EE->TMPL->site_ids);
- $results = $this->EE->db->get('channels');
- foreach($results->result_array() as $row)
- {
- $this->channels_array[$row['channel_id']] = $row['channel_name'];
- }
- }
- $channels = explode('|', trim($params['channel']));
- $allowed = array();
- if (strncmp($channels[0], 'not ', 4) == 0)
- {
- $channels[0] = trim(substr($channels[0], 3));
- $allowed = $this->channels_array;
- foreach($channels as $name)
- {
- if (in_array($name, $allowed))
- {
- foreach (array_keys($allowed, $name) AS $k)
- {
- unset($allowed[$k]);
- }
- }
- }
- }
- else
- {
- foreach($channels as $name)
- {
- if (in_array($name, $this->channels_array))
- {
- foreach (array_keys($this->channels_array, $name) AS $k)
- {
- $allowed[$k] = $name;
- }
- }
- }
- }
- }
- $stati = explode('|', $params['status']);
- $stati = array_map('strtolower', $stati); // match MySQL's case-insensitivity
- $status_state = 'positive';
- // Check for "not "
- if (substr($stati[0], 0, 4) == 'not ')
- {
- $status_state = 'negative';
- $stati[0] = trim(substr($stati[0], 3));
- $stati[] = 'closed';
- }
- $r = 1; // Fixes a problem when a sorting key occurs twice
- foreach($entry_data[$entry_id] as $relating_data)
- {
- $post_fix = ' '.$r;
- $order_set = FALSE;
-
- if ( ! isset($params['channel']) OR ($relating_data['query']->row('channel_id') && array_key_exists($relating_data['query']->row('channel_id'), $allowed)))
- {
- $query_row = $relating_data['query']->row_array();
-
- if (isset($multi_order))
- {
- foreach ($multi_order as $field_val)
- {
- if (isset($query_row[$field_val]))
- {
- $order_set = TRUE;
- $order_key = '';
-
- if ($query_row[$field_val] != '')
- {
- $order_key = $query_row[$field_val];
- $order = $field_val;
- break;
- }
- }
- }
- }
- elseif (isset($query_row[$order]))
- {
- $order_set = TRUE;
- $order_key = $query_row[$order];
- }
- // Needs to have the field we're ordering by
- if ($order_set)
- {
- if ($status_state == 'negative' && ! in_array(strtolower($query_row['status']) , $stati))
- {
- $new[$order_key.$post_fix] = $relating_data;
- }
- elseif (in_array(strtolower($query_row['status']) , $stati))
- {
- $new[$order_key.$post_fix] = $relating_data;
- }
- }
- ++$r;
- }
- }
-
- $sort_flags = SORT_REGULAR;
-
- // Check if the custom field to sort on is numeric, sort numericaly if it is
- if (strncmp($order, 'field_id_', 9) === 0)
- {
- $this->EE->load->library('api');
- $this->EE->api->instantiate('channel_fields');
- $field_settings = $this->EE->api_channel_fields->get_settings(substr($order, 9));
- if (isset($field_settings['field_content_type']) && in_array($field_settings['field_content_type'], array('numeric', 'integer', 'decimal')))
- {
- $sort_flags = SORT_NUMERIC;
- }
- }
-
- // Shuffle if random
- if ($random === TRUE)
- {
- shuffle($new);
- }
- else
- {
- // Sort keys by string comparison
- if (in_array($order, $str_sort))
- {
- uksort($new, 'strnatcasecmp');
- }
- // If it's in the base options and not a string?
- // Sort numeric
- elseif (in_array($order, $base_orders))
- {
- ksort($new, SORT_NUMERIC);
- }
- // Sort keys based on set sort flags
- else
- {
- ksort($new, $sort_flags);
- }
-
- // Reverse sorted array if we're sorting descending
- if ($sort != 'asc')
- {
- $new = array_reverse($new, TRUE);
- }
- }
-
- $output_data[$entry_id] = array_slice($new, $offset, $limit);
- if (count($output_data[$entry_id]) == 0)
- {
- $return_data = str_replace(LD."REV_REL[".$this->EE->TMPL->reverse_related_data[$template]['marker']."][".$entry_id."]REV_REL".RD, $this->EE->TMPL->reverse_related_data[$template]['no_rev_content'], $return_data);
- continue;
- }
- // Finally! We get to process our parents
- foreach($output_data[$entry_id] as $relating_data)
- {
- if ($i == 0)
- {
- $query = clone $relating_data['query'];
- }
- else
- {
- $query->result_array[] = $relating_data['query']->row_array();
- }
- $cats[$relating_data['query']->row('entry_id') ] = $relating_data['categories'];
- ++$i;
- }
- $query->num_rows = $i;
- $this->initialize();
- $this->EE->TMPL->var_single = $this->EE->TMPL->reverse_related_data[$template]['var_single'];
- $this->EE->TMPL->var_pair = $this->EE->TMPL->reverse_related_data[$template]['var_pair'];
- $this->EE->TMPL->var_cond = $this->EE->TMPL->reverse_related_data[$template]['var_cond'];
- $this->EE->TMPL->tagdata = $this->EE->TMPL->reverse_related_data[$template]['tagdata'];
- $this->query = $query;
- $this->categories = $cats;
- $this->parse_channel_entries();
- $return_data = str_replace( LD."REV_REL[".$this->EE->TMPL->reverse_related_data[$template]['marker']."][".$entry_id."]REV_REL".RD,
- $this->return_data,
- $return_data);
- }
- }
- $this->return_data = $return_data;
- }
- // ------------------------------------------------------------------------
- /**
- * Track Views
- */
- public function track_views()
- {
- if ($this->EE->config->item('enable_entry_view_tracking') == 'n')
- {
- return;
- }
-
- if ( ! $this->EE->TMPL->fetch_param('track_views') OR $this->hit_tracking_id === FALSE)
- {
- return;
- }
- if ($this->pagination->field_pagination == TRUE AND $this->pagination->offset > 0)
- {
- return;
- }
- foreach (explode('|', $this->EE->TMPL->fetch_param('track_views')) as $view)
- {
- if ( ! in_array(strtolower($view), array("one", "two", "three", "four")))
- {
- continue;
- }
- $sql = "UPDATE exp_channel_titles SET view_count_{$view} = (view_count_{$view} + 1) WHERE ";
- $sql .= (is_numeric($this->hit_tracking_id)) ? "entry_id = {$this->hit_tracking_id}" : "url_title = '".$this->EE->db->escape_str($this->hit_tracking_id)."'";
- $this->EE->db->query($sql);
- }
- }
- // ------------------------------------------------------------------------
- /**
- * Fetch custom channel field IDs
- */
- public function fetch_custom_channel_fields()
- {
- if (isset($this->EE->session->cache['channel']['custom_channel_fields']) && isset($this->EE->session->cache['channel']['date_fields'])
- && isset($this->EE->session->cache['channel']['relationship_fields']) && isset($this->EE->session->cache['channel']['pair_custom_fields']))
- {
- $this->cfields = $this->EE->session->cache['channel']['custom_channel_fields'];
- $this->dfields = $this->EE->session->cache['channel']['date_fields'];
- $this->rfields = $this->EE->session->cache['channel']['relationship_fields'];
- $this->pfields = $this->EE->session->cache['channel']['pair_custom_fields'];
- return;
- }
-
- $this->EE->load->library('api');
- $this->EE->api->instantiate('channel_fields');
- $fields = $this->EE->api_channel_fields->fetch_custom_channel_fields();
- $this->cfields = $fields['custom_channel_fields'];
- $this->dfields = $fields['date_fields'];
- $this->rfields = $fields['relationship_fields'];
- $this->pfields = $fields['pair_custom_fields'];
- $this->EE->session->cache['channel']['custom_channel_fields'] = $this->cfields;
- $this->EE->session->cache['channel']['date_fields'] = $this->dfields;
- $this->EE->session->cache['channel']['relationship_fields'] = $this->rfields;
- $this->EE->session->cache['channel']['pair_custom_fields'] = $this->pfields;
- }
- // ------------------------------------------------------------------------
- /**
- * Fetch custom member field IDs
- */
- public function fetch_custom_member_fields()
- {
- $this->EE->db->select('m_field_id, m_field_name, m_field_fmt');
- $query = $this->EE->db->get('member_fields');
- $fields_present = FALSE;
- $t1 = microtime(TRUE);
- foreach ($query->result_array() as $row)
- {
- if (strpos($this->EE->TMPL->tagdata, $row['m_field_name']) !== FALSE)
- {
- $fields_present = TRUE;
- }
- $this->mfields[$row['m_field_name']] = array($row['m_field_id'], $row['m_field_fmt']);
- }
- // If we can find no instance of the variable, then let's not process them at all.
- if ($fields_present === FALSE)
- {
- $this->mfields = array();
- }
- }
- // ------------------------------------------------------------------------
- /**
- * Fetch categories
- */
- public function fetch_categories()
- {
- if ($this->enable['category_fields'] === TRUE)
- {
- $query = $this->EE->db->query("SELECT field_id, field_name FROM exp_category_fields WHERE site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."')");
- if ($query->num_rows() > 0)
- {
- foreach ($query->result_array() as $row)
- {
- $this->catfields[] = array('field_name' => $row['field_name'], 'field_id' => $row['field_id']);
- }
- }
- $field_sqla = ", cg.field_html_formatting, fd.* ";
- $field_sqlb = " LEFT JOIN exp_category_field_data AS fd ON fd.cat_id = c.cat_id
- LEFT JOIN exp_category_groups AS cg ON cg.group_id = c.group_id";
- }
- else
- {
- $field_sqla = '';
- $field_sqlb = '';
- }
- $sql = "SELECT c.cat_name, c.cat_url_title, c.cat_id, c.cat_image, c.cat_description, c.parent_id,
- p.cat_id, p.entry_id, c.group_id {$field_sqla}
- FROM (exp_categories AS c, exp_category_posts AS p)
- {$field_sqlb}
- WHERE c.cat_id = p.cat_id
- AND p.entry_id IN (";
- $categories = array();
- foreach ($this->query->result_array() as $row)
- {
- $sql .= "'".$row['entry_id']."',";
- $categories[] = $row['entry_id'];
- }
- $sql = substr($sql, 0, -1).')';
- $sql .= " ORDER BY c.group_id, c.parent_id, c.cat_order";
- $query = $this->EE->db->query($sql);
- if ($query->num_rows() == 0)
- {
- return;
- }
- foreach ($categories as $val)
- {
- $this->temp_array = array();
- $this->cat_array = array();
- $parents = array();
- foreach ($query->result_array() as $row)
- {
- if ($val == $row['entry_id'])
- {
- $this->temp_array[$row['cat_id']] = array($row['cat_id'], $row['parent_id'], $row['cat_name'], $row['cat_image'], $row['cat_description'], $row['group_id'], $row['cat_url_title']);
- foreach ($row as $k => $v)
- {
- if (strpos($k, 'field') !== FALSE)
- {
- $this->temp_array[$row['cat_id']][$k] = $v;
- }
- }
- if ($row['parent_id'] > 0 && ! isset($this->temp_array[$row['parent_id']])) $parents[$row['parent_id']] = '';
- unset($parents[$row['cat_id']]);
- }
- }
- if (count($this->temp_array) == 0)
- {
- $temp = FALSE;
- }
- else
- {
- foreach($this->temp_array as $k => $v)
- {
- if (isset($parents[$v[1]])) $v[1] = 0;
- if (0 == $v[1])
- {
- $this->cat_array[] = $this->temp_array[$k];
- $this->process_subcategories($k);
- }
- }
- }
- $this->categories[$val] = $this->cat_array;
- }
- unset($this->temp_array);
- unset($this->cat_array);
- }
- // ------------------------------------------------------------------------
- /****************************************************************
- * Field Searching
- *
- * Generate the sql for the where clause to implement field
- * searching. Implements cross site field searching with a
- * sloppy search, IE if there are any fields with the same name
- * in any of the sites specified in the [ site="" ] parameter then
- * all of those fields will be searched.
- *
- *****************************************************************/
- protected function generate_field_search_sql($search_fields, $site_ids)
- {
- $sql = '';
- foreach ($search_fields as $field_name => $search_terms)
- {
- $fields_sql = '';
- $sites = ($site_ids ? $site_ids : array($this->EE->config->item('site_id')));
- foreach ($sites as $site_name => $site_id)
- {
- $terms = $search_terms;
- if ( ! isset($this->cfields[$site_id][$field_name]))
- {
- continue;
- }
-
- if (strncmp($terms, '=', 1) == 0)
- {
- /** ---------------------------------------
- /** Exact Match e.g.: search:body="=pickle"
- /** ---------------------------------------*/
- $terms = substr($terms, 1);
- // special handling for IS_EMPTY
- if (strpos($terms, 'IS_EMPTY') !== FALSE)
- {
- // Did this because I don't like repeatedly checking
- // the beginning of the string with strncmp for that
- // 'not', much prefer to do it once and then set a
- // boolean. But..
- $not = false;
- if (strncmp($terms, 'not ', 4) == 0)
- {
- $not = true;
- $terms = substr($terms, 4);
- }
- if (strpos($terms, '|') !== false)
- {
- $terms = str_replace('IS_EMPTY|', '', $terms);
- }
- else
- {
- $terms = str_replace('IS_EMPTY', '', $terms);
- }
-
- $add_search = '';
- $conj = '';
- if ( ! empty($terms))
- {
- // ...it makes this a little hacky. Gonna leave it for the moment,
- // but may come back to it.
- $add_search = $this->EE->functions->sql_andor_string(($not ? 'not ' . $terms : $terms), 'wd.field_id_'.$this->cfields[$site_id][$field_name]);
- // remove the first AND output by $this->EE->functions->sql_andor_string() so we can parenthesize this clause
- $add_search = '(wd.site_id=' . $site_id . ' AND ' . substr($add_search, 3) . ')';
-
- $conj = ($add_search != '' && !$not) ? 'OR' : 'AND';
- }
-
- if ($not)
- {
- $fields_sql .= $add_search.' '.$conj.' (wd.site_id=' . $site_id . ' AND wd.field_id_'.$this->cfields[$site_id][$field_name].' != "")';
- }
- else
- {
- $fields_sql .= $add_search.' '.$conj.' (wd.site_id=' . $site_id . ' AND wd.field_id_'.$this->cfields[$site_id][$field_name].' = "")';
- }
- }
- else
- {
- $fields_sql .= substr($this->EE->functions->sql_andor_string($terms, 'wd.field_id_'.$this->cfields[$site_id][$field_name]), 3).' ';
- }
- }
- else
- {
- /** ---------------------------------------
- /** "Contains" e.g.: search:body="pickle"
- /** ---------------------------------------*/
- $not = '';
- if (strncmp($terms, 'not ', 4) == 0)
- {
- $terms = substr($terms, 4);
- $not = 'NOT';
- }
- if (strpos($terms, '&&') !== FALSE)
- {
- $terms = explode('&&', $terms);
- $andor = $not == 'NOT' ? 'OR' : 'AND';
- }
- else
- {
- $terms = explode('|', $terms);
- $andor = $not == 'NOT' ? 'AND' : 'OR';
- }
- foreach ($terms as $term)
- {
- if ($term == 'IS_EMPTY')
- {
- $fields_sql .= ' (wd.site_id=' . $site_id
- . ' AND wd.field_id_' . $this->cfields[$site_id][$field_name] . ($not=='NOT' ? '!' : '') . '="") '
- . $andor;
- }
- elseif (strpos($term, '\W') !== FALSE) // full word only, no partial matches
- {
- // Note: MySQL's nutty POSIX regex word boundary is [[:>:]]
- $term = '([[:<:]]|^)'.preg_quote(str_replace('\W', '', $term)).'([[:>:]]|$)';
- $fields_sql .= ' (wd.site_id=' . $site_id
- . ' AND wd.field_id_' . $this->cfields[$site_id][$field_name] . ' ' . $not
- . ' REGEXP "' . $this->EE->db->escape_str($term).'") '
- . $andor;
- }
- else
- {
- $fields_sql .= ' (wd.site_id=' . $site_id
- . ' AND wd.field_id_' . $this->cfields[$site_id][$field_name]
- . $not . ' LIKE "%' . $this->EE->db->escape_like_str($term) . '%") '
- . $andor;
- }
- }
-
- // Remove the extra "and" or "or".
- $fields_sql = substr($fields_sql, 0, -strlen($andor));
- }
- $fields_sql .= ' OR ';
- } // foreach($sites as $site_id)
- if ( ! empty($fields_sql))
- {
- $sql .= 'AND (' . substr($fields_sql, 0, -3) . ')';
- }
- }
- return $sql;
- }
-
- /**
- * Build SQL query
- */
- public function build_sql_query($qstring = '')
- {
- $entry_id = '';
- $year = '';
- $month = '';
- $day = '';
- $qtitle = '';
- $cat_id = '';
- $corder = array();
- $offset = 0;
- $page_marker = FALSE;
- $dynamic = TRUE;
- $this->pagination->dynamic_sql = TRUE;
- /**------
- /** Is dynamic='off' set?
- /**------*/
- // If so, we'll override all dynamically set variables
- if ($this->EE->TMPL->fetch_param('dynamic') == 'no')
- {
- $dynamic = FALSE;
- }
- /**------
- /** Do we allow dynamic POST variables to set parameters?
- /**------*/
- if ($this->EE->TMPL->fetch_param('dynamic_parameters') !== FALSE AND isset($_POST) AND count($_POST) > 0)
- {
- foreach (explode('|', $this->EE->TMPL->fetch_param('dynamic_parameters')) as $var)
- {
- if (isset($_POST[$var]) AND in_array($var, array('channel', 'entry_id', 'category', 'orderby', 'sort', 'sticky', 'show_future_entries', 'show_expired', 'entry_id_from', 'entry_id_to', 'not_entry_id', 'start_on', 'stop_before', 'year', 'month', 'day', 'display_by', 'limit', 'username', 'status', 'group_id', 'cat_limit', 'month_limit', 'offset', 'author_id')))
- {
- $this->EE->TMPL->tagparams[$var] = $_POST[$var];
- }
- if (isset($_POST[$var]) && strncmp($var, 'search:', 7) == 0)
- {
- $this->EE->TMPL->search_fields[substr($var, 7)] = $_POST[$var];
- }
- }
- }
- /**------
- /** Parse the URL query string
- /**------*/
- $this->uristr = $this->EE->uri->uri_string;
- if ($qstring == '')
- {
- $qstring = $this->query_string;
- }
-
- $this->pagination->basepath = $this->EE->functions->create_url($this->uristr);
- if ($qstring == '')
- {
- if ($this->EE->TMPL->fetch_param('require_entry') == 'yes')
- {
- return '';
- }
- }
- else
- {
- /** --------------------------------------
- /** Do we have a pure ID number?
- /** --------------------------------------*/
- if ($dynamic && is_numeric($qstring))
- {
- $entry_id = $qstring;
- }
- else
- {
- // Load the string helper
- $this->EE->load->helper('string');
- /** --------------------------------------
- /** Parse day
- /** --------------------------------------*/
- if ($dynamic && preg_match("#(^|\/)(\d{4}/\d{2}/\d{2})#", $qstring, $match))
- {
- $ex = explode('/', $match[2]);
- $year = $ex[0];
- $month = $ex[1];
- $day = $ex[2];
- $qstring = trim_slashes(str_replace($match[0], '', $qstring));
- }
- /** --------------------------------------
- /** Parse /year/month/
- /** --------------------------------------*/
- // added (^|\/) to make sure this doesn't trigger with url titles like big_party_2006
- if ($dynamic && preg_match("#(^|\/)(\d{4}/\d{2})(\/|$)#", $qstring, $match))
- {
- $ex = explode('/', $match[2]);
- $year = $ex[0];
- $month = $ex[1];
- $qstring = trim_slashes(str_replace($match[2], '', $qstring));
- }
- /** --------------------------------------
- /** Parse ID indicator
- /** --------------------------------------*/
- if ($dynamic && preg_match("#^(\d+)(.*)#", $qstring, $match))
- {
- $seg = ( ! isset($match[2])) ? '' : $match[2];
- if (substr($seg, 0, 1) == "/" OR $seg == '')
- {
- $entry_id = $match[1];
- $qstring = trim_slashes(preg_replace("#^".$match[1]."#", '', $qstring));
- }
- }
- /** --------------------------------------
- /** Parse page number
- /** --------------------------------------*/
- if (($dynamic OR $this->EE->TMPL->fetch_param('paginate')) && preg_match("#^P(\d+)|/P(\d+)#", $qstring, $match))
- {
- $this->pagination->offset = (isset($match[2])) ? $match[2] : $match[1];
- $this->pagination->basepath = $this->EE->functions->remove_double_slashes(str_replace($match[0], '', $this->pagination->basepath));
- $this->uristr = $this->EE->functions->remove_double_slashes(str_replace($match[0], '', $this->uristr));
- $qstring = trim_slashes(str_replace($match[0], '', $qstring));
- $page_marker = TRUE;
- }
- /** --------------------------------------
- /** Parse category indicator
- /** --------------------------------------*/
- // Text version of the category
- if ($qstring != '' AND $this->reserved_cat_segment != '' AND in_array($this->reserved_cat_segment, explode("/", $qstring)) AND $dynamic AND $this->EE->TMPL->fetch_param('channel'))
- {
- $qstring = preg_replace("/(.*?)\/".preg_quote($this->reserved_cat_segment)."\//i", '', '/'.$qstring);
- $sql = "SELECT DISTINCT cat_group FROM exp_channels WHERE site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."') AND ";
- $xsql = $this->EE->functions->sql_andor_string($this->EE->TMPL->fetch_param('channel'), 'channel_name');
- if (substr($xsql, 0, 3) == 'AND') $xsql = substr($xsql, 3);
- $sql .= ' '.$xsql;
- $query = $this->EE->db->query($sql);
- if ($query->num_rows() > 0)
- {
- $valid = 'y';
- $valid_cats = explode('|', $query->row('cat_group') );
- foreach($query->result_array() as $row)
- {
- if ($this->EE->TMPL->fetch_param('relaxed_categories') == 'yes')
- {
- $valid_cats = array_merge($valid_cats, explode('|', $row['cat_group']));
- }
- else
- {
- $valid_cats = array_intersect($valid_cats, explode('|', $row['cat_group']));
- }
- $valid_cats = array_unique($valid_cats);
- if (count($valid_cats) == 0)
- {
- $valid = 'n';
- break;
- }
- }
- }
- else
- {
- $valid = 'n';
- }
- if ($valid == 'y')
- {
- // the category URL title should be the first segment left at this point in $qstring,
- // but because prior to this feature being added, category names were used in URLs,
- // and '/' is a valid character for category names. If they have not updated their
- // category url titles since updating to 1.6, their category URL title could still
- // contain a '/'. So we'll try to get the category the correct way first, and if
- // it fails, we'll try the whole $qstring
- // do this as separate commands to work around a PHP 5.0.x bug
- $arr = explode('/', $qstring);
- $cut_qstring = array_shift($arr);
- unset($arr);
- $result = $this->EE->db->query("SELECT cat_id FROM exp_categories
- WHERE cat_url_title='".$this->EE->db->escape_str($cut_qstring)."'
- AND group_id IN ('".implode("','", $valid_cats)."')");
- if ($result->num_rows() == 1)
- {
- $qstring = str_replace($cut_qstring, 'C'.$result->row('cat_id') , $qstring);
- $cat_id = $result->row('cat_id');
- }
- else
- {
- // give it one more try using the whole $qstring
- $result = $this->EE->db->query("SELECT cat_id FROM exp_categories
- WHERE cat_url_title='".$this->EE->db->escape_str($qstring)."'
- AND group_id IN ('".implode("','", $valid_cats)."')");
- if ($result->num_rows() == 1)
- {
- $qstring = 'C'.$result->row('cat_id') ;
- $cat_id = $result->row('cat_id');
- }
- }
- }
- }
-
- // If we got here, category may be numeric
- if (empty($cat_id))
- {
- $this->EE->load->helper('segment');
- $cat_id = parse_category($this->query_string);
- }
-
- // If we were able to get a numeric category ID
- if (is_numeric($cat_id) AND $cat_id !== FALSE)
- {
- $this->cat_request = TRUE;
- }
- // parse_category did not return a numberic ID, blow away $cat_id
- else
- {
- $cat_id = FALSE;
- }
-
- /** --------------------------------------
- /** Remove "N"
- /** --------------------------------------*/
- // The recent comments feature uses "N" as the URL indicator
- // It needs to be removed if presenst
- if (preg_match("#^N(\d+)|/N(\d+)#", $qstring, $match))
- {
- $this->uristr = $this->EE->functions->remove_double_slashes(str_replace($match[0], '', $this->uristr));
- $qstring = trim_slashes(str_replace($match[0], '', $qstring));
- }
- /** --------------------------------------
- /** Parse URL title
- /** --------------------------------------*/
- if (($cat_id == '' AND $year == '') OR $this->EE->TMPL->fetch_param('require_entry') == 'yes')
- {
- if (strpos($qstring, '/') !== FALSE)
- {
- $xe = explode('/', $qstring);
- $qstring = current($xe);
- }
- if ($dynamic == TRUE)
- {
- $sql = "SELECT count(*) AS count
- FROM exp_channel_titles, exp_channels
- WHERE exp_channel_titles.channel_id = exp_channels.channel_id";
- if ($entry_id != '')
- {
- $sql .= " AND exp_channel_titles.entry_id = '".$this->EE->db->escape_str($entry_id)."'";
- }
- else
- {
- $sql .= " AND exp_channel_titles.url_title = '".$this->EE->db->escape_str($qstring)."'";
- }
- $sql .= " AND exp_channels.site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."') ";
- $query = $this->EE->db->query($sql);
- if ($query->row('count') == 0)
- {
- if ($this->EE->TMPL->fetch_param('require_entry') == 'yes')
- {
- return '';
- }
- $qtitle = '';
- }
- else
- {
- $qtitle = $qstring;
- }
- }
- }
- }
- }
- /**------
- /** Entry ID number
- /**------*/
- // If the "entry ID" was hard-coded, use it instead of
- // using the dynamically set one above
- if ($this->EE->TMPL->fetch_param('entry_id'))
- {
- $entry_id = $this->EE->TMPL->fetch_param('entry_id');
- }
- /**------
- /** Only Entries with Pages
- /**------*/
- if ($this->EE->TMPL->fetch_param('show_pages') !== FALSE && in_array($this->EE->TMPL->fetch_param('show_pages'), array('only', 'no')) && ($pages = $this->EE->config->item('site_pages')) !== FALSE)
- {
- $pages_uris = array();
-
- foreach ($pages as $data)
- {
- $pages_uris += $data['uris'];
- }
-
- if (count($pages_uris) > 0 OR $this->EE->TMPL->fetch_param('show_pages') == 'only')
- {
- // consider entry_id
- if ($this->EE->TMPL->fetch_param('entry_id') !== FALSE)
- {
- $not = FALSE;
- if (strncmp($entry_id, 'not', 3) == 0)
- {
- $not = TRUE;
- $entry_id = trim(substr($entry_id, 3));
- }
- $ids = explode('|', $entry_id);
- if ($this->EE->TMPL->fetch_param('show_pages') == 'only')
- {
- if ($not === TRUE)
- {
- $entry_id = implode('|', array_diff(array_flip($pages_uris), explode('|', $ids)));
- }
- else
- {
- $entry_id = implode('|',array_diff($ids, array_diff($ids, array_flip($pages_uris))));
- }
- }
- else
- {
- if ($not === TRUE)
- {
- $entry_id = "not {$entry_id}|".implode('|', array_flip($pages_uris));
- }
- else
- {
- $entry_id = implode('|',array_diff($ids, array_flip($pages_uris)));
- }
- }
- }
- else
- {
- $entry_id = (($this->EE->TMPL->fetch_param('show_pages') == 'no') ? 'not ' : '').implode('|', array_flip($pages_uris));
- }
-
- // No pages and show_pages only
- if ($entry_id == '' && $this->EE->TMPL->fetch_param('show_pages') == 'only')
- {
- $this->sql = '';
- return;
- }
- }
- }
- /**------
- /** Assing the order variables
- /**------*/
- $order = $this->EE->TMPL->fetch_param('orderby');
- $sort = $this->EE->TMPL->fetch_param('sort');
- $sticky = $this->EE->TMPL->fetch_param('sticky');
- /** -------------------------------------
- /** Multiple Orders and Sorts...
- /** -------------------------------------*/
- if ($order !== FALSE && stristr($order, '|'))
- {
- $order_array = explode('|', $order);
- if ($order_array[0] == 'random')
- {
- $order_array = array('random');
- }
- }
- else
- {
- $order_array = array($order);
- }
- if ($sort !== FALSE && stristr($sort, '|'))
- {
- $sort_array = explode('|', $sort);
- }
- else
- {
- $sort_array = array($sort);
- }
- /** -------------------------------------
- /** Validate Results for Later Processing
- /** -------------------------------------*/
- $base_orders = array('random', 'entry_id', 'date', 'entry_date', 'title', 'url_title', 'edit_date', 'comment_total', 'username', 'screen_name', 'most_recent_comment', 'expiration_date',
- 'view_count_one', 'view_count_two', 'view_count_three', 'view_count_four');
- foreach($order_array as $key => $order)
- {
- if ( ! in_array($order, $base_orders))
- {
- if (FALSE !== $order)
- {
- $set = 'n';
- /** -------------------------------------
- /** Site Namespace is Being Used, Parse Out
- /** -------------------------------------*/
- if (strpos($order, ':') !== FALSE)
- {
- $order_parts = explode(':', $order, 2);
- if (isset($this->EE->TMPL->site_ids[$order_parts[0]]) && isset($this->cfields[$this->EE->TMPL->site_ids[$order_parts[0]]][$order_parts[1]]))
- {
- $corder[$key] = $this->cfields[$this->EE->TMPL->site_ids[$order_parts[0]]][$order_parts[1]];
- $order_array[$key] = 'custom_field';
- $set = 'y';
- }
- }
- /** -------------------------------------
- /** Find the Custom Field, Cycle Through All Sites for Tag
- /** - If multiple sites have the same short_name for a field, we do a CONCAT ORDERBY in query
- /** -------------------------------------*/
- if ($set == 'n')
- {
- foreach($this->cfields as $site_id => $cfields)
- {
- // Only those sites specified
- if ( ! in_array($site_id, $this->EE->TMPL->site_ids))
- {
- continue;
- }
- if (isset($cfields[$order]))
- {
- if ($set == 'y')
- {
- $corder[$key] .= '|'.$cfields[$order];
- }
- else
- {
- $corder[$key] = $cfields[$order];
- $order_array[$key] = 'custom_field';
- $set = 'y';
- }
- }
- }
- }
- if ($set == 'n')
- {
- $order_array[$key] = FALSE;
- }
- }
- }
- if ( ! isset($sort_array[$key]))
- {
- $sort_array[$key] = 'desc';
- }
- }
- foreach($sort_array as $key => $sort)
- {
- if ($sort == FALSE OR ($sort != 'asc' AND $sort != 'desc'))
- {
- $sort_array[$key] = "desc";
- }
- }
- // fixed entry id ordering
- if (($fixed_order = $this->EE->TMPL->fetch_param('fixed_order')) === FALSE OR preg_match('/[^0-9\|]/', $fixed_order))
- {
- $fixed_order = FALSE;
- }
- else
- {
- // MySQL will not order the entries correctly unless the results are constrained
- // to matching rows only, so we force the entry_id as well
- $entry_id = $fixed_order;
- $fixed_order = preg_split('/\|/', $fixed_order, -1, PREG_SPLIT_NO_EMPTY);
- // some peeps might want to be able to 'flip' it
- // the default sort order is 'desc' but in this context 'desc' has a stronger "reversing"
- // connotation, so we look not at the sort array, but the tag parameter itself, to see the user's intent
- if ($sort == 'desc')
- {
- $fixed_order = array_reverse($fixed_order);
- }
- }
- /**------
- /** Build the master SQL query
- /**------*/
- $sql_a = "SELECT ";
- $sql_b = ($this->EE->TMPL->fetch_param('category') OR $this->EE->TMPL->fetch_param('category_group') OR $cat_id != '' OR $order_array[0] == 'random') ? "DISTINCT(t.entry_id) " : "t.entry_id ";
- if ($this->pagination->field_pagination == TRUE)
- {
- $sql_b .= ",wd.* ";
- }
- $sql_c = "COUNT(t.entry_id) AS count ";
- $sql = "FROM exp_channel_titles AS t
- LEFT JOIN exp_channels ON t.channel_id = exp_channels.channel_id ";
- if ($this->pagination->field_pagination == TRUE)
- {
- $sql .= "LEFT JOIN exp_channel_data AS wd ON t.entry_id = wd.entry_id ";
- }
- elseif (in_array('custom_field', $order_array))
- {
- $sql .= "LEFT JOIN exp_channel_data AS wd ON t.entry_id = wd.entry_id ";
- }
- elseif ( ! empty($this->EE->TMPL->search_fields))
- {
- $sql .= "LEFT JOIN exp_channel_data AS wd ON wd.entry_id = t.entry_id ";
- }
- $sql .= "LEFT JOIN exp_members AS m ON m.member_id = t.author_id ";
- if ($this->EE->TMPL->fetch_param('category') OR $this->EE->TMPL->fetch_param('category_group') OR ($cat_id != '' && $dynamic == TRUE))
- {
- /* --------------------------------
- /* We use LEFT JOIN when there is a 'not' so that we get
- /* entries that are not assigned to a category.
- /* --------------------------------*/
- if ((substr($this->EE->TMPL->fetch_param('category_group'), 0, 3) == 'not' OR substr($this->EE->TMPL->fetch_param('category'), 0, 3) == 'not') && $this->EE->TMPL->fetch_param('uncategorized_entries') !== 'no')
- {
- $sql .= "LEFT JOIN exp_category_posts ON t.entry_id = exp_category_posts.entry_id
- LEFT JOIN exp_categories ON exp_category_posts.cat_id = exp_categories.cat_id ";
- }
- else
- {
- $sql .= "INNER JOIN exp_category_posts ON t.entry_id = exp_category_posts.entry_id
- INNER JOIN exp_categories ON exp_category_pos…
Large files files are truncated, but you can click here to view the full file