| @@ -69,15 +69,24 @@ | ||
| 69 | 69 | /** |
| 70 | 70 | * Check If the Page is Forum page |
| 71 | 71 | */ |
| 72 | 72 | function forumax_is_forum_page() { |
| 73 | - if ( in_array( 'bbpress', get_body_class(), true ) ) { | |
| 74 | - return true; | |
| 75 | - } | |
| 76 | - return false; | |
| 73 | + return function_exists( 'is_bbpress' ) && is_bbpress(); | |
| 77 | 74 | } |
| 78 | 75 | |
| 79 | 76 | /** |
| 77 | + * Whether the request is a bbPress user profile page. | |
| 78 | + * | |
| 79 | + * Mirrors the 'bbp-user-page' body class without rebuilding the whole | |
| 80 | + * body class list (get_body_class() runs every theme/plugin filter). | |
| 81 | + * | |
| 82 | + * @return bool | |
| 83 | + */ | |
| 84 | +function forumax_is_user_profile_page() { | |
| 85 | + return function_exists( 'bbp_is_single_user' ) && bbp_is_single_user() && ! bbp_is_single_user_edit(); | |
| 86 | +} | |
| 87 | + | |
| 88 | +/** | |
| 80 | 89 | * Add a stable body class for all Forumax/bbPress related pages. |
| 81 | 90 | * |
| 82 | 91 | * This helps themes (e.g. Hello Biz) and custom CSS target Forumax pages |
| 83 | 92 | * reliably, even when the page uses shortcodes/blocks instead of bbPress |
| @@ -836,15 +845,15 @@ | ||
| 836 | 845 | if ( false !== $count ) { |
| 837 | 846 | return (int) $count; |
| 838 | 847 | } |
| 839 | 848 | |
| 840 | - $status = esc_sql( $status ); | |
| 841 | - $where = "WHERE post_type = 'topic' AND post_status = '{$status}'"; | |
| 849 | + $where = $wpdb->prepare( "WHERE post_type = 'topic' AND post_status = %s", $status ); | |
| 842 | 850 | |
| 843 | 851 | if ( false !== $parent_id && is_numeric( $parent_id ) ) { |
| 844 | 852 | $where .= $wpdb->prepare( " AND post_parent = %d", $parent_id ); |
| 845 | 853 | } |
| 846 | 854 | |
| 855 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $where is prepared above. | |
| 847 | 856 | $count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} {$where}" ); |
| 848 | 857 | |
| 849 | 858 | // Set transient cache for 1 hour |
| 850 | 859 | set_transient( $cache_key, (int) $count, HOUR_IN_SECONDS ); |
| @@ -849,8 +858,46 @@ | ||
| 849 | 858 | // Set transient cache for 1 hour |
| 850 | 859 | set_transient( $cache_key, (int) $count, HOUR_IN_SECONDS ); |
| 851 | 860 | |
| 852 | 861 | return (int) $count; |
| 862 | +} | |
| 863 | + | |
| 864 | +/** | |
| 865 | + * Sticky topic IDs from every forum. | |
| 866 | + * | |
| 867 | + * Reads the _bbp_sticky_topics meta of all forums in one query instead of | |
| 868 | + * calling bbp_get_stickies() once per forum. | |
| 869 | + * | |
| 870 | + * @param bool $published_only Only read stickies of published forums. | |
| 871 | + * @return int[] | |
| 872 | + */ | |
| 873 | +function forumax_get_all_forum_stickies( $published_only = false ) { | |
| 874 | + global $wpdb; | |
| 875 | + | |
| 876 | + $sql = $wpdb->prepare( | |
| 877 | + "SELECT pm.meta_value FROM {$wpdb->postmeta} pm | |
| 878 | + INNER JOIN {$wpdb->posts} p ON p.ID = pm.post_id | |
| 879 | + WHERE pm.meta_key = %s AND p.post_type = %s", | |
| 880 | + '_bbp_sticky_topics', | |
| 881 | + 'forum' | |
| 882 | + ); | |
| 883 | + | |
| 884 | + if ( $published_only ) { | |
| 885 | + $sql .= " AND p.post_status = 'publish'"; | |
| 886 | + } | |
| 887 | + | |
| 888 | + // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- prepared above. | |
| 889 | + $rows = $wpdb->get_col( $sql ); | |
| 890 | + | |
| 891 | + $stickies = []; | |
| 892 | + foreach ( $rows as $value ) { | |
| 893 | + $value = maybe_unserialize( $value ); | |
| 894 | + if ( is_array( $value ) ) { | |
| 895 | + $stickies = array_merge( $stickies, $value ); | |
| 896 | + } | |
| 897 | + } | |
| 898 | + | |
| 899 | + return array_values( array_unique( array_filter( array_map( 'intval', $stickies ) ) ) ); | |
| 853 | 900 | } |
| 854 | 901 | |
| 855 | 902 | /** |
| 856 | 903 | * Get unanswered topics count. |