/system/cms/modules/pages/plugin.php

https://bitbucket.org/viktorfabry/banditos · PHP · 482 lines · 264 code · 66 blank · 152 comment · 35 complexity · c289e0be8829478c02d999e3976479b9 MD5 · raw file

  1. <?php defined('BASEPATH') OR exit('No direct script access allowed');
  2. /**
  3. * Pages Plugin
  4. *
  5. * Create links and whatnot.
  6. *
  7. * @author PyroCMS Dev Team
  8. * @package PyroCMS\Core\Modules\Pages\Plugins
  9. */
  10. class Plugin_Pages extends Plugin
  11. {
  12. /**
  13. * Get the URL of a page
  14. *
  15. * Attributes:
  16. * - (int) id : The id of the page to get the URL for.
  17. *
  18. * @return string
  19. */
  20. public function url()
  21. {
  22. $id = $this->attribute('id');
  23. $page = $this->pyrocache->model('page_m', 'get', array($id));
  24. return site_url($page ? $page->uri : '');
  25. }
  26. /**
  27. * Get a page by ID or slug
  28. *
  29. * Attributes:
  30. * - (int) id: The id of the page.
  31. * - (string) slug: The slug of the page.
  32. *
  33. * @return array
  34. */
  35. public function display()
  36. {
  37. $page = $this->db
  38. ->where('pages.id', $this->attribute('id'))
  39. ->or_where('pages.slug', $this->attribute('slug'))
  40. ->where('status', 'live')
  41. ->get('pages')
  42. ->row_array();
  43. // Grab all the chunks that make up the body
  44. $page['chunks'] = $this->db->get_where('page_chunks', array('page_id' => $page['id']))->result_array();
  45. $page['body'] = '';
  46. if ($page['chunks'])
  47. {
  48. foreach ($page['chunks'] as $chunk)
  49. {
  50. $page['body'] .= '<div class="page-chunk ' . $chunk['slug'] . '">' .
  51. (($chunk['type'] == 'markdown') ? $chunk['parsed'] : $chunk['body']) .
  52. '</div>'.PHP_EOL;
  53. }
  54. }
  55. // we'll unset the chunks array as Lex is grouchy about mixed data at the moment
  56. unset($page->chunks);
  57. return $this->content() ? array($page) : $page['body'];
  58. }
  59. /**
  60. * Get a page chunk by page ID and chunk name
  61. *
  62. * Attributes:
  63. * - (int) id : The id of the page.
  64. * - (string) name : The name of the chunk.
  65. * - (string) parse_tags : yes/no - whether or not to parse
  66. * tags within the
  67. *
  68. * @return string|bool
  69. */
  70. public function chunk()
  71. {
  72. $parse_tags = $this->attribute('parse_tags', 'yes');
  73. $chunk = $this->db
  74. ->where('page_id', $this->attribute('id'))
  75. ->where('slug', $this->attribute('name'))
  76. ->get('page_chunks')
  77. ->row_array();
  78. if ($chunk)
  79. {
  80. if ($this->content())
  81. {
  82. $chunk['parsed'] = $this->parse_chunk($chunk['parsed'], $parse_tags);
  83. $chunk['body'] = $this->parse_chunk($chunk['body'], $parse_tags);
  84. return $chunk;
  85. }
  86. else
  87. {
  88. return $this->parse_chunk(($chunk['type'] == 'markdown') ? $chunk['parsed'] : $chunk['body'], $parse_tags);
  89. }
  90. }
  91. }
  92. /**
  93. * Parse chunk content
  94. *
  95. * @access private
  96. * @param string - the chunk content
  97. * @param string - parse Lex tags? - yes/no
  98. * @return string
  99. */
  100. private function parse_chunk($content, $parse_tags)
  101. {
  102. // Lex tags are parsed by default. If you want to
  103. // turn off parsing Lex tags, just set parse_tags to 'no'
  104. if ($parse_tags == 'yes')
  105. {
  106. $parser = new Lex_Parser();
  107. $parser->scope_glue(':');
  108. return $parser->parse($content, array(), array($this->parser, 'parser_callback'));
  109. }
  110. else
  111. {
  112. return $content;
  113. }
  114. }
  115. /**
  116. * Children list
  117. *
  118. * Creates a list of child pages
  119. *
  120. * Attributes:
  121. * - (int) limit: How many pages to show.
  122. * - (string) order-by: One of the column names from the `pages` table.
  123. * - (string) order-dir: Either `asc` or `desc`
  124. *
  125. * Usage:
  126. * {{ pages:children id="1" limit="5" }}
  127. * <h2>{title}</h2>
  128. * {body}
  129. * {{ /pages:children }}
  130. *
  131. * @return array
  132. */
  133. public function children()
  134. {
  135. $limit = $this->attribute('limit', 10);
  136. $order_by = $this->attribute('order-by', 'title');
  137. $order_dir = $this->attribute('order-dir', 'ASC');
  138. $pages = $this->db->select('pages.*')
  139. ->where('pages.parent_id', $this->attribute('id'))
  140. ->where('status', 'live')
  141. ->order_by($order_by, $order_dir)
  142. ->limit($limit)
  143. ->get('pages')
  144. ->result_array();
  145. if ($pages)
  146. {
  147. foreach ($pages as &$page)
  148. {
  149. // Grab all the chunks that make up the body for this page
  150. $page['chunks'] = $this->db
  151. ->get_where('page_chunks', array('page_id' => $page['id']))
  152. ->result_array();
  153. $page['body'] = '';
  154. if ($page['chunks'])
  155. {
  156. foreach ($page['chunks'] as $chunk)
  157. {
  158. $page['body'] .= '<div class="page-chunk '.$chunk['slug'].'">'.
  159. (($chunk['type'] == 'markdown') ? $chunk['parsed'] : $chunk['body']).
  160. '</div>'.PHP_EOL;
  161. }
  162. }
  163. }
  164. }
  165. return $pages;
  166. }
  167. // --------------------------------------------------------------------------
  168. /**
  169. * Page tree function
  170. *
  171. * Creates a nested ul of child pages
  172. *
  173. * Usage:
  174. * {{ pages:page_tree start-id="5" }}
  175. * optional attributes:
  176. *
  177. * disable-levels="slug"
  178. * order-by="title"
  179. * order-dir="desc"
  180. * list-tag="ul"
  181. * link="true"
  182. *
  183. * @param array
  184. * @return array
  185. */
  186. public function page_tree()
  187. {
  188. $start = $this->attribute('start');
  189. $start_id = $this->attribute('start-id', $this->attribute('start_id'));
  190. $disable_levels = $this->attribute('disable-levels');
  191. $order_by = $this->attribute('order-by', 'title');
  192. $order_dir = $this->attribute('order-dir', 'ASC');
  193. $list_tag = $this->attribute('list-tag', 'ul');
  194. $link = $this->attribute('link', true);
  195. // If we have a start URI, let's try and
  196. // find that ID.
  197. if ($start)
  198. {
  199. $page = $this->page_m->get_by_uri($start);
  200. if ( ! $page) return null;
  201. $start_id = $page->id;
  202. }
  203. // If our start doesn't exist, then
  204. // what are we going to do? Nothing.
  205. if(!$start_id) return null;
  206. // Disable individual pages or parent pages by submitting their slug
  207. $this->disable = explode("|", $disable_levels);
  208. return '<'.$list_tag.'>' . $this->_build_tree_html(array(
  209. 'parent_id' => $start_id,
  210. 'order_by' => $order_by,
  211. 'order_dir' => $order_dir,
  212. 'list_tag' => $list_tag,
  213. 'link' => $link
  214. )) . '</'.$list_tag.'>';
  215. }
  216. // --------------------------------------------------------------------------
  217. /**
  218. * Page is function
  219. *
  220. * Check the pages parent or descendent relation
  221. *
  222. * Usage:
  223. * {{ pages:is child="7" parent="cookbook" }} // return 1 (true)
  224. * {{ pages:is child="recipes" descendent="books" }} // return 1 (true)
  225. * {{ pages:is children="7,8,literature" parent="6" }} // return 0 (false)
  226. * {{ pages:is children="recipes,ingredients,9" descendent="4" }} // return 1 (true)
  227. *
  228. * Use Id or Slug as param, following usage data reference
  229. * Id: 4 = Slug: books
  230. * Id: 6 = Slug: cookbook
  231. * Id: 7 = Slug: recipes
  232. * Id: 8 = Slug: ingredients
  233. * Id: 9 = Slug: literature
  234. *
  235. * @param array Plugin attributes
  236. * @return int 0 or 1
  237. */
  238. public function is()
  239. {
  240. $children_ids = $this->attribute('children');
  241. $child_id = $this->attribute('child');
  242. if ( ! $children_ids)
  243. {
  244. return (int) $this->_check_page_is($child_id);
  245. }
  246. $children_ids = explode(',', $children_ids);
  247. $children_ids = array_map('trim', $children_ids);
  248. if ($child_id)
  249. {
  250. $children_ids[] = $child_id;
  251. }
  252. foreach ($children_ids as $child_id)
  253. {
  254. if ( ! $this->_check_page_is($child_id))
  255. {
  256. return (int) false;
  257. }
  258. }
  259. return (int) true;
  260. }
  261. // --------------------------------------------------------------------------
  262. /**
  263. * Page has function
  264. *
  265. * Check if this page has children
  266. *
  267. * Usage:
  268. * {{ pages:has id="4" }}
  269. *
  270. * @param int id The id of the page you want to check
  271. * @return bool
  272. */
  273. public function has()
  274. {
  275. return $this->page_m->has_children($this->attribute('id'));
  276. }
  277. // --------------------------------------------------------------------------
  278. /**
  279. * Check Page is function
  280. *
  281. * Works for page is function
  282. *
  283. * @param mixed The Id or Slug of the page
  284. * @param array Plugin attributes
  285. * @return int 0 or 1
  286. */
  287. private function _check_page_is($child_id = 0)
  288. {
  289. $descendent_id = $this->attribute('descendent');
  290. $parent_id = $this->attribute('parent');
  291. if ($child_id && $descendent_id)
  292. {
  293. if ( ! is_numeric($child_id))
  294. {
  295. $child_id = ($child = $this->page_m->get_by(array('slug' => $child_id))) ? $child->id: 0;
  296. }
  297. if ( ! is_numeric($descendent_id))
  298. {
  299. $descendent_id = ($descendent = $this->page_m->get_by(array('slug' => $descendent_id))) ? $descendent->id: 0;
  300. }
  301. if ( ! ($child_id && $descendent_id))
  302. {
  303. return false;
  304. }
  305. $descendent_ids = $this->page_m->get_descendant_ids($descendent_id);
  306. return in_array($child_id, $descendent_ids);
  307. }
  308. if ($child_id && $parent_id)
  309. {
  310. if ( ! is_numeric($child_id))
  311. {
  312. $parent_id = ($parent = $this->page_m->get_by(array('slug' => $parent_id))) ? $parent->id : 0;
  313. }
  314. return $parent_id ? (int) $this->page_m->count_by(array(
  315. (is_numeric($child_id) ? 'id' : 'slug') => $child_id,
  316. 'parent_id' => $parent_id
  317. )) > 0 : false;
  318. }
  319. }
  320. // --------------------------------------------------------------------------
  321. /**
  322. * Tree html function
  323. *
  324. * Creates a page tree
  325. *
  326. * @param array
  327. * @return array
  328. */
  329. private function _build_tree_html($params)
  330. {
  331. $params = array_merge(array(
  332. 'tree' => array(),
  333. 'parent_id' => 0
  334. ), $params);
  335. extract($params);
  336. if ( ! $tree)
  337. {
  338. $this->db
  339. ->select('id, parent_id, slug, uri, title')
  340. ->where_not_in('slug', $this->disable);
  341. // check if they're logged in
  342. if ( isset($this->current_user->group) )
  343. {
  344. // admins can see them all
  345. if ($this->current_user->group != 'admin')
  346. {
  347. $id_list = array();
  348. $page_list = $this->db
  349. ->select('id, restricted_to')
  350. ->get('pages')
  351. ->result();
  352. foreach ($page_list AS $list_item)
  353. {
  354. // make an array of allowed user groups
  355. $group_array = explode(',', $list_item->restricted_to);
  356. // if restricted_to is 0 or empty (unrestricted) or if the current user's group is allowed
  357. if (($group_array[0] < 1) OR in_array($this->current_user->group_id, $group_array))
  358. {
  359. $id_list[] = $list_item->id;
  360. }
  361. }
  362. // if it's an empty array then evidentally all pages are unrestricted
  363. if (count($id_list) > 0)
  364. {
  365. // select only the pages they have permissions for
  366. $this->db->where_in('id', $id_list);
  367. }
  368. // since they aren't an admin they can't see drafts
  369. $this->db->where('status', 'live');
  370. }
  371. }
  372. else
  373. {
  374. //they aren't logged in, show them all live, unrestricted pages
  375. $this->db
  376. ->where('status', 'live')
  377. ->where('restricted_to <', 1)
  378. ->or_where('restricted_to', null);
  379. }
  380. $pages = $this->db
  381. ->order_by($order_by, $order_dir)
  382. ->get('pages')
  383. ->result();
  384. if ($pages)
  385. {
  386. foreach($pages as $page)
  387. {
  388. $tree[$page->parent_id][] = $page;
  389. }
  390. }
  391. }
  392. if ( ! isset($tree[$parent_id]))
  393. {
  394. return;
  395. }
  396. $html = '';
  397. foreach ($tree[$parent_id] as $item)
  398. {
  399. $html .= '<li';
  400. $html .= (current_url() == site_url($item->uri)) ? ' class="current">' : '>';
  401. $html .= ($link === true) ? '<a href="' . site_url($item->uri) . '">' . $item->title . '</a>' : $item->title;
  402. $nested_list = $this->_build_tree_html(array(
  403. 'tree' => $tree,
  404. 'parent_id' => (int) $item->id,
  405. 'link' => $link,
  406. 'list_tag' => $list_tag
  407. ));
  408. if ($nested_list)
  409. {
  410. $html .= '<'.$list_tag.'>' . $nested_list . '</'.$list_tag.'>';
  411. }
  412. $html .= '</li>';
  413. }
  414. return $html;
  415. }
  416. }