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