version; } /** * Output the BuddyPress database version. * * @since 1.6.0 */ function bp_db_version() { echo bp_get_db_version(); } /** * Return the BuddyPress database version. * * @since 1.6.0 * * @return string The BuddyPress database version. */ function bp_get_db_version() { return buddypress()->db_version; } /** * Output the BuddyPress database version. * * @since 1.6.0 */ function bp_db_version_raw() { echo bp_get_db_version_raw(); } /** * Return the BuddyPress database version. * * @since 1.6.0 * * @return string The BuddyPress version direct from the database. */ function bp_get_db_version_raw() { $bp = buddypress(); return !empty( $bp->db_version_raw ) ? $bp->db_version_raw : 0; } /** * Check whether the current version of WP exceeds a given version. * * @since 7.0.0 * * @param string $version WP version, in "PHP-standardized" format. * @param string $compare Optional. Comparison operator. Default '>='. * @return bool */ function bp_is_running_wp( $version, $compare = '>=' ) { return version_compare( $GLOBALS['wp_version'], $version, $compare ); } /** Functions *****************************************************************/ /** * Get the $wpdb base prefix, run through the 'bp_core_get_table_prefix' filter. * * The filter is intended primarily for use in multinetwork installations. * * @since 1.2.6 * * @global wpdb $wpdb WordPress database object. * * @return string Filtered database prefix. */ function bp_core_get_table_prefix() { global $wpdb; /** * Filters the $wpdb base prefix. * * Intended primarily for use in multinetwork installations. * * @since 1.2.6 * * @param string $base_prefix Base prefix to use. */ return apply_filters( 'bp_core_get_table_prefix', $wpdb->base_prefix ); } /** * Sort an array of objects or arrays by a specific key/property. * * The main purpose for this function is so that you can avoid having to create * your own awkward callback function for usort(). * * @since 2.2.0 * @since 2.7.0 Added $preserve_keys parameter. * * @param array $items The items to be sorted. Its constituent items * can be either associative arrays or objects. * @param string|int $key The array index or property name to sort by. * @param string $type Sort type. 'alpha' for alphabetical, 'num' * for numeric. Default: 'alpha'. * @param bool $preserve_keys Whether to keep the keys or not. * * @return array $items The sorted array. */ function bp_sort_by_key( $items, $key, $type = 'alpha', $preserve_keys = false ) { $callback = function( $a, $b ) use ( $key, $type ) { $values = array( 0 => false, 1 => false ); foreach ( func_get_args() as $indexi => $index ) { if ( isset( $index->{$key} ) ) { $values[ $indexi ] = $index->{$key}; } elseif ( isset( $index[ $key ] ) ) { $values[ $indexi ] = $index[ $key ]; } } if ( isset( $values[0], $values[1] ) ) { if ( 'num' === $type ) { $cmp = $values[0] - $values[1]; } else { $cmp = strcmp( $values[0], $values[1] ); } if ( 0 > $cmp ) { $retval = -1; } elseif ( 0 < $cmp ) { $retval = 1; } else { $retval = 0; } return $retval; } else { return 0; } }; if ( true === $preserve_keys ) { uasort( $items, $callback ); } else { usort( $items, $callback ); } return $items; } /** * Sort an array of objects or arrays by alphabetically sorting by a specific key/property. * * For instance, if you have an array of WordPress post objects, you can sort * them by post_name as follows: * $sorted_posts = bp_alpha_sort_by_key( $posts, 'post_name' ); * * @since 1.9.0 * * @param array $items The items to be sorted. Its constituent items can be either associative arrays or objects. * @param string|int $key The array index or property name to sort by. * @return array $items The sorted array. */ function bp_alpha_sort_by_key( $items, $key ) { return bp_sort_by_key( $items, $key, 'alpha' ); } /** * Format numbers the BuddyPress way. * * @since 1.2.0 * * @param int $number The number to be formatted. * @param bool $decimals Whether to use decimals. See {@link number_format_i18n()}. * @return string The formatted number. */ function bp_core_number_format( $number = 0, $decimals = false ) { // Force number to 0 if needed. if ( ! is_numeric( $number ) ) { $number = 0; } /** * Filters the BuddyPress formatted number. * * @since 1.2.4 * * @param string $value BuddyPress formatted value. * @param int $number The number to be formatted. * @param bool $decimals Whether or not to use decimals. */ return apply_filters( 'bp_core_number_format', number_format_i18n( $number, $decimals ), $number, $decimals ); } /** * A utility for parsing individual function arguments into an array. * * The purpose of this function is to help with backward compatibility in cases where * * function foo( $bar = 1, $baz = false, $barry = array(), $blip = false ) { // ... * * is deprecated in favor of * * function foo( $args = array() ) { * $defaults = array( * 'bar' => 1, * 'arg2' => false, * 'arg3' => array(), * 'arg4' => false, * ); * $r = bp_parse_args( $args, $defaults ); // ... * * The first argument, $old_args_keys, is an array that matches the parameter positions (keys) to * the new $args keys (values): * * $old_args_keys = array( * 0 => 'bar', // because $bar was the 0th parameter for foo() * 1 => 'baz', // because $baz was the 1st parameter for foo() * 2 => 'barry', // etc * 3 => 'blip' * ); * * For the second argument, $func_args, you should just pass the value of func_get_args(). * * @since 1.6.0 * * @param array $old_args_keys Old argument indexes, keyed to their positions. * @param array $func_args The parameters passed to the originating function. * @return array $new_args The parsed arguments. */ function bp_core_parse_args_array( $old_args_keys, $func_args ) { $new_args = array(); foreach ( $old_args_keys as $arg_num => $arg_key ) { if ( isset( $func_args[ $arg_num ] ) ) { $new_args[ $arg_key ] = $func_args[ $arg_num ]; } } return $new_args; } /** * Merge user defined arguments into defaults array. * * This function is used throughout BuddyPress to allow for either a string or * array to be merged into another array. It is identical to wp_parse_args() * except it allows for arguments to be passively or aggressively filtered using * the optional $filter_key parameter. If no $filter_key is passed, no filters * are applied. * * @since 2.0.0 * * @param string|array $args Value to merge with $defaults. * @param array $defaults Array that serves as the defaults. * @param string $filter_key String to key the filters from. * @return array Merged user defined values with defaults. */ function bp_parse_args( $args, $defaults = array(), $filter_key = '' ) { // Setup a temporary array from $args. if ( is_object( $args ) ) { $r = get_object_vars( $args ); } elseif ( is_array( $args ) ) { $r =& $args; } else { wp_parse_str( $args, $r ); } // Passively filter the args before the parse. if ( ! empty( $filter_key ) ) { /** * Filters the arguments key before parsing if filter key provided. * * This is a dynamic filter dependent on the specified key. * * @since 2.0.0 * * @param array $r Array of arguments to use. */ $r = apply_filters( 'bp_before_' . $filter_key . '_parse_args', $r ); } // Parse. if ( is_array( $defaults ) && ! empty( $defaults ) ) { $r = array_merge( $defaults, $r ); } // Aggressively filter the args after the parse. if ( ! empty( $filter_key ) ) { /** * Filters the arguments key after parsing if filter key provided. * * This is a dynamic filter dependent on the specified key. * * @since 2.0.0 * * @param array $r Array of parsed arguments. */ $r = apply_filters( 'bp_after_' . $filter_key . '_parse_args', $r ); } // Return the parsed results. return $r; } /** * Sanitizes a pagination argument based on both the request override and the * original value submitted via a query argument, likely to a template class * responsible for limiting the result set of a template loop. * * @since 2.2.0 * * @param string $page_arg The $_REQUEST argument to look for. * @param int $page The original page value to fall back to. * @return int A sanitized integer value, good for pagination. */ function bp_sanitize_pagination_arg( $page_arg = '', $page = 1 ) { // Check if request overrides exist. if ( isset( $_REQUEST[ $page_arg ] ) ) { // Get the absolute integer value of the override. $int = absint( $_REQUEST[ $page_arg ] ); // If override is 0, do not use it. This prevents unlimited result sets. // @see https://buddypress.trac.wordpress.org/ticket/5796. if ( $int ) { $page = $int; } } return intval( $page ); } /** * Sanitize an 'order' parameter for use in building SQL queries. * * Strings like 'DESC', 'desc', ' desc' will be interpreted into 'DESC'. * Everything else becomes 'ASC'. * * @since 1.8.0 * * @param string $order The 'order' string, as passed to the SQL constructor. * @return string The sanitized value 'DESC' or 'ASC'. */ function bp_esc_sql_order( $order = '' ) { $order = strtoupper( trim( $order ) ); return 'DESC' === $order ? 'DESC' : 'ASC'; } /** * Escape special characters in a SQL LIKE clause. * * In WordPress 4.0, like_escape() was deprecated, due to incorrect * documentation and improper sanitization leading to a history of misuse. To * maintain compatibility with versions of WP before 4.0, we duplicate the * logic of the replacement, wpdb::esc_like(). * * @since 2.1.0 * * @global wpdb $wpdb WordPress database object. * @see wpdb::esc_like() for more details on proper use. * * @param string $text The raw text to be escaped. * @return string Text in the form of a LIKE phrase. Not SQL safe. Run through * wpdb::prepare() before use. */ function bp_esc_like( $text ) { global $wpdb; if ( method_exists( $wpdb, 'esc_like' ) ) { return $wpdb->esc_like( $text ); } return addcslashes( $text, '_%\\' ); } /** * Are we running username compatibility mode? * * @since 1.5.0 * * @todo Move to members component? * * @return bool False when compatibility mode is disabled, true when enabled. * Default: false. */ function bp_is_username_compatibility_mode() { /** * Filters whether or not to use username compatibility mode. * * @since 1.5.0 * * @param bool $value Whether or not username compatibility mode should be used. */ return apply_filters( 'bp_is_username_compatibility_mode', defined( 'BP_ENABLE_USERNAME_COMPATIBILITY_MODE' ) && BP_ENABLE_USERNAME_COMPATIBILITY_MODE ); } /** * Should we use the WP Toolbar? * * The WP Toolbar, introduced in WP 3.1, is fully supported in BuddyPress as * of BP 1.5. For BP 1.6, the WP Toolbar is the default. * * @since 1.5.0 * * @return bool Default: true. False when WP Toolbar support is disabled. */ function bp_use_wp_admin_bar() { // Default to true. $use_admin_bar = true; // Has the WP Toolbar constant been explicitly opted into? if ( defined( 'BP_USE_WP_ADMIN_BAR' ) ) { $use_admin_bar = (bool) BP_USE_WP_ADMIN_BAR; } /** * Filters whether or not to use the admin bar. * * @since 1.5.0 * * @param bool $use_admin_bar Whether or not to use the admin bar. */ return (bool) apply_filters( 'bp_use_wp_admin_bar', $use_admin_bar ); } /** * Return the parent forum ID for the Legacy Forums abstraction layer. * * @since 1.5.0 * @since 3.0.0 Supported for compatibility with bbPress 2. * * @return int Forum ID. */ function bp_forums_parent_forum_id() { /** * Filters the parent forum ID for the bbPress abstraction layer. * * @since 1.5.0 * * @param int BP_FORUMS_PARENT_FORUM_ID The Parent forum ID constant. */ return apply_filters( 'bp_forums_parent_forum_id', BP_FORUMS_PARENT_FORUM_ID ); } /** Directory *****************************************************************/ /** * Returns an array of core component IDs. * * @since 2.1.0 * * @return array */ function bp_core_get_packaged_component_ids() { $components = array( 'activity', 'members', 'groups', 'blogs', 'xprofile', 'friends', 'messages', 'settings', 'notifications', ); return $components; } /** * Fetch a list of BP directory pages from the appropriate meta table. * * @since 1.5.0 * @since 10.0.0 Eventually switch the current site to BP root's one on multisite configs. * * @param string $status 'active' to return only pages associated with active components, 'all' to return all saved * pages. When running save routines, use 'all' to avoid removing data related to inactive * components. Default: 'active'. * @return array|string An array of page IDs, keyed by component names, or an * empty string if the list is not found. */ function bp_core_get_directory_page_ids( $status = 'active' ) { $page_ids = bp_get_option( 'bp-pages', array() ); $switched = false; /* * Make sure to switch the current site to BP root's one, if needed. * * @see https://buddypress.trac.wordpress.org/ticket/8592 */ if ( is_multisite() ) { $bp_site_id = bp_get_root_blog_id(); if ( $bp_site_id !== get_current_blog_id() ) { switch_to_blog( $bp_site_id ); $switched = true; } } // Loop through pages. foreach ( $page_ids as $component_name => $page_id ) { // Ensure that empty indexes are unset. Should only matter in edge cases. if ( empty( $component_name ) || empty( $page_id ) ) { unset( $page_ids[ $component_name ] ); } // Trashed pages should never appear in results. if ( 'trash' == get_post_status( $page_id ) ) { unset( $page_ids[ $component_name ] ); } // 'register' and 'activate' do not have components, but are allowed as special cases. if ( in_array( $component_name, array( 'register', 'activate' ), true ) ) { continue; } // Remove inactive component pages. if ( ( 'active' === $status ) && ! bp_is_active( $component_name ) ) { unset( $page_ids[ $component_name ] ); } } if ( true === $switched ) { restore_current_blog(); } /** * Filters the list of BP directory pages from the appropriate meta table. * * @since 1.5.0 * @since 2.9.0 Add $status parameter * * @param array $page_ids Array of directory pages. * @param string $status Page status to limit results to */ return (array) apply_filters( 'bp_core_get_directory_page_ids', $page_ids, $status ); } /** * Get the page ID corresponding to a component directory. * * @since 2.6.0 * * @param string|null $component The slug representing the component. Defaults to the current component. * @return int|false The ID of the directory page associated with the component. False if none is found. */ function bp_core_get_directory_page_id( $component = null ) { if ( ! $component ) { $component = bp_current_component(); } $bp_pages = bp_core_get_directory_page_ids( 'all' ); $page_id = false; if ( $component && isset( $bp_pages[ $component ] ) ) { $page_id = (int) $bp_pages[ $component ]; } return $page_id; } /** * Store the list of BP directory pages in the appropriate meta table. * * The bp-pages data is stored in site_options (falls back to options on non-MS), * in an array keyed by blog_id. This allows you to change your * bp_get_root_blog_id() and go through the setup process again. * * @since 1.5.0 * * @param array $blog_page_ids The IDs of the WP pages corresponding to BP * component directories. */ function bp_core_update_directory_page_ids( $blog_page_ids ) { bp_update_option( 'bp-pages', $blog_page_ids ); } /** * Get names and slugs for BuddyPress component directory pages. * * @since 1.5.0 * * @return object Page names, IDs, and slugs. */ function bp_core_get_directory_pages() { global $wpdb; // Look in cache first. $pages = wp_cache_get( 'directory_pages', 'bp_pages' ); if ( false === $pages ) { // Set pages as standard class. $pages = new stdClass; // Get pages and IDs. $page_ids = bp_core_get_directory_page_ids(); if ( !empty( $page_ids ) ) { // Always get page data from the root blog, except on multiblog mode, when it comes // from the current blog. $posts_table_name = bp_is_multiblog_mode() ? $wpdb->posts : $wpdb->get_blog_prefix( bp_get_root_blog_id() ) . 'posts'; $page_ids_sql = implode( ',', wp_parse_id_list( $page_ids ) ); $page_names = $wpdb->get_results( "SELECT ID, post_name, post_parent, post_title FROM {$posts_table_name} WHERE ID IN ({$page_ids_sql}) AND post_status = 'publish' " ); foreach ( (array) $page_ids as $component_id => $page_id ) { foreach ( (array) $page_names as $page_name ) { if ( $page_name->ID == $page_id ) { if ( !isset( $pages->{$component_id} ) || !is_object( $pages->{$component_id} ) ) { $pages->{$component_id} = new stdClass; } $pages->{$component_id}->name = $page_name->post_name; $pages->{$component_id}->id = $page_name->ID; $pages->{$component_id}->title = $page_name->post_title; $slug[] = $page_name->post_name; // Get the slug. while ( $page_name->post_parent != 0 ) { $parent = $wpdb->get_results( $wpdb->prepare( "SELECT post_name, post_parent FROM {$posts_table_name} WHERE ID = %d", $page_name->post_parent ) ); $slug[] = $parent[0]->post_name; $page_name->post_parent = $parent[0]->post_parent; } $pages->{$component_id}->slug = implode( '/', array_reverse( (array) $slug ) ); } unset( $slug ); } } } wp_cache_set( 'directory_pages', $pages, 'bp_pages' ); } /** * Filters the names and slugs for BuddyPress component directory pages. * * @since 1.5.0 * * @param object $pages Object holding page names and slugs. */ return apply_filters( 'bp_core_get_directory_pages', $pages ); } /** * Creates necessary directory pages. * * Directory pages are those WordPress pages used by BP components to display * content (eg, the 'groups' page created by BP). * * @since 1.7.0 * * @param array $components Components to create pages for. * @param string $existing 'delete' if you want to delete existing page mappings * and replace with new ones. Otherwise existing page mappings * are kept, and the gaps filled in with new pages. Default: 'keep'. */ function bp_core_add_page_mappings( $components, $existing = 'keep' ) { // If no value is passed, there's nothing to do. if ( empty( $components ) ) { return; } // Make sure that the pages are created on the root blog no matter which // dashboard the setup is being run on. if ( ! bp_is_root_blog() ) { switch_to_blog( bp_get_root_blog_id() ); } $pages = bp_core_get_directory_page_ids( 'all' ); // Delete any existing pages. if ( 'delete' === $existing ) { foreach ( $pages as $page_id ) { wp_delete_post( $page_id, true ); } $pages = array(); } $page_titles = bp_core_get_directory_page_default_titles(); $pages_to_create = array(); foreach ( array_keys( $components ) as $component_name ) { if ( ! isset( $pages[ $component_name ] ) && isset( $page_titles[ $component_name ] ) ) { $pages_to_create[ $component_name ] = $page_titles[ $component_name ]; } } // Register and Activate are not components, but need pages when // registration is enabled. if ( bp_allow_access_to_registration_pages() ) { foreach ( array( 'register', 'activate' ) as $slug ) { if ( ! isset( $pages[ $slug ] ) ) { $pages_to_create[ $slug ] = $page_titles[ $slug ]; } } } // No need for a Sites directory unless we're on multisite. if ( ! is_multisite() && isset( $pages_to_create['blogs'] ) ) { unset( $pages_to_create['blogs'] ); } // Members must always have a page, no matter what. if ( ! isset( $pages['members'] ) && ! isset( $pages_to_create['members'] ) ) { $pages_to_create['members'] = $page_titles['members']; } // Create the pages. foreach ( $pages_to_create as $component_name => $page_name ) { $exists = get_page_by_path( $component_name ); // If page already exists, use it. if ( ! empty( $exists ) ) { $pages[ $component_name ] = $exists->ID; } else { $pages[ $component_name ] = wp_insert_post( array( 'comment_status' => 'closed', 'ping_status' => 'closed', 'post_status' => 'publish', 'post_title' => $page_name, 'post_type' => 'page', ) ); } } // Save the page mapping. bp_update_option( 'bp-pages', $pages ); // If we had to switch_to_blog, go back to the original site. if ( ! bp_is_root_blog() ) { restore_current_blog(); } } /** * Get the default page titles for BP directory pages. * * @since 2.7.0 * * @return array */ function bp_core_get_directory_page_default_titles() { $page_default_titles = array( 'activity' => _x( 'Activity', 'Page title for the Activity directory.', 'buddypress' ), 'groups' => _x( 'Groups', 'Page title for the Groups directory.', 'buddypress' ), 'blogs' => _x( 'Sites', 'Page title for the Sites directory.', 'buddypress' ), 'members' => _x( 'Members', 'Page title for the Members directory.', 'buddypress' ), 'activate' => _x( 'Activate', 'Page title for the user activation screen.', 'buddypress' ), 'register' => _x( 'Register', 'Page title for the user registration screen.', 'buddypress' ), ); /** * Filters the default page titles array * * @since 2.7.0 * * @param array $page_default_titles the array of default WP (post_title) titles. */ return apply_filters( 'bp_core_get_directory_page_default_titles', $page_default_titles ); } /** * Remove the entry from bp_pages when the corresponding WP page is deleted. * * Bails early on multisite installations when not viewing the root site. * * @link https://buddypress.trac.wordpress.org/ticket/6226 * * @since 2.2.0 * * @param int $post_id Post ID. */ function bp_core_on_directory_page_delete( $post_id ) { // Stop if we are not on the main BP root blog. if ( ! bp_is_root_blog() ) { return; } $page_ids = bp_core_get_directory_page_ids( 'all' ); $component_name = array_search( $post_id, $page_ids ); if ( ! empty( $component_name ) ) { unset( $page_ids[ $component_name ] ); } bp_core_update_directory_page_ids( $page_ids ); } add_action( 'delete_post', 'bp_core_on_directory_page_delete' ); /** * Create a default component slug from a WP page root_slug. * * Since 1.5, BP components get their root_slug (the slug used immediately * following the root domain) from the slug of a corresponding WP page. * * E.g. if your BP installation at example.com has its members page at * example.com/community/people, $bp->members->root_slug will be * 'community/people'. * * By default, this function creates a shorter version of the root_slug for * use elsewhere in the URL, by returning the content after the final '/' * in the root_slug ('people' in the example above). * * Filter on 'bp_core_component_slug_from_root_slug' to override this method * in general, or define a specific component slug constant (e.g. * BP_MEMBERS_SLUG) to override specific component slugs. * * @since 1.5.0 * * @param string $root_slug The root slug, which comes from $bp->pages->[component]->slug. * @return string The short slug for use in the middle of URLs. */ function bp_core_component_slug_from_root_slug( $root_slug ) { $slug_chunks = explode( '/', $root_slug ); $slug = array_pop( $slug_chunks ); /** * Filters the default component slug from a WP page root_slug. * * @since 1.5.0 * * @param string $slug Short slug for use in the middle of URLs. * @param string $root_slug The root slug which comes from $bp->pages-[component]->slug. */ return apply_filters( 'bp_core_component_slug_from_root_slug', $slug, $root_slug ); } /** * Add support for a top-level ("root") component. * * This function originally (pre-1.5) let plugins add support for pages in the * root of the install. These root level pages are now handled by actual * WordPress pages and this function is now a convenience for compatibility * with the new method. * * @since 1.0.0 * * @param string $slug The slug of the component being added to the root list. */ function bp_core_add_root_component( $slug ) { $bp = buddypress(); if ( empty( $bp->pages ) ) { $bp->pages = bp_core_get_directory_pages(); } $match = false; // Check if the slug is registered in the $bp->pages global. foreach ( (array) $bp->pages as $key => $page ) { if ( $key == $slug || $page->slug == $slug ) { $match = true; } } // Maybe create the add_root array. if ( empty( $bp->add_root ) ) { $bp->add_root = array(); } // If there was no match, add a page for this root component. if ( empty( $match ) ) { $add_root_items = $bp->add_root; $add_root_items[] = $slug; $bp->add_root = $add_root_items; } // Make sure that this component is registered as requiring a top-level directory. if ( isset( $bp->{$slug} ) ) { $bp->loaded_components[$bp->{$slug}->slug] = $bp->{$slug}->id; $bp->{$slug}->has_directory = true; } } /** * Create WordPress pages to be used as BP component directories. * * @since 1.5.0 */ function bp_core_create_root_component_page() { // Get BuddyPress. $bp = buddypress(); $new_page_ids = array(); foreach ( (array) $bp->add_root as $slug ) { $new_page_ids[ $slug ] = wp_insert_post( array( 'comment_status' => 'closed', 'ping_status' => 'closed', 'post_title' => ucwords( $slug ), 'post_status' => 'publish', 'post_type' => 'page' ) ); } $page_ids = array_merge( $new_page_ids, bp_core_get_directory_page_ids( 'all' ) ); bp_core_update_directory_page_ids( $page_ids ); } /** * Get the 'search' query argument for a given component. * * @since 2.4.0 * @since 2.7.0 The `$component` parameter was made optional, with the current component * as the fallback value. * * @param string|null $component Optional. Component name. Defaults to current component. * @return string|bool Query argument on success. False on failure. */ function bp_core_get_component_search_query_arg( $component = null ) { if ( ! $component ) { $component = bp_current_component(); } $query_arg = false; if ( isset( buddypress()->{$component}->search_query_arg ) ) { $query_arg = sanitize_title( buddypress()->{$component}->search_query_arg ); } /** * Filters the query arg for a component search string. * * @since 2.4.0 * * @param string $query_arg Query argument. * @param string $component Component name. */ return apply_filters( 'bp_core_get_component_search_query_arg', $query_arg, $component ); } /** * Get a list of all active component objects. * * @since 8.0.0 * * @param array $args { * Optional. An array of key => value arguments to match against the component objects. * Default empty array. * * @type string $name Translatable name for the component. * @type string $id Unique ID for the component. * @type string $slug Unique slug for the component, for use in query strings and URLs. * @type bool $has_directory True if the component has a top-level directory. False otherwise. * @type string $root_slug Slug used by the component's directory page. * } * @param string $output Optional. The type of output to return. Accepts 'ids' * or 'objects'. Default 'ids'. * @param string $operator Optional. The logical operation to perform. 'or' means only one * element from the array needs to match; 'and' means all elements * must match. Accepts 'or' or 'and'. Default 'and'. * @return array A list of component ids or objects. */ function bp_core_get_active_components( $args = array(), $output = 'ids', $operator = 'and' ) { $bp = buddypress(); $active_components = array_keys( $bp->active_components ); $xprofile_id = array_search( 'xprofile', $active_components, true ); if ( false !== $xprofile_id ) { $active_components[ $xprofile_id ] = 'profile'; } $components = array(); foreach ( $active_components as $id ) { if ( isset( $bp->{$id} ) && $bp->{$id} instanceof BP_Component ) { $components[ $id ] = $bp->{$id}; } } $components = wp_filter_object_list( $components, $args, $operator ); if ( 'ids' === $output ) { $components = wp_list_pluck( $components, 'id' ); } return $components; } /** * Determine whether BuddyPress should register the bp-themes directory. * * @since 1.9.0 * * @return bool True if bp-themes should be registered, false otherwise. */ function bp_do_register_theme_directory() { // If bp-default exists in another theme directory, bail. // This ensures that the version of bp-default in the regular themes // directory will always take precedence, as part of a migration away // from the version packaged with BuddyPress. foreach ( array_values( (array) $GLOBALS['wp_theme_directories'] ) as $directory ) { if ( is_dir( $directory . '/bp-default' ) ) { return false; } } // If the current theme is bp-default (or a bp-default child), BP // should register its directory. $register = 'bp-default' === get_stylesheet() || 'bp-default' === get_template(); // Legacy sites continue to have the theme registered. if ( empty( $register ) && ( 1 == get_site_option( '_bp_retain_bp_default' ) ) ) { $register = true; } /** * Filters whether BuddyPress should register the bp-themes directory. * * @since 1.9.0 * * @param bool $register If bp-themes should be registered. */ return apply_filters( 'bp_do_register_theme_directory', $register ); } /** URI ***********************************************************************/ /** * Return the domain for the root blog. * * Eg: http://example.com OR https://example.com * * @since 1.0.0 * * @return string The domain URL for the blog. */ function bp_core_get_root_domain() { $domain = get_home_url( bp_get_root_blog_id() ); /** * Filters the domain for the root blog. * * @since 1.0.1 * * @param string $domain The domain URL for the blog. */ return apply_filters( 'bp_core_get_root_domain', $domain ); } /** * Perform a status-safe wp_redirect() that is compatible with BP's URI parser. * * @since 1.0.0 * * @param string $location The redirect URL. * @param int $status Optional. The numeric code to give in the redirect * headers. Default: 302. */ function bp_core_redirect( $location = '', $status = 302 ) { // On some setups, passing the value of wp_get_referer() may result in an // empty value for $location, which results in an error. Ensure that we // have a valid URL. if ( empty( $location ) ) { $location = bp_get_root_domain(); } // Make sure we don't call status_header() in bp_core_do_catch_uri() as this // conflicts with wp_redirect() and wp_safe_redirect(). buddypress()->no_status_set = true; wp_safe_redirect( $location, $status ); // If PHPUnit is running, do not kill execution. if ( ! defined( 'BP_TESTS_DIR' ) ) { die; } } /** * Return the URL path of the referring page. * * This is a wrapper for `wp_get_referer()` that sanitizes the referer URL to * a webroot-relative path. For example, 'http://example.com/foo/' will be * reduced to '/foo/'. * * @since 2.3.0 * * @return bool|string Returns false on error, a URL path on success. */ function bp_get_referer_path() { $referer = wp_get_referer(); if ( false === $referer ) { return false; } // Turn into an absolute path. $referer = preg_replace( '|https?\://[^/]+/|', '/', $referer ); return $referer; } /** * Get the path of the current site. * * @since 1.0.0 * * @global object $current_site * * @return string URL to the current site. */ function bp_core_get_site_path() { global $current_site; if ( is_multisite() ) { $site_path = $current_site->path; } else { $site_path = (array) explode( '/', home_url() ); if ( count( $site_path ) < 2 ) { $site_path = '/'; } else { // Unset the first three segments (http(s)://example.com part). unset( $site_path[0] ); unset( $site_path[1] ); unset( $site_path[2] ); if ( !count( $site_path ) ) { $site_path = '/'; } else { $site_path = '/' . implode( '/', $site_path ) . '/'; } } } /** * Filters the path of the current site. * * @since 1.2.0 * * @param string $site_path URL to the current site. */ return apply_filters( 'bp_core_get_site_path', $site_path ); } /** Time **********************************************************************/ /** * Get the current GMT time to save into the DB. * * @since 1.2.6 * * @param bool $gmt True to use GMT (rather than local) time. Default: true. * @param string $type See the 'type' parameter in {@link current_time()}. * Default: 'mysql'. * @return string Current time in 'Y-m-d h:i:s' format. */ function bp_core_current_time( $gmt = true, $type = 'mysql' ) { /** * Filters the current GMT time to save into the DB. * * @since 1.2.6 * * @param string $value Current GMT time. */ return apply_filters( 'bp_core_current_time', current_time( $type, $gmt ) ); } /** * Calculate the human time difference between two dates. * * Based on function created by Dunstan Orchard - http://1976design.com * * @since 8.0.0 * * @param array $args { * An array of arguments. All arguments are technically optional. * * @type int|string $older_date An integer Unix timestamp or a date string of the format 'Y-m-d h:i:s'. * @type int|string $newer_date An integer Unix timestamp or a date string of the format 'Y-m-d h:i:s'. * @type int $time_chunks The number of time chunks to get (1 or 2). * } * @return null|array|false Null if there's no time diff. An array containing 1 or 2 chunks * of human time. False if travelling into the future. */ function bp_core_time_diff( $args = array() ) { $retval = null; $r = bp_parse_args( $args, array( 'older_date' => 0, 'newer_date' => bp_core_current_time( true, 'timestamp' ), 'time_chunks' => 2, ) ); // Array of time period chunks. $chunks = array( YEAR_IN_SECONDS, 30 * DAY_IN_SECONDS, WEEK_IN_SECONDS, DAY_IN_SECONDS, HOUR_IN_SECONDS, MINUTE_IN_SECONDS, 1 ); foreach ( array( 'older_date', 'newer_date' ) as $date ) { if ( ! $r[ $date ] ) { continue; } if ( ! is_numeric( $r[ $date ] ) ) { $time_chunks = explode( ':', str_replace( ' ', ':', $r[ $date ] ) ); $date_chunks = explode( '-', str_replace( ' ', '-', $r[ $date ] ) ); $r[ $date ] = gmmktime( (int) $time_chunks[1], (int) $time_chunks[2], (int) $time_chunks[3], (int) $date_chunks[1], (int) $date_chunks[2], (int) $date_chunks[0] ); } } // Difference in seconds. $diff = $r['newer_date'] - $r['older_date']; /** * We only want to return one or two chunks of time here, eg: * - `array( 'x years', 'xx months' )`, * - `array( 'x days', 'xx hours' )`. * So there's only two bits of calculation below. */ if ( 0 <= $diff && (int) $r['time_chunks'] ) { // Step one: the first chunk. for ( $i = 0, $j = count( $chunks ); $i < $j; ++$i ) { $seconds = $chunks[$i]; // Finding the biggest chunk (if the chunk fits, break). $count = floor( $diff / $seconds ); if ( 0 != $count ) { break; } } // Add the first chunk of time diff. if ( isset( $chunks[ $i ] ) ) { $retval = array(); switch ( $seconds ) { case YEAR_IN_SECONDS : /* translators: %s: the number of years. */ $retval[] = sprintf( _n( '%s year', '%s years', $count, 'buddypress' ), $count ); break; case 30 * DAY_IN_SECONDS : /* translators: %s: the number of months. */ $retval[] = sprintf( _n( '%s month', '%s months', $count, 'buddypress' ), $count ); break; case WEEK_IN_SECONDS : /* translators: %s: the number of weeks. */ $retval[]= sprintf( _n( '%s week', '%s weeks', $count, 'buddypress' ), $count ); break; case DAY_IN_SECONDS : /* translators: %s: the number of days. */ $retval[] = sprintf( _n( '%s day', '%s days', $count, 'buddypress' ), $count ); break; case HOUR_IN_SECONDS : /* translators: %s: the number of hours. */ $retval[] = sprintf( _n( '%s hour', '%s hours', $count, 'buddypress' ), $count ); break; case MINUTE_IN_SECONDS : /* translators: %s: the number of minutes. */ $retval[] = sprintf( _n( '%s minute', '%s minutes', $count, 'buddypress' ), $count ); break; default: /* translators: %s: the number of seconds. */ $retval[] = sprintf( _n( '%s second', '%s seconds', $count, 'buddypress' ), $count ); } /** * Step two: the second chunk. * * A quirk in the implementation means that this condition fails in the case of minutes and seconds. * We've left the quirk in place, since fractions of a minute are not a useful piece of information * for our purposes. */ if ( 2 === (int) $r['time_chunks'] && $i + 2 < $j ) { $seconds2 = $chunks[$i + 1]; $count2 = floor( ( $diff - ( $seconds * $count ) ) / $seconds2 ); // Add the second chunk of time diff. if ( 0 !== (int) $count2 ) { switch ( $seconds2 ) { case 30 * DAY_IN_SECONDS : /* translators: %s: the number of months. */ $retval[] = sprintf( _n( '%s month', '%s months', $count2, 'buddypress' ), $count2 ); break; case WEEK_IN_SECONDS : /* translators: %s: the number of weeks. */ $retval[] = sprintf( _n( '%s week', '%s weeks', $count2, 'buddypress' ), $count2 ); break; case DAY_IN_SECONDS : /* translators: %s: the number of days. */ $retval[] = sprintf( _n( '%s day', '%s days', $count2, 'buddypress' ), $count2 ); break; case HOUR_IN_SECONDS : /* translators: %s: the number of hours. */ $retval[] = sprintf( _n( '%s hour', '%s hours', $count2, 'buddypress' ), $count2 ); break; case MINUTE_IN_SECONDS : /* translators: %s: the number of minutes. */ $retval[] = sprintf( _n( '%s minute', '%s minutes', $count2, 'buddypress' ), $count2 ); break; default: /* translators: %s: the number of seconds. */ $retval[] = sprintf( _n( '%s second', '%s seconds', $count2, 'buddypress' ), $count2 ); } } } } } else { // Something went wrong with date calculation and we ended up with a negative date. $retval = false; } return $retval; } /** * Get an English-language representation of the time elapsed since a given date. * * This function will return an English representation of the time elapsed * since a given date. * eg: 2 hours, 50 minutes * eg: 4 days * eg: 4 weeks, 6 days * * Note that fractions of minutes are not represented in the return string. So * an interval of 3 minutes will be represented by "3 minutes ago", as will an * interval of 3 minutes 59 seconds. * * @since 1.0.0 * @since 8.0.0 Move the time difference calculation into `bp_core_time_diff()`. * * @param int|string $older_date The earlier time from which you're calculating * the time elapsed. Enter either as an integer Unix timestamp, * or as a date string of the format 'Y-m-d h:i:s'. * @param int|bool $newer_date Optional. Unix timestamp of date to compare older * date to. Default: false (current time). * @return string String representing the time since the older date, eg * "2 hours, 50 minutes". */ function bp_core_time_since( $older_date, $newer_date = false ) { /** * Filters whether or not to bypass BuddyPress' time_since calculations. * * @since 1.7.0 * * @param bool $value Whether or not to bypass. * @param string $older_date Earlier time from which we're calculating time elapsed. * @param string $newer_date Unix timestamp of date to compare older time to. */ $pre_value = apply_filters( 'bp_core_time_since_pre', false, $older_date, $newer_date ); if ( false !== $pre_value ) { return $pre_value; } $newer_date = (int) $newer_date; $args = array( 'older_date' => $older_date, ); if ( $newer_date) { $args['newer_date'] = $newer_date; } // Calculate the time difference. $time_diff = bp_core_time_diff( $args ); /** * Filters the value to use if the time since is some time ago. * * @since 1.5.0 * * @param string $value String representing the time since the older date. */ $ago_text = apply_filters( 'bp_core_time_since_ago_text', /* translators: %s: the human time diff. */ __( '%s ago', 'buddypress' ) ); /** * Filters the value to use if the time since is right now. * * @since 1.5.0 * * @param string $value String representing the time since the older date. */ $output = apply_filters( 'bp_core_time_since_right_now_text', __( 'right now', 'buddypress' ) ); if ( is_array( $time_diff ) ) { $separator = _x( ',', 'Separator in time since', 'buddypress' ) . ' '; $diff_text = implode( $separator, $time_diff ); $output = sprintf( $ago_text, $diff_text ); } elseif ( false === $time_diff ) { /** * Filters the value to use if the time since is unknown. * * @since 1.5.0 * * @param string $value String representing the time since the older date. */ $unknown_text = apply_filters( 'bp_core_time_since_unknown_text', __( 'sometime', 'buddypress' ) ); $output = sprintf( $ago_text, $unknown_text ); } /** * Filters the English-language representation of the time elapsed since a given date. * * @since 1.7.0 * * @param string $output Final 'time since' string. * @param string $older_date Earlier time from which we're calculating time elapsed. * @param string $newer_date Unix timestamp of date to compare older time to. */ return apply_filters( 'bp_core_time_since', $output, $older_date, $newer_date ); } /** * Get an age to display according to the birth date. * * @since 8.0.0 * * @param int|string $birth_date A timestamp or a MySQL formatted date. * @return string The age to display. */ function bp_core_time_old( $birth_date ) { $time_diff = bp_core_time_diff( array( 'older_date' => $birth_date, 'time_chunks' => 1 ) ); $retval = '—'; if ( $time_diff ) { $age = reset( $time_diff ); /** * Filters the value to use to display the age. * * @since 8.0.0 * * @param string $value String representing the time since the older date. * @param int $age The age. */ $age_text = apply_filters( 'bp_core_time_old_text', /* translators: %d: the age . */ __( '%s old', 'buddypress' ), $age ); $retval = sprintf( $age_text, $age ); } return $retval; } /** * Output an ISO-8601 date from a date string. * * @since 2.7.0 * * @param string String of date to convert. Timezone should be UTC before using this. * @return string|null */ function bp_core_iso8601_date( $timestamp = '' ) { echo bp_core_get_iso8601_date( $timestamp ); } /** * Return an ISO-8601 date from a date string. * * @since 2.7.0 * * @param string String of date to convert. Timezone should be UTC before using this. * @return string */ function bp_core_get_iso8601_date( $timestamp = '' ) { if ( ! $timestamp ) { return ''; } try { $date = new DateTime( $timestamp, new DateTimeZone( 'UTC' ) ); // Not a valid date, so return blank string. } catch( Exception $e ) { return ''; } return $date->format( DateTime::ISO8601 ); } /** Messages ******************************************************************/ /** * Add a feedback (error/success) message to the WP cookie so it can be displayed after the page reloads. * * @since 1.0.0 * * @param string $message Feedback message to be displayed. * @param string $type Message type. 'updated', 'success', 'error', 'warning'. * Default: 'success'. */ function bp_core_add_message( $message, $type = '' ) { // Success is the default. if ( empty( $type ) ) { $type = 'success'; } // Send the values to the cookie for page reload display. @setcookie( 'bp-message', $message, time() + 60 * 60 * 24, COOKIEPATH, COOKIE_DOMAIN, is_ssl() ); @setcookie( 'bp-message-type', $type, time() + 60 * 60 * 24, COOKIEPATH, COOKIE_DOMAIN, is_ssl() ); // Get BuddyPress. $bp = buddypress(); /** * Send the values to the $bp global so we can still output messages * without a page reload */ $bp->template_message = $message; $bp->template_message_type = $type; } /** * Set up the display of the 'template_notices' feedback message. * * Checks whether there is a feedback message in the WP cookie and, if so, adds * a "template_notices" action so that the message can be parsed into the * template and displayed to the user. * * After the message is displayed, it removes the message vars from the cookie * so that the message is not shown to the user multiple times. * * @since 1.1.0 */ function bp_core_setup_message() { // Get BuddyPress. $bp = buddypress(); if ( empty( $bp->template_message ) && isset( $_COOKIE['bp-message'] ) ) { $bp->template_message = stripslashes( $_COOKIE['bp-message'] ); } if ( empty( $bp->template_message_type ) && isset( $_COOKIE['bp-message-type'] ) ) { $bp->template_message_type = stripslashes( $_COOKIE['bp-message-type'] ); } add_action( 'template_notices', 'bp_core_render_message' ); if ( isset( $_COOKIE['bp-message'] ) ) { @setcookie( 'bp-message', false, time() - 1000, COOKIEPATH, COOKIE_DOMAIN, is_ssl() ); } if ( isset( $_COOKIE['bp-message-type'] ) ) { @setcookie( 'bp-message-type', false, time() - 1000, COOKIEPATH, COOKIE_DOMAIN, is_ssl() ); } } add_action( 'bp_actions', 'bp_core_setup_message', 5 ); /** * Render the 'template_notices' feedback message. * * The hook action 'template_notices' is used to call this function, it is not * called directly. * * @since 1.1.0 */ function bp_core_render_message() { // Get BuddyPress. $bp = buddypress(); if ( !empty( $bp->template_message ) ) : $type = ( 'success' === $bp->template_message_type ) ? 'updated' : 'error'; /** * Filters the 'template_notices' feedback message content. * * @since 1.5.5 * * @param string $template_message Feedback message content. * @param string $type The type of message being displayed. * Either 'updated' or 'error'. */ $content = apply_filters( 'bp_core_render_message_content', $bp->template_message, $type ); ?>
"{{usermessage}}"\n\nGo to the discussion to reply or catch up on the conversation.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{poster.name}} replied to one of your updates:\n\n\"{{usermessage}}\"\n\nGo to the discussion to reply or catch up on the conversation: {{{thread.url}}}", 'buddypress' ), ), 'activity-comment-author' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] {{poster.name}} replied to one of your comments', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{poster.name}} replied to one of your comments:\n\n
"{{usermessage}}"\n\nGo to the discussion to reply or catch up on the conversation.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{poster.name}} replied to one of your comments:\n\n\"{{usermessage}}\"\n\nGo to the discussion to reply or catch up on the conversation: {{{thread.url}}}", 'buddypress' ), ), 'activity-at-message' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] {{poster.name}} mentioned you in a status update', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{poster.name}} mentioned you in a status update:\n\n
"{{usermessage}}"\n\nGo to the discussion to reply or catch up on the conversation.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{poster.name}} mentioned you in a status update:\n\n\"{{usermessage}}\"\n\nGo to the discussion to reply or catch up on the conversation: {{{mentioned.url}}}", 'buddypress' ), ), 'groups-at-message' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] {{poster.name}} mentioned you in an update', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{poster.name}} mentioned you in the group \"{{group.name}}\":\n\n
"{{usermessage}}"\n\nGo to the discussion to reply or catch up on the conversation.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{poster.name}} mentioned you in the group \"{{group.name}}\":\n\n\"{{usermessage}}\"\n\nGo to the discussion to reply or catch up on the conversation: {{{mentioned.url}}}", 'buddypress' ), ), 'core-user-registration' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Activate your account', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "Thanks for registering!\n\nTo complete the activation of your account, go to the following link and click on the Activate button:\n{{{activate.url}}}\n\nIf the 'Activation Key' field is empty, copy and paste the following into the field - {{key}}", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "Thanks for registering!\n\nTo complete the activation of your account, go to the following link and click on the 'Activate' button: {{{activate.url}}}\n\nIf the 'Activation Key' field is empty, copy and paste the following into the field - {{key}}", 'buddypress' ) ), 'core-user-registration-with-blog' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Activate {{{user-site.url}}}', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "Thanks for registering!\n\nTo complete the activation of your account and site, go to the following link: {{{activate-site.url}}}.\n\nAfter you activate, you can visit your site at {{{user-site.url}}}.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "Thanks for registering!\n\nTo complete the activation of your account and site, go to the following link: {{{activate-site.url}}}\n\nAfter you activate, you can visit your site at {{{user-site.url}}}.", 'buddypress' ), 'args' => array( 'multisite' => true, ), ), 'friends-request' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] New friendship request from {{initiator.name}}', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{initiator.name}} wants to add you as a friend.\n\nTo accept this request and manage all of your pending requests, visit: {{{friend-requests.url}}}", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{initiator.name}} wants to add you as a friend.\n\nTo accept this request and manage all of your pending requests, visit: {{{friend-requests.url}}}\n\nTo view {{initiator.name}}'s profile, visit: {{{initiator.url}}}", 'buddypress' ), ), 'friends-request-accepted' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] {{friend.name}} accepted your friendship request', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{friend.name}} accepted your friend request.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{friend.name}} accepted your friend request.\n\nTo learn more about them, visit their profile: {{{friendship.url}}}", 'buddypress' ), ), 'groups-details-updated' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Group details updated', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "Group details for the group "{{group.name}}" were updated:\n
{{changed_text}}", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "Group details for the group \"{{group.name}}\" were updated:\n\n{{changed_text}}\n\nTo view the group, visit: {{{group.url}}}", 'buddypress' ), ), 'groups-invitation' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] You have an invitation to the group: "{{group.name}}"', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{inviter.name}} has invited you to join the group: "{{group.name}}".\n\n{{invite.message}}\n\nGo here to accept your invitation or visit the group to learn more.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{inviter.name}} has invited you to join the group: \"{{group.name}}\".\n\n{{invite.message}}\n\nTo accept your invitation, visit: {{{invites.url}}}\n\nTo learn more about the group, visit: {{{group.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ), ), 'groups-member-promoted' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] You have been promoted in the group: "{{group.name}}"', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "You have been promoted to {{promoted_to}} in the group "{{group.name}}".", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "You have been promoted to {{promoted_to}} in the group: \"{{group.name}}\".\n\nTo visit the group, go to: {{{group.url}}}", 'buddypress' ), ), 'groups-membership-request' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Membership request for group: {{group.name}}', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{requesting-user.name}} wants to join the group "{{group.name}}".\n {{request.message}}\n As you are an administrator of this group, you must either accept or reject the membership request.\n\nGo here to manage this and all other pending requests.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{requesting-user.name}} wants to join the group \"{{group.name}}\". As you are the administrator of this group, you must either accept or reject the membership request.\n\nTo manage this and all other pending requests, visit: {{{group-requests.url}}}\n\nTo view {{requesting-user.name}}'s profile, visit: {{{profile.url}}}", 'buddypress' ), ), 'messages-unread' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] New message from {{sender.name}}', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{sender.name}} sent you a new message: "{{usersubject}}"\n\n
"{{usermessage}}"\n\nGo to the discussion to reply or catch up on the conversation.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{sender.name}} sent you a new message: \"{{usersubject}}\"\n\n\"{{usermessage}}\"\n\nGo to the discussion to reply or catch up on the conversation: {{{message.url}}}", 'buddypress' ), ), 'settings-verify-email-change' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Verify your new email address', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "You recently changed the email address associated with your account on {{site.name}} to {{user.email}}. If this is correct, go here to confirm the change.\n\nOtherwise, you can safely ignore and delete this email if you have changed your mind, or if you think you have received this email in error.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "You recently changed the email address associated with your account on {{site.name}} to {{user.email}}. If this is correct, go to the following link to confirm the change: {{{verify.url}}}\n\nOtherwise, you can safely ignore and delete this email if you have changed your mind, or if you think you have received this email in error.", 'buddypress' ), ), 'groups-membership-request-accepted' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Membership request for group "{{group.name}}" accepted', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "Your membership request for the group "{{group.name}}" has been accepted.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been accepted.\n\nTo view the group, visit: {{{group.url}}}", 'buddypress' ), ), 'groups-membership-request-rejected' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Membership request for group "{{group.name}}" rejected', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "Your membership request for the group "{{group.name}}" has been rejected.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "Your membership request for the group \"{{group.name}}\" has been rejected.\n\nTo request membership again, visit: {{{group.url}}}", 'buddypress' ), ), 'groups-membership-request-accepted-by-admin' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Membership request for group "{{group.name}}" accepted', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "An administrator accepted an invitation to join "{{group.name}}" on your behalf.\n\nIf you disagree with this, you can leave the group at anytime visiting your groups memberships page.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "An administrator accepted an invitation to join \"{{group.name}}\" on your behalf.\n\nIf you disagree with this, you can leave the group at anytime visiting your groups memberships page: {{{leave-group.url}}}", 'buddypress' ), ), 'groups-membership-request-rejected-by-admin' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '[{{{site.name}}}] Membership request for group "{{group.name}}" rejected', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "An administrator rejected an invitation to join "{{group.name}}" on your behalf.\n\nIf you disagree with this, please contact the site administrator.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "An administrator rejected an invitation to join \"{{group.name}}\" on your behalf.\n\nIf you disagree with this, please contact the site administrator.", 'buddypress' ), ), 'bp-members-invitation' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '{{inviter.name}} has invited you to join {{site.name}}', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{inviter.name}} has invited you to join the site: "{{site.name}}".\n\n{{usermessage}}\n\nAccept your invitation or visit the site to learn more.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{inviter.name}} has invited you to join the site \"{{site.name}}\".\n\n{{usermessage}}\n\nTo accept your invitation, visit: {{{invite.accept_url}}}\n\nTo learn more about the site, visit: {{{site.url}}}.\nTo view {{inviter.name}}'s profile, visit: {{{inviter.url}}}", 'buddypress' ), ), 'members-membership-request' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( '{{requesting-user.user_login}} would like to join {{site.name}}', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "{{requesting-user.user_login}} would like to join the site: "{{site.name}}".\n\nManage the request.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "{{requesting-user.user_login}} would like to join the site \"{{site.name}}\".\n\nTo manage the request, visit: {{{manage.url}}}.", 'buddypress' ), ), 'members-membership-request-rejected' => array( /* translators: do not remove {} brackets or translate its contents. */ 'post_title' => __( 'Your request to join {{site.name}} has been declined', 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_content' => __( "Sorry, your request to join the site "{{site.name}}" has been declined.", 'buddypress' ), /* translators: do not remove {} brackets or translate its contents. */ 'post_excerpt' => __( "Sorry, your request to join the site \"{{site.name}}\" has been declined.", 'buddypress' ), ), ) ); } /** * Get a list of emails for populating email type taxonomy terms. * * @since 2.5.1 * @since 2.7.0 $field argument added. * * @param string $field Optional; defaults to "description" for backwards compatibility. Other values: "all". * @return array { * The array of email types and their schema. * * @type string $description The description of the action which causes this to trigger. * @type array $unsubscribe { * Replacing this with false indicates that a user cannot unsubscribe from this type. * * @type string $meta_key The meta_key used to toggle the email setting for this notification. * @type string $message The message shown when the user has successfully unsubscribed. * } */ function bp_email_get_type_schema( $field = 'description' ) { $activity_comment = array( 'description' => __( 'A member has replied to an activity update that the recipient posted.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_activity_new_reply', 'message' => __( 'You will no longer receive emails when someone replies to an update or comment you posted.', 'buddypress' ), ), ); $activity_comment_author = array( 'description' => __( 'A member has replied to a comment on an activity update that the recipient posted.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_activity_new_reply', 'message' => __( 'You will no longer receive emails when someone replies to an update or comment you posted.', 'buddypress' ), ), ); $activity_at_message = array( 'description' => __( 'Recipient was mentioned in an activity update.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_activity_new_mention', 'message' => __( 'You will no longer receive emails when someone mentions you in an update.', 'buddypress' ), ), ); $groups_at_message = array( 'description' => __( 'Recipient was mentioned in a group activity update.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_activity_new_mention', 'message' => __( 'You will no longer receive emails when someone mentions you in an update.', 'buddypress' ), ), ); $core_user_registration = array( 'description' => __( 'Recipient has registered for an account.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => false, ); $core_user_registration_with_blog = array( 'description' => __( 'Recipient has registered for an account and site.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => false, ); $friends_request = array( 'description' => __( 'A member has sent a friend request to the recipient.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_friends_friendship_request', 'message' => __( 'You will no longer receive emails when someone sends you a friend request.', 'buddypress' ), ), ); $friends_request_accepted = array( 'description' => __( 'Recipient has had a friend request accepted by a member.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_friends_friendship_accepted', 'message' => __( 'You will no longer receive emails when someone accepts your friendship request.', 'buddypress' ), ), ); $groups_details_updated = array( 'description' => __( "A group's details were updated.", 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_groups_group_updated', 'message' => __( 'You will no longer receive emails when one of your groups is updated.', 'buddypress' ), ), ); $groups_invitation = array( 'description' => __( 'A member has sent a group invitation to the recipient.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_groups_invite', 'message' => __( 'You will no longer receive emails when you are invited to join a group.', 'buddypress' ), ), ); $groups_member_promoted = array( 'description' => __( "Recipient's status within a group has changed.", 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_groups_admin_promotion', 'message' => __( 'You will no longer receive emails when you have been promoted in a group.', 'buddypress' ), ), ); $groups_membership_request = array( 'description' => __( 'A member has requested permission to join a group.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_groups_membership_request', 'message' => __( 'You will no longer receive emails when someone requests to be a member of your group.', 'buddypress' ), ), ); $messages_unread = array( 'description' => __( 'Recipient has received a private message.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_messages_new_message', 'message' => __( 'You will no longer receive emails when someone sends you a message.', 'buddypress' ), ), ); $settings_verify_email_change = array( 'description' => __( 'Recipient has changed their email address.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => false, ); $groups_membership_request_accepted = array( 'description' => __( 'Recipient had requested to join a group, which was accepted.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_membership_request_completed', 'message' => __( 'You will no longer receive emails when your request to join a group has been accepted or denied.', 'buddypress' ), ), ); $groups_membership_request_rejected = array( 'description' => __( 'Recipient had requested to join a group, which was rejected.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_membership_request_completed', 'message' => __( 'You will no longer receive emails when your request to join a group has been accepted or denied.', 'buddypress' ), ), ); $groups_membership_request_accepted_by_admin = array( 'description' => __( 'Recipient had requested to join a group, which was accepted by admin.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => false, ); $groups_membership_request_rejected_by_admin = array( 'description' => __( 'Recipient had requested to join a group, which was rejected by admin.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => false, ); $core_user_activation = array( 'description' => __( 'Recipient has successfully activated an account.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => false, ); $members_invitation = array( 'description' => __( 'A site member has sent a site invitation to the recipient.', 'buddypress' ), 'named_salutation' => false, 'unsubscribe' => array( 'meta_key' => 'notification_bp_members_invite', 'message' => __( 'You will no longer receive emails when you are invited to join this site.', 'buddypress' ), ), ); $members_membership_request = array( 'description' => __( 'Someone has requested membership on this site.', 'buddypress' ), 'named_salutation' => true, 'unsubscribe' => array( 'meta_key' => 'notification_members_membership_request', 'message' => __( 'You will no longer receive emails when people submit requests to join this site.', 'buddypress' ), ), ); $members_membership_request_rejected = array( 'description' => __( 'A site membership request has been rejected.', 'buddypress' ), 'named_salutation' => false, 'unsubscribe' => false, ); $types = array( 'activity-comment' => $activity_comment, 'activity-comment-author' => $activity_comment_author, 'activity-at-message' => $activity_at_message, 'groups-at-message' => $groups_at_message, 'core-user-registration' => $core_user_registration, 'core-user-registration-with-blog' => $core_user_registration_with_blog, 'friends-request' => $friends_request, 'friends-request-accepted' => $friends_request_accepted, 'groups-details-updated' => $groups_details_updated, 'groups-invitation' => $groups_invitation, 'groups-member-promoted' => $groups_member_promoted, 'groups-membership-request' => $groups_membership_request, 'messages-unread' => $messages_unread, 'settings-verify-email-change' => $settings_verify_email_change, 'groups-membership-request-accepted' => $groups_membership_request_accepted, 'groups-membership-request-rejected' => $groups_membership_request_rejected, 'core-user-activation' => $core_user_activation, 'bp-members-invitation' => $members_invitation, 'members-membership-request' => $members_membership_request, 'members-membership-request-rejected' => $members_membership_request_rejected, 'groups-membership-request-accepted-by-admin' => $groups_membership_request_accepted_by_admin, 'groups-membership-request-rejected-by-admin' => $groups_membership_request_rejected_by_admin, ); if ( $field !== 'all' ) { return wp_list_pluck( $types, $field ); } else { return $types; } } /** * Handles unsubscribing user from notification emails. * * @since 2.7.0 */ function bp_email_unsubscribe_handler() { $emails = bp_email_get_unsubscribe_type_schema(); $raw_email_type = ! empty( $_GET['nt'] ) ? $_GET['nt'] : ''; $raw_hash = ! empty( $_GET['nh'] ) ? $_GET['nh'] : ''; $raw_user_id = ! empty( $_GET['uid'] ) ? absint( $_GET['uid'] ) : 0; $raw_user_email = ! empty( $_GET['uem'] ) ? $_GET['uem'] : ''; $raw_member_id = ! empty( $_GET['mid'] ) ? absint( $_GET['mid'] ) : 0; $redirect_to = ''; $new_hash = ''; if ( ! empty( $raw_user_id ) ) { $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_id}", bp_email_get_salt() ); } else if ( ! empty( $raw_user_email ) ) { $new_hash = hash_hmac( 'sha1', "{$raw_email_type}:{$raw_user_email}", bp_email_get_salt() ); } // Check required values. if ( ( ! $raw_user_id && ! $raw_user_email ) || ! $raw_email_type || ! $raw_hash || ! array_key_exists( $raw_email_type, $emails ) ) { $redirect_to = wp_login_url(); $result_msg = __( 'Something has gone wrong.', 'buddypress' ); $unsub_msg = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' ); // Check valid hash. } elseif ( ! hash_equals( $new_hash, $raw_hash ) ) { $redirect_to = wp_login_url(); $result_msg = __( 'Something has gone wrong.', 'buddypress' ); $unsub_msg = __( 'Please log in and go to your settings to unsubscribe from notification emails.', 'buddypress' ); // Don't let authenticated users unsubscribe other users' email notifications. } elseif ( is_user_logged_in() && get_current_user_id() !== $raw_user_id ) { $result_msg = __( 'Something has gone wrong.', 'buddypress' ); $unsub_msg = __( 'Please go to your notifications settings to unsubscribe from emails.', 'buddypress' ); if ( bp_is_active( 'settings' ) ) { $redirect_to = sprintf( '%s%s/notifications/', bp_core_get_user_domain( get_current_user_id() ), bp_get_settings_slug() ); } else { $redirect_to = bp_core_get_user_domain( get_current_user_id() ); } // This is an unsubscribe request from a nonmember. } else if ( $raw_user_email ) { // Unsubscribe. if ( bp_user_has_opted_out() ) { $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message']; $unsub_msg = __( 'You have already unsubscribed from all communication from this site.', 'buddypress' ); } else { $optout_args = array( 'email_address' => $raw_user_email, 'user_id' => $raw_member_id, 'email_type' => $raw_email_type, 'date_modified' => bp_core_current_time(), ); bp_add_optout( $optout_args ); $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message']; $unsub_msg = __( 'You have been unsubscribed.', 'buddypress' ); } // This is an unsubscribe request from a current member. } else { if ( bp_is_active( 'settings' ) ) { $redirect_to = sprintf( '%s%s/notifications/', bp_core_get_user_domain( $raw_user_id ), bp_get_settings_slug() ); } else { $redirect_to = bp_core_get_user_domain( $raw_user_id ); } // Unsubscribe. $meta_key = $emails[ $raw_email_type ]['unsubscribe']['meta_key']; bp_update_user_meta( $raw_user_id, $meta_key, 'no' ); $result_msg = $emails[ $raw_email_type ]['unsubscribe']['message']; $unsub_msg = __( 'You can change this or any other email notification preferences in your email settings.', 'buddypress' ); } if ( $raw_user_id && $redirect_to ) { $message = sprintf( '%1$s %3$s', $result_msg, esc_url( $redirect_to ), esc_html( $unsub_msg ) ); // Template notices are only displayed on BP pages. bp_core_add_message( $message ); bp_core_redirect( bp_core_get_user_domain( $raw_user_id ) ); exit; } else { wp_die( sprintf( '%1$s %2$s', esc_html( $unsub_msg ), esc_html( $result_msg ) ), esc_html( $unsub_msg ), array( 'link_url' => home_url(), 'link_text' => __( 'Go to website\'s home page.', 'buddypress' ), ) ); } } /** * Creates unsubscribe link for notification emails. * * @since 2.7.0 * * @param string $redirect_to The URL to which the unsubscribe query string is appended. * @param array $args { * Used to build unsubscribe query string. * * @type string $notification_type Which notification type is being sent. * @type string $user_id The ID of the user to whom the notification is sent. * @type string $redirect_to Optional. The url to which the user will be redirected. Default is the activity directory. * @type string $email Optional. The email address of the user to whom the notification is sent. * } * @return string The unsubscribe link. */ function bp_email_get_unsubscribe_link( $args ) { $emails = bp_email_get_unsubscribe_type_schema(); if ( empty( $args['notification_type'] ) || ! array_key_exists( $args['notification_type'], $emails ) ) { return wp_login_url(); } $email_type = $args['notification_type']; $redirect_to = ! empty( $args['redirect_to'] ) ? $args['redirect_to'] : site_url(); $user_id = (int) $args['user_id']; // Bail out if the activity type is not un-unsubscribable. if ( empty( $emails[ $email_type ]['unsubscribe'] ) ) { return ''; } $link = ''; // Case where the recipient is a member of the site. if ( ! empty( $user_id ) ) { $link = add_query_arg( array( 'action' => 'unsubscribe', 'nh' => hash_hmac( 'sha1', "{$email_type}:{$user_id}", bp_email_get_salt() ), 'nt' => $args['notification_type'], 'uid' => $user_id, ), $redirect_to ); // Case where the recipient is not a member of the site. } else if ( ! empty( $args['email_address'] ) ) { $email_address = $args['email_address']; $member_id = (int) $args['member_id']; $link = add_query_arg( array( 'action' => 'unsubscribe', 'nh' => hash_hmac( 'sha1', "{$email_type}:{$email_address}", bp_email_get_salt() ), 'nt' => $args['notification_type'], 'mid' => $member_id, 'uem' => $email_address, ), $redirect_to ); } /** * Filters the unsubscribe link. * * @since 2.7.0 */ return apply_filters( 'bp_email_get_link', $link, $redirect_to, $args ); } /** * Get a persistent salt for email unsubscribe links. * * @since 2.7.0 * * @return string|null Returns null if value isn't set, otherwise string. */ function bp_email_get_salt() { return bp_get_option( 'bp-emails-unsubscribe-salt', null ); } /** * Get a list of emails for use in our unsubscribe functions. * * @since 2.8.0 * * @see https://buddypress.trac.wordpress.org/ticket/7431 * * @return array The array of email types and their schema. */ function bp_email_get_unsubscribe_type_schema() { $emails = bp_email_get_type_schema( 'all' ); /** * Filters the return of `bp_email_get_type_schema( 'all' )` for use with * our unsubscribe functionality. * * @since 2.8.0 * * @param array $emails The array of email types and their schema. */ return (array) apply_filters( 'bp_email_get_unsubscribe_type_schema', $emails ); } /** * Gets the BP Email type of a BP Email ID or object. * * @since 8.0.0 * * @param int|WP_Post $email Optional. BP Email ID or BP Email object. Defaults to global $post. * @return string The type of the BP Email object. */ function bp_email_get_type( $email = null ) { $email = get_post( $email ); if ( ! $email ) { return ''; } $types = bp_get_object_terms( $email->ID, bp_get_email_tax_type(), array( 'fields' => 'slugs' ) ); $type = reset( $types ); return $type; } /** * Get BuddyPress content allowed tags. * * @since 3.0.0 * * @global array $allowedtags KSES allowed HTML elements. * @return array BuddyPress content allowed tags. */ function bp_get_allowedtags() { global $allowedtags; return array_merge_recursive( $allowedtags, array( 'a' => array( 'aria-label' => array(), 'class' => array(), 'data-bp-tooltip' => array(), 'id' => array(), 'rel' => array(), ), 'img' => array( 'src' => array(), 'alt' => array(), 'width' => array(), 'height' => array(), 'class' => array(), 'id' => array(), ), 'span'=> array( 'class' => array(), 'data-livestamp' => array(), ), 'ul' => array(), 'ol' => array(), 'li' => array(), ) ); } /** * Remove script and style tags from a string. * * @since 3.0.1 * * @param string $string The string to strip tags from. * @return string The stripped tags string. */ function bp_strip_script_and_style_tags( $string ) { return preg_replace( '@<(script|style)[^>]*?>.*?\\1>@si', '', $string ); } /** * Checks whether the current installation is "large". * * By default, an installation counts as "large" if there are 10000 users or more. * Filter 'bp_is_large_install' to adjust. * * @since 4.1.0 * * @return bool */ function bp_is_large_install() { // Use the Multisite function if available. if ( function_exists( 'wp_is_large_network' ) ) { $is_large = wp_is_large_network( 'users' ); } else { $is_large = bp_core_get_total_member_count() > 10000; } /** * Filters whether the current installation is "large". * * @since 4.1.0 * * @param bool $is_large True if the network is "large". */ return (bool) apply_filters( 'bp_is_large_install', $is_large ); } /** * Returns the upper limit on the "max" item count, for widgets that support it. * * @since 5.0.0 * * @param string $widget_class Optional. Class name of the calling widget. * @return int */ function bp_get_widget_max_count_limit( $widget_class = '' ) { /** * Filters the upper limit on the "max" item count, for widgets that support it. * * @since 5.0.0 * * @param int $count Defaults to 50. * @param string $widget_class Class name of the calling widget. */ return apply_filters( 'bp_get_widget_max_count_limit', 50, $widget_class ); } /** * Add a new BP_Optout. * * @since 8.0.0 * * @param array $args { * An array of arguments describing the new opt-out. * @type string $email_address Email address of user who has opted out. * @type int $user_id Optional. ID of user whose communication * prompted the user to opt-out. * @type string $email_type Optional. Name of the email type that * prompted the user to opt-out. * @type string $date_modified Optional. Specify a time, else now will be used. * } * @return false|int False on failure, ID of new (or existing) opt-out if successful. */ function bp_add_optout( $args = array() ) { $optout = new BP_Optout(); $r = bp_parse_args( $args, array( 'email_address' => '', 'user_id' => 0, 'email_type' => '', 'date_modified' => bp_core_current_time(), ), 'add_optout' ); // Opt-outs must have an email address. if ( empty( $r['email_address'] ) ) { return false; } // Avoid creating duplicate opt-outs. $optout_id = $optout->optout_exists( array( 'email_address' => $r['email_address'], 'user_id' => $r['user_id'], 'email_type' => $r['email_type'], ) ); if ( ! $optout_id ) { // Set up the new opt-out. $optout->email_address = $r['email_address']; $optout->user_id = $r['user_id']; $optout->email_type = $r['email_type']; $optout->date_modified = $r['date_modified']; $optout_id = $optout->save(); } return $optout_id; } /** * Find matching BP_Optouts. * * @since 8.0.0 * * @see BP_Optout::get() for a description of parameters and return values. * * @param array $args See {@link BP_Optout::get()}. * @return array See {@link BP_Optout::get()}. */ function bp_get_optouts( $args = array() ) { $optout_class = new BP_Optout(); return $optout_class::get( $args ); } /** * Check an email address to see if that individual has opted out. * * @since 8.0.0 * * @param string $email_address Email address to check. * @return bool True if the user has opted out, false otherwise. */ function bp_user_has_opted_out( $email_address = '' ) { $optout_class = new BP_Optout(); $optout_id = $optout_class->optout_exists( array( 'email_address' => $email_address, ) ); return (bool) $optout_id; } /** * Delete a BP_Optout by ID. * * @since 8.0.0 * * @param int $id ID of the optout to delete. * @return bool True on success, false on failure. */ function bp_delete_optout_by_id( $id = 0 ) { $optout_class = new BP_Optout(); return $optout_class::delete_by_id( $id ); }