/bp-core/bp-core-template-loader.php

  1. <?php 
  2. /** 
  3. * BuddyPress Template Functions. 
  4. * 
  5. * This file contains functions necessary to mirror the WordPress core template 
  6. * loading process. Many of those functions are not filterable, and even then 
  7. * would not be robust enough to predict where BuddyPress templates might exist. 
  8. * 
  9. * @package BuddyPress 
  10. * @subpackage TemplateFunctions 
  11. * @since 1.7.0 
  12. */ 
  13.  
  14. // Exit if accessed directly. 
  15. defined( 'ABSPATH' ) || exit; 
  16.  
  17. /** 
  18. * Get a BuddyPress template part for display in a theme. 
  19. * 
  20. * @since 1.7.0 
  21. * 
  22. * @param string $slug Template part slug. Used to generate filenames,  
  23. * eg 'friends' for 'friends.php'. 
  24. * @param string|null $name Optional. Template part name. Used to generate 
  25. * secondary filenames, eg 'personal' for 'activity-personal.php'. 
  26. * @return string Path to located template. See {@link bp_locate_template()}. 
  27. */ 
  28. function bp_get_template_part( $slug, $name = null ) { 
  29.  
  30. /** 
  31. * Fires at the start of bp_get_template_part(). 
  32. * 
  33. * This is a variable hook that is dependent on the slug passed in. 
  34. * 
  35. * @since 1.7.0 
  36. * 
  37. * @param string $slug Template part slug requested. 
  38. * @param string $name Template part name requested. 
  39. */ 
  40. do_action( 'get_template_part_' . $slug, $slug, $name ); 
  41.  
  42. // Setup possible parts. 
  43. $templates = array(); 
  44. if ( isset( $name ) ) { 
  45. $templates[] = $slug . '-' . $name . '.php'; 
  46. $templates[] = $slug . '.php'; 
  47.  
  48. /** 
  49. * Filters the template parts to be loaded. 
  50. * 
  51. * @since 1.7.0 
  52. * 
  53. * @param array $templates Array of templates located. 
  54. * @param string $slug Template part slug requested. 
  55. * @param string $name Template part name requested. 
  56. */ 
  57. $templates = apply_filters( 'bp_get_template_part', $templates, $slug, $name ); 
  58.  
  59. // Return the part that is found. 
  60. return bp_locate_template( $templates, true, false ); 
  61.  
  62. /** 
  63. * Get an asset template part. 
  64. * 
  65. * Basically the same as {@link bp_get_template_part()}, but with 'assets/' 
  66. * prepended to the slug. 
  67. * 
  68. * @since 2.6.0 
  69. * 
  70. * @see bp_get_template_part() for full documentation. 
  71. * 
  72. * @param string $slug Template slug. 
  73. * @param string|null $name Template name. 
  74. * @return string 
  75. */ 
  76. function bp_get_asset_template_part( $slug, $name = null ) { 
  77. return bp_get_template_part( "assets/{$slug}", $name ); 
  78.  
  79. /** 
  80. * Retrieve the name of the highest priority template file that exists. 
  81. * 
  82. * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which 
  83. * inherit from a parent theme can just overload one file. If the template is 
  84. * not found in either of those, it looks in the theme-compat folder last. 
  85. * 
  86. * @since 1.7.0 
  87. * 
  88. * @param string|array $template_names Template file(s) to search for, in order. 
  89. * @param bool $load Optional. If true, the template file will be loaded when 
  90. * found. If false, the path will be returned. Default: false. 
  91. * @param bool $require_once Optional. Whether to require_once or require. Has 
  92. * no effect if $load is false. Default: true. 
  93. * @return string The template filename if one is located. 
  94. */ 
  95. function bp_locate_template( $template_names, $load = false, $require_once = true ) { 
  96.  
  97. // Bail when there are no templates to locate 
  98. if ( empty( $template_names ) ) { 
  99. return false; 
  100.  
  101. // No file found yet. 
  102. $located = false; 
  103. $template_locations = bp_get_template_stack(); 
  104.  
  105. // Try to find a template file. 
  106. foreach ( (array) $template_names as $template_name ) { 
  107.  
  108. // Continue if template is empty. 
  109. if ( empty( $template_name ) ) { 
  110. continue; 
  111.  
  112. // Trim off any slashes from the template name. 
  113. $template_name = ltrim( $template_name, '/' ); 
  114.  
  115. // Loop through template stack. 
  116. foreach ( (array) $template_locations as $template_location ) { 
  117.  
  118. // Continue if $template_location is empty. 
  119. if ( empty( $template_location ) ) { 
  120. continue; 
  121.  
  122. // Check child theme first. 
  123. if ( file_exists( trailingslashit( $template_location ) . $template_name ) ) { 
  124. $located = trailingslashit( $template_location ) . $template_name; 
  125. break 2; 
  126.  
  127. /** 
  128. * This action exists only to follow the standard BuddyPress coding convention,  
  129. * and should not be used to short-circuit any part of the template locator. 
  130. * 
  131. * If you want to override a specific template part, please either filter 
  132. * 'bp_get_template_part' or add a new location to the template stack. 
  133. */ 
  134. do_action( 'bp_locate_template', $located, $template_name, $template_names, $template_locations, $load, $require_once ); 
  135.  
  136. /** 
  137. * Filter here to allow/disallow template loading. 
  138. * 
  139. * @since 2.5.0 
  140. * 
  141. * @param bool $value True to load the template, false otherwise. 
  142. */ 
  143. $load_template = (bool) apply_filters( 'bp_locate_template_and_load', true ); 
  144.  
  145. if ( $load_template && $load && ! empty( $located ) ) { 
  146. load_template( $located, $require_once ); 
  147.  
  148. return $located; 
  149.  
  150. /** 
  151. * Get file data of the highest priority asset that exists. 
  152. * 
  153. * Similar to {@link bp_locate_template()}, but for files like CSS and JS. 
  154. * 
  155. * @since 2.6.0 
  156. * 
  157. * @param string $filename Relative filename to search for. 
  158. * @return array|bool Array of asset data if one is located (includes absolute filepath and URI). 
  159. * Boolean false on failure. 
  160. */ 
  161. function bp_locate_template_asset( $filename ) { 
  162. // Ensure assets can be located when running from /src/. 
  163. if ( defined( 'BP_SOURCE_SUBDIRECTORY' ) && 'src' === BP_SOURCE_SUBDIRECTORY ) { 
  164. $filename = str_replace( '.min', '', $filename ); 
  165.  
  166. // Use bp_locate_template() to find our asset. 
  167. $located = bp_locate_template( $filename, false ); 
  168. if ( false === $located ) { 
  169. return false; 
  170.  
  171. // Set up data array. 
  172. $data = array(); 
  173. $data['file'] = $data['uri'] = $located; 
  174.  
  175. $find = array( 
  176. get_theme_root(),  
  177. bp_get_theme_compat_dir() 
  178. ); 
  179.  
  180. $replace = array( 
  181. get_theme_root_uri(),  
  182. bp_get_theme_compat_url() 
  183. ); 
  184.  
  185. // Make sure URI path is relative to site URL. 
  186. $data['uri'] = str_replace( $find, $replace, $data['uri'] ); 
  187.  
  188. return $data; 
  189.  
  190. /** 
  191. * Register a new template stack location. 
  192. * 
  193. * This allows for templates to live in places beyond just the parent/child 
  194. * relationship, to allow for custom template locations. Used in conjunction 
  195. * with bp_locate_template(), this allows for easy template overrides. 
  196. * 
  197. * @since 1.7.0 
  198. * 
  199. * @param string $location_callback Callback function that returns the stack location. 
  200. * @param int $priority Optional. The priority parameter as passed to 
  201. * add_filter(). Default: 10. 
  202. * @return bool See {@link add_filter()}. 
  203. */ 
  204. function bp_register_template_stack( $location_callback = '', $priority = 10 ) { 
  205.  
  206. // Bail if no location, or function/method is not callable. 
  207. if ( empty( $location_callback ) || ! is_callable( $location_callback ) ) { 
  208. return false; 
  209.  
  210. // Add location callback to template stack. 
  211. return add_filter( 'bp_template_stack', $location_callback, (int) $priority ); 
  212.  
  213. /** 
  214. * Deregister a previously registered template stack location. 
  215. * 
  216. * @since 1.7.0 
  217. * 
  218. * @see bp_register_template_stack() 
  219. * 
  220. * @param string $location_callback Callback function that returns the stack location. 
  221. * @param int $priority Optional. The priority parameter passed to 
  222. * {@link bp_register_template_stack()}. Default: 10. 
  223. * @return bool See {@link remove_filter()}. 
  224. */ 
  225. function bp_deregister_template_stack( $location_callback = '', $priority = 10 ) { 
  226.  
  227. // Bail if no location, or function/method is not callable. 
  228. if ( empty( $location_callback ) || ! is_callable( $location_callback ) ) { 
  229. return false; 
  230.  
  231. // Add location callback to template stack. 
  232. return remove_filter( 'bp_template_stack', $location_callback, (int) $priority ); 
  233.  
  234. /** 
  235. * Get the "template stack", a list of registered directories where templates can be found. 
  236. * 
  237. * Calls the functions added to the 'bp_template_stack' filter hook, and return 
  238. * an array of the template locations. 
  239. * 
  240. * @since 1.7.0 
  241. * 
  242. * @see bp_register_template_stack() 
  243. * 
  244. * @global array $wp_filter Stores all of the filters. 
  245. * @global array $merged_filters Merges the filter hooks using this function. 
  246. * @global array $wp_current_filter Stores the list of current filters with 
  247. * the current one last. 
  248. * @return array The filtered value after all hooked functions are applied to it. 
  249. */ 
  250. function bp_get_template_stack() { 
  251. global $wp_filter, $merged_filters, $wp_current_filter; 
  252.  
  253. // Setup some default variables. 
  254. $tag = 'bp_template_stack'; 
  255. $args = $stack = array(); 
  256.  
  257. // Add 'bp_template_stack' to the current filter array. 
  258. $wp_current_filter[] = $tag; 
  259.  
  260. // Sort. 
  261. if ( class_exists( 'WP_Hook' ) ) { 
  262. $filter = $wp_filter[ $tag ]->callbacks; 
  263. } else { 
  264. $filter = &$wp_filter[ $tag ]; 
  265.  
  266. if ( ! isset( $merged_filters[ $tag ] ) ) { 
  267. ksort( $filter ); 
  268. $merged_filters[ $tag ] = true; 
  269.  
  270. // Ensure we're always at the beginning of the filter array. 
  271. reset( $filter ); 
  272.  
  273. // Loop through 'bp_template_stack' filters, and call callback functions. 
  274. do { 
  275. foreach( (array) current( $filter ) as $the_ ) { 
  276. if ( ! is_null( $the_['function'] ) ) { 
  277. $args[1] = $stack; 
  278. $stack[] = call_user_func_array( $the_['function'], array_slice( $args, 1, (int) $the_['accepted_args'] ) ); 
  279. } while ( next( $filter ) !== false ); 
  280.  
  281. // Remove 'bp_template_stack' from the current filter array. 
  282. array_pop( $wp_current_filter ); 
  283.  
  284. // Remove empties and duplicates. 
  285. $stack = array_unique( array_filter( $stack ) ); 
  286.  
  287. /** 
  288. * Filters the "template stack" list of registered directories where templates can be found. 
  289. * 
  290. * @since 1.7.0 
  291. * 
  292. * @param array $stack Array of registered directories for template locations. 
  293. */ 
  294. return (array) apply_filters( 'bp_get_template_stack', $stack ) ; 
  295.  
  296. /** 
  297. * Put a template part into an output buffer, and return it. 
  298. * 
  299. * @since 1.7.0 
  300. * 
  301. * @see bp_get_template_part() for a description of $slug and $name params. 
  302. * 
  303. * @param string $slug See {@link bp_get_template_part()}. 
  304. * @param string|null $name See {@link bp_get_template_part()}. 
  305. * @param bool $echo If true, template content will be echoed. If false,  
  306. * returned. Default: true. 
  307. * @return string|null If $echo, returns the template content. 
  308. */ 
  309. function bp_buffer_template_part( $slug, $name = null, $echo = true ) { 
  310. ob_start(); 
  311.  
  312. // Remove 'bp_replace_the_content' filter to prevent infinite loops. 
  313. remove_filter( 'the_content', 'bp_replace_the_content' ); 
  314.  
  315. bp_get_template_part( $slug, $name ); 
  316.  
  317. // Remove 'bp_replace_the_content' filter to prevent infinite loops. 
  318. add_filter( 'the_content', 'bp_replace_the_content' ); 
  319.  
  320. // Get the output buffer contents. 
  321. $output = ob_get_clean(); 
  322.  
  323. // Echo or return the output buffer contents. 
  324. if ( true === $echo ) { 
  325. echo $output; 
  326. } else { 
  327. return $output; 
  328.  
  329. /** 
  330. * Retrieve the path to a template. 
  331. * 
  332. * Used to quickly retrieve the path of a template without including the file 
  333. * extension. It will also check the parent theme and theme-compat theme with 
  334. * the use of {@link bp_locate_template()}. Allows for more generic template 
  335. * locations without the use of the other get_*_template() functions. 
  336. * 
  337. * @since 1.7.0 
  338. * 
  339. * @param string $type Filename without extension. 
  340. * @param array $templates An optional list of template candidates. 
  341. * @return string Full path to file. 
  342. */ 
  343. function bp_get_query_template( $type, $templates = array() ) { 
  344. $type = preg_replace( '|[^a-z0-9-]+|', '', $type ); 
  345.  
  346. if ( empty( $templates ) ) { 
  347. $templates = array( "{$type}.php" ); 
  348.  
  349. /** 
  350. * Filters possible file paths to check for for a template. 
  351. * 
  352. * This is a variable filter based on the type passed into 
  353. * bp_get_query_template. 
  354. * 
  355. * @since 1.7.0 
  356. * 
  357. * @param array $templates Array of template files already prepared. 
  358. */ 
  359. $templates = apply_filters( "bp_get_{$type}_template", $templates ); 
  360.  
  361. // Filter possible templates, try to match one, and set any BuddyPress theme 
  362. // compat properties so they can be cross-checked later. 
  363. $templates = bp_set_theme_compat_templates( $templates ); 
  364. $template = bp_locate_template( $templates ); 
  365. $template = bp_set_theme_compat_template( $template ); 
  366.  
  367. /** 
  368. * Filters the path to a template file. 
  369. * 
  370. * This is a variable filter based on the type passed into 
  371. * bp_get_query_template. 
  372. * 
  373. * @since 1.7.0 
  374. * 
  375. * @param string $template Path to the most appropriate found template file. 
  376. */ 
  377. return apply_filters( "bp_{$type}_template", $template ); 
  378.  
  379. /** 
  380. * Get the possible subdirectories to check for templates in. 
  381. * 
  382. * @since 1.7.0 
  383. * 
  384. * @param array $templates Templates we are looking for. 
  385. * @return array Possible subfolders to look in. 
  386. */ 
  387. function bp_get_template_locations( $templates = array() ) { 
  388. $locations = array( 
  389. 'buddypress',  
  390. 'community',  
  391. '' 
  392. ); 
  393.  
  394. /** 
  395. * Filters the possible subdirectories to check for templates in. 
  396. * 
  397. * @since 1.7.0 
  398. * 
  399. * @param array $locations Array of subfolders to look in. 
  400. * @param array $templates Array of templates we are looking for. 
  401. */ 
  402. return apply_filters( 'bp_get_template_locations', $locations, $templates ); 
  403.  
  404. /** 
  405. * Add template locations to template files being searched for. 
  406. * 
  407. * @since 1.7.0 
  408. * 
  409. * @param array $stacks Array of template locations. 
  410. * @return array Array of all template locations registered so far. 
  411. */ 
  412. function bp_add_template_stack_locations( $stacks = array() ) { 
  413. $retval = array(); 
  414.  
  415. // Get alternate locations. 
  416. $locations = bp_get_template_locations(); 
  417.  
  418. // Loop through locations and stacks and combine. 
  419. foreach ( (array) $stacks as $stack ) { 
  420. foreach ( (array) $locations as $custom_location ) { 
  421. $retval[] = untrailingslashit( trailingslashit( $stack ) . $custom_location ); 
  422.  
  423. /** 
  424. * Filters the template locations to template files being searched for. 
  425. * 
  426. * @since 1.7.0 
  427. * 
  428. * @param array $value Array of all template locations registered so far. 
  429. * @param array $stacks Array of template locations. 
  430. */ 
  431. return apply_filters( 'bp_add_template_stack_locations', array_unique( $retval ), $stacks ); 
  432.  
  433. /** 
  434. * Add checks for BuddyPress conditions to 'parse_query' action. 
  435. * 
  436. * @since 1.7.0 
  437. * 
  438. * @param WP_Query $posts_query WP_Query object. 
  439. */ 
  440. function bp_parse_query( $posts_query ) { 
  441.  
  442. // Bail if $posts_query is not the main loop. 
  443. if ( ! $posts_query->is_main_query() ) { 
  444. return; 
  445.  
  446. // Bail if filters are suppressed on this query. 
  447. if ( true == $posts_query->get( 'suppress_filters' ) ) { 
  448. return; 
  449.  
  450. // Bail if in admin. 
  451. if ( is_admin() ) { 
  452. return; 
  453.  
  454. /** 
  455. * Fires at the end of the bp_parse_query function. 
  456. * 
  457. * Allow BuddyPress components to parse the main query. 
  458. * 
  459. * @since 1.7.0 
  460. * 
  461. * @param WP_Query $posts_query WP_Query instance. Passed by reference. 
  462. */ 
  463. do_action_ref_array( 'bp_parse_query', array( &$posts_query ) ); 
  464.  
  465. /** 
  466. * Possibly intercept the template being loaded. 
  467. * 
  468. * Listens to the 'template_include' filter and waits for any BuddyPress specific 
  469. * template condition to be met. If one is met and the template file exists,  
  470. * it will be used; otherwise. 
  471. * 
  472. * Note that the _edit() checks are ahead of their counterparts, to prevent them 
  473. * from being stomped on accident. 
  474. * 
  475. * @since 1.7.0 
  476. * 
  477. * @param string $template The path to the template file that is being used. 
  478. * @return string The path to the template file that is being used. 
  479. */ 
  480. function bp_template_include_theme_supports( $template = '' ) { 
  481.  
  482. /** 
  483. * Filters whether or not to override the template being loaded in parent/child themes. 
  484. * 
  485. * @since 1.7.0 
  486. * 
  487. * @param bool $value Whether or not there is a file override. Default false. 
  488. * @param string $template The path to the template file that is being used. 
  489. */ 
  490. $new_template = apply_filters( 'bp_get_root_template', false, $template ); 
  491.  
  492. // A BuddyPress template file was located, so override the WordPress 
  493. // template and use it to switch off BuddyPress's theme compatibility. 
  494. if ( ! empty( $new_template ) ) { 
  495. $template = bp_set_template_included( $new_template ); 
  496.  
  497. /** 
  498. * Filters the final template being loaded in parent/child themes. 
  499. * 
  500. * @since 1.7.0 
  501. * 
  502. * @param string $template The path to the template file that is being used. 
  503. */ 
  504. return apply_filters( 'bp_template_include_theme_supports', $template ); 
  505.  
  506. /** 
  507. * Set the included template. 
  508. * 
  509. * @since 1.8.0 
  510. * 
  511. * @param mixed $template Default: false. 
  512. * @return mixed False if empty. Template name if template included. 
  513. */ 
  514. function bp_set_template_included( $template = false ) { 
  515. buddypress()->theme_compat->found_template = $template; 
  516.  
  517. return buddypress()->theme_compat->found_template; 
  518.  
  519. /** 
  520. * Is a BuddyPress template being included? 
  521. * 
  522. * @since 1.8.0 
  523. * 
  524. * @return bool True if yes, false if no. 
  525. */ 
  526. function bp_is_template_included() { 
  527. return ! empty( buddypress()->theme_compat->found_template ); 
  528.  
  529. /** 
  530. * Attempt to load a custom BP functions file, similar to each themes functions.php file. 
  531. * 
  532. * @since 1.7.0 
  533. * 
  534. * @global string $pagenow 
  535. */ 
  536. function bp_load_theme_functions() { 
  537. global $pagenow, $wp_query; 
  538.  
  539. // Do not load our custom BP functions file if theme compat is disabled. 
  540. if ( ! bp_use_theme_compat_with_current_theme() ) { 
  541. return; 
  542.  
  543. // Do not include on BuddyPress deactivation. 
  544. if ( bp_is_deactivation() ) { 
  545. return; 
  546.  
  547. // If the $wp_query global is empty (the main query has not been run,  
  548. // or has been reset), load_template() will fail at setting certain 
  549. // global values. This does not happen on a normal page load, but can 
  550. // cause problems when running automated tests. 
  551. if ( ! is_a( $wp_query, 'WP_Query' ) ) { 
  552. return; 
  553.  
  554. // Only include if not installing or if activating via wp-activate.php. 
  555. if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { 
  556. bp_locate_template( 'buddypress-functions.php', true ); 
  557.  
  558. /** 
  559. * Get the templates to use as the endpoint for BuddyPress template parts. 
  560. * 
  561. * @since 1.7.0 
  562. * @since 2.4.0 Added singular.php to stack 
  563. * 
  564. * @return array Array of possible root level wrapper template files. 
  565. */ 
  566. function bp_get_theme_compat_templates() { 
  567. return bp_get_query_template( 'buddypress', array( 
  568. 'plugin-buddypress.php',  
  569. 'buddypress.php',  
  570. 'community.php',  
  571. 'generic.php',  
  572. 'page.php',  
  573. 'single.php',  
  574. 'singular.php',  
  575. 'index.php' 
  576. ) ); 
.