/class.bcn_breadcrumb_trail.php

  1. <?php 
  2. /**  
  3. Copyright 2007-2016 John Havlik (email : john.havlik@mtekk.us) 
  4.   
  5. This program is free software; you can redistribute it and/or modify 
  6. it under the terms of the GNU General Public License as published by 
  7. the Free Software Foundation; either version 2 of the License, or 
  8. (at your option) any later version. 
  9.   
  10. This program is distributed in the hope that it will be useful,  
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of 
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 
  13. GNU General Public License for more details. 
  14.   
  15. You should have received a copy of the GNU General Public License 
  16. along with this program; if not, write to the Free Software 
  17. Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 
  18. */ 
  19. require_once(dirname(__FILE__) . '/includes/block_direct_access.php'); 
  20. //The trail class 
  21. class bcn_breadcrumb_trail 
  22. //Our member variables 
  23. const version = '5.5.0'; 
  24. //An array of breadcrumbs 
  25. public $breadcrumbs = array(); 
  26. public $trail = array(); 
  27. //The options 
  28. public $opt; 
  29. //Default constructor 
  30. public function __construct() 
  31. //@see https://core.trac.wordpress.org/ticket/10527 
  32. if(!is_textdomain_loaded('breadcrumb-navxt')) 
  33. load_plugin_textdomain('breadcrumb-navxt', false, 'breadcrumb-navxt/languages'); 
  34. $this->trail = &$this->breadcrumbs; 
  35. //Initilize with default option values 
  36. $this->opt = array( 
  37. //Should the mainsite be shown 
  38. 'bmainsite_display' => true,  
  39. //The breadcrumb template for the main site 
  40. 'Hmainsite_template' => bcn_breadcrumb::get_default_template(),  
  41. //The breadcrumb template for the main site, used when an anchor is not needed 
  42. 'Hmainsite_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  43. //Should the home page be shown 
  44. 'bhome_display' => true,  
  45. //The breadcrumb template for the home page 
  46. 'Hhome_template' => bcn_breadcrumb::get_default_template(),  
  47. //The breadcrumb template for the home page, used when an anchor is not needed 
  48. 'Hhome_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  49. //Should the blog page be shown globally 
  50. 'bblog_display' => true,  
  51. //The breadcrumb template for the blog page only in static front page mode 
  52. 'Hblog_template' => bcn_breadcrumb::get_default_template(),  
  53. //The breadcrumb template for the blog page only in static front page mode, used when an anchor is not needed 
  54. 'Hblog_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  55. //Separator that is placed between each item in the breadcrumb trial, but not placed before 
  56. //the first and not after the last breadcrumb 
  57. 'hseparator' => ' > ',  
  58. //Whether or not we should trim the breadcrumb titles 
  59. 'blimit_title' => false,  
  60. //The maximum title length 
  61. 'amax_title_length' => 20,  
  62. //Current item options 
  63. 'bcurrent_item_linked' => false,  
  64. //Static page options 
  65. //The anchor template for page breadcrumbs 
  66. 'Hpost_page_template' => bcn_breadcrumb::get_default_template(),  
  67. //The anchor template for page breadcrumbs, used when an anchor is not needed 
  68. 'Hpost_page_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  69. //Just a link to the page on front property 
  70. 'apost_page_root' => get_option('page_on_front'),  
  71. //Paged options 
  72. //The template for paged breadcrumb 
  73. 'Hpaged_template' => __('<span property="itemListElement" typeof="ListItem"><span property="name">Page %htitle%</span><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  74. //Should we try filling out paged information 
  75. 'bpaged_display' => false,  
  76. //The post options previously singleblogpost 
  77. //The breadcrumb template for post breadcrumbs 
  78. 'Hpost_post_template' => bcn_breadcrumb::get_default_template(),  
  79. //The breadcrumb template for post breadcrumbs, used when an anchor is not needed 
  80. 'Hpost_post_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  81. //Just a link for the page for posts 
  82. 'apost_post_root' => get_option('page_for_posts'),  
  83. //Should the trail include the taxonomy of the post 
  84. 'bpost_post_taxonomy_display' => true,  
  85. //Should the trail reflect the referer taxonomy or not 
  86. 'bpost_post_taxonomy_referer' => false,  
  87. //What taxonomy should be shown leading to the post, tag or category 
  88. 'Spost_post_taxonomy_type' => 'category',  
  89. //Attachment settings 
  90. //The breadcrumb template for attachment breadcrumbs 
  91. 'Hpost_attachment_template' => bcn_breadcrumb::get_default_template(),  
  92. //The breadcrumb template for attachment breadcrumbs, used when an anchor is not needed 
  93. 'Hpost_attachment_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  94. //404 page settings 
  95. //The template for 404 breadcrumbs 
  96. 'H404_template' => bcn_breadcrumb::default_template_no_anchor,  
  97. //The text to be shown in the breadcrumb for a 404 page 
  98. 'S404_title' => __('404', 'breadcrumb-navxt'),  
  99. //Search page options 
  100. //The breadcrumb template for search breadcrumbs 
  101. 'Hsearch_template' => __('<span property="itemListElement" typeof="ListItem"><span property="name">Search results for '<a property="item" typeof="WebPage" title="Go to the first page of search results for %title%." href="%link%" class="%type%">%htitle%</a>'</span><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  102. //The breadcrumb template for search breadcrumbs, used when an anchor is not necessary 
  103. 'Hsearch_template_no_anchor' => __('<span property="itemListElement" typeof="ListItem"><span property="name">Search results for '%htitle%'</span><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  104. //Tag related stuff 
  105. //The breadcrumb template for tag breadcrumbs 
  106. 'Htax_post_tag_template' => __('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="Go to the %title% tag archives." href="%link%" class="%type%"><span property="name">%htitle%</span></a><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  107. //The breadcrumb template for tag breadcrumbs, used when an anchor is not necessary 
  108. 'Htax_post_tag_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  109. //Post format related stuff 
  110. //The breadcrumb template for post format breadcrumbs, used when an anchor is not necessary 
  111. 'Htax_post_format_template' => __('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="Go to the %title% archives." href="%link%" class="%type%"><span property="name">%htitle%</span></a><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  112. //The breadcrumb template for post format breadcrumbs 
  113. 'Htax_post_format_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  114. //Author page stuff 
  115. //The anchor template for author breadcrumbs 
  116. 'Hauthor_template' => __('<span property="itemListElement" typeof="ListItem"><span property="name">Articles by: <a title="Go to the first page of posts by %title%." href="%link%" class="%type%">%htitle%</a>', 'breadcrumb-navxt'),  
  117. //The anchor template for author breadcrumbs, used when anchors are not needed 
  118. 'Hauthor_template_no_anchor' => __('<span property="itemListElement" typeof="ListItem"><span property="name">Articles by: %htitle%</span><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  119. //Which of the various WordPress display types should the author breadcrumb display 
  120. 'Sauthor_name' => 'display_name',  
  121. //Category stuff 
  122. //The breadcrumb template for category breadcrumbs 
  123. 'Htax_category_template' => __('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="Go to the %title% category archives." href="%link%" class="%type%"><span property="name">%htitle%</span></a><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  124. //The breadcrumb template for category breadcrumbs, used when anchors are not needed 
  125. 'Htax_category_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor,  
  126. //The breadcrumb template for date breadcrumbs 
  127. 'Hdate_template' => __('<span property="itemListElement" typeof="ListItem"><a property="item" typeof="WebPage" title="Go to the %title% archives." href="%link%" class="%type%"><span property="name">%htitle%</span></a><meta property="position" content="%position%"></span>', 'breadcrumb-navxt'),  
  128. //The breadcrumb template for date breadcrumbs, used when anchors are not needed 
  129. 'Hdate_template_no_anchor' => bcn_breadcrumb::default_template_no_anchor 
  130. ); 
  131. /** 
  132. * This returns the internal version 
  133. * 
  134. * @return string internal version of the Breadcrumb trail 
  135. */ 
  136. public function get_version() 
  137. _deprecated_function( __FUNCTION__, '5.2', 'bcn_breadcrumb_trail::version' ); 
  138. return self::version; 
  139. /** 
  140. * Adds a breadcrumb to the breadcrumb trail 
  141. *  
  142. * @param bcn_breadcrumb $object Breadcrumb to add to the trail 
  143. * @return pointer to the just added Breadcrumb 
  144. */ 
  145. public function &add(bcn_breadcrumb $object) 
  146. $this->breadcrumbs[] = $object; 
  147. //Return the just added object 
  148. return $this->breadcrumbs[count($this->breadcrumbs) - 1]; 
  149. /** 
  150. * A Breadcrumb Trail Filling Function 
  151. *  
  152. * This functions fills a breadcrumb for a search page. 
  153. */ 
  154. protected function do_search() 
  155. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  156. $breadcrumb = $this->add(new bcn_breadcrumb(get_search_query(), $this->opt['Hsearch_template_no_anchor'], array('search', 'current-item'))); 
  157. //If we're paged, or allowing the current item to be linked, let's link to the first page 
  158. if($this->opt['bcurrent_item_linked'] || (is_paged() && $this->opt['bpaged_display'])) 
  159. //Since we are paged and are linking the root breadcrumb, time to change to the regular template 
  160. $breadcrumb->set_template($this->opt['Hsearch_template']); 
  161. //Figure out the anchor for the search 
  162. $breadcrumb->set_url(get_search_link()); 
  163. /** 
  164. * A Breadcrumb Trail Filling Function 
  165. *  
  166. * This functions fills a breadcrumb for an author page. 
  167. */ 
  168. protected function do_author() 
  169. if(get_query_var('author_name')) 
  170. $authordata = get_user_by('slug', get_query_var('author_name')); 
  171. else 
  172. $authordata = get_userdata(get_query_var('author')); 
  173. //Setup array of valid author_name values 
  174. $valid_author_name = array('display_name', 'nickname', 'first_name', 'last_name'); 
  175. //Make sure user picks only safe values 
  176. if(in_array($this->opt['Sauthor_name'], $valid_author_name)) 
  177. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  178. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_author_meta($this->opt['Sauthor_name'], $authordata->ID), $this->opt['Hauthor_template_no_anchor'], array('author', 'current-item'), NULL, $authordata->ID)); 
  179. //If we're paged, or allowing the current item to be linked, let's link to the first page 
  180. if($this->opt['bcurrent_item_linked'] || (is_paged() && $this->opt['bpaged_display'])) 
  181. //Set the template to our one containing an anchor 
  182. $breadcrumb->set_template($this->opt['Hauthor_template']); 
  183. $breadcrumb->set_url(get_author_posts_url($authordata->ID)); 
  184. /** 
  185. * Determines the taxonomy name represented by the specified query var 
  186. *  
  187. * @param string $query_var The query var to attempt to find the corresponding taxonomy 
  188. * @return string|bool Either the name of the taxonomy corresponding to the query_var or false if no taxonomy exists for the specified query_var 
  189. */ 
  190. protected function query_var_to_taxonomy($query_var) 
  191. global $wp_taxonomies; 
  192. foreach($wp_taxonomies as $taxonomy) 
  193. if($taxonomy->query_var === $query_var) 
  194. return $taxonomy->name; 
  195. return false; 
  196. /** 
  197. * Determines the referer taxonomy 
  198. *  
  199. * @return string|bool Either the name of the taxonomy to use or false if a referer taxonomy wasn't found 
  200. */ 
  201. protected function determine_taxonomy() 
  202. global $wp; 
  203. //Backup the server request variable 
  204. $bk_req = $_SERVER['REQUEST_URI']; 
  205. //Now set the request URL to the referrer URL 
  206. //Could just chain the [1] selection, but that's not PHP5.3 compatible 
  207. $url_split = explode(home_url(), wp_get_referer()); 
  208. if(isset($url_split[1])) 
  209. $_SERVER['REQUEST_URI'] = $url_split[1]; 
  210. else 
  211. return false; 
  212. //Create our own new instance of WP, and have it parse our faux request 
  213. $bcn_wp = new WP(); 
  214. //Copy over the current global wp object's query_vars since CPTs and taxonomies are added directly to the global $wp 
  215. $bcn_wp->public_query_vars = $wp->public_query_vars; 
  216. $bcn_wp->parse_request(); 
  217. $_SERVER['REQUEST_URI'] = $bk_req; 
  218. if(is_array($bcn_wp->query_vars)) 
  219. foreach($bcn_wp->query_vars as $query_var => $value) 
  220. if($taxonomy = $this->query_var_to_taxonomy($query_var)) 
  221. return $taxonomy; 
  222. return false; 
  223. /** 
  224. * This function selects the term that should be used for a post's hierarchy 
  225. *  
  226. * @param int $id The ID of the post to find the term for 
  227. * @param string $type The post type of the post to figure out the taxonomy for 
  228. * @param string $taxonomy The taxonomy to use 
  229. * @return WP_Term|bool The term object to use for the post hierarchy or false if no suitable term was found  
  230. */ 
  231. protected function pick_post_term($id, $type, $taxonomy) 
  232. //Fill a temporary object with the terms 
  233. $bcn_object = get_the_terms($id, $taxonomy); 
  234. $potential_parent = 0; 
  235. //Make sure we have an non-empty array 
  236. if(is_array($bcn_object)) 
  237. //Now try to find the deepest term of those that we know of 
  238. $bcn_use_term = key($bcn_object); 
  239. foreach($bcn_object as $key => $object) 
  240. //Can't use the next($bcn_object) trick since order is unknown 
  241. if($object->parent > 0 && ($potential_parent === 0 || $object->parent === $potential_parent)) 
  242. $bcn_use_term = $key; 
  243. $potential_parent = $object->term_id; 
  244. return $bcn_object[$bcn_use_term]; 
  245. return false; 
  246. /** 
  247. * A Breadcrumb Trail Filling Function 
  248. *  
  249. * This function fills breadcrumbs for any post taxonomy 
  250. * @param int $id The id of the post to figure out the taxonomy for 
  251. * @param string $type The post type of the post to figure out the taxonomy for 
  252. * @param int $parent (optional) The id of the parent of the current post, used if hiearchal posts will be the "taxonomy" for the current post 
  253. */ 
  254. protected function post_hierarchy($id, $type, $parent = NULL) 
  255. //Check to see if breadcrumbs for the taxonomy of the post needs to be generated 
  256. if($this->opt['bpost_' . $type . '_taxonomy_display']) 
  257. //TODO: Remove deprecated type selection 
  258. //Check if we have a date 'taxonomy' request 
  259. if($this->opt['Spost_' . $type . '_taxonomy_type'] === 'BCN_DATE' || $this->opt['Spost_' . $type . '_taxonomy_type'] === 'date') 
  260. $this->do_archive_by_date($type); 
  261. //TODO: Remove deprecated type selection 
  262. //Handle the use of hierarchical posts as the 'taxonomy' 
  263. else if($this->opt['Spost_' . $type . '_taxonomy_type'] === 'BCN_POST_PARENT' || $this->opt['Spost_' . $type . '_taxonomy_type'] === 'page') 
  264. if($parent == NULL) 
  265. //We have to grab the post to find its parent, can't use $post for this one 
  266. $parent = get_post($id); 
  267. $parent = $parent->post_parent; 
  268. //Grab the frontpage, we'll need it shortly 
  269. $bcn_frontpage = get_option('page_on_front'); 
  270. //If there is a parent page let's find it 
  271. if($parent && $id != $parent && $bcn_frontpage != $parent) 
  272. $parent = $this->post_parents($parent, $bcn_frontpage); 
  273. else 
  274. $taxonomy = $this->opt['Spost_' . $type . '_taxonomy_type']; 
  275. //Possibly let the referer influence the taxonomy used 
  276. if($this->opt['bpost_' . $type . '_taxonomy_referer'] && $referrer_taxonomy = $this->determine_taxonomy()) 
  277. //See if there were any terms, if so, we can use the referrer influenced taxonomy 
  278. $terms = get_the_terms($id, $referrer_taxonomy); 
  279. if(is_array($terms)) 
  280. $taxonomy = $referrer_taxonomy; 
  281. //Handle all hierarchical taxonomies, including categories 
  282. if(is_taxonomy_hierarchical($taxonomy)) 
  283. //Filter the results of post_pick_term 
  284. $term = apply_filters('bcn_pick_post_term', $this->pick_post_term($id, $type, $taxonomy), $id, $type, $taxonomy); 
  285. //Only do something if we found a term 
  286. if($term instanceof WP_Term) 
  287. //Fill out the term hiearchy 
  288. $parent = $this->term_parents($term->term_id, $taxonomy); 
  289. //Handle the rest of the taxonomies, including tags 
  290. else 
  291. $this->post_terms($id, $taxonomy); 
  292. //If we never got a good parent for the type_archive, make it now 
  293. if(!($parent instanceof WP_Post)) 
  294. $parent = get_post($id); 
  295. //Finish off with trying to find the type archive 
  296. $this->type_archive($parent); 
  297. /** 
  298. * A Breadcrumb Trail Filling Function 
  299. *  
  300. * This functions fills a breadcrumb for the terms of a post 
  301. * @param int $id The id of the post to find the terms for 
  302. * @param string $taxonomy The name of the taxonomy that the term belongs to 
  303. *  
  304. * TODO Need to implement this cleaner 
  305. */ 
  306. protected function post_terms($id, $taxonomy) 
  307. //Apply a filter to the terms for the post referred to by ID 
  308. $bcn_terms = apply_filters('bcn_post_terms', get_the_terms($id, $taxonomy), $taxonomy, $id); 
  309. //Only process if we have terms 
  310. if(is_array($bcn_terms)) 
  311. $title = '';  
  312. $is_first = true; 
  313. //Loop through all of the term results 
  314. foreach($bcn_terms as $term) 
  315. //Everything but the first term needs a comma separator 
  316. if($is_first == false) 
  317. $title .= ', '; 
  318. //This is a bit hackish, but it compiles the term anchor and appends it to the current breadcrumb title 
  319. $title .= str_replace( 
  320. array('%title%', '%link%', '%htitle%', '%type%'),  
  321. array($term->name, $this->maybe_add_post_type_arg(get_term_link($term), NULL, $term->taxonomy), $term->name, $term->taxonomy),  
  322. $this->opt['Htax_' . $term->taxonomy . '_template']); 
  323. $is_first = false; 
  324. //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return 
  325. $breadcrumb = $this->add(new bcn_breadcrumb($title, NULL, array('taxonomy', $taxonomy))); 
  326. /** 
  327. * A Breadcrumb Trail Filling Function 
  328. *  
  329. * This recursive functions fills the trail with breadcrumbs for parent terms. 
  330. * @param int $id The id of the term. 
  331. * @param string $taxonomy The name of the taxonomy that the term belongs to 
  332. * @return WP_Term The term we stopped at 
  333. */ 
  334. protected function term_parents($id, $taxonomy) 
  335. //Get the current category object, filter applied within this call 
  336. $term = get_term($id, $taxonomy); 
  337. //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return 
  338. $breadcrumb = $this->add(new bcn_breadcrumb($term->name, $this->opt['Htax_' . $taxonomy . '_template'], array('taxonomy', $taxonomy), $this->maybe_add_post_type_arg(get_term_link($term), NULL, $taxonomy), $id)); 
  339. //Make sure the id is valid, and that we won't end up spinning in a loop 
  340. if($term->parent && $term->parent != $id) 
  341. //Figure out the rest of the term hiearchy via recursion 
  342. $term = $this->term_parents($term->parent, $taxonomy); 
  343. return $term; 
  344. /** 
  345. * A Breadcrumb Trail Filling Function 
  346. *  
  347. * This recursive functions fills the trail with breadcrumbs for parent posts/pages. 
  348. * @param int $id The id of the parent page. 
  349. * @param int $frontpage The id of the front page. 
  350. * @return WP_Post The parent we stopped at 
  351. */ 
  352. protected function post_parents($id, $frontpage) 
  353. //Use WordPress API, though a bit heavier than the old method, this will ensure compatibility with other plug-ins 
  354. $parent = get_post($id); 
  355. //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return 
  356. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title($id), $this->opt['Hpost_' . $parent->post_type . '_template'], array('post', 'post-' . $parent->post_type), get_permalink($id), $id)); 
  357. //Make sure the id is valid, and that we won't end up spinning in a loop 
  358. if($parent->post_parent >= 0 && $parent->post_parent != false && $id != $parent->post_parent && $frontpage != $parent->post_parent) 
  359. //If valid, recursively call this function 
  360. $parent = $this->post_parents($parent->post_parent, $frontpage); 
  361. return $parent; 
  362. /** 
  363. * A Breadcrumb Trail Filling Function 
  364. *  
  365. * This functions fills a breadcrumb for posts 
  366. *  
  367. * @param $post WP_Post Instance of WP_Post object to create a breadcrumb for 
  368. */ 
  369. protected function do_post($post) 
  370. //If we did not get a WP_Post object, warn developer and return early 
  371. if(!($post instanceof WP_Post)) 
  372. _doing_it_wrong(__CLASS__ . '::' . __FUNCTION__, __('$post global is not of type WP_Post', 'breadcrumb-navxt'), '5.1.1'); 
  373. return; 
  374. //Place the breadcrumb in the trail, uses the bcn_breadcrumb constructor to set the title, template, and type 
  375. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title($post), $this->opt['Hpost_' . $post->post_type . '_template_no_anchor'], array('post', 'post-' . $post->post_type, 'current-item'), NULL, $post->ID)); 
  376. //If the current item is to be linked, or this is a paged post, add in links 
  377. if(is_attachment() || $this->opt['bcurrent_item_linked'] || (get_query_var('page') > 1 && $this->opt['bpaged_display'])) 
  378. //Change the template over to the normal, linked one 
  379. $breadcrumb->set_template($this->opt['Hpost_' . $post->post_type . '_template']); 
  380. //Add the link 
  381. $breadcrumb->set_url(get_permalink($post)); 
  382. //If we have page, force it to go through the parent tree 
  383. if($post->post_type === 'page') 
  384. //Done with the current item, now on to the parents 
  385. $frontpage = get_option('page_on_front'); 
  386. //If there is a parent page let's find it 
  387. if($post->post_parent && $post->ID != $post->post_parent && $frontpage != $post->post_parent) 
  388. $this->post_parents($post->post_parent, $frontpage); 
  389. //Otherwise we need the follow the hiearchy tree 
  390. else 
  391. //Handle the post's hiearchy 
  392. $this->post_hierarchy($post->ID, $post->post_type, $post->post_parent); 
  393. /** 
  394. * A Breadcrumb Trail Filling Function 
  395. *  
  396. * This functions fills a breadcrumb for an attachment page. 
  397. */ 
  398. protected function do_attachment() 
  399. $post = get_post(); 
  400. //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return 
  401. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title(), $this->opt['Hpost_attachment_template_no_anchor'], array('post', 'post-attachment', 'current-item'), NULL, $post->ID)); 
  402. if($this->opt['bcurrent_item_linked']) 
  403. //Change the template over to the normal, linked one 
  404. $breadcrumb->set_template($this->opt['Hpost_attachment_template']); 
  405. //Add the link 
  406. $breadcrumb->set_url(get_permalink()); 
  407. //Done with the current item, now on to the parents 
  408. $frontpage = get_option('page_on_front'); 
  409. //Make sure the id is valid, and that we won't end up spinning in a loop 
  410. if($post->post_parent >= 0 && $post->post_parent != false && $post->ID != $post->post_parent && $frontpage != $post->post_parent) 
  411. //Get the parent's information 
  412. $parent = get_post($post->post_parent); 
  413. //Take care of the parent's breadcrumb 
  414. $this->do_post($parent); 
  415. /** 
  416. * A Breadcrumb Trail Filling Function 
  417. *  
  418. * This function fills a breadcrumb for any taxonomy archive, was previously two separate functions 
  419. */ 
  420. protected function do_archive_by_term() 
  421. global $wp_query; 
  422. //Simmilar to using $post, but for things $post doesn't cover 
  423. $term = $wp_query->get_queried_object(); 
  424. //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, get a pointer to it in return 
  425. $breadcrumb = $this->add(new bcn_breadcrumb($term->name, $this->opt['Htax_' . $term->taxonomy . '_template_no_anchor'], array('archive', 'taxonomy', $term->taxonomy, 'current-item'), NULL, $term->term_id)); 
  426. //If we're paged, let's link to the first page 
  427. if($this->opt['bcurrent_item_linked'] || (is_paged() && $this->opt['bpaged_display'])) 
  428. $breadcrumb->set_template($this->opt['Htax_' . $term->taxonomy . '_template']); 
  429. //Figure out the anchor for current category 
  430. $breadcrumb->set_url($this->maybe_add_post_type_arg(get_term_link($term), NULL, $term->taxonomy)); 
  431. //Get parents of current term 
  432. if($term->parent) 
  433. $this->term_parents($term->parent, $term->taxonomy); 
  434. /** 
  435. * A Breadcrumb Trail Filling Function 
  436. *  
  437. * This functions fills a breadcrumb for a date archive. 
  438. *  
  439. * @param string $type The type to restrict the date archives to 
  440. */ 
  441. protected function do_archive_by_date($type) 
  442. global $wp_query; 
  443. //First deal with the day breadcrumb 
  444. if(is_day() || is_single()) 
  445. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  446. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_time(_x('d', 'day archive breadcrumb date format', 'breadcrumb-navxt')), $this->opt['Hdate_template_no_anchor'], array('archive', 'date-day'))); 
  447. //If this is a day archive, add current-item type 
  448. if(is_day()) 
  449. $breadcrumb->add_type('current-item'); 
  450. //If we're paged, let's link to the first page 
  451. if($this->opt['bcurrent_item_linked'] || is_paged() && $this->opt['bpaged_display'] || is_single()) 
  452. //We're linking, so set the linked template 
  453. $breadcrumb->set_template($this->opt['Hdate_template']); 
  454. $url = get_day_link(get_the_time('Y'), get_the_time('m'), get_the_time('d')); 
  455. //Deal with the anchor 
  456. $breadcrumb->set_url($this->maybe_add_post_type_arg($url, $type)); 
  457. //Now deal with the month breadcrumb 
  458. if(is_month() || is_day() || is_single()) 
  459. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  460. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_time(_x('F', 'month archive breadcrumb date format', 'breadcrumb-navxt')), $this->opt['Hdate_template_no_anchor'], array('archive', 'date-month'))); 
  461. //If this is a month archive, add current-item type 
  462. if(is_month()) 
  463. $breadcrumb->add_type('current-item'); 
  464. //If we're paged, or not in the archive by month let's link to the first archive by month page 
  465. if($this->opt['bcurrent_item_linked'] || is_day() || is_single() || (is_month() && is_paged() && $this->opt['bpaged_display'])) 
  466. //We're linking, so set the linked template 
  467. $breadcrumb->set_template($this->opt['Hdate_template']); 
  468. $url = get_month_link(get_the_time('Y'), get_the_time('m')); 
  469. //Deal with the anchor 
  470. $breadcrumb->set_url($this->maybe_add_post_type_arg($url, $type)); 
  471. //Place the year breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  472. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_time(_x('Y', 'year archive breadcrumb date format', 'breadcrumb-navxt')), $this->opt['Hdate_template_no_anchor'], array('archive', 'date-year'))); 
  473. //If this is a year archive, add current-item type 
  474. if(is_year()) 
  475. $breadcrumb->add_type('current-item'); 
  476. //If we're paged, or not in the archive by year let's link to the first archive by year page 
  477. if($this->opt['bcurrent_item_linked'] || is_day() || is_month() || is_single() || (is_paged() && $this->opt['bpaged_display'])) 
  478. //We're linking, so set the linked template 
  479. $breadcrumb->set_template($this->opt['Hdate_template']); 
  480. $url = get_year_link(get_the_time('Y')); 
  481. //Deal with the anchor 
  482. $breadcrumb->set_url($this->maybe_add_post_type_arg($url, $type)); 
  483. /** 
  484. * A Breadcrumb Trail Filling Function 
  485. *  
  486. * This functions fills a breadcrumb for a post type archive (WP 3.1 feature) 
  487. */ 
  488. protected function do_archive_by_post_type() 
  489. $type_str = $this->get_type_string_query_var(); 
  490. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  491. $breadcrumb = $this->add(new bcn_breadcrumb(post_type_archive_title('', false), $this->opt['Hpost_' . $type_str . '_template_no_anchor'], array('archive', 'post-' . $type_str . '-archive', 'current-item'))); 
  492. if($this->opt['bcurrent_item_linked'] || is_paged() && $this->opt['bpaged_display']) 
  493.  
  494. $breadcrumb->set_template($this->opt['Hpost_' . $type_str . '_template']); 
  495. //Deal with the anchor 
  496. $breadcrumb->set_url(get_post_type_archive_link($type_str)); 
  497. /** 
  498. * A Breadcrumb Trail Filling Function 
  499. *  
  500. * This functions fills a breadcrumb for the front page. 
  501. */ 
  502. protected function do_front_page() 
  503. global $current_site; 
  504. //Get the site name 
  505. $site_name = get_option('blogname'); 
  506. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  507. $breadcrumb = $this->add(new bcn_breadcrumb($site_name, $this->opt['Hhome_template_no_anchor'], array('home', 'current-item'))); 
  508. //If we're paged, let's link to the first page 
  509. if($this->opt['bcurrent_item_linked'] || (is_paged() && $this->opt['bpaged_display'])) 
  510. $breadcrumb->set_template($this->opt['Hhome_template']); 
  511. //Figure out the anchor for home page 
  512. $breadcrumb->set_url(get_home_url()); 
  513. //If we have a multi site and are not on the main site we may need to add a breadcrumb for the main site 
  514. if($this->opt['bmainsite_display'] && !is_main_site()) 
  515. //Get the site name 
  516. $site_name = get_site_option('site_name'); 
  517. //Place the main site breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  518. $breadcrumb = $this->add(new bcn_breadcrumb($site_name, $this->opt['Hmainsite_template'], array('main-home'), get_home_url($current_site->blog_id))); 
  519. /** 
  520. * A Breadcrumb Trail Filling Function 
  521. *  
  522. * This functions fills a breadcrumb for the home page. 
  523. */ 
  524. protected function do_home() 
  525. global $current_site; 
  526. //On everything else we need to link, but no current item (pre/suf)fixes 
  527. if($this->opt['bhome_display']) 
  528. //Get the site name 
  529. $site_name = get_option('blogname'); 
  530. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  531. $breadcrumb = $this->add(new bcn_breadcrumb($site_name, $this->opt['Hhome_template'], array('home'), get_home_url())); 
  532. //If we have a multi site and are not on the main site we need to add a breadcrumb for the main site 
  533. if($this->opt['bmainsite_display'] && !is_main_site()) 
  534. //Get the site name 
  535. $site_name = get_site_option('site_name'); 
  536. //Place the main site breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  537. $breadcrumb = $this->add(new bcn_breadcrumb($site_name, $this->opt['Hmainsite_template'], array('main-home'), get_home_url($current_site->blog_id))); 
  538. /** 
  539. * A modified version of WordPress' function of the same name 
  540. *  
  541. * @param object $object the post or taxonomy object used to attempt to find the title 
  542. * @return string the title 
  543. */ 
  544. protected function post_type_archive_title($object) 
  545. if(isset($object->labels->name)) 
  546. //Core filter use here is ok for time being 
  547. //TODO: Recheck validitiy prior to each release 
  548. return apply_filters('post_type_archive_title', $object->labels->name, $object->name); 
  549. /** 
  550. * Determines if a post type is a built in type or not 
  551. *  
  552. * @param string $post_type the name of the post type 
  553. * @return bool 
  554. */ 
  555. protected function is_builtin($post_type) 
  556. $type = get_post_type_object($post_type); 
  557. //If we get a null, that means either then type wasn't found, or we had 'any' as a type, treat as builtin 
  558. if($type === null) 
  559. return true; 
  560. else 
  561. return $type->_builtin; 
  562. /** 
  563. * Determines if the current location is a for a root page or not 
  564. *  
  565. * @param string $post_type the name of the post type 
  566. * @return bool 
  567. */ 
  568. protected function treat_as_root_page($post_type) 
  569. return (is_home() || (is_post_type_archive() && is_numeric($this->opt['apost_' . $post_type . '_root']) && !$this->opt['bpost_' . $post_type . '_archive_display'])); 
  570. /** 
  571. * Determines if a post type has archives enabled or not 
  572. *  
  573. * @param string $post_type the name of the post type 
  574. * @return bool 
  575. */ 
  576. protected function has_archive($post_type) 
  577. $type = get_post_type_object($post_type); 
  578. return $type->has_archive; 
  579. /** 
  580. * Retrieves the query var for 'post_type', sets default to post, and escapes 
  581. *  
  582. * @param string $default[optional] The default value to return if nothing was found/set or if post_type was an array 
  583. *  
  584. * @return string The post type string found in the post_type query var 
  585. */ 
  586. protected function get_type_string_query_var($default = 'post') 
  587. $type_str = get_query_var('post_type', $default); 
  588. if($type_str === '' || is_array($type_str)) 
  589. $type_str = $default; 
  590. return esc_attr($type_str); 
  591. /** 
  592. * Retrieves the query var for 'post_type', and returns whether or not it is an array 
  593. *  
  594. * @return bool Whether or not the post_type query var is an array 
  595. */ 
  596. protected function is_type_query_var_array() 
  597. return is_array(get_query_var('post_type')); 
  598. /** 
  599. * Adds the post type argument to the URL iff the passed in type is not post 
  600. *  
  601. * @param string $url The URL to possibly add the post_type argument to 
  602. * @param string $type[optional] The type to possibly add to the URL 
  603. * @param string $taxonomy[optional] If we're dealing with a taxonomy term, the taxonomy of that term 
  604. *  
  605. * @return string The possibly modified URL 
  606. */ 
  607. protected function maybe_add_post_type_arg($url, $type = NULL, $taxonomy = NULL) 
  608. global $wp_taxonomies; 
  609. //Rather than default to post, we should try to find the type 
  610. if($type == NULL) 
  611. $type = $this->get_type_string_query_var(); 
  612. //Add a query arg if we are not on the default post type for the archive in question and the post type is not post 
  613. $add_query_arg = (!($taxonomy && $type === $wp_taxonomies[$taxonomy]->object_type[0]) && $type !== 'post'); 
  614. //Filter the add_query_arg logic, only add the query arg if necessary 
  615. if(apply_filters('bcn_add_post_type_arg', $add_query_arg, $type, $taxonomy)) 
  616. $url = add_query_arg(array('post_type' => $type), $url); 
  617. return $url; 
  618. /** 
  619. * A Breadcrumb Trail Filling Function 
  620. *  
  621. * Deals with the post type archive and taxonomy archives 
  622. *  
  623. * @param WP_Post|WP_Taxonomy $type The post or taxonomy to generate the archive breadcrumb for 
  624. */ 
  625. protected function type_archive($type) 
  626. global $wp_taxonomies; 
  627. $type_str = false; 
  628. if(!isset($type->taxonomy)) 
  629. $type_str = $this->get_type_string_query_var(); 
  630. //If this is a custom post type with a post type archive, add it 
  631. if($type_str && !$this->is_builtin($type_str) && $this->opt['bpost_' . $type_str . '_archive_display'] && $this->has_archive($type_str)) 
  632. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  633. $breadcrumb = $this->add(new bcn_breadcrumb($this->post_type_archive_title(get_post_type_object($type_str)), $this->opt['Hpost_' . $type_str . '_template'], array('post', 'post-' . $type_str . '-archive'), get_post_type_archive_link($type_str))); 
  634. //Otherwise, if this is a custom taxonomy with an archive, add it 
  635. else if(isset($type->taxonomy) && isset($wp_taxonomies[$type->taxonomy]->object_type[0])  
  636. && !$this->is_builtin($this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]))  
  637. && $this->opt['bpost_' . $this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]) . '_archive_display']  
  638. && $this->has_archive($this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0])) 
  639. && !$this->is_type_query_var_array()) 
  640. //We end up using the post type in several places, give it a variable 
  641. $post_type = apply_filters('bcn_type_archive_post_type', $this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0])); 
  642. //Place the breadcrumb in the trail, uses the constructor to set the title, prefix, and suffix, get a pointer to it in return 
  643. $breadcrumb = $this->add(new bcn_breadcrumb($this->post_type_archive_title(get_post_type_object($post_type)), $this->opt['Hpost_' . $post_type . '_template'], array('post', 'post-' . $post_type . '-archive'), get_post_type_archive_link($post_type))); 
  644. /** 
  645. * This function populates our type_str and root_id variables 
  646. *  
  647. * @param post $type A post object we are using to figureout the type 
  648. * @param string $type_str The type string variable, passed by reference 
  649. * @param int $root_id The ID for the post type root 
  650. *  
  651. * TODO, can probably clean up all the logic here and use the code for the CPT archives for all paths 
  652. */ 
  653. protected function find_type($type, &$type_str, &$root_id) 
  654. global $wp_taxonomies; 
  655. //We need to do special things for custom post types 
  656. if(is_singular() && !$this->is_builtin($type->post_type)) 
  657. //We need the type for later, so save it 
  658. $type_str = $type->post_type; 
  659. //This will assign a ID for root page of a custom post 
  660. if(is_numeric($this->opt['apost_' . $type_str . '_root'])) 
  661. $root_id = $this->opt['apost_' . $type_str . '_root']; 
  662. //For CPT archives 
  663. else if(is_post_type_archive() && !isset($type->taxonomy)) 
  664. //We need the type for later, so save it 
  665. $type_str = get_query_var('post_type'); 
  666. //May be an array, if so, rewind the iterator and grab first item 
  667. if(is_array($type_str)) 
  668. $type_str = reset($type_str); 
  669. //This will assign a ID for root page of a custom post's taxonomy archive 
  670. if(is_numeric($this->opt['apost_' . $type_str . '_root'])) 
  671. $root_id = $this->opt['apost_' . $type_str . '_root']; 
  672. //We need to do special things for custom post type archives, but not author or date archives 
  673. else if(is_archive() && !is_author() && !is_date() && !$this->is_builtin($this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]))) 
  674. //We need the type for later, so save it 
  675. $type_str = $this->get_type_string_query_var($wp_taxonomies[$type->taxonomy]->object_type[0]); 
  676. //This will assign a ID for root page of a custom post's taxonomy archive 
  677. if(is_numeric($this->opt['apost_' . $type_str . '_root'])) 
  678. $root_id = $this->opt['apost_' . $type_str . '_root']; 
  679. else 
  680. $type_str = 'post'; 
  681. $root_id = get_option('page_for_posts'); 
  682. /** 
  683. * A Breadcrumb Trail Filling Function  
  684. * 
  685. * Handles only the root page stuff for post types, including the "page for posts" 
  686. */ 
  687. protected function do_root() 
  688. global $wp_query; 
  689. //If this is an attachment then we need to change the queried object to the parent post 
  690. if(is_attachment()) 
  691. //Could use the $post global, but we can't really trust it 
  692. $post = get_post(); 
  693. $type = get_post($post->post_parent); 
  694. //If the parent of the attachment is a page, exit early (works around bug where is_single() returns true for an attachment to a page) 
  695. if($type->post_type == 'page') 
  696. return; 
  697. else 
  698. //Simmilar to using $post, but for things $post doesn't cover 
  699. $type = $wp_query->get_queried_object(); 
  700. $root_id = -1; 
  701. $type_str = ''; 
  702. //Find our type string and root_id 
  703. $this->find_type($type, $type_str, $root_id); 
  704. //Continue only if we have a valid root_id 
  705. if($root_id > 1) 
  706. $frontpage_id = get_option('page_on_front'); 
  707. //We'll have to check if this ID is valid, e.g. user has specified a posts page 
  708. if($root_id && $root_id != $frontpage_id) 
  709. //Place the breadcrumb in the trail, uses the constructor to set the title, template, and type, we get a pointer to it in return 
  710. $breadcrumb = $this->add(new bcn_breadcrumb(get_the_title($root_id), $this->opt['Hpost_' . $type_str . '_template_no_anchor'], array($type_str . '-root', 'post', 'post-' . $type_str), NULL, $root_id)); 
  711. //If we are at home, or any root page archive then we need to add the current item type 
  712. if($this->treat_as_root_page($type_str)) 
  713. $breadcrumb->add_type('current-item'); 
  714. //If we're not on the current item we need to setup the anchor 
  715. if(!$this->treat_as_root_page($type_str) 
  716. || (is_paged() && $this->opt['bpaged_display']) 
  717. || ($this->treat_as_root_page($type_str) && $this->opt['bcurrent_item_linked'])) 
  718. $breadcrumb->set_template($this->opt['Hpost_' . $type_str . '_template']); 
  719. //Figure out the anchor for home page 
  720. $breadcrumb->set_url(get_permalink($root_id)); 
  721. //Done with the "root", now on to the parents 
  722. //Get the blog page 
  723. $bcn_post = get_post($root_id); 
  724. //If there is a parent post let's find it 
  725. if($bcn_post->post_parent && $bcn_post->ID != $bcn_post->post_parent && $frontpage_id != $bcn_post->post_parent) 
  726. $this->post_parents($bcn_post->post_parent, $frontpage_id); 
  727. /** 
  728. * A Breadcrumb Trail Filling Function 
  729. *  
  730. * This functions fills a breadcrumb for 404 pages. 
  731. */ 
  732. protected function do_404() 
  733. //Place the breadcrumb in the trail, uses the bcn_breadcrumb constructor to set the title, prefix, and suffix 
  734. $this->breadcrumbs[] = new bcn_breadcrumb($this->opt['S404_title'], $this->opt['H404_template'], array('404', 'current-item')); 
  735. /** 
  736. * A Breadcrumb Trail Filling Function 
  737. *  
  738. * This functions fills a breadcrumb for paged pages. 
  739. */ 
  740. protected function do_paged() 
  741. //Need to switch between paged and page for archives and singular (posts) 
  742. if(get_query_var('paged') > 0) 
  743. //Can use simple type hinting here to int since we already checked for greater than 0 
  744. $page_number = (int) get_query_var('paged'); 
  745. else 
  746. $page_number = absint(get_query_var('page')); 
  747. //Place the breadcrumb in the trail, uses the bcn_breadcrumb constructor to set the title, prefix, and suffix 
  748. $this->breadcrumbs[] = new bcn_breadcrumb($page_number, $this->opt['Hpaged_template'], array('paged')); 
  749. /** 
  750. * Breadcrumb Trail Filling Function 
  751. *  
  752. * This functions fills the breadcrumb trail. 
  753. */ 
  754. public function fill() 
  755. global $wpdb, $wp_query, $wp; 
  756. //Check to see if the trail is already populated 
  757. if(count($this->breadcrumbs) > 0) 
  758. //Exit early since we have breadcrumbs in the trail 
  759. return NULL; 
  760. //Do any actions if necessary, we past through the current object instance to keep life simple 
  761. do_action('bcn_before_fill', $this); 
  762. //Do specific opperations for the various page types 
  763. //Check if this isn't the first of a multi paged item 
  764. if($this->opt['bpaged_display'] && (is_paged() || is_singular() && get_query_var('page') > 1)) 
  765. $this->do_paged(); 
  766. //For the front page, as it may also validate as a page, do it first 
  767. if(is_front_page()) 
  768. //Must have two seperate branches so that we don't evaluate it as a page 
  769. if($this->opt['bhome_display']) 
  770. $this->do_front_page(); 
  771. //For posts 
  772. else if(is_singular()) 
  773. //For attachments 
  774. if(is_attachment()) 
  775. $this->do_attachment(); 
  776. //For all other post types 
  777. else 
  778. $this->do_post(get_post()); 
  779. //For searches 
  780. else if(is_search()) 
  781. $this->do_search(); 
  782. //For author pages 
  783. else if(is_author()) 
  784. $this->do_author(); 
  785. //For archives 
  786. else if(is_archive()) 
  787. $type = $wp_query->get_queried_object(); 
  788. //We need the type for later, so save it 
  789. $type_str = get_query_var('post_type'); 
  790. //May be an array, if so, rewind the iterator and grab first item 
  791. if(is_array($type_str)) 
  792. $type_str = reset($type_str); 
  793. //For date based archives 
  794. if(is_date()) 
  795. $this->do_archive_by_date($this->get_type_string_query_var()); 
  796. $this->type_archive($type); 
  797. //If we have a post type archive, and it does not have a root page generate the archive 
  798. else if(is_post_type_archive() && !isset($type->taxonomy) 
  799. && (!is_numeric($this->opt['apost_' . $type_str . '_root']) || $this->opt['bpost_' . $type_str . '_archive_display'])) 
  800. $this->do_archive_by_post_type(); 
  801. //For taxonomy based archives 
  802. else if(is_category() || is_tag() || is_tax()) 
  803. $this->do_archive_by_term(); 
  804. $this->type_archive($type); 
  805. else 
  806. $this->type_archive($type); 
  807. //For 404 pages 
  808. else if(is_404()) 
  809. $this->do_404(); 
  810. else 
  811. //If we are here, there may have been problems detecting the type 
  812. $type = $wp_query->get_queried_object(); 
  813. //If it looks, walks, and quacks like a taxonomy, treat is as one 
  814. if(isset($type->taxonomy)) 
  815. $this->do_archive_by_term(); 
  816. $this->type_archive($type); 
  817. //We always do the home link last, unless on the frontpage 
  818. if(!is_front_page()) 
  819. $this->do_root(); 
  820. $this->do_home(); 
  821. //Do any actions if necessary, we past through the current object instance to keep life simple 
  822. do_action('bcn_after_fill', $this); 
  823. /** 
  824. * This function will either set the order of the trail to reverse key  
  825. * order, or make sure it is forward key ordered. 
  826. *  
  827. * @param bool $reverse[optional] Whether to reverse the trail or not. 
  828. */ 
  829. protected function order($reverse = false) 
  830. if($reverse) 
  831. //Since there may be multiple calls our trail may be in a non-standard order 
  832. ksort($this->breadcrumbs); 
  833. else 
  834. //For normal opperation we must reverse the array by key 
  835. krsort($this->breadcrumbs); 
  836. /** 
  837. * This functions outputs or returns the breadcrumb trail in string form. 
  838. * 
  839. * @return void Void if Option to print out breadcrumb trail was chosen. 
  840. * @return string String-Data of breadcrumb trail. 
  841. * @param bool $return Whether to return data or to echo it. 
  842. * @param bool $linked[optional] Whether to allow hyperlinks in the trail or not. 
  843. * @param bool $reverse[optional] Whether to reverse the output or not. 
  844. *  
  845. * TODO: Fold display and display_list together, two functions are very simmilar  
  846. */ 
  847. public function display($return = false, $linked = true, $reverse = false) 
  848. //Set trail order based on reverse flag 
  849. $this->order($reverse); 
  850. //Initilize the string which will hold the assembled trail 
  851. $trail_str = ''; 
  852. $position = 1; 
  853. //The main compiling loop 
  854. foreach($this->breadcrumbs as $key => $breadcrumb) 
  855. //We do different things for the separator based on the breadcrumb order 
  856. if($reverse) 
  857. //Add in the separator only if we are the 2nd or greater element 
  858. if($key > 0) 
  859. $trail_str .= $this->opt['hseparator']; 
  860. else 
  861. //Only show the separator when necessary 
  862. if($key < count($this->breadcrumbs) - 1) 
  863. $trail_str .= $this->opt['hseparator']; 
  864. //Trim titles, if needed 
  865. if($this->opt['blimit_title'] && $this->opt['amax_title_length'] > 0) 
  866. //Trim the breadcrumb's title 
  867. $breadcrumb->title_trim($this->opt['amax_title_length']); 
  868. //Place in the breadcrumb's assembled elements 
  869. $trail_str .= $breadcrumb->assemble($linked, $position); 
  870. $position++; 
  871. //Should we return or echo the assembled trail? 
  872. if($return) 
  873. return $trail_str; 
  874. else 
  875. //Helps track issues, please don't remove it 
  876. $credits = "<!-- Breadcrumb NavXT " . $this::version . " -->\n"; 
  877. echo $credits . $trail_str; 
  878. /** 
  879. * This functions outputs or returns the breadcrumb trail in list form. 
  880. * 
  881. * @return void Void if option to print out breadcrumb trail was chosen. 
  882. * @return string String version of the breadcrumb trail. 
  883. * @param bool $return Whether to return data or to echo it. 
  884. * @param bool $linked[optional] Whether to allow hyperlinks in the trail or not. 
  885. * @param bool $reverse[optional] Whether to reverse the output or not.  
  886. *  
  887. * TODO: Can probably write this one in a smarter way now 
  888. */ 
  889. public function display_list($return = false, $linked = true, $reverse = false) 
  890. //Set trail order based on reverse flag 
  891. $this->order($reverse); 
  892. //Initilize the string which will hold the assembled trail 
  893. $trail_str = ''; 
  894. $position = 1; 
  895. //The main compiling loop 
  896. foreach($this->breadcrumbs as $key => $breadcrumb) 
  897. $li_class = ''; 
  898. //On the first run we need to add in a class for the home breadcrumb 
  899. if($trail_str === '') 
  900. $li_class .= ' class="home'; 
  901. if($key === 0) 
  902. $li_class .= ' current_item'; 
  903. $li_class .= '"'; 
  904. //If we are on the current item there are some things that must be done 
  905. else if($key === 0) 
  906. //Add in a class for current_item 
  907. $li_class .= ' class="current_item"'; 
  908. //Filter li_attributes adding attributes to the li element 
  909. $li_attribs = apply_filters('bcn_li_attributes', $li_class, $breadcrumb->type, $breadcrumb->get_id()); 
  910. //Trim titles, if requested 
  911. if($this->opt['blimit_title'] && $this->opt['amax_title_length'] > 0) 
  912. //Trim the breadcrumb's title 
  913. $breadcrumb->title_trim($this->opt['amax_title_length']); 
  914. //Assemble the breadrumb and wrap with li's 
  915. $trail_str .= sprintf("<li%s>%s</li>\n", $li_attribs, $breadcrumb->assemble($linked, $position)); 
  916. $position++; 
  917. //Should we return or echo the assembled trail? 
  918. if($return) 
  919. return $trail_str; 
  920. else 
  921. //Helps track issues, please don't remove it 
  922. $credits = "<!-- Breadcrumb NavXT " . $this::version . " -->\n"; 
  923. echo $credits . $trail_str; 
.