| @@ -18,8 +18,30 @@ | ||
| 18 | 18 | return $default; |
| 19 | 19 | } |
| 20 | 20 | |
| 21 | 21 | /** |
| 22 | + * Render the guest login form used on topic/reply/forum prompts. | |
| 23 | + * | |
| 24 | + * Uses the Shortcodes setting when set; otherwise falls back to [forumax_login_form] | |
| 25 | + * so Sign In / Create Account tabs always appear (when registration is allowed). | |
| 26 | + * | |
| 27 | + * @return void | |
| 28 | + */ | |
| 29 | +function forumax_render_topic_login_form() { | |
| 30 | + $shortcode = ''; | |
| 31 | + | |
| 32 | + if ( function_exists( 'forumax_get_opt' ) ) { | |
| 33 | + $shortcode = trim( (string) forumax_get_opt( 'topic_login_shortcode', '[forumax_login_form]' ) ); | |
| 34 | + } | |
| 35 | + | |
| 36 | + if ( '' === $shortcode ) { | |
| 37 | + $shortcode = '[forumax_login_form]'; | |
| 38 | + } | |
| 39 | + | |
| 40 | + echo do_shortcode( $shortcode ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped | |
| 41 | +} | |
| 42 | + | |
| 43 | +/** | |
| 22 | 44 | * Check if a plugin has been installed for specific number of days |
| 23 | 45 | * |
| 24 | 46 | * @param string $plugin_path The plugin path (e.g. 'woocommerce/woocommerce.php') |
| 25 | 47 | * @param int $days Number of days to check against |
| @@ -47,15 +69,24 @@ | ||
| 47 | 69 | /** |
| 48 | 70 | * Check If the Page is Forum page |
| 49 | 71 | */ |
| 50 | 72 | function forumax_is_forum_page() { |
| 51 | - if ( in_array( 'bbpress', get_body_class(), true ) ) { | |
| 52 | - return true; | |
| 53 | - } | |
| 54 | - return false; | |
| 73 | + return function_exists( 'is_bbpress' ) && is_bbpress(); | |
| 55 | 74 | } |
| 56 | 75 | |
| 57 | 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 | +/** | |
| 58 | 89 | * Add a stable body class for all Forumax/bbPress related pages. |
| 59 | 90 | * |
| 60 | 91 | * This helps themes (e.g. Hello Biz) and custom CSS target Forumax pages |
| 61 | 92 | * reliably, even when the page uses shortcodes/blocks instead of bbPress |
| @@ -814,15 +845,15 @@ | ||
| 814 | 845 | if ( false !== $count ) { |
| 815 | 846 | return (int) $count; |
| 816 | 847 | } |
| 817 | 848 | |
| 818 | - $status = esc_sql( $status ); | |
| 819 | - $where = "WHERE post_type = 'topic' AND post_status = '{$status}'"; | |
| 849 | + $where = $wpdb->prepare( "WHERE post_type = 'topic' AND post_status = %s", $status ); | |
| 820 | 850 | |
| 821 | 851 | if ( false !== $parent_id && is_numeric( $parent_id ) ) { |
| 822 | 852 | $where .= $wpdb->prepare( " AND post_parent = %d", $parent_id ); |
| 823 | 853 | } |
| 824 | 854 | |
| 855 | + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $where is prepared above. | |
| 825 | 856 | $count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} {$where}" ); |
| 826 | 857 | |
| 827 | 858 | // Set transient cache for 1 hour |
| 828 | 859 | set_transient( $cache_key, (int) $count, HOUR_IN_SECONDS ); |
| @@ -827,8 +858,46 @@ | ||
| 827 | 858 | // Set transient cache for 1 hour |
| 828 | 859 | set_transient( $cache_key, (int) $count, HOUR_IN_SECONDS ); |
| 829 | 860 | |
| 830 | 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 ) ) ) ); | |
| 831 | 900 | } |
| 832 | 901 | |
| 833 | 902 | /** |
| 834 | 903 | * Get unanswered topics count. |