/bp-core/bp-core-theme-compatibility.php

  1. <?php 
  2. /** 
  3. * BuddyPress Core Theme Compatibility. 
  4. * 
  5. * @package BuddyPress 
  6. * @subpackage ThemeCompatibility 
  7. * @since 1.7.0 
  8. */ 
  9.  
  10. // Exit if accessed directly. 
  11. defined( 'ABSPATH' ) || exit; 
  12.  
  13. /** Theme Compat **************************************************************/ 
  14.  
  15. /** 
  16. * What follows is an attempt at intercepting the natural page load process 
  17. * to replace the_content() with the appropriate BuddyPress content. 
  18. * 
  19. * To do this, BuddyPress does several direct manipulations of global variables 
  20. * and forces them to do what they are not supposed to be doing. 
  21. * 
  22. * Don't try anything you're about to witness here, at home. Ever. 
  23. */ 
  24.  
  25. /** Functions *****************************************************************/ 
  26.  
  27. /** 
  28. * Set up the default theme compat theme. 
  29. * 
  30. * @since 1.7.0 
  31. * 
  32. * @param string $theme Optional. The unique ID identifier of a theme package. 
  33. */ 
  34. function bp_setup_theme_compat( $theme = '' ) { 
  35. $bp = buddypress(); 
  36.  
  37. // Make sure theme package is available, set to default if not. 
  38. if ( ! isset( $bp->theme_compat->packages[$theme] ) || ! is_a( $bp->theme_compat->packages[$theme], 'BP_Theme_Compat' ) ) { 
  39. $theme = 'legacy'; 
  40.  
  41. // Set the active theme compat theme. 
  42. $bp->theme_compat->theme = $bp->theme_compat->packages[$theme]; 
  43.  
  44. /** 
  45. * Get the ID of the theme package being used. 
  46. * 
  47. * This can be filtered or set manually. Tricky theme authors can override the 
  48. * default and include their own BuddyPress compatibility layers for their themes. 
  49. * 
  50. * @since 1.7.0 
  51. * 
  52. * @return string ID of the theme package in use. 
  53. */ 
  54. function bp_get_theme_compat_id() { 
  55.  
  56. /** 
  57. * Filters the ID of the theme package being used. 
  58. * 
  59. * @since 1.7.0 
  60. * 
  61. * @param string $id ID of the theme package in use. 
  62. */ 
  63. return apply_filters( 'bp_get_theme_compat_id', buddypress()->theme_compat->theme->id ); 
  64.  
  65. /** 
  66. * Get the name of the theme package being used. 
  67. * 
  68. * This can be filtered or set manually. Tricky theme authors can override the 
  69. * default and include their own BuddyPress compatibility layers for their themes. 
  70. * 
  71. * @since 1.7.0 
  72. * 
  73. * @return string Name of the theme package currently in use. 
  74. */ 
  75. function bp_get_theme_compat_name() { 
  76.  
  77. /** 
  78. * Filters the name of the theme package being used. 
  79. * 
  80. * @since 1.7.0 
  81. * 
  82. * @param string $name Name of the theme package in use. 
  83. */ 
  84. return apply_filters( 'bp_get_theme_compat_name', buddypress()->theme_compat->theme->name ); 
  85.  
  86. /** 
  87. * Get the version of the theme package being used. 
  88. * 
  89. * This can be filtered or set manually. Tricky theme authors can override the 
  90. * default and include their own BuddyPress compatibility layers for their themes. 
  91. * 
  92. * @since 1.7.0 
  93. * 
  94. * @return string The version string of the theme package currently in use. 
  95. */ 
  96. function bp_get_theme_compat_version() { 
  97.  
  98. /** 
  99. * Filters the version of the theme package being used. 
  100. * 
  101. * @since 1.7.0 
  102. * 
  103. * @param string $version The version string of the theme package in use. 
  104. */ 
  105. return apply_filters( 'bp_get_theme_compat_version', buddypress()->theme_compat->theme->version ); 
  106.  
  107. /** 
  108. * Get the absolute path of the theme package being used. 
  109. * 
  110. * Or set manually. Tricky theme authors can override the default and include 
  111. * their own BuddyPress compatibility layers for their themes. 
  112. * 
  113. * @since 1.7.0 
  114. * 
  115. * @return string The absolute path of the theme package currently in use. 
  116. */ 
  117. function bp_get_theme_compat_dir() { 
  118.  
  119. /** 
  120. * Filters the absolute path of the theme package being used. 
  121. * 
  122. * @since 1.7.0 
  123. * 
  124. * @param string $dir The absolute path of the theme package in use. 
  125. */ 
  126. return apply_filters( 'bp_get_theme_compat_dir', buddypress()->theme_compat->theme->dir ); 
  127.  
  128. /** 
  129. * Get the URL of the theme package being used. 
  130. * 
  131. * This can be filtered, or set manually. Tricky theme authors can override 
  132. * the default and include their own BuddyPress compatibility layers for their 
  133. * themes. 
  134. * 
  135. * @since 1.7.0 
  136. * 
  137. * @return string URL of the theme package currently in use. 
  138. */ 
  139. function bp_get_theme_compat_url() { 
  140.  
  141. /** 
  142. * Filters the URL of the theme package being used. 
  143. * 
  144. * @since 1.7.0 
  145. * 
  146. * @param string $url URL of the theme package in use. 
  147. */ 
  148. return apply_filters( 'bp_get_theme_compat_url', buddypress()->theme_compat->theme->url ); 
  149.  
  150. /** 
  151. * Should we use theme compat for this theme? 
  152. * 
  153. * If the current theme's need for theme compat hasn't yet been detected, we 
  154. * do so using bp_detect_theme_compat_with_current_theme(). 
  155. * 
  156. * @since 1.9.0 
  157. * 
  158. * @return bool True if the current theme needs theme compatibility. 
  159. */ 
  160. function bp_use_theme_compat_with_current_theme() { 
  161. if ( ! isset( buddypress()->theme_compat->use_with_current_theme ) ) { 
  162. bp_detect_theme_compat_with_current_theme(); 
  163.  
  164. /** 
  165. * Filters whether or not to use theme compat for the active theme. 
  166. * 
  167. * @since 1.9.0 
  168. * 
  169. * @param bool $use_with_current_theme True if the current theme needs theme compatibility. 
  170. */ 
  171. return apply_filters( 'bp_use_theme_compat_with_current_theme', buddypress()->theme_compat->use_with_current_theme ); 
  172.  
  173. /** 
  174. * Set our flag to determine whether theme compat should be enabled. 
  175. * 
  176. * Theme compat is disabled when a theme meets one of the following criteria: 
  177. * 1) It declares BP support with add_theme_support( 'buddypress' ) 
  178. * 2) It is bp-default, or a child theme of bp-default 
  179. * 3) A legacy template is found at members/members-loop.php. This is a 
  180. * fallback check for themes that were derived from bp-default, and have 
  181. * not been updated for BP 1.7+; we make the assumption that any theme in 
  182. * this category will have the members-loop.php template, and so use its 
  183. * presence as an indicator that theme compatibility is not required 
  184. * 
  185. * @since 1.9.0 
  186. * 
  187. * @return bool True if the current theme needs theme compatibility. 
  188. */ 
  189. function bp_detect_theme_compat_with_current_theme() { 
  190. if ( isset( buddypress()->theme_compat->use_with_current_theme ) ) { 
  191. return buddypress()->theme_compat->use_with_current_theme; 
  192.  
  193. // Theme compat enabled by default. 
  194. $theme_compat = true; 
  195.  
  196. // If the theme supports 'buddypress', bail. 
  197. if ( current_theme_supports( 'buddypress' ) ) { 
  198. $theme_compat = false; 
  199.  
  200. // If the theme doesn't support BP, do some additional checks. 
  201. } else { 
  202. // Bail if theme is a derivative of bp-default. 
  203. if ( in_array( 'bp-default', array( get_template(), get_stylesheet() ) ) ) { 
  204. $theme_compat = false; 
  205.  
  206. // Brute-force check for a BP template. 
  207. // Examples are clones of bp-default. 
  208. } elseif ( locate_template( 'members/members-loop.php', false, false ) ) { 
  209. $theme_compat = false; 
  210.  
  211. // Set a flag in the buddypress() singleton so we don't have to run this again. 
  212. buddypress()->theme_compat->use_with_current_theme = $theme_compat; 
  213.  
  214. return $theme_compat; 
  215.  
  216. /** 
  217. * Is the current page using theme compatibility? 
  218. * 
  219. * @since 1.7.0 
  220. * 
  221. * @return bool True if the current page uses theme compatibility. 
  222. */ 
  223. function bp_is_theme_compat_active() { 
  224. $bp = buddypress(); 
  225.  
  226. if ( empty( $bp->theme_compat->active ) ) { 
  227. return false; 
  228.  
  229. return $bp->theme_compat->active; 
  230.  
  231. /** 
  232. * Set the flag that tells whether the current page is using theme compatibility. 
  233. * 
  234. * @since 1.7.0 
  235. * 
  236. * @param bool $set True to set the flag to true, false to set it to false. 
  237. * @return bool Returns the value of $set. 
  238. */ 
  239. function bp_set_theme_compat_active( $set = true ) { 
  240. buddypress()->theme_compat->active = $set; 
  241.  
  242. return (bool) buddypress()->theme_compat->active; 
  243.  
  244. /** 
  245. * Set the theme compat templates global. 
  246. * 
  247. * Stash possible template files for the current query. Useful if plugins want 
  248. * to override them, or see what files are being scanned for inclusion. 
  249. * 
  250. * @since 1.7.0 
  251. * 
  252. * @param array $templates The template stack. 
  253. * @return array The template stack (value of $templates). 
  254. */ 
  255. function bp_set_theme_compat_templates( $templates = array() ) { 
  256. buddypress()->theme_compat->templates = $templates; 
  257.  
  258. return buddypress()->theme_compat->templates; 
  259.  
  260. /** 
  261. * Set the theme compat template global. 
  262. * 
  263. * Stash the template file for the current query. Useful if plugins want 
  264. * to override it, or see what file is being included. 
  265. * 
  266. * @since 1.7.0 
  267. * 
  268. * @param string $template The template currently in use. 
  269. * @return string The template currently in use (value of $template). 
  270. */ 
  271. function bp_set_theme_compat_template( $template = '' ) { 
  272. buddypress()->theme_compat->template = $template; 
  273.  
  274. return buddypress()->theme_compat->template; 
  275.  
  276. /** 
  277. * Set the theme compat original_template global. 
  278. * 
  279. * Stash the original template file for the current query. Useful for checking 
  280. * if BuddyPress was able to find a more appropriate template. 
  281. * 
  282. * @since 1.7.0 
  283. * 
  284. * @param string $template The template originally selected by WP. 
  285. * @return string The template originally selected by WP (value of $template). 
  286. */ 
  287. function bp_set_theme_compat_original_template( $template = '' ) { 
  288. buddypress()->theme_compat->original_template = $template; 
  289.  
  290. return buddypress()->theme_compat->original_template; 
  291.  
  292. /** 
  293. * Set a theme compat feature 
  294. * 
  295. * @since 2.4.0 
  296. * 
  297. * @param string $theme_id The theme id (eg: legacy). 
  298. * @param array $feature An associative array (eg: array( name => 'feature_name', 'settings' => array() )). 
  299. */ 
  300. function bp_set_theme_compat_feature( $theme_id, $feature = array() ) { 
  301. if ( empty( $theme_id ) || empty( $feature['name'] ) ) { 
  302. return; 
  303.  
  304. // Get BuddyPress instance. 
  305. $bp = buddypress(); 
  306.  
  307. // Get current theme compat theme. 
  308. $theme_compat_theme = $bp->theme_compat->theme; 
  309.  
  310. // Bail if the Theme Compat theme is not in use. 
  311. if ( $theme_id !== bp_get_theme_compat_id() ) { 
  312. return; 
  313.  
  314. $features = $theme_compat_theme->__get( 'features' ); 
  315. if ( empty( $features ) ) { 
  316. $features = array(); 
  317.  
  318. // Bail if the feature is already registered or no settings were provided. 
  319. if ( isset( $features[ $feature['name'] ] ) || empty( $feature['settings'] ) ) { 
  320. return; 
  321.  
  322. // Add the feature. 
  323. $features[ $feature['name'] ] = (object) $feature['settings']; 
  324.  
  325. // The feature is attached to components. 
  326. if ( isset( $features[ $feature['name'] ]->components ) ) { 
  327. // Set the feature for each concerned component. 
  328. foreach ( (array) $features[ $feature['name'] ]->components as $component ) { 
  329. // The xProfile component is specific. 
  330. if ( 'xprofile' === $component ) { 
  331. $component = 'profile'; 
  332.  
  333. if ( isset( $bp->{$component} ) ) { 
  334. if ( isset( $bp->{$component}->features ) ) { 
  335. $bp->{$component}->features[] = $feature['name']; 
  336. } else { 
  337. $bp->{$component}->features = array( $feature['name'] ); 
  338.  
  339. // Finally update the theme compat features. 
  340. $theme_compat_theme->__set( 'features', $features ); 
  341.  
  342. /** 
  343. * Get a theme compat feature 
  344. * 
  345. * @since 2.4.0 
  346. * 
  347. * @param string $feature The feature (eg: cover_image). 
  348. * @return object The feature settings. 
  349. */ 
  350. function bp_get_theme_compat_feature( $feature = '' ) { 
  351. // Get current theme compat theme. 
  352. $theme_compat_theme = buddypress()->theme_compat->theme; 
  353.  
  354. // Get features. 
  355. $features = $theme_compat_theme->__get( 'features' ); 
  356.  
  357. if ( ! isset( $features[ $feature ] ) ) { 
  358. return false; 
  359.  
  360. return $features[ $feature ]; 
  361.  
  362. /** 
  363. * Setup the theme's features. 
  364. * 
  365. * Note: BP Legacy's buddypress-functions.php is not loaded in WP Administration 
  366. * as it's loaded using bp_locate_template(). That's why this function is here. 
  367. * 
  368. * @since 2.4.0 
  369. * 
  370. * @global string $content_width the content width of the theme 
  371. */ 
  372. function bp_register_theme_compat_default_features() { 
  373. global $content_width; 
  374.  
  375. // Do not set up default features on deactivation. 
  376. if ( bp_is_deactivation() ) { 
  377. return; 
  378.  
  379. // If the current theme doesn't need theme compat, bail at this point. 
  380. if ( ! bp_use_theme_compat_with_current_theme() ) { 
  381. return; 
  382.  
  383. // Make sure BP Legacy is the Theme Compat in use. 
  384. if ( 'legacy' !== bp_get_theme_compat_id() ) { 
  385. return; 
  386.  
  387. // Get the theme. 
  388. $current_theme = wp_get_theme(); 
  389. $theme_handle = $current_theme->get_stylesheet(); 
  390. $parent = $current_theme->parent(); 
  391.  
  392. if ( $parent ) { 
  393. $theme_handle = $parent->get_stylesheet(); 
  394.  
  395. /** 
  396. * Since Companion stylesheets, the $content_width is smaller 
  397. * than the width used by BuddyPress, so we need to manually set the 
  398. * content width for the concerned themes. 
  399. * 
  400. * Example: array( stylesheet => content width used by BuddyPress ) 
  401. */ 
  402. $bp_content_widths = array( 
  403. 'twentyfifteen' => 1300,  
  404. 'twentyfourteen' => 955,  
  405. 'twentythirteen' => 890,  
  406. ); 
  407.  
  408. // Default values. 
  409. $bp_content_width = (int) $content_width; 
  410. $bp_handle = 'bp-legacy-css'; 
  411.  
  412. // Specific to themes having companion stylesheets. 
  413. if ( isset( $bp_content_widths[ $theme_handle ] ) ) { 
  414. $bp_content_width = $bp_content_widths[ $theme_handle ]; 
  415. $bp_handle = 'bp-' . $theme_handle; 
  416.  
  417. if ( is_rtl() ) { 
  418. $bp_handle .= '-rtl'; 
  419.  
  420. $top_offset = 150; 
  421. $avatar_height = apply_filters( 'bp_core_avatar_full_height', $top_offset ); 
  422.  
  423. if ( $avatar_height > $top_offset ) { 
  424. $top_offset = $avatar_height; 
  425.  
  426. bp_set_theme_compat_feature( 'legacy', array( 
  427. 'name' => 'cover_image',  
  428. 'settings' => array( 
  429. 'components' => array( 'xprofile', 'groups' ),  
  430. 'width' => $bp_content_width,  
  431. 'height' => $top_offset + round( $avatar_height / 2 ),  
  432. 'callback' => 'bp_legacy_theme_cover_image',  
  433. 'theme_handle' => $bp_handle,  
  434. ),  
  435. ) ); 
  436.  
  437. /** 
  438. * Check whether a given template is the one that WP originally selected to display current page. 
  439. * 
  440. * @since 1.7.0 
  441. * 
  442. * @param string $template The template name to check. 
  443. * @return bool True if the value of $template is the same as the 
  444. * "original_template" originally selected by WP. Otherwise false. 
  445. */ 
  446. function bp_is_theme_compat_original_template( $template = '' ) { 
  447. $bp = buddypress(); 
  448.  
  449. if ( empty( $bp->theme_compat->original_template ) ) { 
  450. return false; 
  451.  
  452. return (bool) ( $bp->theme_compat->original_template == $template ); 
  453.  
  454. /** 
  455. * Register a new BuddyPress theme package in the active theme packages array. 
  456. * 
  457. * For an example of how this function is used, see: 
  458. * {@link BuddyPress::register_theme_packages()}. 
  459. * 
  460. * @since 1.7.0 
  461. * 
  462. * @see BP_Theme_Compat for a description of the $theme parameter arguments. 
  463. * 
  464. * @param array $theme See {@link BP_Theme_Compat}. 
  465. * @param bool $override If true, overrides whatever package is currently set. 
  466. * Default: true. 
  467. */ 
  468. function bp_register_theme_package( $theme = array(), $override = true ) { 
  469.  
  470. // Create new BP_Theme_Compat object from the $theme array. 
  471. if ( is_array( $theme ) ) { 
  472. $theme = new BP_Theme_Compat( $theme ); 
  473.  
  474. // Bail if $theme isn't a proper object. 
  475. if ( ! is_a( $theme, 'BP_Theme_Compat' ) ) { 
  476. return; 
  477.  
  478. // Load up BuddyPress. 
  479. $bp = buddypress(); 
  480.  
  481. // Only set if the theme package was not previously registered or if the 
  482. // override flag is set. 
  483. if ( empty( $bp->theme_compat->packages[$theme->id] ) || ( true === $override ) ) { 
  484. $bp->theme_compat->packages[$theme->id] = $theme; 
  485.  
  486. /** 
  487. * Populate various WordPress globals with dummy data to prevent errors. 
  488. * 
  489. * This dummy data is necessary because theme compatibility essentially fakes 
  490. * WordPress into thinking that there is content where, in fact, there is none 
  491. * (at least, no WordPress post content). By providing dummy data, we ensure 
  492. * that template functions - things like is_page() - don't throw errors. 
  493. * 
  494. * @since 1.7.0 
  495. * 
  496. * @global WP_Query $wp_query WordPress database access object. 
  497. * @global object $post Current post object. 
  498. * 
  499. * @param array $args Array of optional arguments. Arguments parallel the properties 
  500. * of {@link WP_Post}; see that class for more details. 
  501. */ 
  502. function bp_theme_compat_reset_post( $args = array() ) { 
  503. global $wp_query, $post; 
  504.  
  505. // Switch defaults if post is set. 
  506. if ( isset( $wp_query->post ) ) { 
  507. $dummy = wp_parse_args( $args, array( 
  508. 'ID' => $wp_query->post->ID,  
  509. 'post_status' => $wp_query->post->post_status,  
  510. 'post_author' => $wp_query->post->post_author,  
  511. 'post_parent' => $wp_query->post->post_parent,  
  512. 'post_type' => $wp_query->post->post_type,  
  513. 'post_date' => $wp_query->post->post_date,  
  514. 'post_date_gmt' => $wp_query->post->post_date_gmt,  
  515. 'post_modified' => $wp_query->post->post_modified,  
  516. 'post_modified_gmt' => $wp_query->post->post_modified_gmt,  
  517. 'post_content' => $wp_query->post->post_content,  
  518. 'post_title' => $wp_query->post->post_title,  
  519. 'post_excerpt' => $wp_query->post->post_excerpt,  
  520. 'post_content_filtered' => $wp_query->post->post_content_filtered,  
  521. 'post_mime_type' => $wp_query->post->post_mime_type,  
  522. 'post_password' => $wp_query->post->post_password,  
  523. 'post_name' => $wp_query->post->post_name,  
  524. 'guid' => $wp_query->post->guid,  
  525. 'menu_order' => $wp_query->post->menu_order,  
  526. 'pinged' => $wp_query->post->pinged,  
  527. 'to_ping' => $wp_query->post->to_ping,  
  528. 'ping_status' => $wp_query->post->ping_status,  
  529. 'comment_status' => $wp_query->post->comment_status,  
  530. 'comment_count' => $wp_query->post->comment_count,  
  531. 'filter' => $wp_query->post->filter,  
  532.  
  533. 'is_404' => false,  
  534. 'is_page' => false,  
  535. 'is_single' => false,  
  536. 'is_archive' => false,  
  537. 'is_tax' => false,  
  538. ) ); 
  539. } else { 
  540. $dummy = wp_parse_args( $args, array( 
  541. 'ID' => -9999,  
  542. 'post_status' => 'public',  
  543. 'post_author' => 0,  
  544. 'post_parent' => 0,  
  545. 'post_type' => 'page',  
  546. 'post_date' => 0,  
  547. 'post_date_gmt' => 0,  
  548. 'post_modified' => 0,  
  549. 'post_modified_gmt' => 0,  
  550. 'post_content' => '',  
  551. 'post_title' => '',  
  552. 'post_excerpt' => '',  
  553. 'post_content_filtered' => '',  
  554. 'post_mime_type' => '',  
  555. 'post_password' => '',  
  556. 'post_name' => '',  
  557. 'guid' => '',  
  558. 'menu_order' => 0,  
  559. 'pinged' => '',  
  560. 'to_ping' => '',  
  561. 'ping_status' => '',  
  562. 'comment_status' => 'closed',  
  563. 'comment_count' => 0,  
  564. 'filter' => 'raw',  
  565.  
  566. 'is_404' => false,  
  567. 'is_page' => false,  
  568. 'is_single' => false,  
  569. 'is_archive' => false,  
  570. 'is_tax' => false,  
  571. ) ); 
  572.  
  573. // Bail if dummy post is empty. 
  574. if ( empty( $dummy ) ) { 
  575. return; 
  576.  
  577. // Set the $post global. 
  578. $post = new WP_Post( (object) $dummy ); 
  579.  
  580. // Copy the new post global into the main $wp_query. 
  581. $wp_query->post = $post; 
  582. $wp_query->posts = array( $post ); 
  583.  
  584. // Prevent comments form from appearing. 
  585. $wp_query->post_count = 1; 
  586. $wp_query->is_404 = $dummy['is_404']; 
  587. $wp_query->is_page = $dummy['is_page']; 
  588. $wp_query->is_single = $dummy['is_single']; 
  589. $wp_query->is_archive = $dummy['is_archive']; 
  590. $wp_query->is_tax = $dummy['is_tax']; 
  591.  
  592. // Clean up the dummy post. 
  593. unset( $dummy ); 
  594.  
  595. /** 
  596. * Force the header back to 200 status if not a deliberate 404. 
  597. * 
  598. * @see https://bbpress.trac.wordpress.org/ticket/1973 
  599. */ 
  600. if ( ! $wp_query->is_404() ) { 
  601. status_header( 200 ); 
  602.  
  603. // If we are resetting a post, we are in theme compat. 
  604. bp_set_theme_compat_active( true ); 
  605.  
  606. // If we are in theme compat, we don't need the 'Edit' post link. 
  607. add_filter( 'get_edit_post_link', 'bp_core_filter_edit_post_link', 10, 2 ); 
  608.  
  609. /** 
  610. * Reset main query vars and filter 'the_content' to output a BuddyPress template part as needed. 
  611. * 
  612. * @since 1.7.0 
  613. * 
  614. * @param string $template Template name. 
  615. * @return string $template Template name. 
  616. */ 
  617. function bp_template_include_theme_compat( $template = '' ) { 
  618. // If embed template, bail. 
  619. if ( true === function_exists( 'is_embed' ) && is_embed() ) { 
  620. return $template; 
  621.  
  622. // If the current theme doesn't need theme compat, bail at this point. 
  623. if ( ! bp_use_theme_compat_with_current_theme() ) { 
  624. return $template; 
  625.  
  626. /** 
  627. * Fires when resetting main query vars and filtering 'the_content' to output BuddyPress template parts. 
  628. * 
  629. * Use this action to execute code that will communicate to BuddyPress's 
  630. * theme compatibility layer whether or not we're replacing the_content() 
  631. * with some other template part. 
  632. * 
  633. * @since 1.7.0 
  634. */ 
  635. do_action( 'bp_template_include_reset_dummy_post_data' ); 
  636.  
  637. // Bail if the template already matches a BuddyPress template. 
  638. if ( ! empty( buddypress()->theme_compat->found_template ) ) { 
  639. return $template; 
  640.  
  641. /** 
  642. * If we are relying on BuddyPress's built in theme compatibility to load 
  643. * the proper content, we need to intercept the_content, replace the 
  644. * output, and display ours instead. 
  645. * 
  646. * To do this, we first remove all filters from 'the_content' and hook 
  647. * our own function into it, which runs a series of checks to determine 
  648. * the context, and then uses the built in shortcodes to output the 
  649. * correct results from inside an output buffer. 
  650. * 
  651. * Uses bp_get_theme_compat_templates() to provide fall-backs that 
  652. * should be coded without superfluous mark-up and logic (prev/next 
  653. * navigation, comments, date/time, etc...) 
  654. * 
  655. * Hook into 'bp_get_buddypress_template' to override the array of 
  656. * possible templates, or 'bp_buddypress_template' to override the result. 
  657. */ 
  658. if ( bp_is_theme_compat_active() ) { 
  659. $template = bp_get_theme_compat_templates(); 
  660.  
  661. add_filter( 'the_content', 'bp_replace_the_content' ); 
  662.  
  663. // Add BuddyPress's head action to wp_head. 
  664. if ( ! has_action( 'wp_head', 'bp_head' ) ) { 
  665. add_action( 'wp_head', 'bp_head' ); 
  666.  
  667. /** 
  668. * Filters the template name to include. 
  669. * 
  670. * @since 1.7.0 
  671. * 
  672. * @param string $template Template name. 
  673. */ 
  674. return apply_filters( 'bp_template_include_theme_compat', $template ); 
  675.  
  676. /** 
  677. * Conditionally replace 'the_content'. 
  678. * 
  679. * Replaces the_content() if the post_type being displayed is one that would 
  680. * normally be handled by BuddyPress, but proper single page templates do not 
  681. * exist in the currently active theme. 
  682. * 
  683. * @since 1.7.0 
  684. * 
  685. * @param string $content Original post content. 
  686. * @return string $content Post content, potentially modified. 
  687. */ 
  688. function bp_replace_the_content( $content = '' ) { 
  689.  
  690. // Bail if not the main loop where theme compat is happening. 
  691. if ( ! bp_do_theme_compat() ) { 
  692. return $content; 
  693.  
  694. // Set theme compat to false early, to avoid recursion from nested calls to 
  695. // the_content() that execute before theme compat has unhooked itself. 
  696. bp_set_theme_compat_active( false ); 
  697.  
  698. /** 
  699. * Filters the content to replace in the post. 
  700. * 
  701. * @since 1.7.0 
  702. * 
  703. * @param string $content Original post content. 
  704. */ 
  705. $new_content = apply_filters( 'bp_replace_the_content', $content ); 
  706.  
  707. // Juggle the content around and try to prevent unsightly comments. 
  708. if ( ! empty( $new_content ) && ( $new_content !== $content ) ) { 
  709.  
  710. // Set the content to be the new content. 
  711. $content = $new_content; 
  712.  
  713. // Clean up after ourselves. 
  714. unset( $new_content ); 
  715.  
  716. // Reset the $post global. 
  717. wp_reset_postdata(); 
  718.  
  719. // Return possibly hi-jacked content. 
  720. return $content; 
  721.  
  722. /** 
  723. * Are we currently replacing the_content? 
  724. * 
  725. * @since 1.8.0 
  726. * 
  727. * @return bool True if the_content is currently in the process of being 
  728. * filtered and replaced. 
  729. */ 
  730. function bp_do_theme_compat() { 
  731. return (bool) ( ! bp_is_template_included() && in_the_loop() && bp_is_theme_compat_active() ); 
  732.  
  733. /** Filters *******************************************************************/ 
  734.  
  735. /** 
  736. * Remove all filters from a WordPress filter hook. 
  737. * 
  738. * Removed filters are stashed in the $bp global, in case they need to be 
  739. * restored later. 
  740. * 
  741. * @since 1.7.0 
  742. * 
  743. * @global WP_filter $wp_filter 
  744. * @global array $merged_filters 
  745. * 
  746. * @param string $tag The filter tag to remove filters from. 
  747. * @param int|bool $priority Optional. If present, only those callbacks attached 
  748. * at a given priority will be removed. Otherwise, all callbacks 
  749. * attached to the tag will be removed, regardless of priority. 
  750. * @return bool True on success. 
  751. */ 
  752. function bp_remove_all_filters( $tag, $priority = false ) { 
  753. global $wp_filter, $merged_filters; 
  754.  
  755. $bp = buddypress(); 
  756.  
  757. // Filters exist. 
  758. if ( isset( $wp_filter[$tag] ) ) { 
  759.  
  760. // Filters exist in this priority. 
  761. if ( ! empty( $priority ) && isset( $wp_filter[$tag][$priority] ) ) { 
  762.  
  763. // Store filters in a backup. 
  764. $bp->filters->wp_filter[$tag][$priority] = $wp_filter[$tag][$priority]; 
  765.  
  766. // Unset the filters. 
  767. unset( $wp_filter[$tag][$priority] ); 
  768.  
  769. // Priority is empty. 
  770. } else { 
  771.  
  772. // Store filters in a backup. 
  773. $bp->filters->wp_filter[$tag] = $wp_filter[$tag]; 
  774.  
  775. // Unset the filters. 
  776. unset( $wp_filter[$tag] ); 
  777.  
  778. // Check merged filters. 
  779. if ( isset( $merged_filters[$tag] ) ) { 
  780.  
  781. // Store filters in a backup. 
  782. $bp->filters->merged_filters[$tag] = $merged_filters[$tag]; 
  783.  
  784. // Unset the filters. 
  785. unset( $merged_filters[$tag] ); 
  786.  
  787. return true; 
  788.  
  789. /** 
  790. * Restore filters that were removed using bp_remove_all_filters(). 
  791. * 
  792. * @since 1.7.0 
  793. * 
  794. * @global WP_filter $wp_filter 
  795. * @global array $merged_filters 
  796. * 
  797. * @param string $tag The tag to which filters should be restored. 
  798. * @param int|bool $priority Optional. If present, only those filters that were originally 
  799. * attached to the tag with $priority will be restored. Otherwise,  
  800. * all available filters will be restored, regardless of priority. 
  801. * @return bool True on success. 
  802. */ 
  803. function bp_restore_all_filters( $tag, $priority = false ) { 
  804. global $wp_filter, $merged_filters; 
  805.  
  806. $bp = buddypress(); 
  807.  
  808. // Filters exist. 
  809. if ( isset( $bp->filters->wp_filter[$tag] ) ) { 
  810.  
  811. // Filters exist in this priority. 
  812. if ( ! empty( $priority ) && isset( $bp->filters->wp_filter[$tag][$priority] ) ) { 
  813.  
  814. // Store filters in a backup. 
  815. $wp_filter[$tag][$priority] = $bp->filters->wp_filter[$tag][$priority]; 
  816.  
  817. // Unset the filters. 
  818. unset( $bp->filters->wp_filter[$tag][$priority] ); 
  819.  
  820. // Priority is empty. 
  821. } else { 
  822.  
  823. // Store filters in a backup. 
  824. $wp_filter[$tag] = $bp->filters->wp_filter[$tag]; 
  825.  
  826. // Unset the filters. 
  827. unset( $bp->filters->wp_filter[$tag] ); 
  828.  
  829. // Check merged filters. 
  830. if ( isset( $bp->filters->merged_filters[$tag] ) ) { 
  831.  
  832. // Store filters in a backup. 
  833. $merged_filters[$tag] = $bp->filters->merged_filters[$tag]; 
  834.  
  835. // Unset the filters. 
  836. unset( $bp->filters->merged_filters[$tag] ); 
  837.  
  838. return true; 
  839.  
  840. /** 
  841. * Force comments_status to 'closed' for BuddyPress post types. 
  842. * 
  843. * @since 1.7.0 
  844. * 
  845. * @param bool $open True if open, false if closed. 
  846. * @param int $post_id ID of the post to check. 
  847. * @return bool True if open, false if closed. 
  848. */ 
  849. function bp_comments_open( $open, $post_id = 0 ) { 
  850.  
  851. $retval = is_buddypress() ? false : $open; 
  852.  
  853. /** 
  854. * Filters whether or not to force comments_status to closed for BuddyPress post types. 
  855. * 
  856. * @since 1.7.0 
  857. * 
  858. * @param bool $retval Whether or not we are on a BuddyPress post type. 
  859. * @param bool $open True if comments open, false if closed. 
  860. * @param int $post_id Post ID for the checked post. 
  861. */ 
  862. return apply_filters( 'bp_force_comment_status', $retval, $open, $post_id ); 
  863.  
  864. /** 
  865. * Do not allow {@link comments_template()} to render during theme compatibility. 
  866. * 
  867. * When theme compatibility sets the 'is_page' flag to true via 
  868. * {@link bp_theme_compat_reset_post()}, themes that use comments_template() 
  869. * in their page template will run. 
  870. * 
  871. * To prevent comments_template() from rendering, we set the 'is_page' and 
  872. * 'is_single' flags to false since that function looks at these conditionals 
  873. * before querying the database for comments and loading the comments template. 
  874. * 
  875. * This is done during the output buffer as late as possible to prevent any 
  876. * wonkiness. 
  877. * 
  878. * @since 1.9.2 
  879. * 
  880. * @param string $retval The current post content. 
  881. * @return string $retval 
  882. */ 
  883. function bp_theme_compat_toggle_is_page( $retval = '' ) { 
  884. global $wp_query; 
  885.  
  886. if ( $wp_query->is_page ) { 
  887. $wp_query->is_page = false; 
  888.  
  889. // Set a switch so we know that we've toggled these WP_Query properties. 
  890. buddypress()->theme_compat->is_page_toggled = true; 
  891.  
  892. return $retval; 
  893. add_filter( 'bp_replace_the_content', 'bp_theme_compat_toggle_is_page', 9999 ); 
  894.  
  895. /** 
  896. * Restores the 'is_single' and 'is_page' flags if toggled by BuddyPress. 
  897. * 
  898. * @since 1.9.2 
  899. * 
  900. * @see bp_theme_compat_toggle_is_page() 
  901. * @param object $query The WP_Query object. 
  902. */ 
  903. function bp_theme_compat_loop_end( $query ) { 
  904.  
  905. // Get BuddyPress. 
  906. $bp = buddypress(); 
  907.  
  908. // Bail if page is not toggled. 
  909. if ( ! isset( $bp->theme_compat->is_page_toggled ) ) { 
  910. return; 
  911.  
  912. // Revert our toggled WP_Query properties. 
  913. $query->is_page = true; 
  914.  
  915. // Unset our switch. 
  916. unset( $bp->theme_compat->is_page_toggled ); 
  917. add_action( 'loop_end', 'bp_theme_compat_loop_end' ); 
.