Making WordPress.org

source: sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-support/functions.php

Last change on this file was 11571, checked in by dd32, 3 months ago

Support: Attempt to fix the ajaxification of topic admin actions on views.

See #1965.

  • Property svn:eol-style set to native
File size: 31.3 KB
Line 
1<?php
2/**
3 * WPBBP functions and definitions
4 *
5 * @package WPBBP
6 */
7
8/**
9 * Use the ‘Lead Topic’ uses the single topic part
10 * allowing styling the lead topic separately from the main reply loop.
11 */
12add_filter( 'bbp_show_lead_topic', '__return_true' );
13
14/**
15 * Add theme support for some features.
16 */
17function wporg_support_theme_support() {
18        add_theme_support( 'html5', array( 'comment-form' ) );
19        add_theme_support( 'title-tag' );
20}
21add_action( 'after_setup_theme', 'wporg_support_theme_support' );
22
23/**
24 * Swaps out the no-js for the js body class if the browser supports Javascript.
25 */
26function nojs_body_tag() {
27        echo "<script>document.body.className = document.body.className.replace('no-js','js');</script>\n";
28}
29add_action( 'wp_body_open', __NAMESPACE__ . '\nojs_body_tag' );
30
31/**
32 * Enqueue scripts and styles.
33 *
34 * Enqueue existing wordpress.org/support stylesheets
35 * @link https://meta.trac.wordpress.org/browser/sites/trunk/wordpress.org/public_html/style
36 */
37function wporg_support_scripts() {
38
39        wp_enqueue_style( 'forum-wp4-style', get_stylesheet_uri(), [ 'dashicons' ], filemtime( __DIR__ . '/style.css' ) );
40        wp_style_add_data( 'forum-wp4-style', 'rtl', 'replace' );
41
42        wp_enqueue_script( 'wporg-support-navigation', get_template_directory_uri() . '/js/navigation.js', array(), '20181209', true );
43        wp_enqueue_script( 'wporg-support-forums', get_template_directory_uri() . '/js/forums.js', array( 'jquery' ), '20220217', true );
44
45        wp_localize_script(
46                'wporg-support-forums',
47                'wporgSupport',
48                array(
49                        'strings' => array(
50                                'approve'       => __( 'The approval status of this post has been changed.', 'wporg-forums' ),
51                                'spam'          => __( 'The spam status of this post has been changed.', 'wporg-forums' ),
52                                'archive'       => __( 'The archive status of this post has been changed.', 'wporg-forums' ),
53                                'action_failed' => __( 'Unable to complete the requested action, please try again.', 'wporg-forums' ),
54                        ),
55                )
56        );
57}
58add_action( 'wp_enqueue_scripts', 'wporg_support_scripts' );
59
60/**
61 * Register widget areas used by the theme.
62 *
63 * @uses register_sidebar()
64 */
65function wporg_support_register_widget_areas() {
66        register_sidebar( array(
67                'name'          => __( 'Front page blocks', 'wporg-forums' ),
68                'id'            => 'front-page-blocks',
69                'description'   => __( 'Contains blocks to display on the front page of this site', 'wporg-forums' ),
70                'before_widget' => '<div id="%1$s" class="widget %2$s">',
71                'after_widget'  => '</div>',
72        ) );
73        register_sidebar( array(
74                'name'          => __( 'HelpHub Sidebar', 'wporg-forums' ),
75                'id'            => 'helphub-sidebar',
76                'description'   => __( 'Contains blocks to display on HelpHub articles', 'wporg-forums' ),
77                'before_widget' => '<div id="%1$s" class="widget %2$s">',
78                'after_widget'  => '</div>',
79        ) );
80}
81add_action( 'widgets_init', 'wporg_support_register_widget_areas' );
82
83/**
84 * Don't include comments on HelpHub articles in REST responses.
85 *
86 * These comments are not intended to be public, and only read by HelpHub editors.
87 *
88 * @param array $args
89 *
90 * @return array
91 */
92function wporg_support_rest_comment_query( $args ) {
93        $post_types        = get_post_types( array( 'name' => 'helphub_article' ), 'names', 'NOT' );
94        $args['post_type'] = $post_types;
95
96        return $args;
97}
98add_filter( 'rest_comment_query', 'wporg_support_rest_comment_query' );
99
100/**
101 * Prevent viewing of individual comments on HelpHub articles via the REST API.
102 *
103 * These comments are not intended to be public, and only read by HelpHub editors.
104 *
105 * @param WP_REST_Response $response
106 * @param WP_Comment       $comment
107 *
108 * @return WP_REST_Response|WP_Error
109 */
110function wporg_support_rest_prepare_comment( $response, $comment ) {
111        $post_type = get_post_type( $comment->comment_post_ID );
112
113        if ( 'helphub_article' === $post_type ) {
114                return new WP_Error(
115                        'rest_cannot_read',
116                        __( 'Sorry, you are not allowed to read this comment.' ),
117                        array( 'status' => rest_authorization_required_code() )
118                );
119        }
120
121        return $response;
122}
123add_filter( 'rest_prepare_comment', 'wporg_support_rest_prepare_comment', 10, 2 );
124
125/**
126 * Modify the redirect after a feedback comment is submitted on an Article.
127 *
128 * @param string     $location
129 * @param WP_Comment $comment
130 *
131 * @return string
132 */
133function wporg_support_comment_post_redirect( $location, $comment ) {
134        if ( 'helphub_article' === get_post_type( $comment->comment_post_ID ) ) {
135                $location  = substr( $location, 0, strpos( $location, '#' ) );
136                $location  = add_query_arg( 'feedback_submitted', 1, $location );
137                $location .= '#reply-title';
138        }
139
140        return $location;
141}
142add_filter( 'comment_post_redirect', 'wporg_support_comment_post_redirect', 10, 2 );
143
144/**
145 * Customized breadcrumb arguments
146 * Breadcrumb Root Text: "WordPress Support"
147 * Custom separator: `«` and `»`
148 *
149 * @uses bbp_before_get_breadcrumb_parse_args() To parse the custom arguments
150 */
151function wporg_support_breadcrumb() {
152        // Separator
153        $args['sep']             = is_rtl() ? __( '&laquo;', 'wporg-forums' ) : __( '&raquo;', 'wporg-forums' );
154        $args['pad_sep']         = 1;
155        $args['sep_before']      = '<span class="bbp-breadcrumb-sep">' ;
156        $args['sep_after']       = '</span>';
157
158        // Crumbs
159        $args['crumb_before']    = '';
160        $args['crumb_after']     = '';
161
162        // Home
163        $args['include_home']    = true;
164        $args['home_text']       = __( 'Support', 'wporg-forums' );
165
166        // Forum root
167        $args['include_root']    = false;
168
169        // Current
170        $args['include_current'] = true;
171        $args['current_before']  = '<span class="bbp-breadcrumb-current">';
172        $args['current_after']   = '</span>';
173
174        return $args;
175}
176add_filter( 'bbp_before_get_breadcrumb_parse_args', 'wporg_support_breadcrumb' );
177
178/**
179 * Customize arguments for Subscribe/Unsubscribe link.
180 *
181 * Removes '&nbsp;|&nbsp;' separator added by BBP_Default::ajax_subscription().
182 *
183 * @param array $args Arguments passed to bbp_get_user_subscribe_link().
184 * @return array Filtered arguments.
185 */
186function wporg_support_subscribe_link( $args ) {
187        $args['before'] = '';
188
189        return $args;
190}
191add_filter( 'bbp_after_get_user_subscribe_link_parse_args', 'wporg_support_subscribe_link' );
192
193/**
194 * Register these bbPress views:
195 *  View: All topics
196 *  View: Tagged modlook
197 *
198 * @uses bbp_register_view() To register the view
199 */
200function wporg_support_custom_views() {
201        bbp_register_view( 'all-topics', __( 'All topics', 'wporg-forums' ), array( 'order' => 'DESC' ), false );
202        if ( get_current_user_id() && current_user_can( 'moderate' ) ) {
203                bbp_register_view( 'taggedmodlook', __( 'Tagged modlook', 'wporg-forums' ), array( 'topic-tag' => 'modlook' ) );
204        }
205}
206add_action( 'bbp_register_views', 'wporg_support_custom_views' );
207
208/**
209 * Display an ordered list of bbPress views
210 */
211function wporg_support_get_views() {
212        $views = array(
213                'all-topics',
214                'no-replies',
215                'support-forum-no',
216                'taggedmodlook',
217        );
218
219        $output = array();
220
221        foreach ( $views as $view ) {
222                if ( empty( bbpress()->views[ $view ] ) ) {
223                        continue;
224                }
225
226                $output[] = sprintf( '<li class="view"><a href="%s">%s</a></li>',
227                        esc_url( bbp_get_view_url( $view ) ),
228                        bbp_get_view_title( $view )
229                );
230        }
231
232        echo implode( ' | ', $output );
233}
234
235/**
236 * Custom Body Classes
237 *
238 * @uses get_body_class() To add the `wporg-support` class
239 */
240function wporg_support_body_class($classes) {
241        $classes[] = 'wporg-responsive';
242        $classes[] = 'wporg-support';
243
244        // Add specific classes to HelpHub pages.
245        $helphub_post_types = array( 'helphub_article', 'helphub_version' );
246        if ( is_singular( $helphub_post_types ) ||
247                is_post_type_archive( $helphub_post_types ) ) {
248                $classes[] = 'helphub-page';
249        }
250
251        if ( is_active_sidebar( 'helphub-sidebar' ) ) {
252                $classes[] = 'helphub-with-sidebar';
253        }
254
255        return $classes;
256}
257add_filter( 'body_class', 'wporg_support_body_class' );
258
259/**
260 * Change the amount of words allowed in excerpts on archive listings.
261 *
262 * @param int $length
263 *
264 * @return int
265 */
266function wporg_support_excerpt_length( $length ) {
267        if ( is_archive() ) {
268                return 25;
269        }
270
271        return $length;
272}
273add_filter( 'excerpt_length', 'wporg_support_excerpt_length' );
274
275function wporg_support_bbp_raw_title( $title ) {
276        if ( get_query_var( 'paged' ) && ! is_404() ) {
277                $title .= sprintf( ' - page %s', get_query_var( 'paged' ) );
278        }
279
280        return $title;
281}
282add_filter( 'bbp_raw_title', 'wporg_support_bbp_raw_title' );
283
284/**
285 * Add bbPress titles to the document title.
286 *
287 * bbPress doesn't support `title-tag` theme support, instead relying upon `wp_title` filters instead.
288 */
289function wporg_support_pre_get_document_title( $title ) {
290        // See wp_get_document_title()
291        $sep = apply_filters( 'document_title_separator', '&#124;' );
292
293        return bbp_title( $title, $sep, 'right' );
294}
295add_filter( 'pre_get_document_title', 'wporg_support_pre_get_document_title' );
296
297/**
298 * The Footer for our theme.
299 *
300 * @package WPBBP
301 */
302function wporg_get_global_footer() {
303        require WPORGPATH . 'footer.php';
304}
305
306/**
307 * Append an optimized site name.
308 *
309 * @param array $title Parts of the page title.
310 * @return array Filtered title parts.
311 */
312function wporg_support_document_title( $title ) {
313        if ( is_front_page() ) {
314                $title[1] = _x( 'Support', 'Site title', 'wporg-forums' );
315        }
316
317        return $title;
318}
319add_filter( 'wp_title_parts', 'wporg_support_document_title' );
320
321/**
322 * Link user profiles to their global profiles.
323 */
324function wporg_support_profile_url( $user_id ) {
325        $user = get_userdata( $user_id );
326
327        return esc_url( 'https://profiles.wordpress.org/' . $user->user_nicename . '/' );
328}
329// Temporarily remove the redirect to `https://profiles.wordpress.org/`, see #meta1868.
330// add_filter( 'bbp_pre_get_user_profile_url', 'wporg_support_profile_url' );
331
332/**
333 * Get user's WordPress.org profile link.
334 *
335 * @param int $user_id
336 * @return string
337 */
338function wporg_support_get_wporg_profile_link( $user_id = 0 ) {
339        $user_nicename = bbp_get_user_nicename( $user_id );
340
341        return sprintf( '<a href="%s">@%s</a>',
342                esc_url( 'https://profiles.wordpress.org/' . $user_nicename . '/' ),
343                $user_nicename
344        );
345}
346
347/**
348 * Get user's Slack username.
349 *
350 * @param int $user_id
351 * @return string The user's Slack username (without '@') if user has one.
352 */
353function wporg_support_get_slack_username( $user_id = 0 ) {
354        global $wpdb;
355
356        $user_id = bbp_get_user_id( $user_id );
357        $slack_username = '';
358
359        $data = $wpdb->get_var( $wpdb->prepare( "SELECT profiledata FROM slack_users WHERE user_id = %d", $user_id ) );
360        if ( $data && ( $data = json_decode( $data, true ) ) ) {
361                if ( isset( $data['profile']['display_name'] ) ) {
362                        $slack_username = $data['profile']['display_name'];
363                }
364        }
365
366        return $slack_username;
367}
368
369/**
370 * Get user's registration date.
371 *
372 * @param int $user_id
373 * @return string
374 */
375function wporg_support_get_user_registered_date( $user_id = 0 ) {
376        $user = get_userdata( bbp_get_user_id( $user_id ) );
377
378        /* translators: registration date format, see https://www.php.net/date */
379        return mysql2date( __( 'F jS, Y', 'wporg-forums' ), $user->user_registered );
380}
381
382/**
383 * Return the raw database count of topics by a user, excluding reviews.
384 *
385 * @param int $user_id User ID to get count for.
386 * @return int Raw DB count of topics.
387 */
388function wporg_support_get_user_topics_count( $user_id = 0 ) {
389        if ( ! class_exists( 'WordPressdotorg\Forums\Plugin' ) ) {
390                return 0;
391        }
392
393        $plugin_instance = WordPressdotorg\Forums\Plugin::get_instance();
394
395        return $plugin_instance->users->get_user_topics_count( $user_id );
396}
397
398/**
399 * Return the raw database count of reviews by a user.
400 *
401 * @param int $user_id User ID to get count for.
402 * @return int Raw DB count of reviews.
403 */
404function wporg_support_get_user_reviews_count( $user_id = 0 ) {
405        if ( ! class_exists( 'WordPressdotorg\Forums\Plugin' ) ) {
406                return 0;
407        }
408
409        $plugin_instance = WordPressdotorg\Forums\Plugin::get_instance();
410
411        return $plugin_instance->users->get_user_reviews_count( $user_id );
412}
413
414/**
415 * Check if the current page is a single review.
416 *
417 * @return bool True if the current page is a single review, false otherwise.
418 */
419function wporg_support_is_single_review() {
420        if ( ! class_exists( 'WordPressdotorg\Forums\Plugin' ) || ! bbp_is_single_topic() ) {
421                return false;
422        }
423
424        return ( WordPressdotorg\Forums\Plugin::REVIEWS_FORUM_ID == bbp_get_topic_forum_id() );
425}
426
427/**
428 * Get post title for single review
429 *
430 * @return string|bool Returns post title if it exists. Otherwise returns false.
431 */
432function wporg_support_get_single_review_title() {
433        if ( ! class_exists( 'WordPressdotorg\Forums\Plugin' ) || ! bbp_is_single_topic() ) {
434                return false;
435        }
436
437        $plugin_instance = WordPressdotorg\Forums\Plugin::get_instance();
438        $review = $plugin_instance->plugins->plugin ?? $plugin_instance->themes->theme;
439
440        return isset( $review ) ? $review->post_title : false;
441}
442
443/**
444 * Check if the current page is a user's "Reviews Written" page.
445 *
446 * @return bool True if the page is a "Reviews Written" page, false otherwise.
447 */
448function wporg_support_is_single_user_reviews() {
449        return (bool) get_query_var( 'wporg_single_user_reviews' );
450}
451
452/**
453 * Check if the current page is a user's "Topics Replied To" page.
454 *
455 * @return bool True if the page is a "Topics Replied To" page, false otherwise.
456 */
457function wporg_support_is_single_user_topics_replied_to() {
458        return (bool) get_query_var( 'wporg_single_user_topics_replied_to' );
459}
460
461/**
462 * Get the list of plugin- and theme-specific views.
463 *
464 * @return array Array of compat views.
465 */
466function wporg_support_get_compat_views() {
467        return array( 'theme', 'plugin', 'reviews', 'active', 'unresolved' );
468}
469
470/**
471 * Check if the current page is a plugin- or theme-specific view.
472 *
473 * @param string $view_id View ID to check.
474 * @return bool True if the current page is a compat view, false otherwise.
475 */
476function wporg_support_is_compat_view( $view_id = 0 ) {
477        if ( ! bbp_is_single_view() ) {
478                return false;
479        }
480
481        $view_id = bbp_get_view_id( $view_id );
482
483        return in_array( $view_id, wporg_support_get_compat_views() );
484}
485
486/**
487 * Get current plugin or theme object in plugin- or theme-specific views.
488 *
489 * @return object|null Plugin or theme object on success, null on failure.
490 */
491function wporg_support_get_compat_object() {
492        if ( ! class_exists( 'WordPressdotorg\Forums\Plugin' ) ) {
493                return null;
494        }
495
496        $object          = null;
497        $plugin_instance = WordPressdotorg\Forums\Plugin::get_instance();
498
499        if ( ! empty( $plugin_instance->plugins->plugin ) ) {
500                $object = $plugin_instance->plugins->plugin;
501
502                /* translators: %s: link to plugin support or review forum */
503                $object->search_prefix = sprintf( __( 'Plugin: %s', 'wporg-forums' ), $object->post_title );
504                $object->type          = 'plugin';
505        } elseif ( ! empty( $plugin_instance->themes->theme ) ) {
506                $object = $plugin_instance->themes->theme;
507
508                /* translators: %s: link to theme support or review forum */
509                $object->search_prefix = sprintf( __( 'Theme: %s', 'wporg-forums' ), $object->post_title );
510                $object->type          = 'theme';
511        }
512
513        // The search prefix must be sans any special characters.
514        // This may cause some plugins to match other plugins of similar prefixed names.
515        if ( ! empty( $object->search_prefix ) ) {
516                $search_special_chars  = '|';
517                $object->search_prefix = rtrim( strtok( $object->search_prefix, $search_special_chars ) );
518        }
519
520        return $object;
521}
522
523/**
524 * Display a notice for messages caught in the moderation queue.
525 */
526function wporg_support_add_moderation_notice() {
527        $post            = get_post();
528        $post_time       = mysql2date( 'U', $post->post_date );
529
530        $hours_passed    = (int) ( ( current_time( 'timestamp' ) - $post_time ) / HOUR_IN_SECONDS );
531        $is_moderator    = current_user_can( 'moderate', $post->ID );
532        $is_user_blocked = ! current_user_can( 'spectate' );
533
534        $notice_class    = '';
535        $notices         = array();
536
537        if ( $is_moderator && in_array( $post->post_status, array( 'archived', 'pending', 'spam' ) ) ) :
538
539                if ( 'spam' === $post->post_status ) {
540                        $notice_class = 'warning';
541
542                        $reporter = get_post_meta( $post->ID, '_bbp_akismet_user', true );
543
544                        if ( $reporter ) {
545                                /* translators: %s: reporter's username */
546                                $notices[] = sprintf( __( 'This post has been flagged as spam by %s.', 'wporg-forums' ), $reporter );
547                        } else {
548                                $notices[] = __( 'This post has been flagged as spam.', 'wporg-forums' );
549                        }
550                } elseif ( 'archived' === $post->post_status ) {
551                        $moderator = get_post_meta( $post->ID, '_wporg_bbp_moderator', true );
552
553                        if ( $moderator ) {
554                                /* translators: %s: moderator's username */
555                                $notices[] = sprintf( __( 'This post has been archived by %s.', 'wporg-forums' ), $moderator );
556                        } else {
557                                $notices[] = __( 'This post is currently archived.', 'wporg-forums' );
558                        }
559                } else {
560                        $moderator = get_post_meta( $post->ID, '_wporg_bbp_moderator', true );
561
562                        if ( $moderator ) {
563                                /* translators: %s: moderator's username */
564                                $notices[] = sprintf( __( 'This post has been unapproved by %s.', 'wporg-forums' ), $moderator );
565                        } else {
566                                $notices[] = __( 'This post is currently pending.', 'wporg-forums' );
567                        }
568                }
569
570                if ( class_exists( 'WordPressdotorg\Forums\User_Moderation\Plugin' ) ) :
571                        $plugin_instance = WordPressdotorg\Forums\User_Moderation\Plugin::get_instance();
572                        $is_user_flagged = $plugin_instance->is_user_flagged( $post->post_author );
573                        $moderator       = get_user_meta( $post->post_author, $plugin_instance::MODERATOR_META, true );
574                        $moderation_date = get_user_meta( $post->post_author, $plugin_instance::MODERATION_DATE_META, true );
575
576                        if ( $is_user_flagged ) {
577                                if ( $moderator && $moderation_date ) {
578                                        $notices[] = sprintf(
579                                                /* translators: 1: linked moderator's username, 2: moderation date, 3: moderation time */
580                                                __( 'This user has been flagged by %1$s on %2$s at %3$s.', 'wporg-forums' ),
581                                                sprintf( '<a href="%s">%s</a>', esc_url( home_url( "/users/$moderator/" ) ), $moderator ),
582                                                /* translators: localized date format, see https://secure.php.net/date */
583                                                mysql2date( __( 'F j, Y', 'wporg-forums' ), $moderation_date ),
584                                                /* translators: localized time format, see https://secure.php.net/date */
585                                                mysql2date( __( 'g:i a', 'wporg-forums' ), $moderation_date )
586                                        );
587                                } elseif ( $moderator ) {
588                                        $notices[] = sprintf(
589                                                /* translators: %s: linked moderator's username */
590                                                __( 'This user has been flagged by %s.', 'wporg-forums' ),
591                                                sprintf( '<a href="%s">%s</a>', esc_url( home_url( "/users/$moderator/" ) ), $moderator )
592                                        );
593                                } else {
594                                        $notices[] = __( 'This user has been flagged.', 'wporg-forums' );
595                                }
596                        }
597                endif;
598
599        elseif ( in_array( $post->post_status, array( 'pending', 'spam' ) ) ) :
600
601                /* translators: Number of hours the user should wait for a pending post to get approved before contacting moderators. */
602                $moderation_timeframe = (int) __( '96', 'wporg-forums' );
603                if ( ! $moderation_timeframe ) {
604                        $moderation_timeframe = 96;
605                }
606
607                if ( $is_user_blocked ) {
608                        // Blocked users get a generic message with no call to action or moderation timeframe.
609                        $notices[] = __( 'This post has been held for moderation by our automated system.', 'wporg-forums' );
610                } elseif ( $hours_passed > $moderation_timeframe ) {
611                        $notice_class = 'warning';
612                        $notices[]    = sprintf(
613                                /* translators: %s: WordPress Slack URL */
614                                __( 'This post was held for moderation by our automated system but has taken longer than expected to get approved. Please come to the #forums channel on <a href="%s">WordPress Slack</a> and let us know. Provide a link to the post.', 'wporg-forums' ),
615                                esc_url( __( 'https://make.wordpress.org/chat/', 'wporg-forums' ) )
616                        );
617                } else {
618                        $notices[] = __( 'This post has been held for moderation by our automated system and will be manually reviewed by a moderator.', 'wporg-forums' );
619                }
620
621        endif;
622
623        if ( $notices ) {
624                printf(
625                        '<div class="bbp-template-notice %s"><p>%s</p></div>',
626                        esc_attr( $notice_class ),
627                        implode( '</p><p>', $notices )
628                );
629        }
630}
631add_action( 'bbp_theme_before_topic_content', 'wporg_support_add_moderation_notice' );
632add_action( 'bbp_theme_before_reply_content', 'wporg_support_add_moderation_notice' );
633
634/**
635 * Change "Stick (to front)" link text to "Stick (to all forums)".
636 */
637function wporg_support_change_super_sticky_text( $links ) {
638        if ( isset( $links['stick'] ) ) {
639                $links['stick'] = bbp_get_topic_stick_link( array( 'super_text' => __( '(to all forums)', 'wporg-forums' ) ) );
640        }
641
642        return $links;
643}
644add_filter( 'bbp_topic_admin_links', 'wporg_support_change_super_sticky_text' );
645
646/**
647 * Check if the current user can stick a topic to a plugin or theme forum.
648 *
649 * @param int $topic_id Topic ID.
650 * @return bool True if the user can stick the topic, false otherwise.
651 */
652function wporg_support_current_user_can_stick( $topic_id ) {
653        if ( ! class_exists( 'WordPressdotorg\Forums\Plugin' ) ) {
654                return false;
655        }
656
657        $user_can_stick  = false;
658        $stickies        = null;
659        $plugin_instance = WordPressdotorg\Forums\Plugin::get_instance();
660
661        if ( ! empty( $plugin_instance->plugins->stickies ) ) {
662                $stickies = $plugin_instance->plugins->stickies;
663        } elseif ( ! empty( $plugin_instance->themes->stickies ) ) {
664                $stickies = $plugin_instance->themes->stickies;
665        }
666
667        if ( $stickies && $stickies->term ) {
668                $user_can_stick = $stickies->user_can_stick( get_current_user_id(), $stickies->term->term_id, $topic_id );
669        }
670
671        return $user_can_stick;
672}
673
674/**
675 * Correct reply URLs for pending posts.
676 *
677 * bbPress appends '/edit/' even to ugly permalinks, which pending posts will
678 * always have.
679 *
680 * @see https://meta.trac.wordpress.org/ticket/2478
681 * @see https://bbpress.trac.wordpress.org/ticket/3054
682 *
683 * @param string $url     URL to edit the post.
684 * @param int    $post_id Post ID.
685 * @return string
686 */
687function wporg_support_fix_pending_posts_reply_url( $url, $post_id ) {
688        if ( false !== strpos( $url, '?' ) ) {
689                if ( false !== strpos( $url, '/edit/' ) ) {
690                        $url = str_replace( '/edit/', '', $url );
691                        $url = add_query_arg( 'edit', '1', $url );
692                } elseif ( false !== strpos( $url, '%2Fedit%2F' ) ) {
693                        $url = str_replace( '%2Fedit%2F', '', $url );
694                        $url = add_query_arg( 'edit', '1', $url );
695                }
696        }
697
698        return $url;
699}
700add_filter( 'bbp_get_topic_edit_url', 'wporg_support_fix_pending_posts_reply_url', 10, 2 );
701add_filter( 'bbp_get_reply_edit_url', 'wporg_support_fix_pending_posts_reply_url', 10, 2 );
702
703/**
704 * Prevent standalone <li> tags from breaking the theme layout.
705 *
706 * If a <li> tag is not preceded by <ul> or <ol>, prepend it with <ul>
707 * and let force_balance_tags() do the rest.
708 *
709 * @see https://meta.trac.wordpress.org/ticket/20
710 * @see https://bbpress.trac.wordpress.org/ticket/2357
711 *
712 * @param string $content Topic or reply content.
713 * @return string Filtered content.
714 */
715function wporg_support_wrap_standalone_li_tags_in_ul( $content ) {
716        // No lists? No worries.
717        if ( false === stripos( $content, '<li>' ) ) {
718                return $content;
719        }
720
721        // Split the content into chunks of <Not a List, OL/UL tags, Content of Ol/UL tags>.
722        $parts = preg_split( '#(<[uo]l(?:\s+[^>]+)?>)#im', $content, -1, PREG_SPLIT_NO_EMPTY | PREG_SPLIT_DELIM_CAPTURE );
723
724        // We can rebuild.
725        $content = '';
726
727        for ( $i = 0; $i < count( $parts ); $i++ ) {
728                $part = $parts[ $i ];
729                $next_part = $parts[ $i + 1 ] ?? '';
730
731                // If the chunk is a list element, process it as such.
732                if ( preg_match( '#^<([uo]l)(\s+[^>]+)?>#i', $part, $m ) ) {
733                        $closing_tag_pos = stripos( $next_part, '</' . $m[1] . '>' );
734                        if ( false !== $closing_tag_pos ) {
735                                // List is closed, assume that part of the content is OK
736                                $content .= $part . substr( $next_part, 0, $closing_tag_pos + 5 );
737
738                                // But check the content after the list too.
739                                $next_part = substr( $next_part, $closing_tag_pos + 5 );
740                                if ( $next_part ) {
741                                        // Replace the first li tag if one exists.
742                                        // This may break nested lists, but that's okay.
743                                        $next_part = preg_replace( '#<li>#i', '<ul><li>', $next_part, 1 );
744
745                                        $content .= force_balance_tags( $next_part );
746                                }
747                        } else {
748                                // List is not closed, balance it.
749                                $content .= force_balance_tags( $part . $next_part );
750                        }
751                        $i++; // Skip $next_part;
752
753                // Does this text chunk contain a <li>? If so, it's got no matching start element.
754                } elseif ( false !== stripos( $part, '<li>' ) ) {
755                        $part = preg_replace( '#<li>#i', '<ul><li>', $part, 1 ); // Replace the first li tag
756                        $content .= force_balance_tags( $part );
757
758                // This shouldn't actually be hit, but is here for completeness.
759                } else {
760                        $content .= force_balance_tags( $part );
761                }
762        }
763
764        return $content;
765}
766add_filter( 'bbp_get_topic_content', 'wporg_support_wrap_standalone_li_tags_in_ul', 50 );
767add_filter( 'bbp_get_reply_content', 'wporg_support_wrap_standalone_li_tags_in_ul', 50 );
768
769/**
770 * Set 'is_single' query var to true on single replies.
771 *
772 * @see https://meta.trac.wordpress.org/ticket/2551
773 * @see https://bbpress.trac.wordpress.org/ticket/3055
774 *
775 * @param array $args Theme compat query vars.
776 * @return array
777 */
778function wporg_support_set_is_single_on_single_replies( $args ) {
779        if ( bbp_is_single_reply() ) {
780                $args['is_single'] = true;
781        }
782
783        return $args;
784}
785add_filter( 'bbp_after_theme_compat_reset_post_parse_args', 'wporg_support_set_is_single_on_single_replies' );
786
787
788/** bb Base *******************************************************************/
789
790function bb_base_search_form() {
791?>
792
793        <form role="search" method="get" id="searchform" action="https://wordpress.org/search/do-search.php">
794                <div>
795                        <h3><?php _e( 'Forum Search', 'wporg-forums' ); ?></h3>
796                        <label class="screen-reader-text hidden" for="search"><?php _e( 'Search for:', 'wporg-forums' ); ?></label>
797                        <input name="search" class="text" id="forumsearchbox" value type="text" />
798                        <input name="go" class="button" type="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'wporg-forums' ); ?>" />
799                        <input value="1" name="forums" type="hidden">
800                </div>
801        </form>
802
803<?php
804}
805
806function bb_base_topic_search_form() {
807?>
808
809        <form role="search" method="get" id="searchform" action="">
810                <div>
811                        <h3><?php _e( 'Forum Search', 'wporg-forums' ); ?></h3>
812                        <label class="screen-reader-text hidden" for="ts"><?php _e( 'Search for:', 'wporg-forums' ); ?></label>
813                        <input type="text" value="<?php echo bb_base_topic_search_query(); ?>" name="ts" id="ts" />
814                        <input class="button" type="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'wporg-forums' ); ?>" />
815                </div>
816        </form>
817
818<?php
819}
820
821function bb_base_reply_search_form() {
822?>
823
824        <form role="search" method="get" id="searchform" action="">
825                <div>
826                        <h3><?php _e( 'Reply Search', 'wporg-forums' ); ?></h3>
827                        <label class="screen-reader-text hidden" for="rs"><?php _e( 'Search for:', 'wporg-forums' ); ?></label>
828                        <input type="text" value="<?php echo bb_base_reply_search_query(); ?>" name="rs" id="rs" />
829                        <input class="button" type="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'wporg-forums' ); ?>" />
830                </div>
831        </form>
832
833<?php
834}
835
836function bb_base_plugin_search_form() {
837?>
838
839        <form role="search" method="get" id="searchform" action="">
840                <div>
841                        <h3><?php _e( 'Plugin Search', 'wporg-forums' ); ?></h3>
842                        <label class="screen-reader-text hidden" for="ps"><?php _e( 'Search for:', 'wporg-forums' ); ?></label>
843                        <input type="text" value="<?php echo bb_base_plugin_search_query(); ?>" name="ps" id="ts" />
844                        <input class="button" type="submit" id="searchsubmit" value="<?php esc_attr_e( 'Search', 'wporg-forums' ); ?>" />
845                </div>
846        </form>
847
848<?php
849}
850
851function bb_base_topic_search_query( $escaped = true ) {
852
853        if ( empty( $_GET['ts'] ) ) {
854                return false;
855        }
856
857        $query = apply_filters( 'bb_base_topic_search_query', $_GET['ts'] );
858        if ( true === $escaped ) {
859                $query = stripslashes( esc_attr( $query ) );
860        }
861
862        return $query;
863}
864
865function bb_base_reply_search_query( $escaped = true ) {
866
867        if ( empty( $_GET['rs'] ) ) {
868                return false;
869        }
870
871        $query = apply_filters( 'bb_base_reply_search_query', $_GET['rs'] );
872        if ( true === $escaped ) {
873                $query = stripslashes( esc_attr( $query ) );
874        }
875
876        return $query;
877}
878
879function bb_base_plugin_search_query( $escaped = true ) {
880
881        if ( empty( $_GET['ps'] ) ) {
882                return false;
883        }
884
885        $query = apply_filters( 'bb_base_plugin_search_query', $_GET['ps'] );
886        if ( true === $escaped ) {
887                $query = stripslashes( esc_attr( $query ) );
888        }
889
890        return $query;
891}
892
893function bb_base_single_topic_description() {
894
895        // Validate topic_id
896        $topic_id = bbp_get_topic_id();
897
898        // Unhook the 'view all' query var adder
899        remove_filter( 'bbp_get_topic_permalink', 'bbp_add_view_all' );
900
901        // Build the topic description
902        $voice_count = bbp_get_topic_voice_count   ( $topic_id, true );
903        $reply_count = bbp_get_topic_replies_link  ( $topic_id );
904        $time_since  = bbp_get_topic_freshness_link( $topic_id );
905
906        // Singular/Plural
907        $voice_count = sprintf( _n( '%s participant', '%s participants', $voice_count, 'wporg-forums' ), bbp_number_format( $voice_count ) );
908        $last_reply  = bbp_get_topic_last_active_id( $topic_id );
909
910        // WP version
911        $wp_version = '';
912        if ( function_exists( 'WordPressdotorg\Forums\Version_Dropdown\get_topic_version' ) ) {
913                $wp_version = WordPressdotorg\Forums\Version_Dropdown\get_topic_version( $topic_id );
914        }
915
916        ?>
917
918        <li class="topic-forum"><?php
919                /* translators: %s: forum title */
920                printf( __( 'In: %s', 'wporg-forums' ),
921                        sprintf( '<a href="%s">%s</a>',
922                                esc_url( bbp_get_forum_permalink( bbp_get_topic_forum_id() ) ),
923                                bbp_get_topic_forum_title()
924                        )
925                );
926        ?></li>
927        <?php if ( !empty( $reply_count ) ) : ?>
928                <li class="reply-count"><?php echo $reply_count; ?></li>
929        <?php endif; ?>
930        <?php if ( !empty( $voice_count ) ) : ?>
931                <li class="voice-count"><?php echo $voice_count; ?></li>
932        <?php endif; ?>
933        <?php if ( !empty( $last_reply  ) ) : ?>
934                <li class="topic-freshness-author"><?php
935                        /* translators: %s: reply author link */
936                        printf( __( 'Last reply from: %s', 'wporg-forums' ),
937                                bbp_get_author_link( array( 'type' => 'name', 'post_id' => $last_reply, 'size' => '15' ) )
938                        );
939                ?></li>
940        <?php endif; ?>
941        <?php if ( !empty( $time_since  ) ) : ?>
942                <li class="topic-freshness-time"><?php
943                        /* translators: %s: date/time link to the latest post */
944                        printf( __( 'Last activity: %s', 'wporg-forums' ), $time_since );
945                ?></li>
946        <?php endif; ?>
947        <?php if ( ! empty( $wp_version ) ) : ?>
948                <li class="wp-version"><?php echo esc_html( $wp_version ); ?></li>
949        <?php endif; ?>
950        <?php if ( function_exists( 'WordPressdotorg\Forums\Topic_Resolution\get_topic_resolution_form' ) ) : ?>
951                <?php if ( WordPressdotorg\Forums\Topic_Resolution\Plugin::get_instance()->is_enabled_on_forum() && ( bbp_is_single_topic() || bbp_is_topic_edit() ) ) : ?>
952                        <li class="topic-resolved"><?php WordPressdotorg\Forums\Topic_Resolution\get_topic_resolution_form( $topic_id ); ?></li>
953                <?php endif; ?>
954        <?php endif; ?>
955        <?php if ( bbp_current_user_can_access_create_reply_form() /*bbp_is_topic_open( $_topic_id )*/ ) : ?>
956                <li class="create-reply"><a href="#new-post"><?php
957                        if ( wporg_support_is_single_review() ) {
958                                _e( 'Reply to Review', 'wporg-forums' );
959                        } else {
960                                _e( 'Reply to Topic', 'wporg-forums' );
961                        }
962                ?></a></li>
963        <?php endif; ?>
964        <?php if ( is_user_logged_in() ) : ?>
965                <?php $_topic_id = bbp_is_reply_edit() ? bbp_get_reply_topic_id() : $topic_id; ?>
966                <li class="topic-subscribe"><?php bbp_topic_subscription_link( array( 'before' => '', 'topic_id' => $_topic_id ) ); ?></li>
967                <li class="topic-favorite"><?php bbp_topic_favorite_link( array( 'topic_id' => $_topic_id ) ); ?></li>
968        <?php endif; ?>
969
970        <?php
971        do_action( 'wporg_support_after_topic_info' );
972}
973
974function bb_base_single_forum_description() {
975
976        // Unhook the 'view all' query var adder
977        remove_filter( 'bbp_get_forum_permalink', 'bbp_add_view_all' );
978
979        if ( bbp_get_forum_parent_id() ) : ?>
980                <li class="topic-parent"><?php
981                        /* translators: %s: forum title */
982                        printf( __( 'In: %s', 'wporg-forums' ),
983                                sprintf( '<a href="%s">%s</a>',
984                                        esc_url( bbp_get_forum_permalink( bbp_get_forum_parent_id() ) ),
985                                        bbp_get_forum_title( bbp_get_forum_parent_id() )
986                                )
987                        );
988                ?></li>
989        <?php endif;
990}
991
992function bb_is_intl_forum() {
993        return get_locale() != 'en_US';
994}
995
996/**
997 * Include the Strings for the supporg/update-php page.
998 */
999include_once __DIR__ . '/helphub-update-php-strings.php';
Note: See TracBrowser for help on using the repository browser.