File: D:/HostingSpaces/KWessing/buddypress/bp-core/bp-core-theme-compatibility.php
<?php
/**
* BuddyPress Core Theme Compatibility.
*
* @package BuddyPress
* @subpackage ThemeCompatibility
*/
// Exit if accessed directly
if ( !defined( 'ABSPATH' ) ) exit;
/** Theme Compat **************************************************************/
/**
* What follows is an attempt at intercepting the natural page load process
* to replace the_content() with the appropriate BuddyPress content.
*
* To do this, BuddyPress does several direct manipulations of global variables
* and forces them to do what they are not supposed to be doing.
*
* Don't try anything you're about to witness here, at home. Ever.
*/
/** Base Class ****************************************************************/
/**
* Theme Compatibility base class.
*
* This is only intended to be extended, and is included here as a basic guide
* for future Theme Packs to use. {@link BP_Legacy} is a good example of
* extending this class.
*
* @since BuddyPress (1.7.0)
*
* @todo We should probably do something similar to BP_Component::start().
* @todo If this is only intended to be extended, it should be abstract.
*
* @param array $properties {
* An array of properties describing the theme compat package.
* @type string $id ID of the package. Must be unique.
* @type string $name Name of the theme. This should match the name given
* in style.css.
* @type string $version Theme version. Used for busting script and style
* browser caches.
* @type string $dir Filesystem path of the theme.
* @type string $url Base URL of the theme.
* }
*/
class BP_Theme_Compat {
/**
* Template package properties, as passed to the constructor.
*
* @var array
*/
protected $_data = array();
/**
* Pass the $properties to the object on creation.
*
* @since BuddyPress (1.7.0)
*/
public function __construct( Array $properties = array() ) {
$this->_data = $properties;
}
/**
* Set up the BuddyPress-specific theme compat methods.
*
* Themes shoud use this method in their constructor.
*
* @since BuddyPress (1.7.0)
*/
protected function start() {
// Sanity check
if ( ! bp_use_theme_compat_with_current_theme() ) {
return;
}
// Setup methods
$this->setup_globals();
$this->setup_actions();
}
/**
* Set up global data for your template package.
*
* Meant to be overridden in your class. See
* {@link BP_Legacy::setup_globals()} for an example.
*
* @since BuddyPress (1.7.0)
*/
protected function setup_globals() {}
/**
* Set up theme hooks for your template package.
*
* Meant to be overridden in your class. See
* {@link BP_Legacy::setup_actions()} for an example.
*
* @since BuddyPress (1.7.0)
*/
protected function setup_actions() {}
/**
* Set a theme's property.
*
* @since BuddyPress (1.7.0)
*
* @param string $property Property name.
* @param mixed $value Property value.
* @return bool True on success, false on failure.
*/
public function __set( $property, $value ) {
return $this->_data[$property] = $value;
}
/**
* Get a theme's property.
*
* @since BuddyPress (1.7.0)
*
* @param string $property Property name.
* @return mixed The value of the property if it exists, otherwise an
* empty string.
*/
public function __get( $property ) {
return array_key_exists( $property, $this->_data ) ? $this->_data[$property] : '';
}
}
/** Functions *****************************************************************/
/**
* Set up the default theme compat theme.
*
* @since BuddyPress (1.7.0)
*
* @param string $theme Optional. The unique ID identifier of a theme package.
*/
function bp_setup_theme_compat( $theme = '' ) {
$bp = buddypress();
// Make sure theme package is available, set to default if not
if ( ! isset( $bp->theme_compat->packages[$theme] ) || ! is_a( $bp->theme_compat->packages[$theme], 'BP_Theme_Compat' ) ) {
$theme = 'legacy';
}
// Set the active theme compat theme
$bp->theme_compat->theme = $bp->theme_compat->packages[$theme];
}
/**
* Get the ID of the theme package being used.
*
* This can be filtered or set manually. Tricky theme authors can override the
* default and include their own BuddyPress compatability layers for their themes.
*
* @since BuddyPress (1.7.0)
*
* @uses apply_filters()
*
* @return string ID of the theme package in use.
*/
function bp_get_theme_compat_id() {
return apply_filters( 'bp_get_theme_compat_id', buddypress()->theme_compat->theme->id );
}
/**
* Get the name of the theme package being used.
*
* This can be filtered or set manually. Tricky theme authors can override the
* default and include their own BuddyPress compatability layers for their themes.
*
* @since BuddyPress (1.7.0)
*
* @uses apply_filters()
*
* @return string Name of the theme package currently in use.
*/
function bp_get_theme_compat_name() {
return apply_filters( 'bp_get_theme_compat_name', buddypress()->theme_compat->theme->name );
}
/**
* Get the version of the theme package being used.
*
* This can be filtered or set manually. Tricky theme authors can override the
* default and include their own BuddyPress compatability layers for their themes.
*
* @since BuddyPress (1.7.0)
*
* @uses apply_filters()
*
* @return string The version string of the theme package currently in use.
*/
function bp_get_theme_compat_version() {
return apply_filters( 'bp_get_theme_compat_version', buddypress()->theme_compat->theme->version );
}
/**
* Get the absolute path of the theme package being used.
*
* or set manually. Tricky theme authors can override the default and include
* their own BuddyPress compatability layers for their themes.
*
* @since BuddyPress (1.7.0)
*
* @uses apply_filters()
*
* @return string The absolute path of the theme package currently in use.
*/
function bp_get_theme_compat_dir() {
return apply_filters( 'bp_get_theme_compat_dir', buddypress()->theme_compat->theme->dir );
}
/**
* Get the URL of the theme package being used.
*
* This can be filtered, or set manually. Tricky theme authors can override
* the default and include their own BuddyPress compatability layers for their
* themes.
*
* @since BuddyPress (1.7.0)
*
* @uses apply_filters()
*
* @return string URL of the theme package currently in use.
*/
function bp_get_theme_compat_url() {
return apply_filters( 'bp_get_theme_compat_url', buddypress()->theme_compat->theme->url );
}
/**
* Should we use theme compat for this theme?
*
* If the current theme's need for theme compat hasn't yet been detected, we
* do so using bp_detect_theme_compat_with_current_theme().
*
* @since BuddyPress (1.9.0)
*
* @uses bp_detect_theme_compat_with_current_theme()
*
* @return bool True if the current theme needs theme compatibility.
*/
function bp_use_theme_compat_with_current_theme() {
if ( ! isset( buddypress()->theme_compat->use_with_current_theme ) ) {
bp_detect_theme_compat_with_current_theme();
}
return apply_filters( 'bp_use_theme_compat_with_current_theme', buddypress()->theme_compat->use_with_current_theme );
}
/**
* Set our flag to determine whether theme compat should be enabled.
*
* Theme compat is disabled when a theme meets one of the following criteria:
* 1) It declares BP support with add_theme_support( 'buddypress' )
* 2) It is bp-default, or a child theme of bp-default
* 3) A legacy template is found at members/members-loop.php. This is a
* fallback check for themes that were derived from bp-default, and have
* not been updated for BP 1.7+; we make the assumption that any theme in
* this category will have the members-loop.php template, and so use its
* presence as an indicator that theme compatibility is not required
*
* @since BuddyPress (1.9.0)
*
* @return bool True if the current theme needs theme compatibility.
*/
function bp_detect_theme_compat_with_current_theme() {
if ( isset( buddypress()->theme_compat->use_with_current_theme ) ) {
return buddypress()->theme_compat->use_with_current_theme;
}
// theme compat enabled by default
$theme_compat = true;
// If the theme supports 'buddypress', bail.
if ( current_theme_supports( 'buddypress' ) ) {
$theme_compat = false;
// If the theme doesn't support BP, do some additional checks
} else {
// Bail if theme is a derivative of bp-default
if ( in_array( 'bp-default', array( get_template(), get_stylesheet() ) ) ) {
$theme_compat = false;
// Bruteforce check for a BP template
// Examples are clones of bp-default
} else if ( locate_template( 'members/members-loop.php', false, false ) ) {
$theme_compat = false;
}
}
// set a flag in the buddypress() singleton so we don't have to run this again
buddypress()->theme_compat->use_with_current_theme = $theme_compat;
return $theme_compat;
}
/**
* Is the current page using theme compatibility?
*
* @since BuddyPress (1.7.0)
*
* @return bool True if the current page uses theme compatibility.
*/
function bp_is_theme_compat_active() {
$bp = buddypress();
if ( empty( $bp->theme_compat->active ) )
return false;
return $bp->theme_compat->active;
}
/**
* Set the flag that tells whether the current page is using theme compatibility.
*
* @since BuddyPress (1.7.0)
*
* @param bool $set True to set the flag to true, false to set it to false.
* @return bool Returns the value of $set.
*/
function bp_set_theme_compat_active( $set = true ) {
buddypress()->theme_compat->active = $set;
return (bool) buddypress()->theme_compat->active;
}
/**
* Set the theme compat templates global.
*
* Stash possible template files for the current query. Useful if plugins want
* to override them, or see what files are being scanned for inclusion.
*
* @since BuddyPress (1.7.0)
*
* @param array $templates The template stack.
* @return array The template stack (value of $templates).
*/
function bp_set_theme_compat_templates( $templates = array() ) {
buddypress()->theme_compat->templates = $templates;
return buddypress()->theme_compat->templates;
}
/**
* Set the theme compat template global.
*
* Stash the template file for the current query. Useful if plugins want
* to override it, or see what file is being included.
*
* @since BuddyPress (1.7.0)
*
* @param string $template The template currently in use.
* @return string The template currently in use (value of $template).
*/
function bp_set_theme_compat_template( $template = '' ) {
buddypress()->theme_compat->template = $template;
return buddypress()->theme_compat->template;
}
/**
* Set the theme compat original_template global.
*
* Stash the original template file for the current query. Useful for checking
* if BuddyPress was able to find a more appropriate template.
*
* @since BuddyPress (1.7.0)
*
* @param string $template The template originally selected by WP.
* @return string The template originally selected by WP (value of $template).
*/
function bp_set_theme_compat_original_template( $template = '' ) {
buddypress()->theme_compat->original_template = $template;
return buddypress()->theme_compat->original_template;
}
/**
* Check whether a given template is the one that WP originally selected to display current page.
*
* @since BuddyPress (1.7.0)
*
* @param string $template The template name to check.
* @return bool True if the value of $template is the same as the
* "original_template" originally selected by WP. Otherwise false.
*/
function bp_is_theme_compat_original_template( $template = '' ) {
$bp = buddypress();
if ( empty( $bp->theme_compat->original_template ) )
return false;
return (bool) ( $bp->theme_compat->original_template == $template );
}
/**
* Register a new BuddyPress theme package in the active theme packages array.
*
* For an example of how this function is used, see:
* {@link BuddyPress::register_theme_packages()}.
*
* @since BuddyPress (1.7)
*
* @see BP_Theme_Compat for a description of the $theme parameter arguments.
*
* @param array $theme See {@link BP_Theme_Compat}.
* @param bool $override If true, overrides whatever package is currently set.
* Default: true.
*/
function bp_register_theme_package( $theme = array(), $override = true ) {
// Create new BP_Theme_Compat object from the $theme array
if ( is_array( $theme ) ) {
$theme = new BP_Theme_Compat( $theme );
}
// Bail if $theme isn't a proper object
if ( ! is_a( $theme, 'BP_Theme_Compat' ) ) {
return;
}
// Load up BuddyPress
$bp = buddypress();
// Only set if the theme package was not previously registered or if the
// override flag is set
if ( empty( $bp->theme_compat->packages[$theme->id] ) || ( true === $override ) ) {
$bp->theme_compat->packages[$theme->id] = $theme;
}
}
/**
* Populate various WordPress globals with dummy data to prevent errors.
*
* This dummy data is necessary because theme compatibility essentially fakes
* WordPress into thinking that there is content where, in fact, there is none
* (at least, no WordPress post content). By providing dummy data, we ensure
* that template functions - things like is_page() - don't throw errors.
*
* @since BuddyPress (1.7.0)
*
* @global WP_Query $wp_query WordPress database access object.
* @global object $post Current post object.
*
* @param array $args Array of optional arguments. Arguments parallel the
* properties of {@link WP_Post}; see that class for more details.
*/
function bp_theme_compat_reset_post( $args = array() ) {
global $wp_query, $post;
// Switch defaults if post is set
if ( isset( $wp_query->post ) ) {
$dummy = wp_parse_args( $args, array(
'ID' => $wp_query->post->ID,
'post_status' => $wp_query->post->post_status,
'post_author' => $wp_query->post->post_author,
'post_parent' => $wp_query->post->post_parent,
'post_type' => $wp_query->post->post_type,
'post_date' => $wp_query->post->post_date,
'post_date_gmt' => $wp_query->post->post_date_gmt,
'post_modified' => $wp_query->post->post_modified,
'post_modified_gmt' => $wp_query->post->post_modified_gmt,
'post_content' => $wp_query->post->post_content,
'post_title' => $wp_query->post->post_title,
'post_excerpt' => $wp_query->post->post_excerpt,
'post_content_filtered' => $wp_query->post->post_content_filtered,
'post_mime_type' => $wp_query->post->post_mime_type,
'post_password' => $wp_query->post->post_password,
'post_name' => $wp_query->post->post_name,
'guid' => $wp_query->post->guid,
'menu_order' => $wp_query->post->menu_order,
'pinged' => $wp_query->post->pinged,
'to_ping' => $wp_query->post->to_ping,
'ping_status' => $wp_query->post->ping_status,
'comment_status' => $wp_query->post->comment_status,
'comment_count' => $wp_query->post->comment_count,
'filter' => $wp_query->post->filter,
'is_404' => false,
'is_page' => false,
'is_single' => false,
'is_archive' => false,
'is_tax' => false,
) );
} else {
$dummy = wp_parse_args( $args, array(
'ID' => -9999,
'post_status' => 'public',
'post_author' => 0,
'post_parent' => 0,
'post_type' => 'page',
'post_date' => 0,
'post_date_gmt' => 0,
'post_modified' => 0,
'post_modified_gmt' => 0,
'post_content' => '',
'post_title' => '',
'post_excerpt' => '',
'post_content_filtered' => '',
'post_mime_type' => '',
'post_password' => '',
'post_name' => '',
'guid' => '',
'menu_order' => 0,
'pinged' => '',
'to_ping' => '',
'ping_status' => '',
'comment_status' => 'closed',
'comment_count' => 0,
'filter' => 'raw',
'is_404' => false,
'is_page' => false,
'is_single' => false,
'is_archive' => false,
'is_tax' => false,
) );
}
// Bail if dummy post is empty
if ( empty( $dummy ) ) {
return;
}
// Set the $post global
$post = new WP_Post( (object) $dummy );
// Copy the new post global into the main $wp_query
$wp_query->post = $post;
$wp_query->posts = array( $post );
// Prevent comments form from appearing
$wp_query->post_count = 1;
$wp_query->is_404 = $dummy['is_404'];
$wp_query->is_page = $dummy['is_page'];
$wp_query->is_single = $dummy['is_single'];
$wp_query->is_archive = $dummy['is_archive'];
$wp_query->is_tax = $dummy['is_tax'];
// Clean up the dummy post
unset( $dummy );
/**
* Force the header back to 200 status if not a deliberate 404
*
* @see http://bbpress.trac.wordpress.org/ticket/1973
*/
if ( ! $wp_query->is_404() ) {
status_header( 200 );
}
// If we are resetting a post, we are in theme compat
bp_set_theme_compat_active( true );
}
/**
* Reset main query vars and filter 'the_content' to output a BuddyPress template part as needed.
*
* @since BuddyPress (1.7.0)
*
* @uses bp_is_single_user() To check if page is single user.
* @uses bp_get_single_user_template() To get user template.
* @uses bp_is_single_user_edit() To check if page is single user edit.
* @uses bp_get_single_user_edit_template() To get user edit template.
* @uses bp_is_single_view() To check if page is single view.
* @uses bp_get_single_view_template() To get view template.
* @uses bp_is_forum_edit() To check if page is forum edit.
* @uses bp_get_forum_edit_template() To get forum edit template.
* @uses bp_is_topic_merge() To check if page is topic merge.
* @uses bp_get_topic_merge_template() To get topic merge template.
* @uses bp_is_topic_split() To check if page is topic split.
* @uses bp_get_topic_split_template() To get topic split template.
* @uses bp_is_topic_edit() To check if page is topic edit.
* @uses bp_get_topic_edit_template() To get topic edit template.
* @uses bp_is_reply_edit() To check if page is reply edit.
* @uses bp_get_reply_edit_template() To get reply edit template.
* @uses bp_set_theme_compat_template() To set the global theme compat template.
*
* @param string $template Template name.
* @return string $template Template name.
*/
function bp_template_include_theme_compat( $template = '' ) {
// If the current theme doesn't need theme compat, bail at this point.
if ( ! bp_use_theme_compat_with_current_theme() ) {
return $template;
}
/**
* Use this action to execute code that will communicate to BuddyPress's
* theme compatibility layer whether or not we're replacing the_content()
* with some other template part.
*/
do_action( 'bp_template_include_reset_dummy_post_data' );
// Bail if the template already matches a BuddyPress template
if ( !empty( buddypress()->theme_compat->found_template ) )
return $template;
/**
* If we are relying on BuddyPress's built in theme compatibility to load
* the proper content, we need to intercept the_content, replace the
* output, and display ours instead.
*
* To do this, we first remove all filters from 'the_content' and hook
* our own function into it, which runs a series of checks to determine
* the context, and then uses the built in shortcodes to output the
* correct results from inside an output buffer.
*
* Uses bp_get_theme_compat_templates() to provide fall-backs that
* should be coded without superfluous mark-up and logic (prev/next
* navigation, comments, date/time, etc...)
*
* Hook into 'bp_get_buddypress_template' to override the array of
* possible templates, or 'bp_buddypress_template' to override the result.
*/
if ( bp_is_theme_compat_active() ) {
$template = bp_get_theme_compat_templates();
add_filter( 'the_content', 'bp_replace_the_content' );
// Add BuddyPress's head action to wp_head
if ( ! has_action( 'wp_head', 'bp_head' ) ) {
add_action( 'wp_head', 'bp_head' );
}
}
return apply_filters( 'bp_template_include_theme_compat', $template );
}
/**
* Conditionally replace 'the_content'.
*
* Replaces the_content() if the post_type being displayed is one that would
* normally be handled by BuddyPress, but proper single page templates do not
* exist in the currently active theme.
*
* @since BuddyPress (1.7.0)
*
* @param string $content Original post content.
* @return string $content Post content, potentially modified.
*/
function bp_replace_the_content( $content = '' ) {
// Bail if not the main loop where theme compat is happening
if ( ! bp_do_theme_compat() )
return $content;
// Set theme compat to false early, to avoid recursion from nested calls to
// the_content() that execute before theme compat has unhooked itself.
bp_set_theme_compat_active( false );
// Do we have new content to replace the old content?
$new_content = apply_filters( 'bp_replace_the_content', $content );
// Juggle the content around and try to prevent unsightly comments
if ( !empty( $new_content ) && ( $new_content !== $content ) ) {
// Set the content to be the new content
$content = $new_content;
// Clean up after ourselves
unset( $new_content );
// Reset the $post global
wp_reset_postdata();
}
// Return possibly hi-jacked content
return $content;
}
/**
* Are we currently replacing the_content?
*
* @since BuddyPress (1.8.0)
*
* @return bool True if the_content is currently in the process of being
* filtered and replaced.
*/
function bp_do_theme_compat() {
return (bool) ( ! bp_is_template_included() && in_the_loop() && bp_is_theme_compat_active() );
}
/** Filters *******************************************************************/
/**
* Remove all filters from a WordPress filter hook.
*
* Removed filters are stashed in the $bp global, in case they need to be
* restored later.
*
* @since BuddyPress (1.7.0)
*
* @global WP_filter $wp_filter
* @global array $merged_filters
*
* @param string $tag The filter tag to remove filters from.
* @param int $priority Optional. If present, only those callbacks attached
* at a given priority will be removed. Otherwise, all callbacks
* attached to the tag will be removed, regardless of priority.
* @return bool True on success.
*/
function bp_remove_all_filters( $tag, $priority = false ) {
global $wp_filter, $merged_filters;
$bp = buddypress();
// Filters exist
if ( isset( $wp_filter[$tag] ) ) {
// Filters exist in this priority
if ( !empty( $priority ) && isset( $wp_filter[$tag][$priority] ) ) {
// Store filters in a backup
$bp->filters->wp_filter[$tag][$priority] = $wp_filter[$tag][$priority];
// Unset the filters
unset( $wp_filter[$tag][$priority] );
// Priority is empty
} else {
// Store filters in a backup
$bp->filters->wp_filter[$tag] = $wp_filter[$tag];
// Unset the filters
unset( $wp_filter[$tag] );
}
}
// Check merged filters
if ( isset( $merged_filters[$tag] ) ) {
// Store filters in a backup
$bp->filters->merged_filters[$tag] = $merged_filters[$tag];
// Unset the filters
unset( $merged_filters[$tag] );
}
return true;
}
/**
* Restore filters that were removed using bp_remove_all_filters().
*
* @since BuddyPress (1.7.0)
*
* @global WP_filter $wp_filter
* @global array $merged_filters
*
* @param string $tag The tag to which filters should be restored.
* @param int $priority Optional. If present, only those filters that were
* originally attached to the tag with $priority will be restored.
* Otherwise, all available filters will be restored, regardless of
* priority.
* @return bool True on success.
*/
function bp_restore_all_filters( $tag, $priority = false ) {
global $wp_filter, $merged_filters;
$bp = buddypress();
// Filters exist
if ( isset( $bp->filters->wp_filter[$tag] ) ) {
// Filters exist in this priority
if ( !empty( $priority ) && isset( $bp->filters->wp_filter[$tag][$priority] ) ) {
// Store filters in a backup
$wp_filter[$tag][$priority] = $bp->filters->wp_filter[$tag][$priority];
// Unset the filters
unset( $bp->filters->wp_filter[$tag][$priority] );
// Priority is empty
} else {
// Store filters in a backup
$wp_filter[$tag] = $bp->filters->wp_filter[$tag];
// Unset the filters
unset( $bp->filters->wp_filter[$tag] );
}
}
// Check merged filters
if ( isset( $bp->filters->merged_filters[$tag] ) ) {
// Store filters in a backup
$merged_filters[$tag] = $bp->filters->merged_filters[$tag];
// Unset the filters
unset( $bp->filters->merged_filters[$tag] );
}
return true;
}
/**
* Force comments_status to 'closed' for BuddyPress post types.
*
* @since BuddyPress (1.7.0)
*
* @param bool $open True if open, false if closed.
* @param int $post_id ID of the post to check.
* @return bool True if open, false if closed.
*/
function bp_comments_open( $open, $post_id = 0 ) {
$retval = is_buddypress() ? false : $open;
// Allow override of the override
return apply_filters( 'bp_force_comment_status', $retval, $open, $post_id );
}
/**
* Do not allow {@link comments_template()} to render during theme compatibility.
*
* When theme compatibility sets the 'is_page' flag to true via
* {@link bp_theme_compat_reset_post()}, themes that use comments_template()
* in their page template will run.
*
* To prevent comments_template() from rendering, we set the 'is_page' and
* 'is_single' flags to false since that function looks at these conditionals
* before querying the database for comments and loading the comments template.
*
* This is done during the output buffer as late as possible to prevent any
* wonkiness.
*
* @since BuddyPress (1.9.2)
*
* @param string $retval The current post content.
*/
function bp_theme_compat_toggle_is_page( $retval = '' ) {
global $wp_query;
$wp_query->is_single = false;
$wp_query->is_page = false;
// Set a switch so we know that we've toggled these WP_Query properties
buddypress()->theme_compat->is_page_toggled = true;
return $retval;
}
add_filter( 'bp_replace_the_content', 'bp_theme_compat_toggle_is_page', 9999 );
/**
* Restores the 'is_single' and 'is_page' flags if toggled by BuddyPress.
*
* @since BuddyPress (1.9.2)
*
* @see bp_theme_compat_toggle_is_page()
* @param object $query The WP_Query object.
*/
function bp_theme_compat_loop_end( $query ) {
// Get BuddyPress
$bp = buddypress();
// Bail if page is not toggled
if ( ! isset( $bp->theme_compat->is_page_toggled ) ) {
return;
}
// Revert our toggled WP_Query properties
$query->is_single = true;
$query->is_page = true;
// Unset our switch
unset( $bp->theme_compat->is_page_toggled );
}
add_action( 'loop_end', 'bp_theme_compat_loop_end' );