array( 'class' => true ), 'div' => array( 'class' => true ), 'span' => array( 'class' => true ), 'a' => array( 'href' => true, 'class' => true, 'data-bp-tooltip' => true, ), 'img' => array( 'src' => true, 'class' => true, 'loading' => true, ), ); } if ( 'js' !== $type ) { $template_string = wp_kses( $template_string, $allowed_tags ); return bp_core_replace_tokens_in_text( $template_string, $tokens ); } return $template_string; } /** * Retrieve the name of the highest priority template file that exists. * * Searches in the STYLESHEETPATH before TEMPLATEPATH so that themes which * inherit from a parent theme can just overload one file. If the template is * not found in either of those, it looks in the theme-compat folder last. * * @since 1.7.0 * @since 7.0.0 Added $args parameter. * * @param string|array $template_names Template file(s) to search for, in order. * @param bool $load Optional. If true, the template file will be loaded when * found. If false, the path will be returned. Default: false. * @param bool $require_once Optional. Whether to require_once or require. Has * no effect if $load is false. Default: true. * @param array $args Optional. Extra args to pass to locate_template(). * @return string The template filename if one is located. */ function bp_locate_template( $template_names, $load = false, $require_once = true, $args = array() ) { // Bail when there are no templates to locate. if ( empty( $template_names ) ) { return false; } // No file found yet. $located = false; $template_locations = bp_get_template_stack(); // Try to find a template file. foreach ( (array) $template_names as $template_name ) { // Continue if template is empty. if ( empty( $template_name ) ) { continue; } // Trim off any slashes from the template name. $template_name = ltrim( $template_name, '/' ); // Loop through template stack. foreach ( (array) $template_locations as $template_location ) { // Continue if $template_location is empty. if ( empty( $template_location ) ) { continue; } // Check child theme first. if ( file_exists( trailingslashit( $template_location ) . $template_name ) ) { $located = trailingslashit( $template_location ) . $template_name; break 2; } } } /** * This action exists only to follow the standard BuddyPress coding convention, * and should not be used to short-circuit any part of the template locater. * * If you want to override a specific template part, please either filter * 'bp_get_template_part' or add a new location to the template stack. */ do_action( 'bp_locate_template', $located, $template_name, $template_names, $template_locations, $load, $require_once, $args ); /** * Filter here to allow/disallow template loading. * * @since 2.5.0 * * @param bool $value True to load the template, false otherwise. */ $load_template = (bool) apply_filters( 'bp_locate_template_and_load', true ); if ( $load_template && $load && ! empty( $located ) ) { load_template( $located, $require_once, $args ); } return $located; } /** * Get file data of the highest priority asset that exists. * * Similar to {@link bp_locate_template()}, but for files like CSS and JS. * * @since 2.6.0 * * @param string $filename Relative filename to search for. * @return false|array Array of asset data if one is located (includes absolute filepath and URI). * Boolean false on failure. */ function bp_locate_template_asset( $filename ) { // Ensure assets can be located when running from /src/. if ( defined( 'BP_SOURCE_SUBDIRECTORY' ) && 'src' === BP_SOURCE_SUBDIRECTORY ) { $filename = str_replace( '.min', '', $filename ); } // Use bp_locate_template() to find our asset. $located = bp_locate_template( $filename, false ); if ( false === $located ) { return false; } // Set up data array. $data = array(); $data['file'] = $data['uri'] = $located; $find = array( get_theme_root(), bp_get_theme_compat_dir() ); $replace = array( get_theme_root_uri(), bp_get_theme_compat_url() ); // Make sure URI path is relative to site URL. $data['uri'] = str_replace( $find, $replace, $data['uri'] ); return $data; } /** * Register a new template stack location. * * This allows for templates to live in places beyond just the parent/child * relationship, to allow for custom template locations. Used in conjunction * with bp_locate_template(), this allows for easy template overrides. * * @since 1.7.0 * * @param string $location_callback Callback function that returns the stack location. * @param int $priority Optional. The priority parameter as passed to * add_filter(). Default: 10. * @return bool See {@link add_filter()}. */ function bp_register_template_stack( $location_callback = '', $priority = 10 ) { // Bail if no location, or function/method is not callable. if ( empty( $location_callback ) || ! is_callable( $location_callback ) ) { return false; } // Add location callback to template stack. return add_filter( 'bp_template_stack', $location_callback, (int) $priority ); } /** * Deregister a previously registered template stack location. * * @since 1.7.0 * * @see bp_register_template_stack() * * @param string $location_callback Callback function that returns the stack location. * @param int $priority Optional. The priority parameter passed to * {@link bp_register_template_stack()}. Default: 10. * @return bool See {@link remove_filter()}. */ function bp_deregister_template_stack( $location_callback = '', $priority = 10 ) { // Bail if no location, or function/method is not callable. if ( empty( $location_callback ) || ! is_callable( $location_callback ) ) { return false; } // Add location callback to template stack. return remove_filter( 'bp_template_stack', $location_callback, (int) $priority ); } /** * Get the "template stack", a list of registered directories where templates can be found. * * Calls the functions added to the 'bp_template_stack' filter hook, and return * an array of the template locations. * * @since 1.7.0 * * @see bp_register_template_stack() * * @global array $wp_filter Stores all of the filters. * @global array $merged_filters Merges the filter hooks using this function. * @global array $wp_current_filter Stores the list of current filters with * the current one last. * @return array The filtered value after all hooked functions are applied to it. */ function bp_get_template_stack() { global $wp_filter, $merged_filters, $wp_current_filter; // Setup some default variables. $tag = 'bp_template_stack'; $args = $stack = array(); // Add 'bp_template_stack' to the current filter array. $wp_current_filter[] = $tag; // Sort. if ( class_exists( 'WP_Hook' ) ) { $filter = $wp_filter[ $tag ]->callbacks; } else { $filter = &$wp_filter[ $tag ]; if ( ! isset( $merged_filters[ $tag ] ) ) { ksort( $filter ); $merged_filters[ $tag ] = true; } } // Ensure we're always at the beginning of the filter array. reset( $filter ); // Loop through 'bp_template_stack' filters, and call callback functions. do { foreach( (array) current( $filter ) as $the_ ) { if ( ! is_null( $the_['function'] ) ) { $args[1] = $stack; $stack[] = call_user_func_array( $the_['function'], array_slice( $args, 1, (int) $the_['accepted_args'] ) ); } } } while ( next( $filter ) !== false ); // Remove 'bp_template_stack' from the current filter array. array_pop( $wp_current_filter ); // Remove empties and duplicates. $stack = array_unique( array_filter( $stack ) ); /** * Filters the "template stack" list of registered directories where templates can be found. * * @since 1.7.0 * * @param array $stack Array of registered directories for template locations. */ return (array) apply_filters( 'bp_get_template_stack', $stack ) ; } /** * Put a template part into an output buffer, and return it. * * @since 1.7.0 * @since 7.0.0 Added $args parameter. * * @see bp_get_template_part() for a description of $slug, $name and $args params. * * @param string $slug See {@link bp_get_template_part()}. * @param string|null $name See {@link bp_get_template_part()}. * @param bool $echo If true, template content will be echoed. If false, * returned. Default: true. * @param array $args See {@link bp_get_template_part()}. * @return string|null If $echo, returns the template content. */ function bp_buffer_template_part( $slug, $name = null, $echo = true, $args = array() ) { ob_start(); // Remove 'bp_replace_the_content' filter to prevent infinite loops. remove_filter( 'the_content', 'bp_replace_the_content' ); bp_get_template_part( $slug, $name, $args ); // Remove 'bp_replace_the_content' filter to prevent infinite loops. add_filter( 'the_content', 'bp_replace_the_content' ); // Get the output buffer contents. $output = ob_get_clean(); // Echo or return the output buffer contents. if ( true === $echo ) { echo $output; } else { return $output; } } /** * Retrieve the path to a template. * * Used to quickly retrieve the path of a template without including the file * extension. It will also check the parent theme and theme-compat theme with * the use of {@link bp_locate_template()}. Allows for more generic template * locations without the use of the other get_*_template() functions. * * @since 1.7.0 * * @param string $type Filename without extension. * @param array $templates An optional list of template candidates. * @return string Full path to file. */ function bp_get_query_template( $type, $templates = array() ) { $type = preg_replace( '|[^a-z0-9-]+|', '', $type ); if ( empty( $templates ) ) { $templates = array( "{$type}.php" ); } /** * Filters possible file paths to check for for a template. * * This is a variable filter based on the type passed into * bp_get_query_template. * * @since 1.7.0 * * @param array $templates Array of template files already prepared. */ $templates = apply_filters( "bp_get_{$type}_template", $templates ); /* * Filter possible templates, try to match one, and set any BuddyPress theme * compat properties so they can be cross-checked later. */ $templates = bp_set_theme_compat_templates( $templates ); $template = bp_locate_template( $templates ); /* * The current theme is using the WordPress Full Site Editing feature. * BuddyPress then needs to use the WordPress template canvas to retrieve the community content. */ if ( current_theme_supports( 'block-templates' ) && $template === get_theme_file_path( 'index.php' ) ) { $template = ABSPATH . WPINC . '/template-canvas.php'; } $template = bp_set_theme_compat_template( $template ); /** * Filters the path to a template file. * * This is a variable filter based on the type passed into * bp_get_query_template. * * @since 1.7.0 * * @param string $template Path to the most appropriate found template file. */ return apply_filters( "bp_{$type}_template", $template ); } /** * Get the possible subdirectories to check for templates in. * * @since 1.7.0 * * @param array $templates Templates we are looking for. * @return array Possible subfolders to look in. */ function bp_get_template_locations( $templates = array() ) { $locations = array( 'buddypress', 'community', '' ); /** * Filters the possible subdirectories to check for templates in. * * @since 1.7.0 * * @param array $locations Array of subfolders to look in. * @param array $templates Array of templates we are looking for. */ return apply_filters( 'bp_get_template_locations', $locations, $templates ); } /** * Add template locations to template files being searched for. * * @since 1.7.0 * * @param array $stacks Array of template locations. * @return array Array of all template locations registered so far. */ function bp_add_template_stack_locations( $stacks = array() ) { $retval = array(); // Get alternate locations. $locations = bp_get_template_locations(); // Loop through locations and stacks and combine. foreach ( (array) $stacks as $stack ) { foreach ( (array) $locations as $custom_location ) { $retval[] = untrailingslashit( trailingslashit( $stack ) . $custom_location ); } } /** * Filters the template locations to template files being searched for. * * @since 1.7.0 * * @param array $value Array of all template locations registered so far. * @param array $stacks Array of template locations. */ return apply_filters( 'bp_add_template_stack_locations', array_unique( $retval ), $stacks ); } /** * Add checks for BuddyPress conditions to 'parse_query' action. * * @since 1.7.0 * * @param WP_Query $posts_query WP_Query object. */ function bp_parse_query( $posts_query ) { // Bail if $posts_query is not the main loop. if ( ! $posts_query->is_main_query() ) { return; } // Bail if filters are suppressed on this query. if ( true == $posts_query->get( 'suppress_filters' ) ) { return; } // Bail if in admin. if ( is_admin() ) { return; } /** * Fires at the end of the bp_parse_query function. * * Allow BuddyPress components to parse the main query. * * @since 1.7.0 * * @param WP_Query $posts_query WP_Query instance. Passed by reference. */ do_action_ref_array( 'bp_parse_query', array( &$posts_query ) ); } /** * Possibly intercept the template being loaded. * * Listens to the 'template_include' filter and waits for any BuddyPress specific * template condition to be met. If one is met and the template file exists, * it will be used; otherwise. * * Note that the _edit() checks are ahead of their counterparts, to prevent them * from being stomped on accident. * * @since 1.7.0 * * @param string $template The path to the template file that is being used. * @return string The path to the template file that is being used. */ function bp_template_include_theme_supports( $template = '' ) { /** * Filters whether or not to override the template being loaded in parent/child themes. * * @since 1.7.0 * * @param bool $value Whether or not there is a file override. Default false. * @param string $template The path to the template file that is being used. */ $new_template = apply_filters( 'bp_get_root_template', false, $template ); // A BuddyPress template file was located, so override the WordPress // template and use it to switch off BuddyPress's theme compatibility. if ( ! empty( $new_template ) ) { $template = bp_set_template_included( $new_template ); } /** * Filters the final template being loaded in parent/child themes. * * @since 1.7.0 * * @param string $template The path to the template file that is being used. */ return apply_filters( 'bp_template_include_theme_supports', $template ); } /** * Set the included template. * * @since 1.8.0 * * @param mixed $template Default: false. * @return mixed False if empty. Template name if template included. */ function bp_set_template_included( $template = false ) { buddypress()->theme_compat->found_template = $template; return buddypress()->theme_compat->found_template; } /** * Is a BuddyPress template being included? * * @since 1.8.0 * * @return bool True if yes, false if no. */ function bp_is_template_included() { return isset( buddypress()->theme_compat->found_template ) && buddypress()->theme_compat->found_template; } /** * Attempt to load a custom BP functions file, similar to each themes functions.php file. * * @since 1.7.0 * * @global string $pagenow */ function bp_load_theme_functions() { global $pagenow, $wp_query; // Do not load our custom BP functions file if theme compat is disabled. if ( ! bp_use_theme_compat_with_current_theme() ) { return; } // Do not include on BuddyPress deactivation. if ( bp_is_deactivation() ) { return; } // If the $wp_query global is empty (the main query has not been run, // or has been reset), load_template() will fail at setting certain // global values. This does not happen on a normal page load, but can // cause problems when running automated tests. if ( ! is_a( $wp_query, 'WP_Query' ) ) { return; } // Only include if not installing or if activating via wp-activate.php. if ( ! defined( 'WP_INSTALLING' ) || 'wp-activate.php' === $pagenow ) { bp_locate_template( 'buddypress-functions.php', true ); } } /** * Get the templates to use as the endpoint for BuddyPress template parts. * * @since 1.7.0 * @since 2.4.0 Added singular.php to stack * * @return string Possible root level wrapper template files. */ function bp_get_theme_compat_templates() { return bp_get_query_template( 'buddypress', array( 'plugin-buddypress.php', 'buddypress.php', 'community.php', 'generic.php', 'page.php', 'single.php', 'singular.php', 'index.php' ) ); }