Skip to:
Content

BuddyPress.org

source: trunk/src/bp-core/bp-core-template.php

Last change on this file was 14077, checked in by espellcaste, 14 months ago

PHPDoc - adjust @subpackage name for all components.

See #9173 and #9174.

File size: 105.4 KB
Line 
1<?php
2/**
3 * Core component template tag functions.
4 *
5 * @package BuddyPress
6 * @subpackage Core
7 * @since 1.5.0
8 */
9
10// Exit if accessed directly.
11defined( 'ABSPATH' ) || exit;
12
13/**
14 * Output the "options nav", the secondary-level single item navigation menu.
15 *
16 * Uses the component's nav global to render out the sub navigation for the
17 * current component. Each component adds to its sub navigation array within
18 * its own setup_nav() function.
19 *
20 * This sub navigation array is the secondary level navigation, so for profile
21 * it contains:
22 *      [Public, Edit Profile, Change Avatar]
23 *
24 * The function will also analyze the current action for the current component
25 * to determine whether or not to highlight a particular sub nav item.
26 *
27 * @since 1.0.0
28 *
29 *       viewed user.
30 *
31 * @param string $parent_slug Options nav slug.
32 * @return string
33 */
34function bp_get_options_nav( $parent_slug = '' ) {
35        $bp = buddypress();
36
37        // If we are looking at a member profile, then the we can use the current
38        // component as an index. Otherwise we need to use the component's root_slug.
39        $component_index = !empty( $bp->displayed_user ) ? bp_current_component() : bp_get_root_slug( bp_current_component() );
40        $selected_item   = bp_current_action();
41
42        // Default to the Members nav.
43        if ( ! bp_is_single_item() ) {
44                // Set the parent slug, if not provided.
45                if ( empty( $parent_slug ) ) {
46                        $parent_slug = $component_index;
47                }
48
49                $secondary_nav_items = $bp->members->nav->get_secondary( array( 'parent_slug' => $parent_slug ) );
50
51                if ( ! $secondary_nav_items ) {
52                        return false;
53                }
54
55        // For a single item, try to use the component's nav.
56        } else {
57                $current_item = bp_current_item();
58                $single_item_component = bp_current_component();
59
60                // Adjust the selected nav item for the current single item if needed.
61                if ( ! empty( $parent_slug ) ) {
62                        $current_item  = $parent_slug;
63                        $selected_item = bp_action_variable( 0 );
64                }
65
66                // If the nav is not defined by the parent component, look in the Members nav.
67                if ( ! isset( $bp->{$single_item_component}->nav ) ) {
68                        $secondary_nav_items = $bp->members->nav->get_secondary( array( 'parent_slug' => $current_item ) );
69                } else {
70                        $secondary_nav_items = $bp->{$single_item_component}->nav->get_secondary( array( 'parent_slug' => $current_item ) );
71                }
72
73                if ( ! $secondary_nav_items ) {
74                        return false;
75                }
76        }
77
78        // Loop through each navigation item.
79        foreach ( $secondary_nav_items as $subnav_item ) {
80                if ( empty( $subnav_item->user_has_access ) ) {
81                        continue;
82                }
83
84                // If the current action or an action variable matches the nav item id, then add a highlight CSS class.
85                if ( $subnav_item->slug === $selected_item ) {
86                        $selected = ' class="current selected"';
87                } else {
88                        $selected = '';
89                }
90
91                // List type depends on our current component.
92                $list_type = bp_is_group() ? 'groups' : 'personal';
93
94                // phpcs:ignore WordPress.Security.EscapeOutput
95                echo apply_filters(
96                        /**
97                         * Filters the "options nav", the secondary-level single item navigation menu.
98                         *
99                         * This is a dynamic filter that is dependent on the provided css_id value.
100                         *
101                         * @since 1.1.0
102                         *
103                         * @param string $value         HTML list item for the submenu item.
104                         * @param array  $subnav_item   Submenu array item being displayed.
105                         * @param string $selected_item Current action.
106                         */
107                        'bp_get_options_nav_' . $subnav_item->css_id,
108                        '<li id="' . esc_attr( $subnav_item->css_id . '-' . $list_type . '-li' ) . '" ' . $selected . '><a id="' . esc_attr( $subnav_item->css_id ) . '" href="' . esc_url( $subnav_item->link ) . '">' . wp_kses( $subnav_item->name, array( 'span' => array( 'class' => true ) ) ) . '</a></li>',
109                        $subnav_item,
110                        $selected_item
111                );
112        }
113}
114
115/**
116 * Get the directory title for a component.
117 *
118 * Used for the <title> element and the page header on the component directory
119 * page.
120 *
121 * @since 2.0.0
122 *
123 * @param string $component Component to get directory title for.
124 * @return string
125 */
126function bp_get_directory_title( $component = '' ) {
127        $title = '';
128
129        // Use the string provided by the component.
130        if ( isset( buddypress()->{$component}->directory_title ) && buddypress()->{$component}->directory_title ) {
131                $title = buddypress()->{$component}->directory_title;
132
133        // If none is found, concatenate.
134        } elseif ( isset( buddypress()->{$component}->name ) ) {
135                /* translators: %s: Name of the BuddyPress component */
136                $title = sprintf( __( '%s Directory', 'buddypress' ), buddypress()->{$component}->name );
137        }
138
139        /**
140         * Filters the directory title for a component.
141         *
142         * @since 2.0.0
143         *
144         * @param string $title     Text to be used in <title> tag.
145         * @param string $component Current component being displayed.
146         */
147        return apply_filters( 'bp_get_directory_title', $title, $component );
148}
149
150/** Avatars *******************************************************************/
151
152/**
153 * Output the current avatar upload step.
154 *
155 * @since 1.1.0
156 */
157function bp_avatar_admin_step() {
158        echo esc_html( bp_get_avatar_admin_step() );
159}
160        /**
161         * Return the current avatar upload step.
162         *
163         * @since 1.1.0
164         *
165         * @return string The current avatar upload step. Returns 'upload-image'
166         *         if none is found.
167         */
168        function bp_get_avatar_admin_step() {
169                $bp   = buddypress();
170                $step = isset( $bp->avatar_admin->step )
171                        ? $step = $bp->avatar_admin->step
172                        : 'upload-image';
173
174                /**
175                 * Filters the current avatar upload step.
176                 *
177                 * @since 1.1.0
178                 *
179                 * @param string $step The current avatar upload step.
180                 */
181                return apply_filters( 'bp_get_avatar_admin_step', $step );
182        }
183
184/**
185 * Output the URL of the avatar to crop.
186 *
187 * @since 1.1.0
188 */
189function bp_avatar_to_crop() {
190        echo esc_url( bp_get_avatar_to_crop() );
191}
192        /**
193         * Return the URL of the avatar to crop.
194         *
195         * @since 1.1.0
196         *
197         * @return string URL of the avatar awaiting cropping.
198         */
199        function bp_get_avatar_to_crop() {
200                $bp  = buddypress();
201                $url = isset( $bp->avatar_admin->image->url )
202                        ? $bp->avatar_admin->image->url
203                        : '';
204
205                /**
206                 * Filters the URL of the avatar to crop.
207                 *
208                 * @since 1.1.0
209                 *
210                 * @param string $url URL for the avatar.
211                 */
212                return apply_filters( 'bp_get_avatar_to_crop', $url );
213        }
214
215/**
216 * Output the relative file path to the avatar to crop.
217 *
218 * @since 1.1.0
219 */
220function bp_avatar_to_crop_src() {
221        echo esc_attr( bp_get_avatar_to_crop_src() );
222}
223        /**
224         * Return the relative file path to the avatar to crop.
225         *
226         * @since 1.1.0
227         *
228         * @return string Relative file path to the avatar.
229         */
230        function bp_get_avatar_to_crop_src() {
231                $bp  = buddypress();
232                $src = isset( $bp->avatar_admin->image->dir )
233                        ? str_replace( WP_CONTENT_DIR, '', $bp->avatar_admin->image->dir )
234                        : '';
235
236                /**
237                 * Filters the relative file path to the avatar to crop.
238                 *
239                 * @since 1.1.0
240                 *
241                 * @param string $src Relative file path for the avatar.
242                 */
243                return apply_filters( 'bp_get_avatar_to_crop_src', $src );
244        }
245
246/**
247 * Output the name of the BP site. Used in RSS headers.
248 *
249 * @since 1.0.0
250 */
251function bp_site_name() {
252        echo esc_html( bp_get_site_name() );
253}
254        /**
255         * Returns the name of the BP site. Used in RSS headers.
256         *
257         * @since 1.6.0
258         *
259         * @return string
260         */
261        function bp_get_site_name() {
262
263                /**
264                 * Filters the name of the BP site. Used in RSS headers.
265                 *
266                 * @since 1.0.0
267                 *
268                 * @param string $value Current BP site name.
269                 */
270                return apply_filters( 'bp_site_name', get_bloginfo( 'name', 'display' ) );
271        }
272
273/**
274 * Format a date based on a UNIX timestamp.
275 *
276 * This function can be used to turn a UNIX timestamp into a properly formatted
277 * (and possibly localized) string, useful for outputting the date & time an
278 * action took place.
279 *
280 * Not to be confused with `bp_core_time_since()`, this function is best used
281 * for displaying a more exact date and time vs. a human-readable time.
282 *
283 * Note: This function may be improved or removed at a later date, as it is
284 * hardly used and adds an additional layer of complexity to calculating dates
285 * and times together with timezone offsets and i18n.
286 *
287 * @since 1.1.0
288 *
289 * @param int|string $time         The UNIX timestamp to be formatted.
290 * @param bool       $exclude_time Optional. True to return only the month + day, false
291 *                                 to return month, day, and time. Default: false.
292 * @param bool       $gmt          Optional. True to display in local time, false to
293 *                                  leave in GMT. Default: true.
294 * @return mixed A string representation of $time, in the format
295 *               "March 18, 2014 at 2:00 pm" (or whatever your
296 *               'date_format' and 'time_format' settings are
297 *               on your root blog). False on failure.
298 */
299function bp_format_time( $time = '', $exclude_time = false, $gmt = true ) {
300
301        // Bail if time is empty or not numeric
302        // @todo We should output something smarter here.
303        if ( empty( $time ) || ! is_numeric( $time ) ) {
304                return false;
305        }
306
307        // Get GMT offset from root blog.
308        if ( true === $gmt ) {
309
310                // Use Timezone string if set.
311                $timezone_string = bp_get_option( 'timezone_string' );
312                if ( ! empty( $timezone_string ) ) {
313                        $timezone_object = timezone_open( $timezone_string );
314                        $datetime_object = date_create( "@{$time}" );
315                        $timezone_offset = timezone_offset_get( $timezone_object, $datetime_object ) / HOUR_IN_SECONDS;
316
317                // Fall back on less reliable gmt_offset.
318                } else {
319                        $timezone_offset = bp_get_option( 'gmt_offset' );
320                }
321
322                // Calculate time based on the offset.
323                $calculated_time = $time + ( $timezone_offset * HOUR_IN_SECONDS );
324
325        // No localizing, so just use the time that was submitted.
326        } else {
327                $calculated_time = $time;
328        }
329
330        // Formatted date: "March 18, 2014".
331        $formatted_date = date_i18n( bp_get_option( 'date_format' ), $calculated_time, $gmt );
332
333        // Should we show the time also?
334        if ( true !== $exclude_time ) {
335
336                // Formatted time: "2:00 pm".
337                $formatted_time = date_i18n( bp_get_option( 'time_format' ), $calculated_time, $gmt );
338
339                // Return string formatted with date and time.
340                $formatted_date = sprintf( esc_html__( '%1$s at %2$s', 'buddypress' ), $formatted_date, $formatted_time );
341        }
342
343        /**
344         * Filters the date based on a UNIX timestamp.
345         *
346         * @since 1.0.0
347         *
348         * @param string $formatted_date Formatted date from the timestamp.
349         */
350        return apply_filters( 'bp_format_time', $formatted_date );
351}
352
353/**
354 * Select between two dynamic strings, according to context.
355 *
356 * This function can be used in cases where a phrase used in a template will
357 * differ for a user looking at his own profile and a user looking at another
358 * user's profile (eg, "My Friends" and "Joe's Friends"). Pass both versions
359 * of the phrase, and bp_word_or_name() will detect which is appropriate, and
360 * do the necessary argument swapping for dynamic phrases.
361 *
362 * @since 1.0.0
363 *
364 * @param string $youtext    The "you" version of the phrase (eg "Your Friends").
365 * @param string $nametext   The other-user version of the phrase. Should be in
366 *                           a format appropriate for sprintf() - use %s in place of the displayed
367 *                           user's name (eg "%'s Friends").
368 * @param bool   $capitalize Optional. Force into title case. Default: true.
369 * @param bool   $echo       Optional. True to echo the results, false to return them.
370 *                           Default: true.
371 * @return string|null $nametext If ! $echo, returns the appropriate string.
372 */
373function bp_word_or_name( $youtext, $nametext, $capitalize = true, $echo = true ) {
374
375        if ( ! empty( $capitalize ) ) {
376                $youtext = bp_core_ucfirst( $youtext );
377        }
378
379        if ( bp_displayed_user_id() == bp_loggedin_user_id() ) {
380                if ( true == $echo ) {
381
382                        /**
383                         * Filters the text used based on context of own profile or someone else's profile.
384                         *
385                         * @since 1.0.0
386                         *
387                         * @param string $youtext Context-determined string to display.
388                         */
389                        echo esc_html( apply_filters( 'bp_word_or_name', $youtext ) );
390                } else {
391
392                        /** This filter is documented in bp-core/bp-core-template.php */
393                        return apply_filters( 'bp_word_or_name', $youtext );
394                }
395        } else {
396                $fullname = bp_get_displayed_user_fullname();
397                $fullname = (array) explode( ' ', $fullname );
398                $nametext = sprintf( $nametext, $fullname[0] );
399                if ( true == $echo ) {
400
401                        /** This filter is documented in bp-core/bp-core-template.php */
402                        echo esc_html( apply_filters( 'bp_word_or_name', $nametext ) );
403                } else {
404
405                        /** This filter is documented in bp-core/bp-core-template.php */
406                        return apply_filters( 'bp_word_or_name', $nametext );
407                }
408        }
409}
410
411/** Search Form ***************************************************************/
412
413/**
414 * Return the "action" attribute for search forms.
415 *
416 * @since 1.0.0
417 *
418 * @return string URL action attribute for search forms, eg example.com/search/.
419 */
420function bp_search_form_action() {
421        $url = bp_rewrites_get_url(
422                array(
423                        'component_id'     => 'core',
424                        'community_search' => 1,
425                )
426        );
427
428        /**
429         * Filters the "action" attribute for search forms.
430         *
431         * @since 1.0.0
432         *
433         * @param string $url Search form action url.
434         */
435        return apply_filters( 'bp_search_form_action', $url );
436}
437
438/**
439 * Generate the basic search form as used in BP-Default's header.
440 *
441 * @since 1.0.0
442 *
443 * @return string HTML <select> element.
444 */
445function bp_search_form_type_select() {
446
447        $options = array();
448
449        if ( bp_is_active( 'xprofile' ) ) {
450                $options['members'] = _x( 'Members', 'search form', 'buddypress' );
451        }
452
453        if ( bp_is_active( 'groups' ) ) {
454                $options['groups']  = _x( 'Groups', 'search form', 'buddypress' );
455        }
456
457        if ( bp_is_active( 'blogs' ) && is_multisite() ) {
458                $options['blogs']   = _x( 'Blogs', 'search form', 'buddypress' );
459        }
460
461        $options['posts'] = _x( 'Posts', 'search form', 'buddypress' );
462
463        // Eventually this won't be needed and a page will be built to integrate all search results.
464        $selection_box  = '<label for="search-which" class="accessibly-hidden">' . esc_html_x( 'Search these:', 'search form', 'buddypress' ) . '</label>';
465        $selection_box .= '<select name="search-which" id="search-which" style="width: auto">';
466
467        /**
468         * Filters all of the component options available for search scope.
469         *
470         * @since 1.5.0
471         *
472         * @param array $options Array of options to add to select field.
473         */
474        $options = apply_filters( 'bp_search_form_type_select_options', $options );
475        foreach ( (array) $options as $option_value => $option_title ) {
476                $selection_box .= sprintf( '<option value="%s">%s</option>', esc_attr( $option_value ), esc_html( $option_title ) );
477        }
478
479        $selection_box .= '</select>';
480
481        /**
482         * Filters the complete <select> input used for search scope.
483         *
484         * @since 1.0.0
485         *
486         * @param string $selection_box <select> input for selecting search scope.
487         */
488        return apply_filters( 'bp_search_form_type_select', $selection_box );
489}
490
491/**
492 * Output the 'name' attribute for search form input element.
493 *
494 * @since 2.7.0
495 *
496 * @param string $component See bp_get_search_input_name().
497 */
498function bp_search_input_name( $component = '' ) {
499        echo esc_attr( bp_get_search_input_name( $component ) );
500}
501
502/**
503 * Get the 'name' attribute for the search form input element.
504 *
505 * @since 2.7.0
506 *
507 * @param string $component Component name. Defaults to current component.
508 * @return string Text for the 'name' attribute.
509 */
510function bp_get_search_input_name( $component = '' ) {
511        if ( ! $component ) {
512                $component = bp_current_component();
513        }
514
515        $bp = buddypress();
516
517        $name = '';
518        if ( isset( $bp->{$component}->id ) ) {
519                $name = $bp->{$component}->id . '_search';
520        }
521
522        return $name;
523}
524
525/**
526 * Output the placeholder text for the search box for a given component.
527 *
528 * @since 2.7.0
529 *
530 * @param string $component See bp_get_search_placeholder().
531 */
532function bp_search_placeholder( $component = '' ) {
533        echo esc_attr( bp_get_search_placeholder( $component ) );
534}
535
536/**
537 * Get the placeholder text for the search box for a given component.
538 *
539 * @since 2.7.0
540 *
541 * @param string $component Component name. Defaults to current component.
542 * @return string Placeholder text for the search field.
543 */
544function bp_get_search_placeholder( $component = '' ) {
545        $query_arg = bp_core_get_component_search_query_arg( $component );
546
547        if ( $query_arg && ! empty( $_REQUEST[ $query_arg ] ) ) {
548                $placeholder = wp_unslash( $_REQUEST[ $query_arg ] );
549        } else {
550                $placeholder = bp_get_search_default_text( $component );
551        }
552
553        return $placeholder;
554}
555
556/**
557 * Output the default text for the search box for a given component.
558 *
559 * @since 1.5.0
560 *
561 * @see bp_get_search_default_text()
562 *
563 * @param string $component See {@link bp_get_search_default_text()}.
564 */
565function bp_search_default_text( $component = '' ) {
566        echo esc_attr( bp_get_search_default_text( $component ) );
567}
568        /**
569         * Return the default text for the search box for a given component.
570         *
571         * @since 1.5.0
572         *
573         * @param string $component Component name. Default: current component.
574         * @return string Placeholder text for search field.
575         */
576        function bp_get_search_default_text( $component = '' ) {
577
578                $bp = buddypress();
579
580                if ( empty( $component ) ) {
581                        $component = bp_current_component();
582                }
583
584                $default_text = __( 'Search anything...', 'buddypress' );
585
586                // Most of the time, $component will be the actual component ID.
587                if ( !empty( $component ) ) {
588                        if ( !empty( $bp->{$component}->search_string ) ) {
589                                $default_text = $bp->{$component}->search_string;
590                        } else {
591                                // When the request comes through AJAX, we need to get the component
592                                // name out of $bp->pages.
593                                if ( !empty( $bp->pages->{$component}->slug ) ) {
594                                        $key = $bp->pages->{$component}->slug;
595                                        if ( !empty( $bp->{$key}->search_string ) ) {
596                                                $default_text = $bp->{$key}->search_string;
597                                        }
598                                }
599                        }
600                }
601
602                /**
603                 * Filters the default text for the search box for a given component.
604                 *
605                 * @since 1.5.0
606                 *
607                 * @param string $default_text Default text for search box.
608                 * @param string $component    Current component displayed.
609                 */
610                return apply_filters( 'bp_get_search_default_text', $default_text, $component );
611        }
612
613/**
614 * Output the attributes for a form field.
615 *
616 * @since 2.2.0
617 *
618 * @param string $name       The field name to output attributes for.
619 * @param array  $attributes Array of existing attributes to add.
620 */
621function bp_form_field_attributes( $name = '', $attributes = array() ) {
622        // phpcs:ignore WordPress.Security.EscapeOutput
623        echo bp_get_form_field_attributes( $name, $attributes );
624}
625        /**
626         * Get the attributes for a form field.
627         *
628         * Primarily to add better support for touchscreen devices, but plugin devs
629         * can use the 'bp_get_form_field_extra_attributes' filter for further
630         * manipulation.
631         *
632         * @since 2.2.0
633         *
634         * @param string $name       The field name to get attributes for.
635         * @param array  $attributes Array of existing attributes to add.
636         * @return string
637         */
638        function bp_get_form_field_attributes( $name = '', $attributes = array() ) {
639                $retval = '';
640
641                if ( empty( $attributes ) ) {
642                        $attributes = array();
643                }
644
645                $name = strtolower( $name );
646
647                switch ( $name ) {
648                        case 'username' :
649                        case 'blogname' :
650                                $attributes['autocomplete']   = 'off';
651                                $attributes['autocapitalize'] = 'none';
652                                break;
653
654                        case 'email' :
655                                if ( wp_is_mobile() ) {
656                                        $attributes['autocapitalize'] = 'none';
657                                }
658                                break;
659
660                        case 'password' :
661                                $attributes['spellcheck']   = 'false';
662                                $attributes['autocomplete'] = 'off';
663
664                                if ( wp_is_mobile() ) {
665                                        $attributes['autocorrect']    = 'false';
666                                        $attributes['autocapitalize'] = 'none';
667                                }
668                                break;
669                }
670
671                /**
672                 * Filter the attributes for a field before rendering output.
673                 *
674                 * @since 2.2.0
675                 *
676                 * @param array  $attributes The field attributes.
677                 * @param string $name       The field name.
678                 */
679                $attributes = (array) apply_filters( 'bp_get_form_field_attributes', $attributes, $name );
680
681                foreach ( $attributes as $attr => $value ) {
682                        // Numeric keyed array.
683                        if (is_numeric( $attr ) ) {
684                                $retval .= sprintf( ' %s', esc_attr( $value ) );
685
686                        // Associative keyed array.
687                        } else {
688                                $retval .= sprintf( ' %s="%s"', sanitize_key( $attr ), esc_attr( $value ) );
689                        }
690                }
691
692                return $retval;
693        }
694
695/**
696 * Create and output a button.
697 *
698 * @since 1.2.6
699 *
700 * @see bp_get_button()
701 *
702 * @param array|string $args See {@link BP_Button}.
703 */
704function bp_button( $args = '' ) {
705        // Escaping is done in `BP_Core_HTML_Element()`.
706        // phpcs:ignore WordPress.Security.EscapeOutput
707        echo bp_get_button( $args );
708}
709        /**
710         * Create and return a button.
711         *
712         * @since 1.2.6
713         *
714         * @see BP_Button for a description of arguments and return value.
715         *
716         * @param array|string $args See {@link BP_Button}.
717         * @return string HTML markup for the button.
718         */
719        function bp_get_button( $args = '' ) {
720                $button = new BP_Button( $args );
721
722                /**
723                 * Filters the requested button output.
724                 *
725                 * @since 1.2.6
726                 *
727                 * @param string    $contents  Button context to be used.
728                 * @param array     $args      Array of args for the button.
729                 * @param BP_Button $button    BP_Button object.
730                 */
731                return apply_filters( 'bp_get_button', $button->contents, $args, $button );
732        }
733
734/**
735 * Truncate text.
736 *
737 * Cuts a string to the length of $length and replaces the last characters
738 * with the ending if the text is longer than length.
739 *
740 * This function is borrowed from CakePHP v2.0, under the MIT license. See
741 * http://book.cakephp.org/view/1469/Text#truncate-1625
742 *
743 * @since 1.0.0
744 * @since 2.6.0 Added 'strip_tags' and 'remove_links' as $options args.
745 *
746 * @param string $text   String to truncate.
747 * @param int    $length Optional. Length of returned string, including ellipsis.
748 *                       Default: 225.
749 * @param array  $options {
750 *     An array of HTML attributes and options. Each item is optional.
751 *     @type string $ending            The string used after truncation.
752 *                                     Default: ' [&hellip;]'.
753 *     @type bool   $exact             If true, $text will be trimmed to exactly $length.
754 *                                     If false, $text will not be cut mid-word. Default: false.
755 *     @type bool   $html              If true, don't include HTML tags when calculating
756 *                                     excerpt length. Default: true.
757 *     @type bool   $filter_shortcodes If true, shortcodes will be stripped.
758 *                                     Default: true.
759 *     @type bool   $strip_tags        If true, HTML tags will be stripped. Default: false.
760 *                                     Only applicable if $html is set to false.
761 *     @type bool   $remove_links      If true, URLs will be stripped. Default: false.
762 *                                     Only applicable if $html is set to false.
763 * }
764 * @return string Trimmed string.
765 */
766function bp_create_excerpt( $text, $length = 225, $options = array() ) {
767
768        // Backward compatibility. The third argument used to be a boolean $filter_shortcodes.
769        $filter_shortcodes_default = is_bool( $options ) ? $options : true;
770
771        $r = bp_parse_args(
772                $options,
773                array(
774                        'ending'            => __( ' [&hellip;]', 'buddypress' ),
775                        'exact'             => false,
776                        'html'              => true,
777                        'filter_shortcodes' => $filter_shortcodes_default,
778                        'strip_tags'        => false,
779                        'remove_links'      => false,
780                ),
781                'create_excerpt'
782        );
783
784        // Save the original text, to be passed along to the filter.
785        $original_text = $text;
786
787        /**
788         * Filters the excerpt length to trim text to.
789         *
790         * @since 1.5.0
791         *
792         * @param int $length Length of returned string, including ellipsis.
793         */
794        $length = apply_filters( 'bp_excerpt_length',      $length      );
795
796        /**
797         * Filters the excerpt appended text value.
798         *
799         * @since 1.5.0
800         *
801         * @param string $value Text to append to the end of the excerpt.
802         */
803        $ending = apply_filters( 'bp_excerpt_append_text', $r['ending'] );
804
805        // Remove shortcodes if necessary.
806        if ( ! empty( $r['filter_shortcodes'] ) ) {
807                $text = strip_shortcodes( $text );
808        }
809
810        // When $html is true, the excerpt should be created without including HTML tags in the
811        // excerpt length.
812        if ( ! empty( $r['html'] ) ) {
813
814                // The text is short enough. No need to truncate.
815                if ( mb_strlen( preg_replace( '/<.*?>/', '', $text ) ) <= $length ) {
816                        return $text;
817                }
818
819                $totalLength = mb_strlen( wp_strip_all_tags( $ending ) );
820                $openTags    = array();
821                $truncate    = '';
822
823                // Find all the tags and HTML comments and put them in a stack for later use.
824                preg_match_all( '/(<\/?([\w+!]+)[^>]*>)?([^<>]*)/', $text, $tags, PREG_SET_ORDER );
825
826                foreach ( $tags as $tag ) {
827                        // Process tags that need to be closed.
828                        if ( !preg_match( '/img|br|input|hr|area|base|basefont|col|frame|isindex|link|meta|param/s',  $tag[2] ) ) {
829                                if ( preg_match( '/<[\w]+[^>]*>/s', $tag[0] ) ) {
830                                        array_unshift( $openTags, $tag[2] );
831                                } elseif ( preg_match('/<\/([\w]+)[^>]*>/s', $tag[0], $closeTag ) ) {
832                                        $pos = array_search( $closeTag[1], $openTags );
833                                        if ( $pos !== false ) {
834                                                array_splice( $openTags, $pos, 1 );
835                                        }
836                                }
837                        }
838
839                        $truncate     .= $tag[1];
840                        $contentLength = mb_strlen( preg_replace( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', ' ', $tag[3] ) );
841
842                        if ( $contentLength + $totalLength > $length ) {
843                                $left = $length - $totalLength;
844                                $entitiesLength = 0;
845                                if ( preg_match_all( '/&[0-9a-z]{2,8};|&#[0-9]{1,7};|&#x[0-9a-f]{1,6};/i', $tag[3], $entities, PREG_OFFSET_CAPTURE ) ) {
846                                        foreach ( $entities[0] as $entity ) {
847                                                if ( $entity[1] + 1 - $entitiesLength <= $left ) {
848                                                        $left--;
849                                                        $entitiesLength += mb_strlen( $entity[0] );
850                                                } else {
851                                                        break;
852                                                }
853                                        }
854                                }
855
856                                $truncate .= mb_substr( $tag[3], 0 , $left + $entitiesLength );
857                                break;
858                        } else {
859                                $truncate .= $tag[3];
860                                $totalLength += $contentLength;
861                        }
862                        if ( $totalLength >= $length ) {
863                                break;
864                        }
865                }
866        } else {
867                // Strip HTML tags if necessary.
868                if ( ! empty( $r['strip_tags'] ) ) {
869                        $text = wp_strip_all_tags( $text );
870                }
871
872                // Remove links if necessary.
873                if ( ! empty( $r['remove_links'] ) ) {
874                        $text = preg_replace( '#^\s*(https?://[^\s"]+)\s*$#im', '', $text );
875                }
876
877                if ( mb_strlen( $text ) <= $length ) {
878                        /**
879                         * Filters the final generated excerpt.
880                         *
881                         * @since 1.1.0
882                         *
883                         * @param string $text          Generated excerpt.
884                         * @param string $original_text Original text provided.
885                         * @param int    $length        Length of returned string, including ellipsis.
886                         * @param array  $options       Array of HTML attributes and options.
887                         */
888                        return apply_filters( 'bp_create_excerpt', $text, $original_text, $length, $options );
889                } else {
890                        $truncate = mb_substr( $text, 0, $length - mb_strlen( $ending ) );
891                }
892        }
893
894        // If $exact is false, we can't break on words.
895        if ( empty( $r['exact'] ) ) {
896                // Find the position of the last space character not part of a tag.
897                preg_match_all( '/<[a-z\!\/][^>]*>/', $truncate, $_truncate_tags, PREG_OFFSET_CAPTURE );
898
899                // Rekey tags by the string index of their last character.
900                $truncate_tags = array();
901                if ( ! empty( $_truncate_tags[0] ) ) {
902                        foreach ( $_truncate_tags[0] as $_tt ) {
903                                $_tt['start'] = $_tt[1];
904                                $_tt['end']   = $_tt[1] + strlen( $_tt[0] );
905                                $truncate_tags[ $_tt['end'] ] = $_tt;
906                        }
907                }
908
909                $truncate_length = mb_strlen( $truncate );
910                $spacepos = $truncate_length + 1;
911                for ( $pos = $truncate_length - 1; $pos >= 0; $pos-- ) {
912                        // Word boundaries are spaces and the close of HTML tags, when the tag is preceded by a space.
913                        $is_word_boundary = ' ' === $truncate[ $pos ];
914                        if ( ! $is_word_boundary && isset( $truncate_tags[ $pos - 1 ] ) ) {
915                                $preceding_tag    = $truncate_tags[ $pos - 1 ];
916                                if ( ' ' === $truncate[ $preceding_tag['start'] - 1 ] ) {
917                                        $is_word_boundary = true;
918                                        break;
919                                }
920                        }
921
922                        if ( ! $is_word_boundary ) {
923                                continue;
924                        }
925
926                        // If there are no tags in the string, the first space found is the right one.
927                        if ( empty( $truncate_tags ) ) {
928                                $spacepos = $pos;
929                                break;
930                        }
931
932                        // Look at each tag to see if the space is inside of it.
933                        $intag = false;
934                        foreach ( $truncate_tags as $tt ) {
935                                if ( $pos > $tt['start'] && $pos < $tt['end'] ) {
936                                        $intag = true;
937                                        break;
938                                }
939                        }
940
941                        if ( ! $intag ) {
942                                $spacepos = $pos;
943                                break;
944                        }
945                }
946
947                if ( $r['html'] ) {
948                        $bits = mb_substr( $truncate, $spacepos );
949                        preg_match_all( '/<\/([a-z]+)>/', $bits, $droppedTags, PREG_SET_ORDER );
950                        if ( !empty( $droppedTags ) ) {
951                                foreach ( $droppedTags as $closingTag ) {
952                                        if ( !in_array( $closingTag[1], $openTags ) ) {
953                                                array_unshift( $openTags, $closingTag[1] );
954                                        }
955                                }
956                        }
957                }
958
959                $truncate = rtrim( mb_substr( $truncate, 0, $spacepos ) );
960        }
961        $truncate .= $ending;
962
963        if ( !empty( $r['html'] ) ) {
964                foreach ( $openTags as $tag ) {
965                        $truncate .= '</' . $tag . '>';
966                }
967        }
968
969        /** This filter is documented in /bp-core/bp-core-template.php */
970        return apply_filters( 'bp_create_excerpt', $truncate, $original_text, $length, $options );
971}
972add_filter( 'bp_create_excerpt', 'stripslashes_deep'  );
973add_filter( 'bp_create_excerpt', 'force_balance_tags' );
974
975/**
976 * Output the total member count for the site.
977 *
978 * @since 1.2.0
979 */
980function bp_total_member_count() {
981        echo esc_html( bp_get_total_member_count() );
982}
983        /**
984         * Return the total member count for the site.
985         *
986         * Since BuddyPress 1.6, this function has used bp_core_get_active_member_count(),
987         * which counts non-spam, non-deleted users who have last_activity.
988         * This value will correctly match the total member count number used
989         * for pagination on member directories.
990         *
991         * Before BuddyPress 1.6, this function used bp_core_get_total_member_count(),
992         * which did not take into account last_activity, and thus often
993         * resulted in higher counts than shown by member directory pagination.
994         *
995         * @since 1.2.0
996         *
997         * @return int Member count.
998         */
999        function bp_get_total_member_count() {
1000
1001                /**
1002                 * Filters the total member count for the site.
1003                 *
1004                 * @since 1.2.0
1005                 *
1006                 * @param int $member_count Member count.
1007                 */
1008                return apply_filters( 'bp_get_total_member_count', bp_core_get_active_member_count() );
1009        }
1010        add_filter( 'bp_get_total_member_count', 'bp_core_number_format' );
1011
1012        /**
1013         * Is blog signup allowed?
1014         *
1015         * Returns true if is_multisite() and blog creation is enabled at
1016         * Network Admin > Settings.
1017         *
1018         * @since 1.2.0
1019         *
1020         * @return bool True if blog signup is allowed, otherwise false.
1021         */
1022        function bp_get_blog_signup_allowed() {
1023
1024                if ( ! is_multisite() ) {
1025                        return false;
1026                }
1027
1028                $status = bp_core_get_root_option( 'registration' );
1029                if ( ( 'none' !== $status ) && ( 'user' !== $status ) ) {
1030                        return true;
1031                }
1032
1033                return false;
1034        }
1035
1036/**
1037 * Check whether an activation has just been completed.
1038 *
1039 * @since 1.1.0
1040 *
1041 * @return bool True if the activation_complete global flag has been set,
1042 *              otherwise false.
1043 */
1044function bp_account_was_activated() {
1045        $bp = buddypress();
1046
1047        $activation_complete = ! empty( $bp->activation_complete ) || ( bp_is_current_component( 'activate' ) && ! empty( $_GET['activated'] ) );
1048
1049        return $activation_complete;
1050}
1051
1052/**
1053 * Check whether registrations require activation on this installation.
1054 *
1055 * On a normal BuddyPress installation, all registrations require email
1056 * activation. This filter exists so that customizations that omit activation
1057 * can remove certain notification text from the registration screen.
1058 *
1059 * @since 1.2.0
1060 *
1061 * @return bool True by default.
1062 */
1063function bp_registration_needs_activation() {
1064
1065        /**
1066         * Filters whether registrations require activation on this installation.
1067         *
1068         * @since 1.2.0
1069         *
1070         * @param bool $value Whether registrations require activation. Default true.
1071         */
1072        return apply_filters( 'bp_registration_needs_activation', true );
1073}
1074
1075/**
1076 * Retrieve a client friendly version of the root blog name.
1077 *
1078 * The blogname option is escaped with esc_html on the way into the database in
1079 * sanitize_option, we want to reverse this for the plain text arena of emails.
1080 *
1081 * @since 1.7.0
1082 * @since 2.5.0 No longer used by BuddyPress, but not deprecated in case any existing plugins use it.
1083 *
1084 * @see https://buddypress.trac.wordpress.org/ticket/4401
1085 *
1086 * @param array $args {
1087 *     Array of optional parameters.
1088 *     @type string $before  String to appear before the site name in the
1089 *                           email subject. Default: '['.
1090 *     @type string $after   String to appear after the site name in the
1091 *                           email subject. Default: ']'.
1092 *     @type string $default The default site name, to be used when none is
1093 *                           found in the database. Default: 'Community'.
1094 *     @type string $text    Text to append to the site name (ie, the main text of
1095 *                           the email subject).
1096 * }
1097 * @return string Sanitized email subject.
1098 */
1099function bp_get_email_subject( $args = array() ) {
1100
1101        $r = bp_parse_args(
1102                $args,
1103                array(
1104                        'before'  => '[',
1105                        'after'   => ']',
1106                        'default' => __( 'Community', 'buddypress' ),
1107                        'text'    => '',
1108                ),
1109                'get_email_subject'
1110        );
1111
1112        $subject = $r['before'] . wp_specialchars_decode( bp_get_option( 'blogname', $r['default'] ), ENT_QUOTES ) . $r['after'] . ' ' . $r['text'];
1113
1114        /**
1115         * Filters a client friendly version of the root blog name.
1116         *
1117         * @since 1.7.0
1118         *
1119         * @param string $subject Client friendly version of the root blog name.
1120         * @param array  $r       Array of arguments for the email subject.
1121         */
1122        return apply_filters( 'bp_get_email_subject', $subject, $r );
1123}
1124
1125/**
1126 * Allow templates to pass parameters directly into the template loops via AJAX.
1127 *
1128 * For the most part this will be filtered in a theme's functions.php for
1129 * example in the default theme it is filtered via bp_dtheme_ajax_querystring().
1130 *
1131 * By using this template tag in the templates it will stop them from showing
1132 * errors if someone copies the templates from the default theme into another
1133 * WordPress theme without coping the functions from functions.php.
1134 *
1135 * @since 1.2.0
1136 *
1137 * @param string|bool $object Current template component.
1138 * @return string The AJAX querystring.
1139 */
1140function bp_ajax_querystring( $object = false ) {
1141        $bp = buddypress();
1142
1143        if ( ! isset( $bp->ajax_querystring ) ) {
1144                $bp->ajax_querystring = '';
1145        }
1146
1147        /**
1148         * Filters the template parameters to be used in the query string.
1149         *
1150         * Allows templates to pass parameters into the template loops via AJAX.
1151         *
1152         * @since 1.2.0
1153         *
1154         * @param string $ajax_querystring Current query string.
1155         * @param string $object           Current template component.
1156         */
1157        return apply_filters( 'bp_ajax_querystring', $bp->ajax_querystring, $object );
1158}
1159
1160/** Template Classes and _is functions ****************************************/
1161
1162/**
1163 * Return the name of the current component.
1164 *
1165 * @since 1.0.0
1166 *
1167 * @return string Component name.
1168 */
1169function bp_current_component() {
1170        $bp                = buddypress();
1171        $current_component = !empty( $bp->current_component )
1172                ? $bp->current_component
1173                : false;
1174
1175        /**
1176         * Filters the name of the current component.
1177         *
1178         * @since 1.0.0
1179         *
1180         * @param string|bool $current_component Current component if available or false.
1181         */
1182        return apply_filters( 'bp_current_component', $current_component );
1183}
1184
1185/**
1186 * Return the name of the current action.
1187 *
1188 * @since 1.0.0
1189 *
1190 * @return string Action name.
1191 */
1192function bp_current_action() {
1193        $bp             = buddypress();
1194        $current_action = !empty( $bp->current_action )
1195                ? $bp->current_action
1196                : '';
1197
1198        /**
1199         * Filters the name of the current action.
1200         *
1201         * @since 1.0.0
1202         *
1203         * @param string $current_action Current action.
1204         */
1205        return apply_filters( 'bp_current_action', $current_action );
1206}
1207
1208/**
1209 * Return the name of the current item.
1210 *
1211 * @since 1.1.0
1212 *
1213 * @return string|bool
1214 */
1215function bp_current_item() {
1216        $bp           = buddypress();
1217        $current_item = !empty( $bp->current_item )
1218                ? $bp->current_item
1219                : false;
1220
1221        /**
1222         * Filters the name of the current item.
1223         *
1224         * @since 1.1.0
1225         *
1226         * @param string|bool $current_item Current item if available or false.
1227         */
1228        return apply_filters( 'bp_current_item', $current_item );
1229}
1230
1231/**
1232 * Return the value of $bp->action_variables.
1233 *
1234 * @since 1.0.0
1235 *
1236 * @return array|bool $action_variables The action variables array, or false
1237 *                                      if the array is empty.
1238 */
1239function bp_action_variables() {
1240        $bp               = buddypress();
1241        $action_variables = !empty( $bp->action_variables )
1242                ? $bp->action_variables
1243                : false;
1244
1245        /**
1246         * Filters the value of $bp->action_variables.
1247         *
1248         * @since 1.0.0
1249         *
1250         * @param array|bool $action_variables Available action variables.
1251         */
1252        return apply_filters( 'bp_action_variables', $action_variables );
1253}
1254
1255/**
1256 * Return the value of a given action variable.
1257 *
1258 * @since 1.5.0
1259 *
1260 * @param int $position The key of the action_variables array that you want.
1261 * @return string|bool $action_variable The value of that position in the
1262 *                                      array, or false if not found.
1263 */
1264function bp_action_variable( $position = 0 ) {
1265        $action_variables = bp_action_variables();
1266        $action_variable  = isset( $action_variables[ $position ] )
1267                ? $action_variables[ $position ]
1268                : false;
1269
1270        /**
1271         * Filters the value of a given action variable.
1272         *
1273         * @since 1.5.0
1274         *
1275         * @param string|bool $action_variable Requested action variable based on position.
1276         * @param int         $position        The key of the action variable requested.
1277         */
1278        return apply_filters( 'bp_action_variable', $action_variable, $position );
1279}
1280
1281/**
1282 * Returns the BP root blog's domain name.
1283 *
1284 * @since 12.0.0
1285 *
1286 * @return string The BP root blog's domain name.
1287 */
1288function bp_get_domain() {
1289        return wp_parse_url( bp_get_root_url(), PHP_URL_HOST );
1290}
1291
1292/**
1293 * Gets the BP root blog's URL.
1294 *
1295 * @since 12.0.0
1296 *
1297 * @return string The BP root blog's URL.
1298 */
1299function bp_get_root_url() {
1300        $bp = buddypress();
1301
1302        if ( ! empty( $bp->root_url ) ) {
1303                $url = $bp->root_url;
1304        } else {
1305                $url          = bp_rewrites_get_root_url();
1306                $bp->root_url = $url;
1307        }
1308
1309        /**
1310         * Filters the "root url", the URL of the BP root blog.
1311         *
1312         * @since 12.0.0
1313         *
1314         * @param string $url URL of the BP root blog.
1315         */
1316        return apply_filters( 'bp_get_root_url', $url );
1317}
1318
1319/**
1320 * Output the "root url", the URL of the BP root blog.
1321 *
1322 * @since 12.0.0
1323 */
1324function bp_root_url() {
1325        echo esc_url( bp_get_root_url() );
1326}
1327
1328/**
1329 * Output the root slug for a given component.
1330 *
1331 * @since 1.5.0
1332 *
1333 * @param string $component The component name.
1334 */
1335function bp_root_slug( $component = '' ) {
1336        echo esc_attr( bp_get_root_slug( $component ) );
1337}
1338        /**
1339         * Get the root slug for given component.
1340         *
1341         * The "root slug" is the string used when concatenating component
1342         * directory URLs. For example, on an installation where the Groups
1343         * component's directory is located at http://example.com/groups/, the
1344         * root slug for the Groups component is 'groups'. This string
1345         * generally corresponds to page_name of the component's directory
1346         * page.
1347         *
1348         * In order to maintain backward compatibility, the following procedure
1349         * is used:
1350         * 1) Use the short slug to get the canonical component name from the
1351         *    active component array.
1352         * 2) Use the component name to get the root slug out of the
1353         *    appropriate part of the $bp global.
1354         * 3) If nothing turns up, it probably means that $component is itself
1355         *    a root slug.
1356         *
1357         * Example: If your groups directory is at /community/companies, this
1358         * function first uses the short slug 'companies' (ie the current
1359         * component) to look up the canonical name 'groups' in
1360         * $bp->active_components. Then it uses 'groups' to get the root slug,
1361         * from $bp->groups->root_slug.
1362         *
1363         * @since 1.5.0
1364         *
1365         * @param string $component Optional. Defaults to the current component.
1366         * @return string $root_slug The root slug.
1367         */
1368        function bp_get_root_slug( $component = '' ) {
1369                $bp        = buddypress();
1370                $root_slug = '';
1371
1372                // Use current global component if none passed.
1373                if ( empty( $component ) ) {
1374                        $component = bp_current_component();
1375                }
1376
1377                // Component is active.
1378                if ( ! empty( $bp->active_components[ $component ] ) ) {
1379
1380                        // Backward compatibility: in legacy plugins, the canonical component id
1381                        // was stored as an array value in $bp->active_components.
1382                        $component_name = ( '1' == $bp->active_components[ $component ] )
1383                                ? $component
1384                                : $bp->active_components[$component];
1385
1386                        // Component has specific root slug.
1387                        if ( ! empty( $bp->{$component_name}->root_slug ) ) {
1388                                $root_slug = $bp->{$component_name}->root_slug;
1389                        }
1390                }
1391
1392                // No specific root slug, so fall back to component slug.
1393                if ( empty( $root_slug ) ) {
1394                        $root_slug = $component;
1395                }
1396
1397                /**
1398                 * Filters the root slug for given component.
1399                 *
1400                 * @since 1.5.0
1401                 *
1402                 * @param string $root_slug Root slug for given component.
1403                 * @param string $component Current component.
1404                 */
1405                return apply_filters( 'bp_get_root_slug', $root_slug, $component );
1406        }
1407
1408/**
1409 * Return the component name based on a root slug.
1410 *
1411 * @since 1.5.0
1412 *
1413 * @param string $root_slug Needle to our active component haystack.
1414 * @return mixed False if none found, component name if found.
1415 */
1416function bp_get_name_from_root_slug( $root_slug = '' ) {
1417        $bp = buddypress();
1418
1419        // If no slug is passed, look at current_component.
1420        if ( empty( $root_slug ) ) {
1421                $root_slug = bp_current_component();
1422        }
1423
1424        // No current component or root slug, so flee.
1425        if ( empty( $root_slug ) ) {
1426                return false;
1427        }
1428
1429        // Loop through active components and look for a match.
1430        foreach ( array_keys( $bp->active_components ) as $component ) {
1431                if ( ( ! empty( $bp->{$component}->slug ) && ( $bp->{$component}->slug == $root_slug ) ) || ( ! empty( $bp->{$component}->root_slug ) && ( $bp->{$component}->root_slug === $root_slug ) ) ) {
1432                        return $bp->{$component}->name;
1433                }
1434        }
1435
1436        return false;
1437}
1438
1439/**
1440 * Returns whether or not a user has access.
1441 *
1442 * @since 1.2.4
1443 *
1444 * @return bool
1445 */
1446function bp_user_has_access() {
1447        $has_access = bp_current_user_can( 'bp_moderate' ) || bp_is_my_profile();
1448
1449        /**
1450         * Filters whether or not a user has access.
1451         *
1452         * @since 1.2.4
1453         *
1454         * @param bool $has_access Whether or not user has access.
1455         */
1456        return (bool) apply_filters( 'bp_user_has_access', $has_access );
1457}
1458
1459/**
1460 * Output the search slug.
1461 *
1462 * @since 1.5.0
1463 *
1464 */
1465function bp_search_slug() {
1466        echo esc_attr( bp_get_search_slug() );
1467}
1468        /**
1469         * Return the search slug.
1470         *
1471         * @since 1.5.0
1472         *
1473         * @return string The search slug. Default: 'search'.
1474         */
1475        function bp_get_search_slug() {
1476
1477                /**
1478                 * Filters the search slug.
1479                 *
1480                 * @since 1.5.0
1481                 *
1482                 * @const string BP_SEARCH_SLUG The search slug. Default "search".
1483                 */
1484                return apply_filters( 'bp_get_search_slug', BP_SEARCH_SLUG );
1485        }
1486
1487/**
1488 * Get the ID of the currently displayed user.
1489 *
1490 * @since 1.0.0
1491 *
1492 * @return int $id ID of the currently displayed user.
1493 */
1494function bp_displayed_user_id() {
1495        $bp = buddypress();
1496        $id = !empty( $bp->displayed_user->id )
1497                ? $bp->displayed_user->id
1498                : 0;
1499
1500        /**
1501         * Filters the ID of the currently displayed user.
1502         *
1503         * @since 1.0.0
1504         *
1505         * @param int $id ID of the currently displayed user.
1506         */
1507        return (int) apply_filters( 'bp_displayed_user_id', $id );
1508}
1509
1510/**
1511 * Get the ID of the currently logged-in user.
1512 *
1513 * @since 1.0.0
1514 *
1515 * @return int ID of the logged-in user.
1516 */
1517function bp_loggedin_user_id() {
1518        $bp = buddypress();
1519        $id = !empty( $bp->loggedin_user->id )
1520                ? $bp->loggedin_user->id
1521                : 0;
1522
1523        /**
1524         * Filters the ID of the currently logged-in user.
1525         *
1526         * @since 1.0.0
1527         *
1528         * @param int $id ID of the currently logged-in user.
1529         */
1530        return (int) apply_filters( 'bp_loggedin_user_id', $id );
1531}
1532
1533/** The is_() functions to determine the current page *****************************/
1534
1535/**
1536 * Check to see whether the current page belongs to the specified component.
1537 *
1538 * This function is designed to be generous, accepting several different kinds
1539 * of value for the $component parameter. It checks $component_name against:
1540 * - the component's root_slug, which matches the page slug in $bp->pages.
1541 * - the component's regular slug.
1542 * - the component's id, or 'canonical' name.
1543 *
1544 * @since 1.5.0
1545 *
1546 * @param string $component Name of the component being checked.
1547 * @return bool Returns true if the component matches, or else false.
1548 */
1549function bp_is_current_component( $component = '' ) {
1550
1551        // Default is no match. We'll check a few places for matches.
1552        $is_current_component = false;
1553
1554        // Always return false if a null value is passed to the function.
1555        if ( empty( $component ) ) {
1556                return false;
1557        }
1558
1559        // Backward compatibility: 'xprofile' should be read as 'profile'.
1560        if ( 'xprofile' === $component ) {
1561                $component = 'profile';
1562        }
1563
1564        $bp = buddypress();
1565
1566        // Only check if BuddyPress found a current_component.
1567        if ( ! empty( $bp->current_component ) ) {
1568
1569                // First, check to see whether $component_name and the current
1570                // component are a simple match.
1571                if ( $bp->current_component == $component ) {
1572                        $is_current_component = true;
1573
1574                // Since the current component is based on the visible URL slug let's
1575                // check the component being passed and see if its root_slug matches.
1576                } elseif ( isset( $bp->{$component}->root_slug ) && $bp->{$component}->root_slug == $bp->current_component ) {
1577                        $is_current_component = true;
1578
1579                // Because slugs can differ from root_slugs, we should check them too.
1580                } elseif ( isset( $bp->{$component}->slug ) && $bp->{$component}->slug == $bp->current_component ) {
1581                        $is_current_component = true;
1582
1583                // Next, check to see whether $component is a canonical,
1584                // non-translatable component name. If so, we can return its
1585                // corresponding slug from $bp->active_components.
1586                } elseif ( $key = array_search( $component, $bp->active_components ) ) {
1587                        if ( strstr( $bp->current_component, $key ) ) {
1588                                $is_current_component = true;
1589                        }
1590
1591                // If we haven't found a match yet, check against the root_slugs
1592                // created by $bp->pages, as well as the regular slugs.
1593                } else {
1594                        foreach ( $bp->active_components as $id ) {
1595                                // If the $component parameter does not match the current_component,
1596                                // then move along, these are not the droids you are looking for.
1597                                if ( empty( $bp->{$id}->root_slug ) || $bp->{$id}->root_slug != $bp->current_component ) {
1598                                        continue;
1599                                }
1600
1601                                if ( $id == $component ) {
1602                                        $is_current_component = true;
1603                                        break;
1604                                }
1605                        }
1606                }
1607        }
1608
1609        /**
1610         * Filters whether the current page belongs to the specified component.
1611         *
1612         * @since 1.5.0
1613         *
1614         * @param bool   $is_current_component Whether or not the current page belongs to specified component.
1615         * @param string $component            Name of the component being checked.
1616         */
1617        return apply_filters( 'bp_is_current_component', $is_current_component, $component );
1618}
1619
1620/**
1621 * Check to see whether the current page matches a given action.
1622 *
1623 * Along with bp_is_current_component() and bp_is_action_variable(), this
1624 * function is mostly used to help determine when to use a given screen
1625 * function.
1626 *
1627 * In BP parlance, the current_action is the URL chunk that comes directly
1628 * after the current item slug. E.g., in
1629 *   http://example.com/groups/my-group/members
1630 * the current_action is 'members'.
1631 *
1632 * @since 1.5.0
1633 *
1634 * @param string $action The action being tested against.
1635 * @return bool True if the current action matches $action.
1636 */
1637function bp_is_current_action( $action = '' ) {
1638        return (bool) ( $action === bp_current_action() );
1639}
1640
1641/**
1642 * Check to see whether the current page matches a given action_variable.
1643 *
1644 * Along with bp_is_current_component() and bp_is_current_action(), this
1645 * function is mostly used to help determine when to use a given screen
1646 * function.
1647 *
1648 * In BP parlance, action_variables are an array made up of the URL chunks
1649 * appearing after the current_action in a URL. For example,
1650 *   http://example.com/groups/my-group/admin/group-settings
1651 * $action_variables[0] is 'group-settings'.
1652 *
1653 * @since 1.5.0
1654 *
1655 * @param string   $action_variable The action_variable being tested against.
1656 * @param int|bool $position        Optional. The array key you're testing against. If you
1657 *                                  don't provide a $position, the function will return true if the
1658 *                                  $action_variable is found *anywhere* in the action variables array.
1659 * @return bool True if $action_variable matches at the $position provided.
1660 */
1661function bp_is_action_variable( $action_variable = '', $position = false ) {
1662        $is_action_variable = false;
1663
1664        if ( false !== $position ) {
1665                // When a $position is specified, check that slot in the action_variables array.
1666                if ( $action_variable ) {
1667                        $is_action_variable = $action_variable == bp_action_variable( $position );
1668                } else {
1669                        // If no $action_variable is provided, we are essentially checking to see
1670                        // whether the slot is empty.
1671                        $is_action_variable = !bp_action_variable( $position );
1672                }
1673        } else {
1674                // When no $position is specified, check the entire array.
1675                $is_action_variable = in_array( $action_variable, (array)bp_action_variables() );
1676        }
1677
1678        /**
1679         * Filters whether the current page matches a given action_variable.
1680         *
1681         * @since 1.5.0
1682         *
1683         * @param bool   $is_action_variable Whether the current page matches a given action_variable.
1684         * @param string $action_variable    The action_variable being tested against.
1685         * @param int    $position           The array key tested against.
1686         */
1687        return apply_filters( 'bp_is_action_variable', $is_action_variable, $action_variable, $position );
1688}
1689
1690/**
1691 * Check against the current_item.
1692 *
1693 * @since 1.5.0
1694 *
1695 * @param string $item The item being checked.
1696 * @return bool True if $item is the current item.
1697 */
1698function bp_is_current_item( $item = '' ) {
1699        $retval = ( $item === bp_current_item() );
1700
1701        /**
1702         * Filters whether or not an item is the current item.
1703         *
1704         * @since 2.1.0
1705         *
1706         * @param bool   $retval Whether or not an item is the current item.
1707         * @param string $item   The item being checked.
1708         */
1709        return (bool) apply_filters( 'bp_is_current_item', $retval, $item );
1710}
1711
1712/**
1713 * Are we looking at a single item? (group, user, etc).
1714 *
1715 * @since 1.1.0
1716 *
1717 * @return bool True if looking at a single item, otherwise false.
1718 */
1719function bp_is_single_item() {
1720        $bp     = buddypress();
1721        $retval = false;
1722
1723        if ( isset( $bp->is_single_item ) ) {
1724                $retval = $bp->is_single_item;
1725        }
1726
1727        /**
1728         * Filters whether or not an item is the a single item. (group, user, etc)
1729         *
1730         * @since 2.1.0
1731         *
1732         * @param bool $retval Whether or not an item is a single item.
1733         */
1734        return (bool) apply_filters( 'bp_is_single_item', $retval );
1735}
1736
1737/**
1738 * Is the logged-in user an admin for the current item?
1739 *
1740 * @since 1.5.0
1741 *
1742 * @return bool True if the current user is an admin for the current item,
1743 *              otherwise false.
1744 */
1745function bp_is_item_admin() {
1746        $bp     = buddypress();
1747        $retval = false;
1748
1749        if ( isset( $bp->is_item_admin ) ) {
1750                $retval = $bp->is_item_admin;
1751        }
1752
1753        /**
1754         * Filters whether or not the logged-in user is an admin for the current item.
1755         *
1756         * @since 2.1.0
1757         *
1758         * @param bool $retval Whether or not the logged-in user is an admin.
1759         */
1760        return (bool) apply_filters( 'bp_is_item_admin', $retval );
1761}
1762
1763/**
1764 * Is the logged-in user a mod for the current item?
1765 *
1766 * @since 1.5.0
1767 *
1768 * @return bool True if the current user is a mod for the current item,
1769 *              otherwise false.
1770 */
1771function bp_is_item_mod() {
1772        $bp     = buddypress();
1773        $retval = false;
1774
1775        if ( isset( $bp->is_item_mod ) ) {
1776                $retval = $bp->is_item_mod;
1777        }
1778
1779        /**
1780         * Filters whether or not the logged-in user is a mod for the current item.
1781         *
1782         * @since 2.1.0
1783         *
1784         * @param bool $retval Whether or not the logged-in user is a mod.
1785         */
1786        return (bool) apply_filters( 'bp_is_item_mod', $retval );
1787}
1788
1789/**
1790 * Is this a component directory page?
1791 *
1792 * @since 1.0.0
1793 *
1794 * @return bool True if the current page is a component directory, otherwise false.
1795 */
1796function bp_is_directory() {
1797        $bp     = buddypress();
1798        $retval = false;
1799
1800        if ( isset( $bp->is_directory ) ) {
1801                $retval = $bp->is_directory;
1802        }
1803
1804        /**
1805         * Filters whether or not user is on a component directory page.
1806         *
1807         * @since 2.1.0
1808         *
1809         * @param bool $retval Whether or not user is on a component directory page.
1810         */
1811        return (bool) apply_filters( 'bp_is_directory', $retval );
1812}
1813
1814/**
1815 * Check to see if a component's URL should be in the root, not under a member page.
1816 *
1817 * - Yes ('groups' is root)    : http://example.com/groups/the-group
1818 * - No  ('groups' is not-root): http://example.com/members/andy/groups/the-group
1819 *
1820 * This function is on the chopping block. It's currently only used by a few
1821 * already deprecated functions.
1822 *
1823 * @since 1.5.0
1824 *
1825 * @param string $component_name Component name to check.
1826 *
1827 * @return bool True if root component, else false.
1828 */
1829function bp_is_root_component( $component_name = '' ) {
1830        $bp     = buddypress();
1831        $retval = false;
1832
1833        // Default to the current component if none is passed.
1834        if ( empty( $component_name ) ) {
1835                $component_name = bp_current_component();
1836        }
1837
1838        // Loop through active components and check for key/slug matches.
1839        if ( ! empty( $bp->active_components ) ) {
1840                foreach ( (array) $bp->active_components as $key => $slug ) {
1841                        if ( ( $key === $component_name ) || ( $slug === $component_name ) ) {
1842                                $retval = true;
1843                                break;
1844                        }
1845                }
1846        }
1847
1848        /**
1849         * Filters whether or not a component's URL should be in the root, not under a member page.
1850         *
1851         * @since 2.1.0
1852         *
1853         * @param bool $retval Whether or not URL should be in the root.
1854         */
1855        return (bool) apply_filters( 'bp_is_root_component', $retval );
1856}
1857
1858/**
1859 * Check if the specified BuddyPress component directory is set to be the front page.
1860 *
1861 * Corresponds to the setting in wp-admin's Settings > Reading screen.
1862 *
1863 * @since 1.5.0
1864 *
1865 * @global int $current_blog WordPress global for the current blog.
1866 *
1867 * @param string $component Optional. Name of the component to check for.
1868 *                          Default: current component.
1869 * @return bool True if the specified component is set to be the site's front
1870 *              page, otherwise false.
1871 */
1872function bp_is_component_front_page( $component = '' ) {
1873        global $current_blog;
1874
1875        $bp = buddypress();
1876
1877        // Default to the current component if none is passed.
1878        if ( empty( $component ) ) {
1879                $component = bp_current_component();
1880        }
1881
1882        // Get the path for the current blog/site.
1883        $path = is_main_site()
1884                ? bp_core_get_site_path()
1885                : $current_blog->path;
1886
1887        // Get the front page variables.
1888        $show_on_front = get_option( 'show_on_front' );
1889        $page_on_front = get_option( 'page_on_front' );
1890
1891        if ( ( 'page' !== $show_on_front ) || empty( $component ) || empty( $bp->pages->{$component} ) || ( $_SERVER['REQUEST_URI'] !== $path ) ) {
1892                return false;
1893        }
1894
1895        /**
1896         * Filters whether or not the specified BuddyPress component directory is set to be the front page.
1897         *
1898         * @since 1.5.0
1899         *
1900         * @param bool   $value     Whether or not the specified component directory is set as front page.
1901         * @param string $component Current component being checked.
1902         */
1903        return (bool) apply_filters( 'bp_is_component_front_page', ( $bp->pages->{$component}->id == $page_on_front ), $component );
1904}
1905
1906/**
1907 * Is this a blog page, ie a non-BP page?
1908 *
1909 * You can tell if a page is displaying BP content by whether the
1910 * current_component has been defined.
1911 *
1912 * @since 1.0.0
1913 *
1914 * @return bool True if it's a non-BP page, false otherwise.
1915 */
1916function bp_is_blog_page() {
1917
1918        $is_blog_page = false;
1919
1920        // Generally, we can just check to see that there's no current component.
1921        // The one exception is single user home tabs, where $bp->current_component
1922        // is unset. Thus the addition of the bp_is_user() check.
1923        if ( ! bp_current_component() && ! bp_is_user() ) {
1924                $is_blog_page = true;
1925        }
1926
1927        /**
1928         * Filters whether or not current page is a blog page or not.
1929         *
1930         * @since 1.5.0
1931         *
1932         * @param bool $is_blog_page Whether or not current page is a blog page.
1933         */
1934        return (bool) apply_filters( 'bp_is_blog_page', $is_blog_page );
1935}
1936
1937/**
1938 * Checks whether the requested URL is site home's one.
1939 *
1940 * @since 12.1.0
1941 *
1942 * @return bool True if the requested URL is site home's one. False otherwise.
1943 */
1944function bp_is_site_home() {
1945        $requested_url = bp_get_requested_url();
1946        $home_url      = home_url( '/' );
1947
1948        if ( is_customize_preview() && ! bp_is_email_customizer() ) {
1949                $requested_url = wp_parse_url( $requested_url, PHP_URL_PATH );
1950                $home_url      = wp_parse_url( $home_url, PHP_URL_PATH );
1951        }
1952
1953        return $home_url === $requested_url;
1954}
1955
1956/**
1957 * Is this a BuddyPress component?
1958 *
1959 * You can tell if a page is displaying BP content by whether the
1960 * current_component has been defined.
1961 *
1962 * Generally, we can just check to see that there's no current component.
1963 * The one exception is single user home tabs, where $bp->current_component
1964 * is unset. Thus the addition of the bp_is_user() check.
1965 *
1966 * @since 1.7.0
1967 *
1968 * @return bool True if it's a BuddyPress page, false otherwise.
1969 */
1970function is_buddypress() {
1971        $retval = (bool) ( bp_current_component() || bp_is_user() );
1972
1973        /**
1974         * Filters whether or not this is a BuddyPress component.
1975         *
1976         * @since 1.7.0
1977         *
1978         * @param bool $retval Whether or not this is a BuddyPress component.
1979         */
1980        return apply_filters( 'is_buddypress', $retval );
1981}
1982
1983/** Components ****************************************************************/
1984
1985/**
1986 * Check whether a given component (or feature of a component) is active.
1987 *
1988 * @since 1.2.0 See r2539.
1989 * @since 2.3.0 Added $feature as a parameter.
1990 *
1991 * @param string $component The component name.
1992 * @param string $feature   The feature name.
1993 * @return bool
1994 */
1995function bp_is_active( $component = '', $feature = '' ) {
1996        $retval = false;
1997
1998        // Default to the current component if none is passed.
1999        if ( empty( $component ) ) {
2000                $component = bp_current_component();
2001        }
2002
2003        // Is component in either the active or required components arrays.
2004        if ( isset( buddypress()->active_components[ $component ] ) || in_array( $component, buddypress()->required_components, true ) ) {
2005                $retval = true;
2006
2007                // Is feature active?
2008                if ( ! empty( $feature ) ) {
2009                        // The xProfile component is specific.
2010                        if ( 'xprofile' === $component ) {
2011                                $component = 'profile';
2012
2013                                // The Cover Image feature has been moved to the Members component in 6.0.0.
2014                                if ( 'cover_image' === $feature && 'profile' === $component ) {
2015                                        _doing_it_wrong( 'bp_is_active( \'profile\', \'cover_image\' )', esc_html__( 'The cover image is a Members component feature, please use bp_is_active( \'members\', \'cover_image\' ) instead.', 'buddypress' ), '6.0.0' );
2016                                        $members_component = buddypress()->members;
2017
2018                                        if ( ! isset( $members_component->features ) || false === in_array( $feature, $members_component->features, true ) ) {
2019                                                $retval = false;
2020                                        }
2021
2022                                        /** This filter is documented in wp-includes/deprecated.php */
2023                                        return apply_filters_deprecated( 'bp_is_profile_cover_image_active', array( $retval ), '6.0.0', 'bp_is_members_cover_image_active' );
2024                                }
2025                        }
2026
2027                        $component_features = isset( buddypress()->{$component}->features ) ? buddypress()->{$component}->features : array();
2028
2029                        if ( empty( $component_features ) || false === in_array( $feature, $component_features, true ) ) {
2030                                $retval = false;
2031                        }
2032
2033                        /**
2034                         * Filters whether or not a given feature for a component is active.
2035                         *
2036                         * This is a variable filter that is based on the component and feature
2037                         * that you are checking of active status of.
2038                         *
2039                         * @since 2.3.0
2040                         *
2041                         * @param bool $retval
2042                         */
2043                        $retval = apply_filters( "bp_is_{$component}_{$feature}_active", $retval );
2044                }
2045        }
2046
2047        /**
2048         * Filters whether or not a given component has been activated by the admin.
2049         *
2050         * @since 2.1.0
2051         *
2052         * @param bool   $retval    Whether or not a given component has been activated by the admin.
2053         * @param string $component Current component being checked.
2054         */
2055        return apply_filters( 'bp_is_active', $retval, $component );
2056}
2057
2058/**
2059 * Check whether the current page is part of the Members component.
2060 *
2061 * @since 1.5.0
2062 *
2063 * @return bool True if the current page is part of the Members component.
2064 */
2065function bp_is_members_component() {
2066        return (bool) bp_is_current_component( 'members' );
2067}
2068
2069/**
2070 * Check whether the current page is part of the Profile component.
2071 *
2072 * @since 1.1.0
2073 *
2074 * @return bool True if the current page is part of the Profile component.
2075 */
2076function bp_is_profile_component() {
2077        return (bool) bp_is_current_component( 'xprofile' );
2078}
2079
2080/**
2081 * Check whether the current page is part of the Activity component.
2082 *
2083 * @since 1.1.0
2084 *
2085 * @return bool True if the current page is part of the Activity component.
2086 */
2087function bp_is_activity_component() {
2088        return (bool) bp_is_current_component( 'activity' );
2089}
2090
2091/**
2092 * Check whether the current page is part of the Blogs component.
2093 *
2094 * @since 1.1.0
2095 *
2096 * @return bool True if the current page is part of the Blogs component.
2097 */
2098function bp_is_blogs_component() {
2099        return (bool) ( is_multisite() && bp_is_current_component( 'blogs' ) );
2100}
2101
2102/**
2103 * Check whether the current page is part of the Messages component.
2104 *
2105 * @since 1.1.0
2106 *
2107 * @return bool True if the current page is part of the Messages component.
2108 */
2109function bp_is_messages_component() {
2110        return (bool) bp_is_current_component( 'messages' );
2111}
2112
2113/**
2114 * Check whether the current page is part of the Friends component.
2115 *
2116 * @since 1.1.0
2117 *
2118 * @return bool True if the current page is part of the Friends component.
2119 */
2120function bp_is_friends_component() {
2121        return (bool) bp_is_current_component( 'friends' );
2122}
2123
2124/**
2125 * Check whether the current page is part of the Groups component.
2126 *
2127 * @since 1.1.0
2128 *
2129 * @return bool True if the current page is part of the Groups component.
2130 */
2131function bp_is_groups_component() {
2132        return (bool) bp_is_current_component( 'groups' );
2133}
2134
2135/**
2136 * Check whether the current page is part of the Forums component.
2137 *
2138 * @since 1.5.0
2139 * @since 3.0.0 Required for bbPress 2 integration.
2140 *
2141 * @return bool True if the current page is part of the Forums component.
2142 */
2143function bp_is_forums_component() {
2144        return (bool) bp_is_current_component( 'forums' );
2145}
2146
2147/**
2148 * Check whether the current page is part of the Notifications component.
2149 *
2150 * @since 1.9.0
2151 *
2152 * @return bool True if the current page is part of the Notifications component.
2153 */
2154function bp_is_notifications_component() {
2155        return (bool) bp_is_current_component( 'notifications' );
2156}
2157
2158/**
2159 * Check whether the current page is part of the Settings component.
2160 *
2161 * @since 1.1.0
2162 *
2163 * @return bool True if the current page is part of the Settings component.
2164 */
2165function bp_is_settings_component() {
2166        return (bool) bp_is_current_component( 'settings' );
2167}
2168
2169/**
2170 * Check whether the current page is an Invitations screen.
2171 *
2172 * @since 8.0.0
2173 *
2174 * @return bool True if the current page is an Invitations screen.
2175 */
2176function bp_is_members_invitations_screen() {
2177        return (bool) bp_is_current_component( bp_get_members_invitations_slug() );
2178}
2179
2180/**
2181 * Is the current component an active core component?
2182 *
2183 * Use this function when you need to check if the current component is an
2184 * active core component of BuddyPress. If the current component is inactive, it
2185 * will return false. If the current component is not part of BuddyPress core,
2186 * it will return false. If the current component is active, and is part of
2187 * BuddyPress core, it will return true.
2188 *
2189 * @since 1.7.0
2190 *
2191 * @return bool True if the current component is active and is one of BP's
2192 *              packaged components.
2193 */
2194function bp_is_current_component_core() {
2195        $retval = false;
2196
2197        foreach ( bp_core_get_packaged_component_ids() as $active_component ) {
2198                if ( bp_is_current_component( $active_component ) ) {
2199                        $retval = true;
2200                        break;
2201                }
2202        }
2203
2204        return $retval;
2205}
2206
2207/** Activity ******************************************************************/
2208
2209/**
2210 * Is the current page the activity directory?
2211 *
2212 * @since 2.0.0
2213 *
2214 * @return bool True if the current page is the activity directory.
2215 */
2216function bp_is_activity_directory() {
2217        if ( ! bp_displayed_user_id() && bp_is_activity_component() && ! bp_current_action() ) {
2218                return true;
2219        }
2220
2221        return false;
2222}
2223
2224/**
2225 * Is the current page a single activity item permalink?
2226 *
2227 * @since 1.5.0
2228 *
2229 * @return bool True if the current page is a single activity item permalink.
2230 */
2231function bp_is_single_activity() {
2232        return (bool) ( bp_is_activity_component() && is_numeric( bp_current_action() ) );
2233}
2234
2235/** User **********************************************************************/
2236
2237/**
2238 * Is the current page the members directory?
2239 *
2240 * @since 2.0.0
2241 *
2242 * @return bool True if the current page is the members directory.
2243 */
2244function bp_is_members_directory() {
2245        if ( ! bp_is_user() && bp_is_members_component() ) {
2246                return true;
2247        }
2248
2249        return false;
2250}
2251
2252/**
2253 * Is the current page part of the profile of the logged-in user?
2254 *
2255 * Will return true for any subpage of the logged-in user's profile, eg
2256 * http://example.com/members/joe/friends/.
2257 *
2258 * @since 1.2.0
2259 *
2260 * @return bool True if the current page is part of the profile of the logged-in user.
2261 */
2262function bp_is_my_profile() {
2263        if ( is_user_logged_in() && bp_loggedin_user_id() == bp_displayed_user_id() ) {
2264                $my_profile = true;
2265        } else {
2266                $my_profile = false;
2267        }
2268
2269        /**
2270         * Filters whether or not current page is part of the profile for the logged-in user.
2271         *
2272         * @since 1.2.4
2273         *
2274         * @param bool $my_profile Whether or not current page is part of the profile for the logged-in user.
2275         */
2276        return apply_filters( 'bp_is_my_profile', $my_profile );
2277}
2278
2279/**
2280 * Is the current page a user page?
2281 *
2282 * Will return true anytime there is a displayed user.
2283 *
2284 * @since 1.5.0
2285 *
2286 * @return bool True if the current page is a user page.
2287 */
2288function bp_is_user() {
2289        return (bool) bp_displayed_user_id();
2290}
2291
2292/**
2293 * Is the current page a user custom front page?
2294 *
2295 * Will return true anytime there is a custom front page for the displayed user.
2296 *
2297 * @since 2.6.0
2298 *
2299 * @return bool True if the current page is a user custom front page.
2300 */
2301function bp_is_user_front() {
2302        return (bool) ( bp_is_user() && bp_is_current_component( 'front' ) );
2303}
2304
2305/**
2306 * Is the current page a user's activity stream page?
2307 *
2308 * Eg http://example.com/members/joe/activity/ (or any subpages thereof).
2309 *
2310 * @since 1.1.0
2311 *
2312 * @return bool True if the current page is a user's activity stream page.
2313 */
2314function bp_is_user_activity() {
2315        return (bool) ( bp_is_user() && bp_is_activity_component() );
2316}
2317
2318/**
2319 * Is the current page a user's Friends activity stream?
2320 *
2321 * Eg http://example.com/members/joe/friends/
2322 *
2323 * @since 1.1.0
2324 *
2325 * @return bool True if the current page is a user's Friends activity stream.
2326 */
2327function bp_is_user_friends_activity() {
2328
2329        if ( ! bp_is_active( 'friends' ) ) {
2330                return false;
2331        }
2332
2333        $slug = bp_get_friends_slug();
2334
2335        if ( empty( $slug ) ) {
2336                $slug = 'friends';
2337        }
2338
2339        if ( bp_is_user_activity() && bp_is_current_action( $slug ) ) {
2340                return true;
2341        }
2342
2343        return false;
2344}
2345
2346/**
2347 * Is the current page a user's Groups activity stream?
2348 *
2349 * Eg http://example.com/members/joe/groups/
2350 *
2351 * @since 1.5.0
2352 *
2353 * @return bool True if the current page is a user's Groups activity stream.
2354 */
2355function bp_is_user_groups_activity() {
2356
2357        if ( ! bp_is_active( 'groups' ) ) {
2358                return false;
2359        }
2360
2361        $slug = ( bp_get_groups_slug() )
2362                ? bp_get_groups_slug()
2363                : 'groups';
2364
2365        if ( bp_is_user_activity() && bp_is_current_action( $slug ) ) {
2366                return true;
2367        }
2368
2369        return false;
2370}
2371
2372/**
2373 * Is the current page part of a user's extended profile?
2374 *
2375 * Eg http://example.com/members/joe/profile/ (or a subpage thereof).
2376 *
2377 * @since 1.1.0
2378 *
2379 * @return bool True if the current page is part of a user's extended profile.
2380 */
2381function bp_is_user_profile() {
2382        return (bool) ( bp_is_profile_component() || bp_is_current_component( 'profile' ) );
2383}
2384
2385/**
2386 * Is the current page part of a user's profile editing section?
2387 *
2388 * Eg http://example.com/members/joe/profile/edit/ (or a subpage thereof).
2389 *
2390 * @since 1.5.0
2391 *
2392 * @return bool True if the current page is a user's profile edit page.
2393 */
2394function bp_is_user_profile_edit() {
2395        return (bool) ( bp_is_profile_component() && bp_is_current_action( 'edit' ) );
2396}
2397
2398/**
2399 * Is the current page part of a user's profile avatar editing section?
2400 *
2401 * Eg http://example.com/members/joe/profile/change-avatar/ (or a subpage thereof).
2402 *
2403 * @since 1.5.0
2404 *
2405 * @return bool True if the current page is the user's avatar edit page.
2406 */
2407function bp_is_user_change_avatar() {
2408        return (bool) ( bp_is_profile_component() && bp_is_current_action( 'change-avatar' ) );
2409}
2410
2411/**
2412 * Is the current page the a user's change cover image profile page?
2413 *
2414 * Eg http://example.com/members/joe/profile/change-cover-image/ (or a subpage thereof).
2415 *
2416 * @since 2.4.0
2417 *
2418 * @return bool True if the current page is a user's profile edit cover image page.
2419 */
2420function bp_is_user_change_cover_image() {
2421        return (bool) ( bp_is_profile_component() && bp_is_current_action( 'change-cover-image' ) );
2422}
2423
2424/**
2425 * Is the current page part of a user's Groups page?
2426 *
2427 * Eg http://example.com/members/joe/groups/ (or a subpage thereof).
2428 *
2429 * @since 1.1.0
2430 *
2431 * @return bool True if the current page is a user's Groups page.
2432 */
2433function bp_is_user_groups() {
2434        return (bool) ( bp_is_user() && bp_is_groups_component() );
2435}
2436
2437/**
2438 * Is the current page part of a user's Blogs page?
2439 *
2440 * Eg http://example.com/members/joe/blogs/ (or a subpage thereof).
2441 *
2442 * @since 1.1.0
2443 *
2444 * @return bool True if the current page is a user's Blogs page.
2445 */
2446function bp_is_user_blogs() {
2447        return (bool) ( bp_is_user() && bp_is_blogs_component() );
2448}
2449
2450/**
2451 * Is the current page a user's Recent Blog Posts page?
2452 *
2453 * Eg http://example.com/members/joe/blogs/recent-posts/.
2454 *
2455 * @since 1.1.0
2456 *
2457 * @return bool True if the current page is a user's Recent Blog Posts page.
2458 */
2459function bp_is_user_recent_posts() {
2460        return (bool) ( bp_is_user_blogs() && bp_is_current_action( 'recent-posts' ) );
2461}
2462
2463/**
2464 * Is the current page a user's Recent Blog Comments page?
2465 *
2466 * Eg http://example.com/members/joe/blogs/recent-comments/.
2467 *
2468 * @since 1.1.0
2469 *
2470 * @return bool True if the current page is a user's Recent Blog Comments page.
2471 */
2472function bp_is_user_recent_commments() {
2473        return (bool) ( bp_is_user_blogs() && bp_is_current_action( 'recent-comments' ) );
2474}
2475
2476/**
2477 * Is the current page a user's Friends page?
2478 *
2479 * Eg http://example.com/members/joe/blogs/friends/ (or a subpage thereof).
2480 *
2481 * @since 1.1.0
2482 *
2483 * @return bool True if the current page is a user's Friends page.
2484 */
2485function bp_is_user_friends() {
2486        return (bool) ( bp_is_user() && bp_is_friends_component() );
2487}
2488
2489/**
2490 * Is the current page a user's Friend Requests page?
2491 *
2492 * Eg http://example.com/members/joe/friends/requests/.
2493 *
2494 * @since 1.5.0
2495 *
2496 * @return bool True if the current page is a user's Friends Requests page.
2497 */
2498function bp_is_user_friend_requests() {
2499        return (bool) ( bp_is_user_friends() && bp_is_current_action( 'requests' ) );
2500}
2501
2502/**
2503 * Is this a user's notifications page?
2504 *
2505 * Eg http://example.com/members/joe/notifications/ (or a subpage thereof).
2506 *
2507 * @since 1.9.0
2508 *
2509 * @return bool True if the current page is a user's Notifications page.
2510 */
2511function bp_is_user_notifications() {
2512        return (bool) ( bp_is_user() && bp_is_notifications_component() );
2513}
2514
2515/**
2516 * Is this a user's settings page?
2517 *
2518 * Eg http://example.com/members/joe/settings/ (or a subpage thereof).
2519 *
2520 * @since 1.5.0
2521 *
2522 * @return bool True if the current page is a user's Settings page.
2523 */
2524function bp_is_user_settings() {
2525        return (bool) ( bp_is_user() && bp_is_settings_component() );
2526}
2527
2528/**
2529 * Is this a user's General Settings page?
2530 *
2531 * Eg http://example.com/members/joe/settings/general/.
2532 *
2533 * @since 1.5.0
2534 *
2535 * @return bool True if the current page is a user's General Settings page.
2536 */
2537function bp_is_user_settings_general() {
2538        return (bool) ( bp_is_user_settings() && bp_is_current_action( 'general' ) );
2539}
2540
2541/**
2542 * Is this a user's Notification Settings page?
2543 *
2544 * Eg http://example.com/members/joe/settings/notifications/.
2545 *
2546 * @since 1.5.0
2547 *
2548 * @return bool True if the current page is a user's Notification Settings page.
2549 */
2550function bp_is_user_settings_notifications() {
2551        return (bool) ( bp_is_user_settings() && bp_is_current_action( 'notifications' ) );
2552}
2553
2554/**
2555 * Is this a user's Account Deletion page?
2556 *
2557 * Eg http://example.com/members/joe/settings/delete-account/.
2558 *
2559 * @since 1.5.0
2560 *
2561 * @return bool True if the current page is a user's Delete Account page.
2562 */
2563function bp_is_user_settings_account_delete() {
2564        return (bool) ( bp_is_user_settings() && bp_is_current_action( 'delete-account' ) );
2565}
2566
2567/**
2568 * Is this a user's profile settings?
2569 *
2570 * Eg http://example.com/members/joe/settings/profile/.
2571 *
2572 * @since 2.0.0
2573 *
2574 * @return bool True if the current page is a user's Profile Settings page.
2575 */
2576function bp_is_user_settings_profile() {
2577        return (bool) ( bp_is_user_settings() && bp_is_current_action( 'profile' ) );
2578}
2579
2580/**
2581 * Is the current page a user's community invitations page?
2582 *
2583 * Eg http://example.com/members/cassie/invitations/ (or a subpage thereof).
2584 *
2585 * @since 8.0.0
2586 *
2587 * @return bool True if the current page is a user's community invitations page.
2588 */
2589function bp_is_user_members_invitations() {
2590        return (bool) ( bp_is_user() && bp_is_members_invitations_screen() );
2591}
2592
2593/**
2594 * Is the current page a user's List Invites page?
2595 *
2596 * Eg http://example.com/members/cassie/invitations/list-invites/.
2597 *
2598 * @since 8.0.0
2599 *
2600 * @return bool True if the current page is a user's List Invites page.
2601 */
2602function bp_is_user_members_invitations_list() {
2603        return (bool) ( bp_is_user_members_invitations() && bp_is_current_action( 'list-invites' ) );
2604}
2605
2606/**
2607 * Is the current page a user's Send Invites page?
2608 *
2609 * Eg http://example.com/members/cassie/invitations/send-invites/.
2610 *
2611 * @since 8.0.0
2612 *
2613 * @return bool True if the current page is a user's Send Invites page.
2614 */
2615function bp_is_user_members_invitations_send_screen() {
2616        return (bool) ( bp_is_user_members_invitations() && bp_is_current_action( 'send-invites' ) );
2617}
2618
2619/** Groups ********************************************************************/
2620
2621/**
2622 * Is the current page the groups directory?
2623 *
2624 * @since 2.0.0
2625 *
2626 * @return bool True if the current page is the groups directory.
2627 */
2628function bp_is_groups_directory() {
2629        $return = false;
2630
2631        if ( bp_is_groups_component() && ! bp_is_group() ) {
2632                $return = ! bp_current_action() || ! empty( buddypress()->groups->current_directory_type );
2633        }
2634
2635        return $return;
2636}
2637
2638/**
2639 * Does the current page belong to a single group?
2640 *
2641 * Will return true for any subpage of a single group.
2642 *
2643 * @since 1.2.0
2644 *
2645 * @return bool True if the current page is part of a single group.
2646 */
2647function bp_is_group() {
2648        $retval = bp_is_active( 'groups' );
2649
2650        if ( ! empty( $retval ) ) {
2651                $retval = bp_is_groups_component() && groups_get_current_group();
2652        }
2653
2654        return (bool) $retval;
2655}
2656
2657/**
2658 * Is the current page a single group's home page?
2659 *
2660 * URL will vary depending on which group tab is set to be the "home". By
2661 * default, it's the group's recent activity.
2662 *
2663 * @since 1.1.0
2664 *
2665 * @return bool True if the current page is a single group's home page.
2666 */
2667function bp_is_group_home() {
2668        if ( bp_is_single_item() && bp_is_groups_component() && ( ! bp_current_action() || bp_is_current_action( 'home' ) ) ) {
2669                return true;
2670        }
2671
2672        return false;
2673}
2674
2675/**
2676 * Is the current page part of the group creation process?
2677 *
2678 * @since 1.1.0
2679 *
2680 * @return bool True if the current page is part of the group creation process.
2681 */
2682function bp_is_group_create() {
2683        return (bool) ( bp_is_groups_component() && bp_is_current_action( 'create' ) );
2684}
2685
2686/**
2687 * Is the current page part of a single group's admin screens?
2688 *
2689 * Eg http://example.com/groups/mygroup/admin/settings/.
2690 *
2691 * @since 1.1.0
2692 *
2693 * @return bool True if the current page is part of a single group's admin.
2694 */
2695function bp_is_group_admin_page() {
2696        return (bool) ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'admin' ) );
2697}
2698
2699/**
2700 * Is the current page a group's activity page?
2701 *
2702 * @since 1.2.1
2703 *
2704 * @return bool True if the current page is a group's activity page.
2705 */
2706function bp_is_group_activity() {
2707        $retval = false;
2708
2709        if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'activity' ) ) {
2710                $retval = true;
2711        }
2712
2713        if ( bp_is_group_home() && bp_is_active( 'activity' ) && ! bp_is_group_custom_front() ) {
2714                $retval = true;
2715        }
2716
2717        return $retval;
2718}
2719
2720/**
2721 * Is the current page a group forum topic?
2722 *
2723 * @since 1.1.0
2724 * @since 3.0.0 Required for bbPress 2 integration.
2725 *
2726 * @return bool True if the current page is part of a group forum topic.
2727 */
2728function bp_is_group_forum_topic() {
2729        return (bool) ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'forum' ) && bp_is_action_variable( 'topic', 0 ) );
2730}
2731
2732/**
2733 * Is the current page a group forum topic edit page?
2734 *
2735 * @since 1.2.0
2736 * @since 3.0.0 Required for bbPress 2 integration.
2737 *
2738 * @return bool True if the current page is part of a group forum topic edit page.
2739 */
2740function bp_is_group_forum_topic_edit() {
2741        return (bool) ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'forum' ) && bp_is_action_variable( 'topic', 0 ) && bp_is_action_variable( 'edit', 2 ) );
2742}
2743
2744/**
2745 * Is the current page a group's Members page?
2746 *
2747 * Eg http://example.com/groups/mygroup/members/.
2748 *
2749 * @since 1.1.0
2750 *
2751 * @return bool True if the current page is part of a group's Members page.
2752 */
2753function bp_is_group_members() {
2754        $retval = false;
2755
2756        if ( bp_is_single_item() && bp_is_groups_component() && bp_is_current_action( 'members' ) ) {
2757                $retval = true;
2758        }
2759
2760        if ( bp_is_group_home() && ! bp_is_active( 'activity' ) && ! bp_is_group_custom_front() ) {
2761                $retval = true;
2762        }
2763
2764        return $retval;
2765}
2766
2767/**
2768 * Is the current page a group's Invites page?
2769 *
2770 * Eg http://example.com/groups/mygroup/send-invites/.
2771 *
2772 * @since 1.1.0
2773 *
2774 * @return bool True if the current page is a group's Send Invites page.
2775 */
2776function bp_is_group_invites() {
2777        return (bool) ( bp_is_groups_component() && bp_is_current_action( 'send-invites' ) );
2778}
2779
2780/**
2781 * Is the current page a group's Request Membership page?
2782 *
2783 * Eg http://example.com/groups/mygroup/request-membership/.
2784 *
2785 * @since 1.2.0
2786 *
2787 * @return bool True if the current page is a group's Request Membership page.
2788 */
2789function bp_is_group_membership_request() {
2790        return (bool) ( bp_is_groups_component() && bp_is_current_action( 'request-membership' ) );
2791}
2792
2793/**
2794 * Is the current page a leave group attempt?
2795 *
2796 * @since 1.1.0
2797 *
2798 * @return bool True if the current page is a Leave Group attempt.
2799 */
2800function bp_is_group_leave() {
2801        return (bool) ( bp_is_groups_component() && bp_is_single_item() && bp_is_current_action( 'leave-group' ) );
2802}
2803
2804/**
2805 * Is the current page part of a single group?
2806 *
2807 * Not currently used by BuddyPress.
2808 *
2809 * @todo How is this functionally different from bp_is_group()?
2810 *
2811 * @return bool True if the current page is part of a single group.
2812 */
2813function bp_is_group_single() {
2814        return (bool) ( bp_is_groups_component() && bp_is_single_item() );
2815}
2816
2817/**
2818 * Is the current group page a custom front?
2819 *
2820 * @since 2.4.0
2821 *
2822 * @return bool True if the current group page is a custom front.
2823 */
2824function bp_is_group_custom_front() {
2825        $bp = buddypress();
2826        return (bool) bp_is_group_home() && ! empty( $bp->groups->current_group->front_template );
2827}
2828
2829/**
2830 * Is the current page the Create a Blog page?
2831 *
2832 * Eg http://example.com/sites/create/.
2833 *
2834 * @since 1.1.0
2835 *
2836 * @return bool True if the current page is the Create a Blog page.
2837 */
2838function bp_is_create_blog() {
2839        return (bool) ( bp_is_blogs_component() && bp_is_current_action( 'create' ) );
2840}
2841
2842/**
2843 * Is the current page the blogs directory ?
2844 *
2845 * @since 2.0.0
2846 *
2847 * @return bool True if the current page is the blogs directory.
2848 */
2849function bp_is_blogs_directory() {
2850        if ( is_multisite() && bp_is_blogs_component() && ! bp_current_action() ) {
2851                return true;
2852        }
2853
2854        return false;
2855}
2856
2857/** Messages ******************************************************************/
2858
2859/**
2860 * Is the current page part of a user's Messages pages?
2861 *
2862 * Eg http://example.com/members/joe/messages/ (or a subpage thereof).
2863 *
2864 * @since 1.2.0
2865 *
2866 * @return bool True if the current page is part of a user's Messages pages.
2867 */
2868function bp_is_user_messages() {
2869        return (bool) ( bp_is_user() && bp_is_messages_component() );
2870}
2871
2872/**
2873 * Is the current page a user's Messages Inbox?
2874 *
2875 * Eg http://example.com/members/joe/messages/inbox/.
2876 *
2877 * @since 1.1.0
2878 *
2879 * @return bool True if the current page is a user's Messages Inbox.
2880 */
2881function bp_is_messages_inbox() {
2882        if ( bp_is_user_messages() && ( ! bp_current_action() || bp_is_current_action( 'inbox' ) ) ) {
2883                return true;
2884        }
2885
2886        return false;
2887}
2888
2889/**
2890 * Is the current page a user's Messages Sentbox?
2891 *
2892 * Eg http://example.com/members/joe/messages/sentbox/.
2893 *
2894 * @since 1.1.0
2895 *
2896 * @return bool True if the current page is a user's Messages Sentbox.
2897 */
2898function bp_is_messages_sentbox() {
2899        return (bool) ( bp_is_user_messages() && bp_is_current_action( 'sentbox' ) );
2900}
2901
2902/**
2903 * Is the current page a user's Messages Compose screen??
2904 *
2905 * Eg http://example.com/members/joe/messages/compose/.
2906 *
2907 * @since 1.1.0
2908 *
2909 * @return bool True if the current page is a user's Messages Compose screen.
2910 */
2911function bp_is_messages_compose_screen() {
2912        return (bool) ( bp_is_user_messages() && bp_is_current_action( 'compose' ) );
2913}
2914
2915/**
2916 * Is the current page the Notices screen?
2917 *
2918 * Eg http://example.com/members/joe/messages/notices/.
2919 *
2920 * @since 1.1.0
2921 *
2922 * @return bool True if the current page is the Notices screen.
2923 */
2924function bp_is_notices() {
2925        return (bool) ( bp_is_user_messages() && bp_is_current_action( 'notices' ) );
2926}
2927
2928/**
2929 * Is the current page a single Messages conversation thread?
2930 *
2931 * @since 1.6.0
2932 *
2933 * @return bool True if the current page a single Messages conversation thread?
2934 */
2935function bp_is_messages_conversation() {
2936        return (bool) ( bp_is_user_messages() && ( bp_is_current_action( 'view' ) ) );
2937}
2938
2939/**
2940 * Not currently used by BuddyPress.
2941 *
2942 * @param string $component Current component to check for.
2943 * @param string $callback  Callback to invoke.
2944 * @return bool
2945 */
2946function bp_is_single( $component, $callback ) {
2947        return (bool) ( bp_is_current_component( $component ) && ( true === call_user_func( $callback ) ) );
2948}
2949
2950/** Registration **************************************************************/
2951
2952/**
2953 * Is the current page the Activate page?
2954 *
2955 * Eg http://example.com/activate/.
2956 *
2957 * @since 1.1.0
2958 *
2959 * @return bool True if the current page is the Activate page.
2960 */
2961function bp_is_activation_page() {
2962        return (bool) bp_is_current_component( 'activate' );
2963}
2964
2965/**
2966 * Is the current page the Register page?
2967 *
2968 * Eg http://example.com/register/.
2969 *
2970 * @since 1.1.0
2971 *
2972 * @return bool True if the current page is the Register page.
2973 */
2974function bp_is_register_page() {
2975        return (bool) bp_is_current_component( 'register' );
2976}
2977
2978/**
2979 * Get the title parts of the BuddyPress displayed page
2980 *
2981 * @since 2.4.3
2982 *
2983 * @param string $seplocation Location for the separator.
2984 * @return array the title parts
2985 */
2986function bp_get_title_parts( $seplocation = 'right' ) {
2987        $bp = buddypress();
2988
2989        // Defaults to an empty array.
2990        $bp_title_parts = array();
2991
2992        // If this is not a BP page, return the empty array.
2993        if ( bp_is_blog_page() ) {
2994                return $bp_title_parts;
2995        }
2996
2997        // If this is a 404, return the empty array.
2998        if ( is_404() ) {
2999                return $bp_title_parts;
3000        }
3001
3002        // If this is the front page of the site, return the empty array.
3003        if ( is_front_page() || is_home() ) {
3004                return $bp_title_parts;
3005        }
3006
3007        // Return the empty array if not a BuddyPress page.
3008        if ( ! is_buddypress() ) {
3009                return $bp_title_parts;
3010        }
3011
3012        // Now we can build the BP Title Parts.
3013        // Is there a displayed user, and do they have a name?
3014        $displayed_user_name = bp_get_displayed_user_fullname();
3015
3016        // Displayed user.
3017        if ( ! empty( $displayed_user_name ) && ! is_404() ) {
3018
3019                // Get the component's ID to try and get its name.
3020                $component_id = $component_name = bp_current_component();
3021
3022                // Set empty subnav name.
3023                $component_subnav_name = '';
3024
3025                if ( ! empty( $bp->members->nav ) ) {
3026                        $primary_nav_item = (array) $bp->members->nav->get_primary( array( 'slug' => $component_id ), false );
3027                        $primary_nav_item = reset( $primary_nav_item );
3028                }
3029
3030                // Use the component nav name.
3031                if ( ! empty( $primary_nav_item->name ) ) {
3032                        $component_name = _bp_strip_spans_from_title( $primary_nav_item->name );
3033
3034                // Fall back on the component ID.
3035                } elseif ( ! empty( $bp->{$component_id}->id ) ) {
3036                        $component_name = ucwords( $bp->{$component_id}->id );
3037                }
3038
3039                if ( ! empty( $bp->members->nav ) ) {
3040                        $secondary_nav_item = $bp->members->nav->get_secondary( array(
3041                                'parent_slug' => $component_id,
3042                                'slug'        => bp_current_action()
3043                        ), false );
3044
3045                        if ( $secondary_nav_item ) {
3046                                $secondary_nav_item = reset( $secondary_nav_item );
3047                        }
3048                }
3049
3050                // Append action name if we're on a member component sub-page.
3051                if ( ! empty( $secondary_nav_item->name ) && ! empty( $bp->canonical_stack['action'] ) ) {
3052                        $component_subnav_name = $secondary_nav_item->name;
3053                }
3054
3055                // If on the user profile's landing page, just use the fullname.
3056                if ( bp_is_current_component( $bp->default_component ) && ( bp_get_requested_url() === bp_displayed_user_url() ) ) {
3057                        $bp_title_parts[] = $displayed_user_name;
3058
3059                // Use component name on member pages.
3060                } else {
3061                        $bp_title_parts = array_merge( $bp_title_parts, array_map( 'wp_strip_all_tags', array(
3062                                $displayed_user_name,
3063                                $component_name,
3064                        ) ) );
3065
3066                        // If we have a subnav name, add it separately for localization.
3067                        if ( ! empty( $component_subnav_name ) ) {
3068                                $bp_title_parts[] = wp_strip_all_tags( $component_subnav_name );
3069                        }
3070                }
3071
3072        // A single item from a component other than Members.
3073        } elseif ( bp_is_single_item() ) {
3074                $component_id = bp_current_component();
3075
3076                if ( ! empty( $bp->{$component_id}->nav ) ) {
3077                        $secondary_nav_item = $bp->{$component_id}->nav->get_secondary( array(
3078                                'parent_slug' => bp_current_item(),
3079                                'slug'        => bp_current_action()
3080                        ), false );
3081
3082                        if ( $secondary_nav_item ) {
3083                                $secondary_nav_item = reset( $secondary_nav_item );
3084                        }
3085                }
3086
3087                $single_item_subnav = '';
3088
3089                if ( ! empty( $secondary_nav_item->name ) ) {
3090                        $single_item_subnav = $secondary_nav_item->name;
3091                }
3092
3093                $bp_title_parts = array( $bp->bp_options_title, $single_item_subnav );
3094
3095        // An index or directory.
3096        } elseif ( bp_is_directory() ) {
3097                $current_component = bp_current_component();
3098
3099                // No current component (when does this happen?).
3100                $bp_title_parts = array( _x( 'Directory', 'component directory title', 'buddypress' ) );
3101
3102                if ( ! empty( $current_component ) ) {
3103                        $bp_title_parts = array( bp_get_directory_title( $current_component ) );
3104                }
3105
3106        // Sign up page.
3107        } elseif ( bp_is_register_page() ) {
3108                if ( bp_get_membership_requests_required() ) {
3109                        $bp_title_parts = array( __( 'Request Membership', 'buddypress' ) );
3110                } else {
3111                        $bp_title_parts = array( __( 'Create an Account', 'buddypress' ) );
3112                }
3113
3114        // Activation page.
3115        } elseif ( bp_is_activation_page() ) {
3116                $bp_title_parts = array( __( 'Activate Your Account', 'buddypress' ) );
3117
3118        // Group creation page.
3119        } elseif ( bp_is_group_create() ) {
3120                $bp_title_parts = array( __( 'Create a Group', 'buddypress' ) );
3121
3122        // Blog creation page.
3123        } elseif ( bp_is_create_blog() ) {
3124                $bp_title_parts = array( __( 'Create a Site', 'buddypress' ) );
3125        }
3126
3127        // Strip spans.
3128        $bp_title_parts = array_map( '_bp_strip_spans_from_title', $bp_title_parts );
3129
3130        // Sep on right, so reverse the order.
3131        if ( 'right' === $seplocation ) {
3132                $bp_title_parts = array_reverse( $bp_title_parts );
3133        }
3134
3135        /**
3136         * Filter BuddyPress title parts before joining.
3137         *
3138         * @since 2.4.3
3139         *
3140         * @param array $bp_title_parts Current BuddyPress title parts.
3141         * @return array
3142         */
3143        return (array) apply_filters( 'bp_get_title_parts', $bp_title_parts );
3144}
3145
3146/**
3147 * Customize the body class, according to the currently displayed BP content.
3148 *
3149 * @since 1.1.0
3150 */
3151function bp_the_body_class() {
3152        echo implode( ' ', array_map( 'sanitize_html_class', bp_get_the_body_class() ) );
3153}
3154        /**
3155         * Customize the body class, according to the currently displayed BP content.
3156         *
3157         * Uses the above is_() functions to output a body class for each scenario.
3158         *
3159         * @since 1.1.0
3160         *
3161         * @param array      $wp_classes     The body classes coming from WP.
3162         * @param array|bool $custom_classes Classes that were passed to get_body_class().
3163         * @return array $classes The BP-adjusted body classes.
3164         */
3165        function bp_get_the_body_class( $wp_classes = array(), $custom_classes = false ) {
3166
3167                $bp_classes = array();
3168
3169                /* Pages *************************************************************/
3170
3171                if ( is_front_page() ) {
3172                        $bp_classes[] = 'home-page';
3173                }
3174
3175                if ( bp_is_directory() ) {
3176                        $bp_classes[] = 'directory';
3177                }
3178
3179                if ( bp_is_single_item() ) {
3180                        $bp_classes[] = 'single-item';
3181                }
3182
3183                /* Components ********************************************************/
3184
3185                if ( ! bp_is_blog_page() ) {
3186                        if ( bp_is_user_profile() )  {
3187                                $bp_classes[] = 'xprofile';
3188                        }
3189
3190                        if ( bp_is_activity_component() ) {
3191                                $bp_classes[] = 'activity';
3192                        }
3193
3194                        if ( bp_is_blogs_component() ) {
3195                                $bp_classes[] = 'blogs';
3196                        }
3197
3198                        if ( bp_is_messages_component() ) {
3199                                $bp_classes[] = 'messages';
3200                        }
3201
3202                        if ( bp_is_friends_component() ) {
3203                                $bp_classes[] = 'friends';
3204                        }
3205
3206                        if ( bp_is_groups_component() ) {
3207                                $bp_classes[] = 'groups';
3208                        }
3209
3210                        if ( bp_is_settings_component()  ) {
3211                                $bp_classes[] = 'settings';
3212                        }
3213                }
3214
3215                /* User **************************************************************/
3216
3217                if ( bp_is_user() ) {
3218                        $bp_classes[] = 'bp-user';
3219
3220                        // Add current user member types.
3221                        if ( $member_types = bp_get_member_type( bp_displayed_user_id(), false ) ) {
3222                                foreach ( $member_types as $member_type ) {
3223                                        $bp_classes[] = sprintf( 'member-type-%s', esc_attr( $member_type ) );
3224                                }
3225                        }
3226                }
3227
3228                if ( ! bp_is_directory() ) {
3229                        if ( bp_is_user_blogs() ) {
3230                                $bp_classes[] = 'my-blogs';
3231                        }
3232
3233                        if ( bp_is_user_groups() ) {
3234                                $bp_classes[] = 'my-groups';
3235                        }
3236
3237                        if ( bp_is_user_activity() ) {
3238                                $bp_classes[] = 'my-activity';
3239                        }
3240                } else {
3241                        if ( bp_get_current_member_type() || ( bp_is_groups_directory() && bp_get_current_group_directory_type() ) ) {
3242                                $bp_classes[] = 'type';
3243                        }
3244                }
3245
3246                if ( bp_is_my_profile() ) {
3247                        $bp_classes[] = 'my-account';
3248                }
3249
3250                if ( bp_is_user_profile() ) {
3251                        $bp_classes[] = 'my-profile';
3252                }
3253
3254                if ( bp_is_user_friends() ) {
3255                        $bp_classes[] = 'my-friends';
3256                }
3257
3258                if ( bp_is_user_messages() ) {
3259                        $bp_classes[] = 'my-messages';
3260                }
3261
3262                if ( bp_is_user_recent_commments() ) {
3263                        $bp_classes[] = 'recent-comments';
3264                }
3265
3266                if ( bp_is_user_recent_posts() ) {
3267                        $bp_classes[] = 'recent-posts';
3268                }
3269
3270                if ( bp_is_user_change_avatar() ) {
3271                        $bp_classes[] = 'change-avatar';
3272                }
3273
3274                if ( bp_is_user_profile_edit() ) {
3275                        $bp_classes[] = 'profile-edit';
3276                }
3277
3278                if ( bp_is_user_friends_activity() ) {
3279                        $bp_classes[] = 'friends-activity';
3280                }
3281
3282                if ( bp_is_user_groups_activity() ) {
3283                        $bp_classes[] = 'groups-activity';
3284                }
3285
3286                /* Messages **********************************************************/
3287
3288                if ( bp_is_messages_inbox() ) {
3289                        $bp_classes[] = 'inbox';
3290                }
3291
3292                if ( bp_is_messages_sentbox() ) {
3293                        $bp_classes[] = 'sentbox';
3294                }
3295
3296                if ( bp_is_messages_compose_screen() ) {
3297                        $bp_classes[] = 'compose';
3298                }
3299
3300                if ( bp_is_notices() ) {
3301                        $bp_classes[] = 'notices';
3302                }
3303
3304                if ( bp_is_user_friend_requests() ) {
3305                        $bp_classes[] = 'friend-requests';
3306                }
3307
3308                if ( bp_is_create_blog() ) {
3309                        $bp_classes[] = 'create-blog';
3310                }
3311
3312                /* Groups ************************************************************/
3313
3314                if ( bp_is_group() ) {
3315                        $bp_classes[] = 'group-' . groups_get_current_group()->slug;
3316
3317                        // Add current group types.
3318                        if ( $group_types = bp_groups_get_group_type( bp_get_current_group_id(), false ) ) {
3319                                foreach ( $group_types as $group_type ) {
3320                                        $bp_classes[] = sprintf( 'group-type-%s', esc_attr( $group_type ) );
3321                                }
3322                        }
3323                }
3324
3325                if ( bp_is_group_leave() ) {
3326                        $bp_classes[] = 'leave-group';
3327                }
3328
3329                if ( bp_is_group_invites() ) {
3330                        $bp_classes[] = 'group-invites';
3331                }
3332
3333                if ( bp_is_group_members() ) {
3334                        $bp_classes[] = 'group-members';
3335                }
3336
3337                if ( bp_is_group_admin_page() ) {
3338                        $bp_classes[] = 'group-admin';
3339                        $bp_classes[] = bp_get_group_current_admin_tab();
3340                }
3341
3342                if ( bp_is_group_create() ) {
3343                        $bp_classes[] = 'group-create';
3344                        $bp_classes[] = bp_get_groups_current_create_step();
3345                }
3346
3347                if ( bp_is_group_home() ) {
3348                        $bp_classes[] = 'group-home';
3349                }
3350
3351                if ( bp_is_single_activity() ) {
3352                        $bp_classes[] = 'activity-permalink';
3353                }
3354
3355                /* Registration ******************************************************/
3356
3357                if ( bp_is_register_page() ) {
3358                        $bp_classes[] = 'registration';
3359                }
3360
3361                if ( bp_is_activation_page() ) {
3362                        $bp_classes[] = 'activation';
3363                }
3364
3365                /* Current Component & Action ****************************************/
3366
3367                if ( ! bp_is_blog_page() ) {
3368                        $bp_classes[] = bp_current_component();
3369                        $bp_classes[] = bp_current_action();
3370                }
3371
3372                /* Clean up ***********************************************************/
3373
3374                // Add BuddyPress class if we are within a BuddyPress page.
3375                if ( ! bp_is_blog_page() ) {
3376                        $bp_classes[] = 'buddypress';
3377                }
3378
3379                // Add the theme name/id to the body classes
3380                $bp_classes[] = 'bp-' . bp_get_theme_compat_id();
3381
3382                // Merge WP classes with BuddyPress classes and remove any duplicates.
3383                $classes = array_unique( array_merge( (array) $bp_classes, (array) $wp_classes ) );
3384
3385                /**
3386                 * Filters the BuddyPress classes to be added to body_class()
3387                 *
3388                 * @since 1.1.0
3389                 *
3390                 * @param array $classes        Array of body classes to add.
3391                 * @param array $bp_classes     Array of BuddyPress-based classes.
3392                 * @param array $wp_classes     Array of WordPress-based classes.
3393                 * @param array $custom_classes Array of classes that were passed to get_body_class().
3394                 */
3395                return apply_filters( 'bp_get_the_body_class', $classes, $bp_classes, $wp_classes, $custom_classes );
3396        }
3397        add_filter( 'body_class', 'bp_get_the_body_class', 10, 2 );
3398
3399/**
3400 * Customizes the post CSS class according to BuddyPress content.
3401 *
3402 * Hooked to the 'post_class' filter.
3403 *
3404 * @since 2.1.0
3405 *
3406 * @param array $wp_classes The post classes coming from WordPress.
3407 * @return array
3408 */
3409function bp_get_the_post_class( $wp_classes = array() ) {
3410        // Don't do anything if we're not on a BP page.
3411        if ( ! is_buddypress() ) {
3412                return $wp_classes;
3413        }
3414
3415        $bp_classes = array();
3416
3417        if ( bp_is_user() || bp_is_single_activity() ) {
3418                $bp_classes[] = 'bp_members';
3419
3420        } elseif ( bp_is_group() ) {
3421                $bp_classes[] = 'bp_group';
3422
3423        } elseif ( bp_is_activity_component() ) {
3424                $bp_classes[] = 'bp_activity';
3425
3426        } elseif ( bp_is_blogs_component() ) {
3427                $bp_classes[] = 'bp_blogs';
3428
3429        } elseif ( bp_is_register_page() ) {
3430                $bp_classes[] = 'bp_register';
3431
3432        } elseif ( bp_is_activation_page() ) {
3433                $bp_classes[] = 'bp_activate';
3434        }
3435
3436        if ( empty( $bp_classes ) ) {
3437                return $wp_classes;
3438        }
3439
3440        // Emulate post type css class.
3441        foreach ( $bp_classes as $bp_class ) {
3442                $bp_classes[] = "type-{$bp_class}";
3443        }
3444
3445        // Okay let's merge!
3446        return array_unique( array_merge( $bp_classes, $wp_classes ) );
3447}
3448add_filter( 'post_class', 'bp_get_the_post_class' );
3449
3450/**
3451 * Sort BuddyPress nav menu items by their position property.
3452 *
3453 * This is an internal convenience function and it will probably be removed in
3454 * a later release. Do not use.
3455 *
3456 * @access private
3457 * @since 1.7.0
3458 *
3459 * @param array $a First item.
3460 * @param array $b Second item.
3461 * @return int Returns an integer less than, equal to, or greater than zero if
3462 *             the first argument is considered to be respectively less than,
3463 *             equal to, or greater than the second.
3464 */
3465function _bp_nav_menu_sort( $a, $b ) {
3466        if ( $a['position'] == $b['position'] ) {
3467                return 0;
3468        } elseif ( $a['position'] < $b['position'] ) {
3469                return -1;
3470        } else {
3471                return 1;
3472        }
3473}
3474
3475/**
3476 * Get the items registered in the primary and secondary BuddyPress navigation menus.
3477 *
3478 * @since 1.7.0
3479 * @since 2.6.0 Introduced the `$component` parameter.
3480 *
3481 * @param string $component Optional. Component whose nav items are being fetched.
3482 * @return array A multidimensional array of all navigation items.
3483 */
3484function bp_get_nav_menu_items( $component = 'members' ) {
3485        $bp    = buddypress();
3486        $menus = array();
3487
3488        if ( ! isset( $bp->{$component}->nav ) ) {
3489                return $menus;
3490        }
3491
3492        // Get the item nav and build the menus.
3493        foreach ( $bp->{$component}->nav->get_item_nav() as $nav_menu ) {
3494                // Get the correct menu link. See https://buddypress.trac.wordpress.org/ticket/4624.
3495                $link = $nav_menu->link;
3496                if ( bp_loggedin_user_url() ) {
3497                        $link = str_replace( bp_loggedin_user_url(), bp_displayed_user_url(), $nav_menu->link );
3498                }
3499
3500                // Add this menu.
3501                $menu         = new stdClass;
3502                $menu->class  = array( 'menu-parent' );
3503                $menu->css_id = $nav_menu->css_id;
3504                $menu->link   = $link;
3505                $menu->name   = $nav_menu->name;
3506                $menu->parent = 0;
3507
3508                if ( ! empty( $nav_menu->children ) ) {
3509                        $submenus = array();
3510
3511                        foreach ( $nav_menu->children as $sub_menu ) {
3512                                $submenu = new stdClass;
3513                                $submenu->class  = array( 'menu-child' );
3514                                $submenu->css_id = $sub_menu->css_id;
3515                                $submenu->link   = $sub_menu->link;
3516                                $submenu->name   = $sub_menu->name;
3517                                $submenu->parent = $nav_menu->slug;
3518
3519                                // If we're viewing this item's screen, record that we need to mark its parent menu to be selected.
3520                                if ( bp_is_current_action( $sub_menu->slug ) && bp_is_current_component( $nav_menu->slug ) ) {
3521                                        $menu->class[]    = 'current-menu-parent';
3522                                        $submenu->class[] = 'current-menu-item';
3523                                }
3524
3525                                $submenus[] = $submenu;
3526                        }
3527                }
3528
3529                $menus[] = $menu;
3530
3531                if ( ! empty( $submenus ) ) {
3532                        $menus = array_merge( $menus, $submenus );
3533                }
3534        }
3535
3536        /**
3537         * Filters the items registered in the primary and secondary BuddyPress navigation menus.
3538         *
3539         * @since 1.7.0
3540         *
3541         * @param array $menus Array of items registered in the primary and secondary BuddyPress navigation.
3542         */
3543        return apply_filters( 'bp_get_nav_menu_items', $menus );
3544}
3545
3546/**
3547 * Display a navigation menu.
3548 *
3549 * @since 1.7.0
3550 *
3551 * @param string|array $args {
3552 *     An array of optional arguments.
3553 *
3554 *     @type string $after           Text after the link text. Default: ''.
3555 *     @type string $before          Text before the link text. Default: ''.
3556 *     @type string $container       The name of the element to wrap the navigation
3557 *                                   with. 'div' or 'nav'. Default: 'div'.
3558 *     @type string $container_class The class that is applied to the container.
3559 *                                   Default: 'menu-bp-container'.
3560 *     @type string $container_id    The ID that is applied to the container.
3561 *                                   Default: ''.
3562 *     @type int    $depth           How many levels of the hierarchy are to be included.
3563 *                                   0 means all. Default: 0.
3564 *     @type bool   $echo            True to echo the menu, false to return it.
3565 *                                   Default: true.
3566 *     @type bool   $fallback_cb     If the menu doesn't exist, should a callback
3567 *                                   function be fired? Default: false (no fallback).
3568 *     @type string $items_wrap      How the list items should be wrapped. Should be
3569 *                                   in the form of a printf()-friendly string, using numbered
3570 *                                   placeholders. Default: '<ul id="%1$s" class="%2$s">%3$s</ul>'.
3571 *     @type string $link_after      Text after the link. Default: ''.
3572 *     @type string $link_before     Text before the link. Default: ''.
3573 *     @type string $menu_class      CSS class to use for the <ul> element which
3574 *                                   forms the menu. Default: 'menu'.
3575 *     @type string $menu_id         The ID that is applied to the <ul> element which
3576 *                                   forms the menu. Default: 'menu-bp', incremented.
3577 *     @type string $walker          Allows a custom walker class to be specified.
3578 *                                   Default: 'BP_Walker_Nav_Menu'.
3579 * }
3580 * @return string|null If $echo is false, returns a string containing the nav
3581 *                     menu markup.
3582 */
3583function bp_nav_menu( $args = array() ) {
3584        static $menu_id_slugs = array();
3585
3586        $defaults = array(
3587                'after'           => '',
3588                'before'          => '',
3589                'container'       => 'div',
3590                'container_class' => '',
3591                'container_id'    => '',
3592                'depth'           => 0,
3593                'echo'            => true,
3594                'fallback_cb'     => false,
3595                'items_wrap'      => '<ul id="%1$s" class="%2$s">%3$s</ul>',
3596                'link_after'      => '',
3597                'link_before'     => '',
3598                'menu_class'      => 'menu',
3599                'menu_id'         => '',
3600                'walker'          => '',
3601        );
3602
3603        $args = bp_parse_args(
3604                $args,
3605                $defaults
3606        );
3607
3608        /**
3609         * Filters the parsed bp_nav_menu arguments.
3610         *
3611         * @since 1.7.0
3612         *
3613         * @param array $args Array of parsed arguments.
3614         */
3615        $args = apply_filters( 'bp_nav_menu_args', $args );
3616        $args = (object) $args;
3617
3618        $items = $nav_menu = '';
3619        $show_container = false;
3620
3621        // Create custom walker if one wasn't set.
3622        if ( empty( $args->walker ) ) {
3623                $args->walker = new BP_Walker_Nav_Menu;
3624        }
3625
3626        // Sanitize values for class and ID.
3627        $args->container_class = sanitize_html_class( $args->container_class );
3628        $args->container_id    = sanitize_html_class( $args->container_id );
3629
3630        // Whether to wrap the ul, and what to wrap it with.
3631        if ( $args->container ) {
3632
3633                /**
3634                 * Filters the allowed tags for the wp_nav_menu_container.
3635                 *
3636                 * @since 1.7.0
3637                 *
3638                 * @param array $value Array of allowed tags. Default 'div' and 'nav'.
3639                 */
3640                $allowed_tags = apply_filters( 'wp_nav_menu_container_allowedtags', array( 'div', 'nav', ) );
3641
3642                if ( in_array( $args->container, $allowed_tags ) ) {
3643                        $show_container = true;
3644
3645                        $class     = $args->container_class ? ' class="' . esc_attr( $args->container_class ) . '"' : ' class="menu-bp-container"';
3646                        $id        = $args->container_id    ? ' id="' . esc_attr( $args->container_id ) . '"'       : '';
3647                        $nav_menu .= '<' . $args->container . $id . $class . '>';
3648                }
3649        }
3650
3651        /**
3652         * Filters the BuddyPress menu objects.
3653         *
3654         * @since 1.7.0
3655         *
3656         * @param array $value Array of nav menu objects.
3657         * @param array $args  Array of arguments for the menu.
3658         */
3659        $menu_items = apply_filters( 'bp_nav_menu_objects', bp_get_nav_menu_items(), $args );
3660        $items      = walk_nav_menu_tree( $menu_items, $args->depth, $args );
3661        unset( $menu_items );
3662
3663        // Set the ID that is applied to the ul element which forms the menu.
3664        if ( ! empty( $args->menu_id ) ) {
3665                $wrap_id = $args->menu_id;
3666
3667        } else {
3668                $wrap_id = 'menu-bp';
3669
3670                // If a specific ID wasn't requested, and there are multiple menus on the same screen, make sure the autogenerated ID is unique.
3671                while ( in_array( $wrap_id, $menu_id_slugs ) ) {
3672                        if ( preg_match( '#-(\d+)$#', $wrap_id, $matches ) ) {
3673                                $wrap_id = preg_replace('#-(\d+)$#', '-' . ++$matches[1], $wrap_id );
3674                        } else {
3675                                $wrap_id = $wrap_id . '-1';
3676                        }
3677                }
3678        }
3679        $menu_id_slugs[] = $wrap_id;
3680
3681        /**
3682         * Filters the BuddyPress menu items.
3683         *
3684         * Allow plugins to hook into the menu to add their own <li>'s
3685         *
3686         * @since 1.7.0
3687         *
3688         * @param array $items Array of nav menu items.
3689         * @param array $args  Array of arguments for the menu.
3690         */
3691        $items = apply_filters( 'bp_nav_menu_items', $items, $args );
3692
3693        // Build the output.
3694        $wrap_class  = $args->menu_class ? $args->menu_class : '';
3695        $nav_menu   .= sprintf( $args->items_wrap, esc_attr( $wrap_id ), esc_attr( $wrap_class ), $items );
3696        unset( $items );
3697
3698        // If we've wrapped the ul, close it.
3699        if ( ! empty( $show_container ) ) {
3700                $nav_menu .= '</' . $args->container . '>';
3701        }
3702
3703        /**
3704         * Filters the final BuddyPress menu output.
3705         *
3706         * @since 1.7.0
3707         *
3708         * @param string $nav_menu Final nav menu output.
3709         * @param array  $args     Array of arguments for the menu.
3710         */
3711        $nav_menu = apply_filters( 'bp_nav_menu', $nav_menu, $args );
3712
3713        if ( ! empty( $args->echo ) ) {
3714                // phpcs:ignore WordPress.Security.EscapeOutput
3715                echo $nav_menu;
3716        } else {
3717                return $nav_menu;
3718        }
3719}
3720
3721/**
3722 * Prints the Recipient Salutation.
3723 *
3724 * @since 2.5.0
3725 *
3726 * @param array $settings Email Settings.
3727 */
3728function bp_email_the_salutation( $settings = array() ) {
3729        echo esc_html( bp_email_get_salutation( $settings ) );
3730}
3731
3732        /**
3733         * Gets the Recipient Salutation.
3734         *
3735         * @since 2.5.0
3736         * @since 8.0.0 Checks current BP Email type schema to eventually use the unnamed salutation.
3737         *
3738         * @param array $settings Email Settings.
3739         * @return string The Recipient Salutation.
3740         */
3741        function bp_email_get_salutation( $settings = array() ) {
3742                $email_type = bp_email_get_type();
3743                $salutation  = '';
3744
3745                if ( $email_type ) {
3746                        $types_schema = bp_email_get_type_schema( 'named_salutation' );
3747
3748                        if ( isset( $types_schema[ $email_type ] ) && false === $types_schema[ $email_type ] ) {
3749                                /**
3750                                 * Filters The Recipient Unnamed Salutation inside the Email Template.
3751                                 *
3752                                 * @since 8.0.0
3753                                 *
3754                                 * @param string $value    The Recipient Salutation.
3755                                 * @param array  $settings Email Settings.
3756                                 */
3757                                $salutation = apply_filters(
3758                                        'bp_email_get_unnamed_salutation',
3759                                        _x( 'Hi,', 'Unnamed recipient salutation', 'buddypress' ),
3760                                        $settings
3761                                );
3762                        }
3763                }
3764
3765                // Named salutations are default.
3766                if ( ! $salutation ) {
3767                        $token = '{{recipient.name}}';
3768
3769                        /**
3770                         * Filters The Recipient Named Salutation inside the Email Template.
3771                         *
3772                         * @since 2.5.0
3773                         *
3774                         * @param string $value    The Recipient Salutation.
3775                         * @param array  $settings Email Settings.
3776                         * @param string $token    The Recipient token.
3777                         */
3778                        $salutation = apply_filters(
3779                                'bp_email_get_salutation',
3780                                sprintf(
3781                                        /* translators: %s: the email token for the recipient name */
3782                                        _x( 'Hi %s,', 'Named recipient salutation', 'buddypress' ),
3783                                        $token
3784                                ),
3785                                $settings,
3786                                $token
3787                        );
3788                }
3789
3790                return $salutation;
3791        }
3792
3793/**
3794 * Outputs the BP Email's template footer.
3795 *
3796 * @since 12.1.0
3797 */
3798function bp_email_footer() {
3799        // `the_block_template_skip_link()` was deprecated in WP 6.4.0.
3800        if ( bp_is_running_wp( '6.4.0', '>=' ) && has_action( 'wp_footer', 'the_block_template_skip_link' ) ) {
3801                remove_action( 'wp_footer', 'the_block_template_skip_link' );
3802        }
3803
3804        wp_footer();
3805}
3806
3807/**
3808 * Checks if a Widget/Block is active.
3809 *
3810 * @since 9.0.0
3811 *
3812 * @param string $block_name     The Block name to check (eg: 'bp/sitewide-notices'). Optional.
3813 * @param string $widget_id_base The Widget ID base to check (eg: 'bp_messages_sitewide_notices_widget' ). Optional.
3814 * @return bool True if the Widget/Block is active. False otherwise.
3815 */
3816function bp_is_widget_block_active( $block_name = '', $widget_id_base = '' ) {
3817        $is_active = array(
3818                'widget' => false,
3819                'block'  => false,
3820        );
3821
3822        if ( $block_name ) {
3823                $widget_blocks = get_option( 'widget_block', array() );
3824                $sidebars      = wp_get_sidebars_widgets();
3825
3826                if ( ! $widget_blocks || ! $sidebars ) {
3827                        return false;
3828                }
3829
3830                // Neutralize inactive sidebar.
3831                unset( $sidebars['wp_inactive_widgets'] );
3832
3833                $widgets_content = '';
3834                foreach ( $widget_blocks as $key => $widget_block ) {
3835                        $widget_block_reference = 'block-' . $key;
3836
3837                        if ( ! isset( $widget_block['content'] ) || ! $widget_block['content'] ) {
3838                                continue;
3839                        }
3840
3841                        foreach ( $sidebars as $sidebar ) {
3842                                if ( is_array( $sidebar ) && in_array( $widget_block_reference, $sidebar, true ) ) {
3843                                        $widgets_content .= $widget_block['content'] . "\n";
3844                                }
3845                        }
3846                }
3847
3848                $is_active['block'] = has_block( $block_name, $widgets_content );
3849        }
3850
3851        if ( $widget_id_base ) {
3852                $is_active['widget'] = is_active_widget( false, false, $widget_id_base, true );
3853        }
3854
3855        return 0 !== count( array_filter( $is_active ) );
3856}
Note: See TracBrowser for help on using the repository browser.