| @@ -24,9 +24,9 @@ | ||
| 24 | 24 | * @param string $plugin_path The plugin path (e.g. 'woocommerce/woocommerce.php') |
| 25 | 25 | * @param int $days Number of days to check against |
| 26 | 26 | * @return bool True if plugin is installed for specified days, false otherwise |
| 27 | 27 | */ |
| 28 | -function forumax_is_plugin_installed_for_days( $days, $plugin_slug = 'bbpc' ) { | |
| 28 | +function forumax_is_plugin_installed_for_days( $days, $plugin_slug='eazydocs' ) { | |
| 29 | 29 | // Get the installation timestamp of the plugin |
| 30 | 30 | $installed_time = get_option( $plugin_slug . '_installed' ); |
| 31 | 31 | |
| 32 | 32 | // Ensure it's a valid timestamp |
| @@ -50,157 +50,11 @@ | ||
| 50 | 50 | function forumax_is_forum_page() { |
| 51 | 51 | if ( in_array( 'bbpress', get_body_class(), true ) ) { |
| 52 | 52 | return true; |
| 53 | 53 | } |
| 54 | - return false; | |
| 55 | 54 | } |
| 56 | 55 | |
| 57 | 56 | /** |
| 58 | - * Add a stable body class for all Forumax/bbPress related pages. | |
| 59 | - * | |
| 60 | - * This helps themes (e.g. Hello Biz) and custom CSS target Forumax pages | |
| 61 | - * reliably, even when the page uses shortcodes/blocks instead of bbPress | |
| 62 | - * native endpoints. | |
| 63 | - * | |
| 64 | - * @param array $classes Existing body classes. | |
| 65 | - * @return array | |
| 66 | - */ | |
| 67 | -function forumax_add_forumax_body_class( $classes ) { | |
| 68 | - if ( is_admin() ) { | |
| 69 | - return $classes; | |
| 70 | - } | |
| 71 | - | |
| 72 | - $should_add = false; | |
| 73 | - | |
| 74 | - // Native bbPress pages (forums, topics, replies, search, user profiles, etc.). | |
| 75 | - if ( function_exists( 'is_bbpress' ) && is_bbpress() ) { | |
| 76 | - $should_add = true; | |
| 77 | - } | |
| 78 | - | |
| 79 | - // Some installs load forum content via shortcodes/blocks on normal pages. | |
| 80 | - if ( ! $should_add ) { | |
| 81 | - $post = get_post(); | |
| 82 | - if ( $post instanceof WP_Post ) { | |
| 83 | - $shortcodes = array( | |
| 84 | - // bbPress shortcodes. | |
| 85 | - 'bbp-forum-index', | |
| 86 | - 'bbp-forum-form', | |
| 87 | - 'bbp-single-forum', | |
| 88 | - 'bbp-topic-index', | |
| 89 | - 'bbp-topic-form', | |
| 90 | - 'bbp-single-topic', | |
| 91 | - 'bbp-reply-form', | |
| 92 | - 'bbp-single-reply', | |
| 93 | - 'bbp-single-view', | |
| 94 | - 'bbp-search-form', | |
| 95 | - 'bbp-search', | |
| 96 | - 'bbp-login', | |
| 97 | - 'bbp-register', | |
| 98 | - 'bbp-lost-pass', | |
| 99 | - | |
| 100 | - // Forumax shortcodes. | |
| 101 | - 'forumax_login_form', | |
| 102 | - 'forumax_chat', | |
| 103 | - ); | |
| 104 | - | |
| 105 | - foreach ( $shortcodes as $shortcode ) { | |
| 106 | - if ( has_shortcode( $post->post_content, $shortcode ) ) { | |
| 107 | - $should_add = true; | |
| 108 | - break; | |
| 109 | - } | |
| 110 | - } | |
| 111 | - | |
| 112 | - // Also check for bbPress/Forumax blocks. | |
| 113 | - if ( ! $should_add && function_exists( 'has_block' ) ) { | |
| 114 | - $blocks = array( | |
| 115 | - 'bbpress/forum-index', | |
| 116 | - 'bbpress/topic-index', | |
| 117 | - 'forumax/forums', | |
| 118 | - ); | |
| 119 | - | |
| 120 | - foreach ( $blocks as $block ) { | |
| 121 | - if ( has_block( $block, $post ) ) { | |
| 122 | - $should_add = true; | |
| 123 | - break; | |
| 124 | - } | |
| 125 | - } | |
| 126 | - } | |
| 127 | - } | |
| 128 | - } | |
| 129 | - | |
| 130 | - if ( $should_add && ! in_array( 'forumax-body', $classes, true ) ) { | |
| 131 | - $classes[] = 'forumax-body'; | |
| 132 | - } | |
| 133 | - | |
| 134 | - return $classes; | |
| 135 | -} | |
| 136 | -add_filter( 'body_class', 'forumax_add_forumax_body_class', 20 ); | |
| 137 | - | |
| 138 | -/** | |
| 139 | - * Get hashed IP address for anonymous user identification. | |
| 140 | - * | |
| 141 | - * This function creates a one-way hash of the user's IP address, | |
| 142 | - * making it impossible to recover the original IP while still | |
| 143 | - * allowing duplicate detection (same IP = same hash). | |
| 144 | - * | |
| 145 | - * GDPR Compliant: Real IP addresses are never stored in the database. | |
| 146 | - * | |
| 147 | - * @since 2.3.1 | |
| 148 | - * | |
| 149 | - * @return string Hashed IP address (64 characters) | |
| 150 | - */ | |
| 151 | -function forumax_get_hashed_ip() { | |
| 152 | - $ip = ''; | |
| 153 | - | |
| 154 | - // Get the real IP address (handles proxies and load balancers) | |
| 155 | - if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { | |
| 156 | - $ip = $_SERVER['HTTP_CLIENT_IP']; | |
| 157 | - } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { | |
| 158 | - // Can contain multiple IPs, get the first one | |
| 159 | - $ip_list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ); | |
| 160 | - $ip = trim( $ip_list[0] ); | |
| 161 | - } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) { | |
| 162 | - $ip = $_SERVER['REMOTE_ADDR']; | |
| 163 | - } | |
| 164 | - | |
| 165 | - // Sanitize the IP | |
| 166 | - $ip = filter_var( $ip, FILTER_VALIDATE_IP ) ? $ip : 'unknown'; | |
| 167 | - | |
| 168 | - // Use WordPress salt for extra security (unique per site) | |
| 169 | - $salt = defined( 'NONCE_SALT' ) ? NONCE_SALT : 'forumax_default_salt_key'; | |
| 170 | - | |
| 171 | - // Create one-way hash - cannot be reversed to get original IP | |
| 172 | - return hash( 'sha256', $ip . $salt ); | |
| 173 | -} | |
| 174 | - | |
| 175 | -/** | |
| 176 | - * Get raw IP address for backward compatibility check only. | |
| 177 | - * | |
| 178 | - * WARNING: This function is used ONLY to check for legacy vote entries. | |
| 179 | - * The raw IP is NEVER stored - it's immediately compared against legacy | |
| 180 | - * data and then discarded. New votes always use forumax_get_hashed_ip(). | |
| 181 | - * | |
| 182 | - * @since 2.3.1 | |
| 183 | - * @access private | |
| 184 | - * | |
| 185 | - * @return string|false Raw IP address or false if invalid | |
| 186 | - */ | |
| 187 | -function forumax_get_raw_ip() { | |
| 188 | - $ip = ''; | |
| 189 | - | |
| 190 | - if ( ! empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { | |
| 191 | - $ip = $_SERVER['HTTP_CLIENT_IP']; | |
| 192 | - } elseif ( ! empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { | |
| 193 | - $ip_list = explode( ',', $_SERVER['HTTP_X_FORWARDED_FOR'] ); | |
| 194 | - $ip = trim( $ip_list[0] ); | |
| 195 | - } elseif ( ! empty( $_SERVER['REMOTE_ADDR'] ) ) { | |
| 196 | - $ip = $_SERVER['REMOTE_ADDR']; | |
| 197 | - } | |
| 198 | - | |
| 199 | - return filter_var( $ip, FILTER_VALIDATE_IP ) ? $ip : false; | |
| 200 | -} | |
| 201 | - | |
| 202 | -/** | |
| 203 | 57 | * Turn on the WordPress visual editor for bbPress |
| 204 | 58 | * |
| 205 | 59 | * @param array $args |
| 206 | 60 | * @return array |
| @@ -205,63 +59,14 @@ | ||
| 205 | 59 | * @param array $args |
| 206 | 60 | * @return array |
| 207 | 61 | */ |
| 208 | 62 | function forumax_bbp_enable_visual_editor( $args = [] ) { |
| 209 | - $args['tinymce'] = true; | |
| 210 | - $args['default_editor'] = 'tinymce'; | |
| 63 | + $args['tinymce'] = true; | |
| 211 | 64 | return $args; |
| 212 | 65 | } |
| 213 | 66 | add_filter( 'bbp_after_get_the_content_parse_args', 'forumax_bbp_enable_visual_editor' ); |
| 214 | 67 | |
| 215 | 68 | /** |
| 216 | - * Sanitize topic and reply content to prevent raw HTML display. | |
| 217 | - * | |
| 218 | - * When topics/replies are submitted from the frontend, bbPress runs | |
| 219 | - * `bbp_encode_bad` which entity-encodes HTML tags (e.g. `<p>` becomes | |
| 220 | - * `<p>`). This causes HTML tags to display as visible plain text | |
| 221 | - * instead of being rendered by the browser. | |
| 222 | - * | |
| 223 | - * This filter detects entity-encoded HTML, decodes it back to real HTML, | |
| 224 | - * and sanitizes the output through `wp_kses_post()` to allow only safe | |
| 225 | - * post-level HTML tags (p, strong, em, a, br, etc.) while stripping | |
| 226 | - * dangerous elements like script or iframe. | |
| 227 | - * | |
| 228 | - * @since 2.2.2 | |
| 229 | - * | |
| 230 | - * @param string $content The topic or reply content. | |
| 231 | - * @return string Sanitized content with proper HTML rendering. | |
| 232 | - */ | |
| 233 | -function forumax_sanitize_block_content( $content ) { | |
| 234 | - // Bail early if content is empty. | |
| 235 | - if ( empty( $content ) ) { | |
| 236 | - return $content; | |
| 237 | - } | |
| 238 | - | |
| 239 | - // Check if content contains entity-encoded HTML tags (e.g. <p>). | |
| 240 | - if ( strpos( $content, '<' ) !== false ) { | |
| 241 | - // Decode entity-encoded HTML back to real HTML tags. | |
| 242 | - $content = html_entity_decode( $content, ENT_QUOTES, 'UTF-8' ); | |
| 243 | - | |
| 244 | - // Sanitize with wp_kses_post — allows safe HTML (p, strong, a, br, etc.) | |
| 245 | - // but strips dangerous tags (script, iframe, etc.). | |
| 246 | - $content = wp_kses_post( $content ); | |
| 247 | - } | |
| 248 | - | |
| 249 | - // Strip inline style attributes from all HTML tags. | |
| 250 | - $content = preg_replace( '/\s+style="[^"]*"/i', '', $content ); | |
| 251 | - | |
| 252 | - // Strip block-editor class attributes (e.g. wp-block-paragraph). | |
| 253 | - $content = preg_replace( '/\s+class="wp-block-[^"]*"/i', '', $content ); | |
| 254 | - | |
| 255 | - // Clean up any remaining empty class attributes. | |
| 256 | - $content = preg_replace( '/\s+class=""/i', '', $content ); | |
| 257 | - | |
| 258 | - return $content; | |
| 259 | -} | |
| 260 | -add_filter( 'bbp_get_topic_content', 'forumax_sanitize_block_content', 4 ); | |
| 261 | -add_filter( 'bbp_get_reply_content', 'forumax_sanitize_block_content', 4 ); | |
| 262 | - | |
| 263 | -/** | |
| 264 | 69 | * Check if the pro plugin and plan is active |
| 265 | 70 | * |
| 266 | 71 | * @return bool|void |
| 267 | 72 | */ |
| @@ -305,16 +110,8 @@ | ||
| 305 | 110 | } elseif ( 'dashboard' === $admin ) { |
| 306 | 111 | if ( admin_url( 'admin.php?page=forumax' ) === $current_url ) { |
| 307 | 112 | return true; |
| 308 | 113 | } |
| 309 | - } elseif ( 'setup' === $admin ) { | |
| 310 | - if ( admin_url( 'admin.php?page=forumax-setup' ) === $current_url ) { | |
| 311 | - return true; | |
| 312 | - } | |
| 313 | - } elseif ( 'analytics' === $admin ) { | |
| 314 | - if ( admin_url( 'admin.php?page=forumax-analytics' ) === $current_url ) { | |
| 315 | - return true; | |
| 316 | - } | |
| 317 | 114 | } |
| 318 | 115 | |
| 319 | 116 | return false; |
| 320 | 117 | } |
| @@ -611,9 +408,9 @@ | ||
| 611 | 408 | } |
| 612 | 409 | add_filter( 'user_has_cap', 'forumax_grant_bbpress_caps_to_admins', 10, 3 ); |
| 613 | 410 | |
| 614 | 411 | /** |
| 615 | - * Mutual Deactivation of old and new plugin paths | |
| 412 | + * Mutual Deactivation of Forumax and bbp-core plugins | |
| 616 | 413 | */ |
| 617 | 414 | add_action( 'activated_plugin', function( $plugin ) { |
| 618 | 415 | if ( ! function_exists( 'is_plugin_active' ) ) { |
| 619 | 416 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| @@ -618,33 +415,31 @@ | ||
| 618 | 415 | if ( ! function_exists( 'is_plugin_active' ) ) { |
| 619 | 416 | require_once ABSPATH . 'wp-admin/includes/plugin.php'; |
| 620 | 417 | } |
| 621 | 418 | |
| 622 | - $free_plugins_new = [ 'forumax/forumax.php' ]; | |
| 623 | - $free_plugins_old = [ 'bbp-core/bbp-core.php', 'bbp-core/forumax.php' ]; | |
| 624 | - | |
| 625 | - $pro_plugins_new = [ 'forumax-pro/forumax.php' ]; | |
| 626 | - $pro_plugins_old = [ 'bbp-core-pro/bbp-core.php', 'forumax-premium/bbp-core.php', 'forumax-premium/forumax.php' ]; | |
| 419 | + // All Forumax plugins | |
| 420 | + $forumax_plugins = [ | |
| 421 | + 'forumax/forumax.php', | |
| 422 | + 'forumax-pro/forumax.php', | |
| 423 | + ]; | |
| 627 | 424 | |
| 628 | - // If activating NEW free, deactivate OLD free | |
| 629 | - if ( in_array( $plugin, $free_plugins_new, true ) ) { | |
| 630 | - deactivate_plugins( $free_plugins_old ); | |
| 425 | + // All bbp-core plugins | |
| 426 | + $bbp_core_plugins = [ | |
| 427 | + 'bbp-core/bbp-core.php', | |
| 428 | + 'bbp-core-pro/bbp-core.php', | |
| 429 | + ]; | |
| 430 | + | |
| 431 | + // If activating Forumax (free or pro) → deactivate bbp-core (all versions) | |
| 432 | + if ( in_array( $plugin, $forumax_plugins, true ) ) { | |
| 433 | + deactivate_plugins( $bbp_core_plugins ); | |
| 631 | 434 | } |
| 632 | 435 | |
| 633 | - // If activating OLD free, deactivate NEW free | |
| 634 | - if ( in_array( $plugin, $free_plugins_old, true ) ) { | |
| 635 | - deactivate_plugins( $free_plugins_new ); | |
| 636 | - } | |
| 637 | - | |
| 638 | - // If activating NEW pro, deactivate OLD pro | |
| 639 | - if ( in_array( $plugin, $pro_plugins_new, true ) ) { | |
| 640 | - deactivate_plugins( $pro_plugins_old ); | |
| 641 | - } | |
| 642 | 436 | |
| 643 | - // If activating OLD pro, deactivate NEW pro | |
| 644 | - if ( in_array( $plugin, $pro_plugins_old, true ) ) { | |
| 645 | - deactivate_plugins( $pro_plugins_new ); | |
| 437 | + // If activating bbp-core (free or pro) → deactivate Forumax (all versions) | |
| 438 | + if ( in_array( $plugin, $bbp_core_plugins, true ) ) { | |
| 439 | + deactivate_plugins( $forumax_plugins ); | |
| 646 | 440 | } |
| 441 | + | |
| 647 | 442 | } ); |
| 648 | 443 | |
| 649 | 444 | /** |
| 650 | 445 | * Register Forum Sidebar widget area |
| @@ -836,9 +631,9 @@ | ||
| 836 | 631 | * @return int The number of unanswered topics. |
| 837 | 632 | */ |
| 838 | 633 | function forumax_get_unanswered_topics_count() { |
| 839 | 634 | $cache_key = 'frmx_unanswered_topics_count'; |
| 840 | - $count = get_transient( $cache_key ); | |
| 635 | + $count = wp_cache_get( $cache_key, 'forumax' ); | |
| 841 | 636 | |
| 842 | 637 | if ( false !== $count ) { |
| 843 | 638 | return $count; |
| 844 | 639 | } |
| @@ -851,9 +646,9 @@ | ||
| 851 | 646 | AND p.post_status = 'publish' |
| 852 | 647 | AND (pm.meta_value IS NULL OR pm.meta_value = '0')" |
| 853 | 648 | ); |
| 854 | 649 | |
| 855 | - set_transient( $cache_key, $count, HOUR_IN_SECONDS ); | |
| 650 | + wp_cache_set( $cache_key, $count, 'forumax', HOUR_IN_SECONDS ); | |
| 856 | 651 | return absint( $count ); |
| 857 | 652 | } |
| 858 | 653 | |
| 859 | 654 | /** |
| @@ -889,9 +684,9 @@ | ||
| 889 | 684 | /** |
| 890 | 685 | * Invalidate unanswered topics cache. |
| 891 | 686 | */ |
| 892 | 687 | function forumax_invalidate_unanswered_topics_cache() { |
| 893 | - delete_transient( 'frmx_unanswered_topics_count' ); | |
| 688 | + wp_cache_delete( 'frmx_unanswered_topics_count', 'forumax' ); | |
| 894 | 689 | } |
| 895 | 690 | add_action( 'bbp_new_reply', 'forumax_invalidate_unanswered_topics_cache' ); |
| 896 | 691 | add_action( 'bbp_deleted_reply', 'forumax_invalidate_unanswered_topics_cache' ); |
| 897 | 692 | add_action( 'bbp_trash_reply', 'forumax_invalidate_unanswered_topics_cache' ); |
| @@ -903,47 +698,4 @@ | ||
| 903 | 698 | add_action( 'bbp_trash_topic', 'forumax_invalidate_unanswered_topics_cache' ); |
| 904 | 699 | add_action( 'bbp_untrash_topic', 'forumax_invalidate_unanswered_topics_cache' ); |
| 905 | 700 | add_action( 'bbp_spam_topic', 'forumax_invalidate_unanswered_topics_cache' ); |
| 906 | 701 | add_action( 'bbp_unspam_topic', 'forumax_invalidate_unanswered_topics_cache' ); |
| 907 | - | |
| 908 | -/** | |
| 909 | - * Filter topics by unanswered status in admin dashboard. | |
| 910 | - * | |
| 911 | - * @param WP_Query $query The WP_Query instance (modified in place). | |
| 912 | - */ | |
| 913 | -function forumax_filter_unanswered_topics_admin( $query ) { | |
| 914 | - if ( ! is_admin() || ! $query->is_main_query() ) { | |
| 915 | - return; | |
| 916 | - } | |
| 917 | - | |
| 918 | - if ( 'topic' !== $query->get( 'post_type' ) ) { | |
| 919 | - return; | |
| 920 | - } | |
| 921 | - | |
| 922 | - $forumax_filter = ''; | |
| 923 | - if ( isset( $_GET['forumax_filter'] ) ) { | |
| 924 | - $forumax_filter = sanitize_key( wp_unslash( $_GET['forumax_filter'] ) ); | |
| 925 | - } | |
| 926 | - | |
| 927 | - if ( 'unanswered' === $forumax_filter ) { | |
| 928 | - $meta_query = $query->get( 'meta_query' ); | |
| 929 | - if ( ! is_array( $meta_query ) ) { | |
| 930 | - $meta_query = []; | |
| 931 | - } | |
| 932 | - | |
| 933 | - $meta_query[] = [ | |
| 934 | - 'relation' => 'OR', | |
| 935 | - [ | |
| 936 | - 'key' => '_bbp_reply_count', | |
| 937 | - 'value' => '0', | |
| 938 | - 'compare' => '=', | |
| 939 | - ], | |
| 940 | - [ | |
| 941 | - 'key' => '_bbp_reply_count', | |
| 942 | - 'compare' => 'NOT EXISTS', | |
| 943 | - ], | |
| 944 | - ]; | |
| 945 | - | |
| 946 | - $query->set( 'meta_query', $meta_query ); | |
| 947 | - } | |
| 948 | -} | |
| 949 | -add_action( 'pre_get_posts', 'forumax_filter_unanswered_topics_admin' ); | |