PageRenderTime 66ms CodeModel.GetById 23ms RepoModel.GetById 1ms app.codeStats 1ms

/html/AppCode/expressionengine/modules/channel/mod.channel.php

https://github.com/w3bg/www.hsifin.com
PHP | 7845 lines | 5641 code | 1342 blank | 862 comment | 1212 complexity | 3d2628a3e95f4072eaddcf440f021598 MD5 | raw file
Possible License(s): AGPL-3.0

Large files files are truncated, but you can click here to view the full file

  1. <?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
  2. /**
  3. * ExpressionEngine - by EllisLab
  4. *
  5. * @package ExpressionEngine
  6. * @author ExpressionEngine Dev Team
  7. * @copyright Copyright (c) 2003 - 2010, EllisLab, Inc.
  8. * @license http://expressionengine.com/user_guide/license.html
  9. * @link http://expressionengine.com
  10. * @since Version 2.0
  11. * @filesource
  12. */
  13. // --------------------------------------------------------------------
  14. /**
  15. * ExpressionEngine Channel Module
  16. *
  17. * @package ExpressionEngine
  18. * @subpackage Modules
  19. * @category Modules
  20. * @author ExpressionEngine Dev Team
  21. * @link http://expressionengine.com
  22. */
  23. class Channel {
  24. var $limit = '100'; // Default maximum query results if not specified.
  25. // These variable are all set dynamically
  26. var $query;
  27. var $TYPE;
  28. var $entry_id = '';
  29. var $uri = '';
  30. var $uristr = '';
  31. var $return_data = ''; // Final data
  32. var $basepath = '';
  33. var $hit_tracking_id = FALSE;
  34. var $sql = FALSE;
  35. var $cfields = array();
  36. var $dfields = array();
  37. var $rfields = array();
  38. var $mfields = array();
  39. var $pfields = array();
  40. var $categories = array();
  41. var $catfields = array();
  42. var $channel_name = array();
  43. var $channels_array = array();
  44. var $related_entries = array();
  45. var $reverse_related_entries= array();
  46. var $reserved_cat_segment = '';
  47. var $use_category_names = FALSE;
  48. var $dynamic_sql = FALSE;
  49. var $cat_request = FALSE;
  50. var $enable = array(); // modified by various tags with disable= parameter
  51. var $absolute_results = NULL; // absolute total results returned by the tag, useful when paginating
  52. // These are used with the nested category trees
  53. var $category_list = array();
  54. var $cat_full_array = array();
  55. var $cat_array = array();
  56. var $temp_array = array();
  57. var $category_count = 0;
  58. // Pagination variables
  59. var $paginate = FALSE;
  60. var $field_pagination = FALSE;
  61. var $paginate_data = '';
  62. var $pagination_links = '';
  63. var $page_next = '';
  64. var $page_previous = '';
  65. var $current_page = 1;
  66. var $total_pages = 1;
  67. var $multi_fields = array();
  68. var $display_by = '';
  69. var $total_rows = 0;
  70. var $pager_sql = '';
  71. var $p_limit = '';
  72. var $p_page = '';
  73. // SQL Caching
  74. var $sql_cache_dir = 'sql_cache/';
  75. // Misc. - Class variable usable by extensions
  76. var $misc = FALSE;
  77. /**
  78. * Constructor
  79. */
  80. function Channel()
  81. {
  82. // Make a local reference to the ExpressionEngine super object
  83. $this->EE =& get_instance();
  84. $this->p_limit = $this->limit;
  85. $this->query_string = ($this->EE->uri->page_query_string != '') ? $this->EE->uri->page_query_string : $this->EE->uri->query_string;
  86. if ($this->EE->config->item("use_category_name") == 'y' && $this->EE->config->item("reserved_category_word") != '')
  87. {
  88. $this->use_category_names = $this->EE->config->item("use_category_name");
  89. $this->reserved_cat_segment = $this->EE->config->item("reserved_category_word");
  90. }
  91. // a number tags utilize the disable= parameter, set it here
  92. if (isset($this->EE->TMPL) && is_object($this->EE->TMPL))
  93. {
  94. $this->_fetch_disable_param();
  95. }
  96. }
  97. // ------------------------------------------------------------------------
  98. /**
  99. * Initialize values
  100. */
  101. function initialize()
  102. {
  103. $this->sql = '';
  104. $this->return_data = '';
  105. }
  106. // ------------------------------------------------------------------------
  107. /**
  108. * Fetch Cache
  109. */
  110. function fetch_cache($identifier = '')
  111. {
  112. $tag = ($identifier == '') ? $this->EE->TMPL->tagproper : $this->EE->TMPL->tagproper.$identifier;
  113. if ($this->EE->TMPL->fetch_param('dynamic_parameters') !== FALSE && isset($_POST) && count($_POST) > 0)
  114. {
  115. foreach (explode('|', $this->EE->TMPL->fetch_param('dynamic_parameters')) as $var)
  116. {
  117. 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')))
  118. {
  119. $tag .= $var.'="'.$_POST[$var].'"';
  120. }
  121. if (isset($_POST[$var]) && strncmp($var, 'search:', 7) == 0)
  122. {
  123. $tag .= $var.'="'.substr($_POST[$var], 7).'"';
  124. }
  125. }
  126. }
  127. $cache_file = APPPATH.'cache/'.$this->sql_cache_dir.md5($tag.$this->uri);
  128. if ( ! $fp = @fopen($cache_file, FOPEN_READ))
  129. {
  130. return FALSE;
  131. }
  132. flock($fp, LOCK_SH);
  133. $sql = @fread($fp, filesize($cache_file));
  134. flock($fp, LOCK_UN);
  135. fclose($fp);
  136. return $sql;
  137. }
  138. // ------------------------------------------------------------------------
  139. /**
  140. * Save Cache
  141. */
  142. function save_cache($sql, $identifier = '')
  143. {
  144. $tag = ($identifier == '') ? $this->EE->TMPL->tagproper : $this->EE->TMPL->tagproper.$identifier;
  145. $cache_dir = APPPATH.'cache/'.$this->sql_cache_dir;
  146. $cache_file = $cache_dir.md5($tag.$this->uri);
  147. if ( ! @is_dir($cache_dir))
  148. {
  149. if ( ! @mkdir($cache_dir, DIR_WRITE_MODE))
  150. {
  151. return FALSE;
  152. }
  153. if ($fp = @fopen($cache_dir.'/index.html', FOPEN_WRITE_CREATE_DESTRUCTIVE))
  154. {
  155. fclose($fp);
  156. }
  157. @chmod($cache_dir, DIR_WRITE_MODE);
  158. }
  159. if ( ! $fp = @fopen($cache_file, FOPEN_WRITE_CREATE_DESTRUCTIVE))
  160. {
  161. return FALSE;
  162. }
  163. flock($fp, LOCK_EX);
  164. fwrite($fp, $sql);
  165. flock($fp, LOCK_UN);
  166. fclose($fp);
  167. @chmod($cache_file, FILE_WRITE_MODE);
  168. return TRUE;
  169. }
  170. // ------------------------------------------------------------------------
  171. /**
  172. * Channel entries
  173. */
  174. function entries()
  175. {
  176. // If the "related_categories" mode is enabled
  177. // we'll call the "related_categories" function
  178. // and bail out.
  179. if ($this->EE->TMPL->fetch_param('related_categories_mode') == 'yes')
  180. {
  181. return $this->related_entries();
  182. }
  183. // Onward...
  184. $this->initialize();
  185. $this->uri = ($this->query_string != '') ? $this->query_string : 'index.php';
  186. if ($this->enable['custom_fields'] == TRUE)
  187. {
  188. $this->fetch_custom_channel_fields();
  189. }
  190. if ($this->enable['member_data'] == TRUE)
  191. {
  192. $this->fetch_custom_member_fields();
  193. }
  194. if ($this->enable['pagination'] == TRUE)
  195. {
  196. $this->fetch_pagination_data();
  197. }
  198. $save_cache = FALSE;
  199. if ($this->EE->config->item('enable_sql_caching') == 'y')
  200. {
  201. if (FALSE == ($this->sql = $this->fetch_cache()))
  202. {
  203. $save_cache = TRUE;
  204. }
  205. else
  206. {
  207. if ($this->EE->TMPL->fetch_param('dynamic') != 'no')
  208. {
  209. if (preg_match("#(^|\/)C(\d+)#", $this->query_string, $match) OR in_array($this->reserved_cat_segment, explode("/", $this->query_string)))
  210. {
  211. $this->cat_request = TRUE;
  212. }
  213. }
  214. }
  215. if (FALSE !== ($cache = $this->fetch_cache('pagination_count')))
  216. {
  217. if (FALSE !== ($this->fetch_cache('field_pagination')))
  218. {
  219. if (FALSE !== ($pg_query = $this->fetch_cache('pagination_query')))
  220. {
  221. $this->paginate = TRUE;
  222. $this->field_pagination = TRUE;
  223. $this->create_pagination(trim($cache), $this->EE->db->query(trim($pg_query)));
  224. }
  225. }
  226. else
  227. {
  228. $this->create_pagination(trim($cache));
  229. }
  230. }
  231. }
  232. if ($this->sql == '')
  233. {
  234. $this->build_sql_query();
  235. }
  236. if ($this->sql == '')
  237. {
  238. return $this->EE->TMPL->no_results();
  239. }
  240. if ($save_cache == TRUE)
  241. {
  242. $this->save_cache($this->sql);
  243. }
  244. $this->query = $this->EE->db->query($this->sql);
  245. if ($this->query->num_rows() == 0)
  246. {
  247. return $this->EE->TMPL->no_results();
  248. }
  249. // -------------------------------------
  250. // "Relaxed" View Tracking
  251. //
  252. // Some people have tags that are used to mimic a single-entry
  253. // page without it being dynamic. This allows Entry View Tracking
  254. // to work for ANY combination that results in only one entry
  255. // being returned by the tag, including channel query caching.
  256. //
  257. // Hidden Configuration Variable
  258. // - relaxed_track_views => Allow view tracking on non-dynamic
  259. // single entries (y/n)
  260. // -------------------------------------
  261. if ($this->EE->config->item('relaxed_track_views') === 'y' && $this->query->num_rows() == 1)
  262. {
  263. $this->hit_tracking_id = $this->query->row('entry_id') ;
  264. }
  265. $this->track_views();
  266. $this->EE->load->library('typography');
  267. $this->EE->typography->initialize();
  268. $this->EE->typography->convert_curly = FALSE;
  269. if ($this->enable['categories'] == TRUE)
  270. {
  271. $this->fetch_categories();
  272. }
  273. $this->parse_channel_entries();
  274. if ($this->enable['pagination'] == TRUE)
  275. {
  276. $this->add_pagination_data();
  277. }
  278. // Does the tag contain "related entries" that we need to parse out?
  279. if (count($this->EE->TMPL->related_data) > 0 && count($this->related_entries) > 0)
  280. {
  281. $this->parse_related_entries();
  282. }
  283. if (count($this->EE->TMPL->reverse_related_data) > 0 && count($this->reverse_related_entries) > 0)
  284. {
  285. $this->parse_reverse_related_entries();
  286. }
  287. return $this->return_data;
  288. }
  289. // ------------------------------------------------------------------------
  290. /**
  291. * Process related entries
  292. */
  293. function parse_related_entries()
  294. {
  295. $sql = "SELECT rel_id, rel_parent_id, rel_child_id, rel_type, rel_data
  296. FROM exp_relationships
  297. WHERE rel_id IN (";
  298. $templates = array();
  299. foreach ($this->related_entries as $val)
  300. {
  301. $x = explode('_', $val);
  302. $sql .= "'".$x[0]."',";
  303. $templates[] = array($x[0], $x[1], $this->EE->TMPL->related_data[$x[1]]);
  304. }
  305. $sql = substr($sql, 0, -1).')';
  306. $query = $this->EE->db->query($sql);
  307. if ($query->num_rows() == 0)
  308. return;
  309. // --------------------------------
  310. // Without this the Related Entries were inheriting the parameters of
  311. // the enclosing Channel Entries tag. Sometime in the future we will
  312. // likely allow Related Entries to have their own parameters
  313. // --------------------------------
  314. $return_data = $this->return_data;
  315. foreach ($templates as $temp)
  316. {
  317. foreach ($query->result_array() as $row)
  318. {
  319. if ($row['rel_id'] != $temp[0])
  320. continue;
  321. // --------------------------------------
  322. // If the data is emptied (cache cleared), then we
  323. // rebuild it with fresh data so processing can continue.
  324. // --------------------------------------
  325. if (trim($row['rel_data']) == '')
  326. {
  327. $rewrite = array(
  328. 'type' => $row['rel_type'],
  329. 'parent_id' => $row['rel_parent_id'],
  330. 'child_id' => $row['rel_child_id'],
  331. 'related_id' => $row['rel_id']
  332. );
  333. $this->EE->functions->compile_relationship($rewrite, FALSE);
  334. $results = $this->EE->db->query("SELECT rel_data FROM exp_relationships WHERE rel_id = '".$row['rel_id']."'");
  335. $row['rel_data'] = $results->row('rel_data') ;
  336. }
  337. // Begin Processing
  338. $this->initialize();
  339. if ($reldata = @unserialize($row['rel_data']))
  340. {
  341. $this->EE->TMPL->var_single = $temp[2]['var_single'];
  342. $this->EE->TMPL->var_pair = $temp[2]['var_pair'];
  343. $this->EE->TMPL->var_cond = $temp[2]['var_cond'];
  344. $this->EE->TMPL->tagdata = $temp[2]['tagdata'];
  345. if ($row['rel_type'] == 'channel')
  346. {
  347. // Bug fix for when categories were not being inserted
  348. // correctly for related channel entries. Bummer.
  349. if (count($reldata['categories'] == 0) && ! isset($reldata['cats_fixed']))
  350. {
  351. $fixdata = array(
  352. 'type' => $row['rel_type'],
  353. 'parent_id' => $row['rel_parent_id'],
  354. 'child_id' => $row['rel_child_id'],
  355. 'related_id' => $row['rel_id']
  356. );
  357. $this->EE->functions->compile_relationship($fixdata, FALSE);
  358. $reldata['categories'] = $this->EE->functions->cat_array;
  359. $reldata['category_fields'] = $this->EE->functions->catfields;
  360. }
  361. $this->query = $reldata['query'];
  362. $this->categories = array($this->query->row('entry_id') => $reldata['categories']);
  363. if (isset($reldata['category_fields']))
  364. {
  365. $this->catfields = array($this->query->row('entry_id') => $reldata['category_fields']);
  366. }
  367. $this->parse_channel_entries();
  368. $marker = LD."REL[".$row['rel_id']."][".$temp[2]['field_name']."]".$temp[1]."REL".RD;
  369. $return_data = str_replace($marker, $this->return_data, $return_data);
  370. }
  371. }
  372. }
  373. }
  374. $this->return_data = $return_data;
  375. }
  376. // ------------------------------------------------------------------------
  377. /**
  378. * Process reverse related entries
  379. */
  380. function parse_reverse_related_entries()
  381. {
  382. $sql = "SELECT rel_id, rel_parent_id, rel_child_id, rel_type, reverse_rel_data
  383. FROM exp_relationships
  384. WHERE rel_child_id IN ('".implode("','", array_keys($this->reverse_related_entries))."')
  385. AND rel_type = 'channel'";
  386. $query = $this->EE->db->query($sql);
  387. if ($query->num_rows() == 0)
  388. {
  389. // remove Reverse Related tags for these entries
  390. foreach ($this->reverse_related_entries as $entry_id => $templates)
  391. {
  392. foreach($templates as $tkey => $template)
  393. {
  394. $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);
  395. }
  396. }
  397. return;
  398. }
  399. // Data Processing Time
  400. $entry_data = array();
  401. for ($i = 0, $total = count($query->result_array()); $i < $total; $i++)
  402. {
  403. $row = array_shift($query->result_array);
  404. // If the data is emptied (cache cleared or first process), then we
  405. // rebuild it with fresh data so processing can continue.
  406. if (trim($row['reverse_rel_data']) == '')
  407. {
  408. $rewrite = array(
  409. 'type' => $row['rel_type'],
  410. 'parent_id' => $row['rel_parent_id'],
  411. 'child_id' => $row['rel_child_id'],
  412. 'related_id' => $row['rel_id']
  413. );
  414. $this->EE->functions->compile_relationship($rewrite, FALSE, TRUE);
  415. $results = $this->EE->db->query("SELECT reverse_rel_data FROM exp_relationships WHERE rel_parent_id = '".$row['rel_parent_id']."'");
  416. $row['reverse_rel_data'] = $results->row('reverse_rel_data') ;
  417. }
  418. // Unserialize the entries data, please
  419. if ($revreldata = @unserialize($row['reverse_rel_data']))
  420. {
  421. $entry_data[$row['rel_child_id']][$row['rel_parent_id']] = $revreldata;
  422. }
  423. }
  424. // Without this the Reverse Related Entries were inheriting the parameters of
  425. // the enclosing Channel Entries tag, which is not appropriate.
  426. $return_data = $this->return_data;
  427. foreach ($this->reverse_related_entries as $entry_id => $templates)
  428. {
  429. // No Entries? Remove Reverse Related Tags and Continue to Next Entry
  430. if ( ! isset($entry_data[$entry_id]))
  431. {
  432. foreach($templates as $tkey => $template)
  433. {
  434. $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);
  435. }
  436. continue;
  437. }
  438. // Process Our Reverse Related Templates
  439. foreach($templates as $tkey => $template)
  440. {
  441. $i = 0;
  442. $cats = array();
  443. $params = $this->EE->TMPL->reverse_related_data[$template]['params'];
  444. if ( ! is_array($params))
  445. {
  446. $params = array('status' => 'open');
  447. }
  448. elseif ( ! isset($params['status']))
  449. {
  450. $params['status'] = 'open';
  451. }
  452. else
  453. {
  454. $params['status'] = trim($params['status'], " |\t\n\r");
  455. }
  456. // Entries have to be ordered, sorted and other stuff
  457. $new = array();
  458. $order = ( ! isset($params['orderby'])) ? 'date' : $params['orderby'];
  459. $offset = ( ! isset($params['offset']) OR ! is_numeric($params['offset'])) ? 0 : $params['offset'];
  460. $limit = ( ! isset($params['limit']) OR ! is_numeric($params['limit'])) ? 100 : $params['limit'];
  461. $sort = ( ! isset($params['sort'])) ? 'asc' : $params['sort'];
  462. $random = ($order == 'random') ? TRUE : FALSE;
  463. $base_orders = array('random', 'date', 'title', 'url_title', 'edit_date', 'comment_total', 'username', 'screen_name', 'most_recent_comment', 'expiration_date', 'entry_id',
  464. 'view_count_one', 'view_count_two', 'view_count_three', 'view_count_four');
  465. $str_sort = array('title', 'url_title', 'username', 'screen_name');
  466. if ( ! in_array($order, $base_orders))
  467. {
  468. $set = 'n';
  469. foreach($this->cfields as $site_id => $cfields)
  470. {
  471. if ( isset($cfields[$order]))
  472. {
  473. $multi_order[] = 'field_id_'.$cfields[$order];
  474. $set = 'y';
  475. $str_sort[] = 'field_id_'.$cfields[$order];
  476. //break;
  477. }
  478. }
  479. if ( $set == 'n' )
  480. {
  481. $order = 'date';
  482. }
  483. }
  484. if ($order == 'date' OR $order == 'random')
  485. {
  486. $order = 'entry_date';
  487. }
  488. if (isset($params['channel']) && trim($params['channel']) != '')
  489. {
  490. if (count($this->channels_array) == 0)
  491. {
  492. $results = $this->EE->db->query("SELECT channel_id, channel_name FROM exp_channels WHERE site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."')");
  493. foreach($results->result_array() as $row)
  494. {
  495. $this->channels_array[$row['channel_id']] = $row['channel_name'];
  496. }
  497. }
  498. $channels = explode('|', trim($params['channel']));
  499. $allowed = array();
  500. if (strncmp($channels[0], 'not ', 4) == 0)
  501. {
  502. $channels[0] = trim(substr($channels[0], 3));
  503. $allowed = $this->channels_array;
  504. foreach($channels as $name)
  505. {
  506. if (in_array($name, $allowed))
  507. {
  508. foreach (array_keys($allowed, $name) AS $k)
  509. {
  510. unset($allowed[$k]);
  511. }
  512. }
  513. }
  514. }
  515. else
  516. {
  517. foreach($channels as $name)
  518. {
  519. if (in_array($name, $this->channels_array))
  520. {
  521. foreach (array_keys($this->channels_array, $name) AS $k)
  522. {
  523. $allowed[$k] = $name;
  524. }
  525. }
  526. }
  527. }
  528. }
  529. $stati = explode('|', $params['status']);
  530. $stati = array_map('strtolower', $stati); // match MySQL's case-insensitivity
  531. $status_state = 'positive';
  532. // Check for "not "
  533. if (substr($stati[0], 0, 4) == 'not ')
  534. {
  535. $status_state = 'negative';
  536. $stati[0] = trim(substr($stati[0], 3));
  537. $stati[] = 'closed';
  538. }
  539. $r = 1; // Fixes a problem when a sorting key occurs twice
  540. foreach($entry_data[$entry_id] as $relating_data)
  541. {
  542. $post_fix = ' '.$r;
  543. $order_set = FALSE;
  544. if ( ! isset($params['channel']) OR ($relating_data['query']->row('channel_id') && array_key_exists($relating_data['query']->row('channel_id'), $allowed)))
  545. {
  546. $query_row = $relating_data['query']->row_array();
  547. if (isset($multi_order))
  548. {
  549. foreach ($multi_order as $field_val)
  550. {
  551. if (isset($query_row[$field_val]))
  552. {
  553. $order_set = TRUE;
  554. $order_key = '';
  555. if ($query_row[$field_val] != '')
  556. {
  557. $order_key = $query_row[$field_val];
  558. $order = $field_val;
  559. break;
  560. }
  561. }
  562. }
  563. }
  564. elseif (isset($query_row[$order]))
  565. {
  566. $order_set = TRUE;
  567. $order_key = $query_row[$order];
  568. }
  569. // Needs to have the field we're ordering by
  570. if ($order_set)
  571. {
  572. if ($status_state == 'negative' && ! in_array(strtolower($query_row['status']) , $stati))
  573. {
  574. $new[$order_key.$post_fix] = $relating_data;
  575. }
  576. elseif (in_array(strtolower($query_row['status']) , $stati))
  577. {
  578. $new[$order_key.$post_fix] = $relating_data;
  579. }
  580. }
  581. ++$r;
  582. }
  583. }
  584. if ($random === TRUE)
  585. {
  586. shuffle($new);
  587. }
  588. elseif ($sort == 'asc') // 1 to 10, A to Z
  589. {
  590. if (in_array($order, $str_sort))
  591. {
  592. ksort($new);
  593. }
  594. else
  595. {
  596. uksort($new, 'strnatcasecmp');
  597. }
  598. }
  599. else
  600. {
  601. if (in_array($order, $str_sort))
  602. {
  603. ksort($new);
  604. }
  605. else
  606. {
  607. uksort($new, 'strnatcasecmp');
  608. }
  609. $new = array_reverse($new, TRUE);
  610. }
  611. $output_data[$entry_id] = array_slice($new, $offset, $limit);
  612. if (count($output_data[$entry_id]) == 0)
  613. {
  614. $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);
  615. continue;
  616. }
  617. // Finally! We get to process our parents
  618. foreach($output_data[$entry_id] as $relating_data)
  619. {
  620. if ($i == 0)
  621. {
  622. $query = $this->EE->functions->clone_object($relating_data['query']);
  623. }
  624. else
  625. {
  626. $query->result_array[] = $relating_data['query']->row_array();
  627. }
  628. $cats[$relating_data['query']->row('entry_id') ] = $relating_data['categories'];
  629. ++$i;
  630. }
  631. $query->num_rows = $i;
  632. $this->initialize();
  633. $this->EE->TMPL->var_single = $this->EE->TMPL->reverse_related_data[$template]['var_single'];
  634. $this->EE->TMPL->var_pair = $this->EE->TMPL->reverse_related_data[$template]['var_pair'];
  635. $this->EE->TMPL->var_cond = $this->EE->TMPL->reverse_related_data[$template]['var_cond'];
  636. $this->EE->TMPL->tagdata = $this->EE->TMPL->reverse_related_data[$template]['tagdata'];
  637. $this->query = $query;
  638. $this->categories = $cats;
  639. $this->parse_channel_entries();
  640. $return_data = str_replace( LD."REV_REL[".$this->EE->TMPL->reverse_related_data[$template]['marker']."][".$entry_id."]REV_REL".RD,
  641. $this->return_data,
  642. $return_data);
  643. }
  644. }
  645. $this->return_data = $return_data;
  646. }
  647. // ------------------------------------------------------------------------
  648. /**
  649. * Track Views
  650. */
  651. function track_views()
  652. {
  653. if ($this->EE->config->item('enable_entry_view_tracking') == 'n')
  654. {
  655. return;
  656. }
  657. if ( ! $this->EE->TMPL->fetch_param('track_views') OR $this->hit_tracking_id === FALSE)
  658. {
  659. return;
  660. }
  661. if ($this->field_pagination == TRUE AND $this->p_page > 0)
  662. {
  663. return;
  664. }
  665. foreach (explode('|', $this->EE->TMPL->fetch_param('track_views')) as $view)
  666. {
  667. if ( ! in_array(strtolower($view), array("one", "two", "three", "four")))
  668. {
  669. continue;
  670. }
  671. $sql = "UPDATE exp_channel_titles SET view_count_{$view} = (view_count_{$view} + 1) WHERE ";
  672. $sql .= (is_numeric($this->hit_tracking_id)) ? "entry_id = {$this->hit_tracking_id}" : "url_title = '".$this->EE->db->escape_str($this->hit_tracking_id)."'";
  673. $this->EE->db->query($sql);
  674. }
  675. }
  676. // ------------------------------------------------------------------------
  677. /**
  678. * Fetch pagination data
  679. */
  680. function fetch_pagination_data()
  681. {
  682. if (strpos($this->EE->TMPL->tagdata, LD.'paginate'.RD) === FALSE) return;
  683. if (preg_match("/".LD."paginate".RD."(.+?)".LD.'\/'."paginate".RD."/s", $this->EE->TMPL->tagdata, $match))
  684. {
  685. if ($this->EE->TMPL->fetch_param('paginate_type') == 'field')
  686. {
  687. if (preg_match("/".LD."multi_field\=[\"'](.+?)[\"']".RD."/s", $this->EE->TMPL->tagdata, $mmatch))
  688. {
  689. $this->multi_fields = $this->EE->functions->fetch_simple_conditions($mmatch[1]);
  690. $this->field_pagination = TRUE;
  691. }
  692. }
  693. // -------------------------------------------
  694. // 'channel_module_fetch_pagination_data' hook.
  695. // - Works with the 'channel_module_create_pagination' hook
  696. // - Developers, if you want to modify the $this object remember
  697. // to use a reference on function call.
  698. //
  699. if ($this->EE->extensions->active_hook('channel_module_fetch_pagination_data') === TRUE)
  700. {
  701. $edata = $this->EE->extensions->universal_call('channel_module_fetch_pagination_data', $this);
  702. if ($this->EE->extensions->end_script === TRUE) return;
  703. }
  704. //
  705. // -------------------------------------------
  706. $this->paginate = TRUE;
  707. $this->paginate_data = $match[1];
  708. $this->EE->TMPL->tagdata = preg_replace("/".LD."paginate".RD.".+?".LD.'\/'."paginate".RD."/s", "", $this->EE->TMPL->tagdata);
  709. }
  710. }
  711. // ------------------------------------------------------------------------
  712. /**
  713. * Add pagination data to result
  714. */
  715. function add_pagination_data()
  716. {
  717. if ($this->pagination_links == '')
  718. {
  719. return;
  720. }
  721. if ($this->paginate == TRUE)
  722. {
  723. $this->paginate_data = str_replace(LD.'current_page'.RD, $this->current_page, $this->paginate_data);
  724. $this->paginate_data = str_replace(LD.'total_pages'.RD, $this->total_pages, $this->paginate_data);
  725. $this->paginate_data = str_replace(LD.'pagination_links'.RD, $this->pagination_links, $this->paginate_data);
  726. if (preg_match("/".LD."if previous_page".RD."(.+?)".LD.'\/'."if".RD."/s", $this->paginate_data, $match))
  727. {
  728. if ($this->page_previous == '')
  729. {
  730. $this->paginate_data = preg_replace("/".LD."if previous_page".RD.".+?".LD.'\/'."if".RD."/s", '', $this->paginate_data);
  731. }
  732. else
  733. {
  734. $match[1] = preg_replace("/".LD.'path.*?'.RD."/", $this->page_previous, $match[1]);
  735. $match[1] = preg_replace("/".LD.'auto_path'.RD."/", $this->page_previous, $match[1]);
  736. $this->paginate_data = str_replace($match[0], $match[1], $this->paginate_data);
  737. }
  738. }
  739. if (preg_match("/".LD."if next_page".RD."(.+?)".LD.'\/'."if".RD."/s", $this->paginate_data, $match))
  740. {
  741. if ($this->page_next == '')
  742. {
  743. $this->paginate_data = preg_replace("/".LD."if next_page".RD.".+?".LD.'\/'."if".RD."/s", '', $this->paginate_data);
  744. }
  745. else
  746. {
  747. $match[1] = preg_replace("/".LD.'path.*?'.RD."/", $this->page_next, $match[1]);
  748. $match[1] = preg_replace("/".LD.'auto_path'.RD."/", $this->page_next, $match[1]);
  749. $this->paginate_data = str_replace($match[0], $match[1], $this->paginate_data);
  750. }
  751. }
  752. $this->paginate_data = $this->EE->functions->prep_conditionals($this->paginate_data, array('total_pages' => $this->total_pages));
  753. $position = ( ! $this->EE->TMPL->fetch_param('paginate')) ? '' : $this->EE->TMPL->fetch_param('paginate');
  754. switch ($position)
  755. {
  756. case "top" : $this->return_data = $this->paginate_data.$this->return_data;
  757. break;
  758. case "both" : $this->return_data = $this->paginate_data.$this->return_data.$this->paginate_data;
  759. break;
  760. default : $this->return_data .= $this->paginate_data;
  761. break;
  762. }
  763. }
  764. }
  765. // ------------------------------------------------------------------------
  766. /**
  767. * Fetch custom channel field IDs
  768. */
  769. function fetch_custom_channel_fields()
  770. {
  771. if (isset($this->EE->session->cache['channel']['custom_channel_fields']) && isset($this->EE->session->cache['channel']['date_fields'])
  772. && isset($this->EE->session->cache['channel']['relationship_fields']) && isset($this->EE->session->cache['channel']['pair_custom_fields']))
  773. {
  774. $this->cfields = $this->EE->session->cache['channel']['custom_channel_fields'];
  775. $this->dfields = $this->EE->session->cache['channel']['date_fields'];
  776. $this->rfields = $this->EE->session->cache['channel']['relationship_fields'];
  777. $this->pfields = $this->EE->session->cache['channel']['pair_custom_fields'];
  778. return;
  779. }
  780. $this->EE->load->library('api');
  781. $this->EE->api->instantiate('channel_fields');
  782. $fields = $this->EE->api_channel_fields->fetch_custom_channel_fields();
  783. $this->cfields = $fields['custom_channel_fields'];
  784. $this->dfields = $fields['date_fields'];
  785. $this->rfields = $fields['relationship_fields'];
  786. $this->pfields = $fields['pair_custom_fields'];
  787. $this->EE->session->cache['channel']['custom_channel_fields'] = $this->cfields;
  788. $this->EE->session->cache['channel']['date_fields'] = $this->dfields;
  789. $this->EE->session->cache['channel']['relationship_fields'] = $this->rfields;
  790. $this->EE->session->cache['channel']['pair_custom_fields'] = $this->pfields;
  791. }
  792. // ------------------------------------------------------------------------
  793. /**
  794. * Fetch custom member field IDs
  795. */
  796. function fetch_custom_member_fields()
  797. {
  798. $this->EE->db->select('m_field_id, m_field_name, m_field_fmt');
  799. $query = $this->EE->db->get('member_fields');
  800. $fields_present = FALSE;
  801. $t1 = microtime(TRUE);
  802. foreach ($query->result_array() as $row)
  803. {
  804. if (strpos($this->EE->TMPL->tagdata, $row['m_field_name']) !== FALSE)
  805. {
  806. $fields_present = TRUE;
  807. }
  808. $this->mfields[$row['m_field_name']] = array($row['m_field_id'], $row['m_field_fmt']);
  809. }
  810. // If we can find no instance of the variable, then let's not process them at all.
  811. if ($fields_present === FALSE)
  812. {
  813. $this->mfields = array();
  814. }
  815. }
  816. // ------------------------------------------------------------------------
  817. /**
  818. * Fetch categories
  819. */
  820. function fetch_categories()
  821. {
  822. if ($this->enable['category_fields'] === TRUE)
  823. {
  824. $query = $this->EE->db->query("SELECT field_id, field_name FROM exp_category_fields WHERE site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."')");
  825. if ($query->num_rows() > 0)
  826. {
  827. foreach ($query->result_array() as $row)
  828. {
  829. $this->catfields[] = array('field_name' => $row['field_name'], 'field_id' => $row['field_id']);
  830. }
  831. }
  832. $field_sqla = ", cg.field_html_formatting, fd.* ";
  833. $field_sqlb = " LEFT JOIN exp_category_field_data AS fd ON fd.cat_id = c.cat_id
  834. LEFT JOIN exp_category_groups AS cg ON cg.group_id = c.group_id";
  835. }
  836. else
  837. {
  838. $field_sqla = '';
  839. $field_sqlb = '';
  840. }
  841. $sql = "SELECT c.cat_name, c.cat_url_title, c.cat_id, c.cat_image, c.cat_description, c.parent_id,
  842. p.cat_id, p.entry_id, c.group_id {$field_sqla}
  843. FROM (exp_categories AS c, exp_category_posts AS p)
  844. {$field_sqlb}
  845. WHERE c.cat_id = p.cat_id
  846. AND p.entry_id IN (";
  847. $categories = array();
  848. foreach ($this->query->result_array() as $row)
  849. {
  850. $sql .= "'".$row['entry_id']."',";
  851. $categories[] = $row['entry_id'];
  852. }
  853. $sql = substr($sql, 0, -1).')';
  854. $sql .= " ORDER BY c.group_id, c.parent_id, c.cat_order";
  855. $query = $this->EE->db->query($sql);
  856. if ($query->num_rows() == 0)
  857. {
  858. return;
  859. }
  860. foreach ($categories as $val)
  861. {
  862. $this->temp_array = array();
  863. $this->cat_array = array();
  864. $parents = array();
  865. foreach ($query->result_array() as $row)
  866. {
  867. if ($val == $row['entry_id'])
  868. {
  869. $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']);
  870. foreach ($row as $k => $v)
  871. {
  872. if (strpos($k, 'field') !== FALSE)
  873. {
  874. $this->temp_array[$row['cat_id']][$k] = $v;
  875. }
  876. }
  877. if ($row['parent_id'] > 0 && ! isset($this->temp_array[$row['parent_id']])) $parents[$row['parent_id']] = '';
  878. unset($parents[$row['cat_id']]);
  879. }
  880. }
  881. if (count($this->temp_array) == 0)
  882. {
  883. $temp = FALSE;
  884. }
  885. else
  886. {
  887. foreach($this->temp_array as $k => $v)
  888. {
  889. if (isset($parents[$v[1]])) $v[1] = 0;
  890. if (0 == $v[1])
  891. {
  892. $this->cat_array[] = $v;
  893. $this->process_subcategories($k);
  894. }
  895. }
  896. }
  897. $this->categories[$val] = $this->cat_array;
  898. }
  899. unset($this->temp_array);
  900. unset($this->cat_array);
  901. }
  902. // ------------------------------------------------------------------------
  903. /**
  904. * Build SQL query
  905. */
  906. function build_sql_query($qstring = '')
  907. {
  908. $entry_id = '';
  909. $year = '';
  910. $month = '';
  911. $day = '';
  912. $qtitle = '';
  913. $cat_id = '';
  914. $corder = array();
  915. $offset = 0;
  916. $page_marker = FALSE;
  917. $dynamic = TRUE;
  918. $this->dynamic_sql = TRUE;
  919. /**------
  920. /** Is dynamic='off' set?
  921. /**------*/
  922. // If so, we'll override all dynamically set variables
  923. if ($this->EE->TMPL->fetch_param('dynamic') == 'no')
  924. {
  925. $dynamic = FALSE;
  926. }
  927. /**------
  928. /** Do we allow dynamic POST variables to set parameters?
  929. /**------*/
  930. if ($this->EE->TMPL->fetch_param('dynamic_parameters') !== FALSE AND isset($_POST) AND count($_POST) > 0)
  931. {
  932. foreach (explode('|', $this->EE->TMPL->fetch_param('dynamic_parameters')) as $var)
  933. {
  934. 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')))
  935. {
  936. $this->EE->TMPL->tagparams[$var] = $_POST[$var];
  937. }
  938. if (isset($_POST[$var]) && strncmp($var, 'search:', 7) == 0)
  939. {
  940. $this->EE->TMPL->search_fields[substr($var, 7)] = $_POST[$var];
  941. }
  942. }
  943. }
  944. /**------
  945. /** Parse the URL query string
  946. /**------*/
  947. $this->uristr = $this->EE->uri->uri_string;
  948. if ($qstring == '')
  949. $qstring = $this->query_string;
  950. $this->basepath = $this->EE->functions->create_url($this->uristr);
  951. if ($qstring == '')
  952. {
  953. if ($this->EE->TMPL->fetch_param('require_entry') == 'yes')
  954. {
  955. return '';
  956. }
  957. }
  958. else
  959. {
  960. /** --------------------------------------
  961. /** Do we have a pure ID number?
  962. /** --------------------------------------*/
  963. if (is_numeric($qstring) AND $dynamic)
  964. {
  965. $entry_id = $qstring;
  966. }
  967. else
  968. {
  969. // Load the string helper
  970. $this->EE->load->helper('string');
  971. /** --------------------------------------
  972. /** Parse day
  973. /** --------------------------------------*/
  974. if (preg_match("#(^|\/)(\d{4}/\d{2}/\d{2})#", $qstring, $match) AND $dynamic)
  975. {
  976. $ex = explode('/', $match[2]);
  977. $year = $ex[0];
  978. $month = $ex[1];
  979. $day = $ex[2];
  980. $qstring = trim_slashes(str_replace($match[0], '', $qstring));
  981. }
  982. /** --------------------------------------
  983. /** Parse /year/month/
  984. /** --------------------------------------*/
  985. // added (^|\/) to make sure this doesn't trigger with url titles like big_party_2006
  986. if (preg_match("#(^|\/)(\d{4}/\d{2})(\/|$)#", $qstring, $match) AND $dynamic)
  987. {
  988. $ex = explode('/', $match[2]);
  989. $year = $ex[0];
  990. $month = $ex[1];
  991. $qstring = trim_slashes(str_replace($match[2], '', $qstring));
  992. // Removed this in order to allow archive pagination
  993. // $this->paginate = FALSE;
  994. }
  995. /** --------------------------------------
  996. /** Parse ID indicator
  997. /** --------------------------------------*/
  998. if (preg_match("#^(\d+)(.*)#", $qstring, $match) AND $dynamic)
  999. {
  1000. $seg = ( ! isset($match[2])) ? '' : $match[2];
  1001. if (substr($seg, 0, 1) == "/" OR $seg == '')
  1002. {
  1003. $entry_id = $match[1];
  1004. $qstring = trim_slashes(preg_replace("#^".$match[1]."#", '', $qstring));
  1005. }
  1006. }
  1007. /** --------------------------------------
  1008. /** Parse page number
  1009. /** --------------------------------------*/
  1010. if (preg_match("#^P(\d+)|/P(\d+)#", $qstring, $match) AND ($dynamic OR $this->EE->TMPL->fetch_param('paginate')))
  1011. {
  1012. $this->p_page = (isset($match[2])) ? $match[2] : $match[1];
  1013. $this->basepath = $this->EE->functions->remove_double_slashes(str_replace($match[0], '', $this->basepath));
  1014. $this->uristr = $this->EE->functions->remove_double_slashes(str_replace($match[0], '', $this->uristr));
  1015. $qstring = trim_slashes(str_replace($match[0], '', $qstring));
  1016. $page_marker = TRUE;
  1017. }
  1018. /** --------------------------------------
  1019. /** Parse category indicator
  1020. /** --------------------------------------*/
  1021. // Text version of the category
  1022. 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'))
  1023. {
  1024. $qstring = preg_replace("/(.*?)\/".preg_quote($this->reserved_cat_segment)."\//i", '', '/'.$qstring);
  1025. $sql = "SELECT DISTINCT cat_group FROM exp_channels WHERE site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."') AND ";
  1026. $xsql = $this->EE->functions->sql_andor_string($this->EE->TMPL->fetch_param('channel'), 'channel_name');
  1027. if (substr($xsql, 0, 3) == 'AND') $xsql = substr($xsql, 3);
  1028. $sql .= ' '.$xsql;
  1029. $query = $this->EE->db->query($sql);
  1030. if ($query->num_rows() > 0)
  1031. {
  1032. $valid = 'y';
  1033. $last = explode('|', $query->row('cat_group') );
  1034. $valid_cats = array();
  1035. foreach($query->result_array() as $row)
  1036. {
  1037. if ($this->EE->TMPL->fetch_param('relaxed_categories') == 'yes')
  1038. {
  1039. $valid_cats = array_merge($valid_cats, explode('|', $row['cat_group']));
  1040. }
  1041. else
  1042. {
  1043. $valid_cats = array_intersect($last, explode('|', $row['cat_group']));
  1044. }
  1045. $valid_cats = array_unique($valid_cats);
  1046. if (count($valid_cats) == 0)
  1047. {
  1048. $valid = 'n';
  1049. break;
  1050. }
  1051. }
  1052. }
  1053. else
  1054. {
  1055. $valid = 'n';
  1056. }
  1057. if ($valid == 'y')
  1058. {
  1059. // the category URL title should be the first segment left at this point in $qstring,
  1060. // but because prior to this feature being added, category names were used in URLs,
  1061. // and '/' is a valid character for category names. If they have not updated their
  1062. // category url titles since updating to 1.6, their category URL title could still
  1063. // contain a '/'. So we'll try to get the category the correct way first, and if
  1064. // it fails, we'll try the whole $qstring
  1065. // do this as separate commands to work around a PHP 5.0.x bug
  1066. $arr = explode('/', $qstring);
  1067. $cut_qstring = array_shift($arr);
  1068. unset($arr);
  1069. $result = $this->EE->db->query("SELECT cat_id FROM exp_categories
  1070. WHERE cat_url_title='".$this->EE->db->escape_str($cut_qstring)."'
  1071. AND group_id IN ('".implode("','", $valid_cats)."')");
  1072. if ($result->num_rows() == 1)
  1073. {
  1074. $qstring = str_replace($cut_qstring, 'C'.$result->row('cat_id') , $qstring);
  1075. }
  1076. else
  1077. {
  1078. // give it one more try using the whole $qstring
  1079. $result = $this->EE->db->query("SELECT cat_id FROM exp_categories
  1080. WHERE cat_url_title='".$this->EE->db->escape_str($qstring)."'
  1081. AND group_id IN ('".implode("','", $valid_cats)."')");
  1082. if ($result->num_rows() == 1)
  1083. {
  1084. $qstring = 'C'.$result->row('cat_id') ;
  1085. }
  1086. }
  1087. }
  1088. }
  1089. // Numeric version of the category
  1090. if (preg_match("#(^|\/)C(\d+)#", $qstring, $match) AND $dynamic)
  1091. {
  1092. $this->cat_request = TRUE;
  1093. $cat_id = $match[2];
  1094. $qstring = trim_slashes(str_replace($match[0], '', $qstring));
  1095. }
  1096. /** --------------------------------------
  1097. /** Remove "N"
  1098. /** --------------------------------------*/
  1099. // The recent comments feature uses "N" as the URL indicator
  1100. // It needs to be removed if presenst
  1101. if (preg_match("#^N(\d+)|/N(\d+)#", $qstring, $match))
  1102. {
  1103. $this->uristr = $this->EE->functions->remove_double_slashes(str_replace($match[0], '', $this->uristr));
  1104. $qstring = trim_slashes(str_replace($match[0], '', $qstring));
  1105. }
  1106. /** --------------------------------------
  1107. /** Parse URL title
  1108. /** --------------------------------------*/
  1109. if (($cat_id == '' AND $year == '') OR $this->EE->TMPL->fetch_param('require_entry') == 'yes')
  1110. {
  1111. if (strpos($qstring, '/') !== FALSE)
  1112. {
  1113. $xe = explode('/', $qstring);
  1114. $qstring = current($xe);
  1115. }
  1116. if ($dynamic == TRUE)
  1117. {
  1118. $sql = "SELECT count(*) AS count
  1119. FROM exp_channel_titles, exp_channels
  1120. WHERE exp_channel_titles.channel_id = exp_channels.channel_id";
  1121. if ($entry_id != '')
  1122. {
  1123. $sql .= " AND exp_channel_titles.entry_id = '".$this->EE->db->escape_str($entry_id)."'";
  1124. }
  1125. else
  1126. {
  1127. $sql .= " AND exp_channel_titles.url_title = '".$this->EE->db->escape_str($qstring)."'";
  1128. }
  1129. $sql .= " AND exp_channels.site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."') ";
  1130. $query = $this->EE->db->query($sql);
  1131. if ($query->row('count') == 0)
  1132. {
  1133. if ($this->EE->TMPL->fetch_param('require_entry') == 'yes')
  1134. {
  1135. return '';
  1136. }
  1137. $qtitle = '';
  1138. }
  1139. else
  1140. {
  1141. $qtitle = $qstring;
  1142. }
  1143. }
  1144. }
  1145. }
  1146. }
  1147. /**------
  1148. /** Entry ID number
  1149. /**------*/
  1150. // If the "entry ID" was hard-coded, use it instead of
  1151. // using the dynamically set one above
  1152. if ($this->EE->TMPL->fetch_param('entry_id'))
  1153. {
  1154. $entry_id = $this->EE->TMPL->fetch_param('entry_id');
  1155. }
  1156. /**------
  1157. /** Only Entries with Pages
  1158. /**------*/
  1159. 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)
  1160. {
  1161. $pages_uris = array();
  1162. foreach ($pages as $data)
  1163. {
  1164. $pages_uris += $data['uris'];
  1165. }
  1166. if (count($pages_uris) > 0 OR $this->EE->TMPL->fetch_param('show_pages') == 'only')
  1167. {
  1168. // consider entry_id
  1169. if ($this->EE->TMPL->fetch_param('entry_id') !== FALSE)
  1170. {
  1171. $not = FALSE;
  1172. if (strncmp($entry_id, 'not', 3) == 0)
  1173. {
  1174. $not = TRUE;
  1175. $entry_id = trim(substr($entry_id, 3));
  1176. }
  1177. $ids = explode('|', $entry_id);
  1178. if ($this->EE->TMPL->fetch_param('show_pages') == 'only')
  1179. {
  1180. if ($not === TRUE)
  1181. {
  1182. $entry_id = implode('|', array_diff(array_flip($pages_uris), explode('|', $ids)));
  1183. }
  1184. else
  1185. {
  1186. $entry_id = implode('|',array_diff($ids, array_diff($ids, array_flip($pages_uris))));
  1187. }
  1188. }
  1189. else
  1190. {
  1191. if ($not === TRUE)
  1192. {
  1193. $entry_id = "not {$entry_id}|".implode('|', array_flip($pages_uris));
  1194. }
  1195. else
  1196. {
  1197. $entry_id = implode('|',array_diff($ids, array_flip($pages_uris)));
  1198. }
  1199. }
  1200. }
  1201. else
  1202. {
  1203. $entry_id = (($this->EE->TMPL->fetch_param('show_pages') == 'no') ? 'not ' : '').implode('|', array_flip($pages_uris));
  1204. }
  1205. // No pages and show_pages only
  1206. if ($entry_id == '' && $this->EE->TMPL->fetch_param('show_pages') == 'only')
  1207. {
  1208. $this->sql = '';
  1209. return;
  1210. }
  1211. }
  1212. }
  1213. /**------
  1214. /** Assing the order variables
  1215. /**------*/
  1216. $order = $this->EE->TMPL->fetch_param('orderby');
  1217. $sort = $this->EE->TMPL->fetch_param('sort');
  1218. $sticky = $this->EE->TMPL->fetch_param('sticky');
  1219. /** -------------------------------------
  1220. /** Multiple Orders and Sorts...
  1221. /** -------------------------------------*/
  1222. if ($order !== FALSE && stristr($order, '|'))
  1223. {
  1224. $order_array = explode('|', $order);
  1225. if ($order_array[0] == 'random')
  1226. {
  1227. $order_array = array('random');
  1228. }
  1229. }
  1230. else
  1231. {
  1232. $order_array = array($order);
  1233. }
  1234. if ($sort !== FALSE && stristr($sort, '|'))
  1235. {
  1236. $sort_array = explode('|', $sort);
  1237. }
  1238. else
  1239. {
  1240. $sort_array = array($sort);
  1241. }
  1242. /** -------------------------------------
  1243. /** Validate Results for Later Processing
  1244. /** -------------------------------------*/
  1245. $base_orders = array('random', 'entry_id', 'date', 'title', 'url_title', 'edit_date', 'comment_total', 'username', 'screen_name', 'most_recent_comment', 'expiration_date',
  1246. 'view_count_one', 'view_count_two', 'view_count_three', 'view_count_four');
  1247. foreach($order_array as $key => $order)
  1248. {
  1249. if ( ! in_array($order, $base_orders))
  1250. {
  1251. if (FALSE !== $order)
  1252. {
  1253. $set = 'n';
  1254. /** -------------------------------------
  1255. /** Site Namespace is Being Used, Parse Out
  1256. /** -------------------------------------*/
  1257. if (strpos($order, ':') !== FALSE)
  1258. {
  1259. $order_parts = explode(':', $order, 2);
  1260. if (isset($this->EE->TMPL->site_ids[$order_parts[0]]) && isset($this->cfields[$this->EE->TMPL->site_ids[$order_parts[0]]][$order_parts[1]]))
  1261. {
  1262. $corder[$key] = $this->cfields[$this->EE->TMPL->site_ids[$order_parts[0]]][$order_parts[1]];
  1263. $order_array[$key] = 'custom_field';
  1264. $set = 'y';
  1265. }
  1266. }
  1267. /** -------------------------------------
  1268. /** Find the Custom Field, Cycle Through All Sites for Tag
  1269. /** - If multiple sites have the same short_name for a field, we do a CONCAT ORDERBY in query
  1270. /** -------------------------------------*/
  1271. if ($set == 'n')
  1272. {
  1273. foreach($this->cfields as $site_id => $cfields)
  1274. {
  1275. // Only those sites specified
  1276. if ( ! in_array($site_id, $this->EE->TMPL->site_ids))
  1277. {
  1278. continue;
  1279. }
  1280. if (isset($cfields[$order]))
  1281. {
  1282. if ($set == 'y')
  1283. {
  1284. $corder[$key] .= '|'.$cfields[$order];
  1285. }
  1286. else
  1287. {
  1288. $corder[$key] = $cfields[$order];
  1289. $order_array[$key] = 'custom_field';
  1290. $set = 'y';
  1291. }
  1292. }
  1293. }
  1294. }
  1295. if ($set == 'n')
  1296. {
  1297. $order_array[$key] = FALSE;
  1298. }
  1299. }
  1300. }
  1301. if ( ! isset($sort_array[$key]))
  1302. {
  1303. $sort_array[$key] = 'desc';
  1304. }
  1305. }
  1306. foreach($sort_array as $key => $sort)
  1307. {
  1308. if ($sort == FALSE OR ($sort != 'asc' AND $sort != 'desc'))
  1309. {
  1310. $sort_array[$key] = "desc";
  1311. }
  1312. }
  1313. // fixed entry id ordering
  1314. if (($fixed_order = $this->EE->TMPL->fetch_param('fixed_order')) === FALSE OR preg_match('/[^0-9\|]/', $fixed_order))
  1315. {
  1316. $fixed_order = FALSE;
  1317. }
  1318. else
  1319. {
  1320. // MySQL will not order the entries correctly unless the results are constrained
  1321. // to matching rows only, so we force the entry_id as well
  1322. $entry_id = $fixed_order;
  1323. $fixed_order = preg_split('/\|/', $fixed_order, -1, PREG_SPLIT_NO_EMPTY);
  1324. // some peeps might want to be able to 'flip' it
  1325. // the default sort order is 'desc' but in this context 'desc' has a stronger "reversing"
  1326. // connotation, so we look not at the sort array, but the tag parameter itself, to see the user's intent
  1327. if ($sort == 'desc')
  1328. {
  1329. $fixed_order = array_reverse($fixed_order);
  1330. }
  1331. }
  1332. /**------
  1333. /** Build the master SQL query
  1334. /**------*/
  1335. $sql_a = "SELECT ";
  1336. $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 ";
  1337. if ($this->field_pagination == TRUE)
  1338. {
  1339. $sql_b .= ",wd.* ";
  1340. }
  1341. $sql_c = "COUNT(t.entry_id) AS count ";
  1342. $sql = "FROM exp_channel_titles AS t
  1343. LEFT JOIN exp_channels ON t.channel_id = exp_channels.channel_id ";
  1344. if ($this->field_pagination == TRUE)
  1345. {
  1346. $sql .= "LEFT JOIN exp_channel_data AS wd ON t.entry_id = wd.entry_id ";
  1347. }
  1348. elseif (in_array('custom_field', $order_array))
  1349. {
  1350. $sql .= "LEFT JOIN exp_channel_data AS wd ON t.entry_id = wd.entry_id ";
  1351. }
  1352. elseif ( ! empty($this->EE->TMPL->search_fields))
  1353. {
  1354. $sql .= "LEFT JOIN exp_channel_data AS wd ON wd.entry_id = t.entry_id ";
  1355. }
  1356. $sql .= "LEFT JOIN exp_members AS m ON m.member_id = t.author_id ";
  1357. if ($this->EE->TMPL->fetch_param('category') OR $this->EE->TMPL->fetch_param('category_group') OR $cat_id != '')
  1358. {
  1359. /* --------------------------------
  1360. /* We use LEFT JOIN when there is a 'not' so that we get
  1361. /* entries that are not assigned to a category.
  1362. /* --------------------------------*/
  1363. 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') !== 'n')
  1364. {
  1365. $sql .= "LEFT JOIN exp_category_posts ON t.entry_id = exp_category_posts.entry_id
  1366. LEFT JOIN exp_categories ON exp_category_posts.cat_id = exp_categories.cat_id ";
  1367. }
  1368. else
  1369. {
  1370. $sql .= "INNER JOIN exp_category_posts ON t.entry_id = exp_category_posts.entry_id
  1371. INNER JOIN exp_categories ON exp_category_posts.cat_id = exp_categories.cat_id ";
  1372. }
  1373. }
  1374. $sql .= "WHERE t.entry_id !='' AND t.site_id IN ('".implode("','", $this->EE->TMPL->site_ids)."') ";
  1375. /**------
  1376. /** We only select entries that have not expired
  1377. /**------*/
  1378. $timestamp = ($this->EE->TMPL->cache_timestamp != '') ? $this->EE->localize->set_gmt($this->EE->TMPL->cache_timestamp) : $this->EE->localize->now;
  1379. if ($this->EE->TMPL->fetch_param('show_future_entries') != 'yes')
  1380. {
  1381. $sql .= " AND t.entry_date < ".$timestamp." ";
  1382. }
  1383. if ($this->EE->TMPL->fetch_param('show_expired') != 'yes')
  1384. {
  1385. $sql .= " AND (t.expiration_date = 0 OR t.expiration_date > ".$timestamp.") ";
  1386. }
  1387. /**------
  1388. /** Limit query by post ID for individual entries
  1389. /**------*/
  1390. if ($entry_id != '')
  1391. {
  1392. $sql .= $this->EE->functions->sql_andor_string($entry_id, 't.entry_id').' ';
  1393. }
  1394. /**------
  1395. /** Limit query by post url_title for individual entries
  1396. /**------*/
  1397. if ($url_title = $this->EE->TMPL->fetch_param('url_title'))
  1398. {
  1399. $sql .= $this->EE->functions->sql_andor_string($url_title, 't.url_title').' ';
  1400. }
  1401. /**------
  1402. /** Limit query by entry_id range
  1403. /**------*/
  1404. if ($entry_id_from = $this->EE->TMPL->fetch_param('entry_id_from'))
  1405. {
  1406. $sql .= "AND t.entry_id >= '$entry_id_from' ";
  1407. }
  1408. if ($entry_id_to = $this->EE->TMPL->fetch_param('entry_id_to'))
  1409. {
  1410. $sql .= "AND t.entry_id <= '$entry_id_to' ";
  1411. }
  1412. /**------
  1413. /** Exclude an individual entry
  1414. /**------*/
  1415. if ($not_entry_id = $this->EE->TMPL->fetch_param('not_entry_id'))
  1416. {
  1417. $sql .= ( ! is_numeric($not_entry_id))
  1418. ? "AND t.url_title != '{$not_entry_id}' "
  1419. : "AND t.entry_id != '{$not_entry_id}' ";
  1420. }
  1421. /**------
  1422. /** Limit to/exclude specific channels
  1423. /**------*/
  1424. if ($channel = $this->EE->TMPL->fetch_param('channel'))
  1425. {
  1426. $xql = "SELECT channel_id FROM exp_channels WHERE ";
  1427. $str = $this->EE->functions->sql_andor_string($channel, 'channel_name');
  1428. if (substr($str, 0, 3) == 'AND')
  1429. {
  1430. $str = substr($str, 3);
  1431. }
  1432. $xql .= $str;
  1433. $query = $this->EE->db->query($xql);
  1434. if ($query->num_rows() == 0)
  1435. {
  1436. return '';
  1437. }
  1438. else
  1439. {
  1440. if ($query->num_rows() == 1)
  1441. {
  1442. $sql .= "AND t.channel_id = '".$query->row('channel_id') ."' ";
  1443. }
  1444. else
  1445. {
  1446. $sql .= "AND (";
  1447. foreach ($query->result_array() as $row)
  1448. {
  1449. $sql .= "t.channel_id = '".$row['channel_id']."' OR ";
  1450. }

Large files files are truncated, but you can click here to view the full file