PluginProbe
Forumax – AI Powered Advanced Community Forum Plugin / 2.2.0
Forumax – AI Powered Advanced Community Forum Plugin v2.2.0
2.4.4 2.4.3 2.4.2 2.4.1 2.4.0 trunk 1.0.8 1.1.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 2.0.0 2.1.0 All 29 releases
← All changes | includes/functions.php +203 -10 2.1.02.2.0 View file →
@@ -300,21 +300,116 @@
300 300 return $empty + $menu_locations;
301 301 }
302 302
303 303 /**
304 - * Enable REST API for bbPress forum post type
305 - * This allows the forum post type to be accessed via the WordPress REST API
306 - * which is required for the Gutenberg block to fetch forum data
304 + * Fix Gutenberg editor support for bbPress forum and topic post types.
305 + *
306 + * Filters the post type registration arguments to enable full REST API
307 + * support, ensure thumbnail support, and force correct labels so that
308 + * Gutenberg displays the proper post type name instead of "Document".
309 + *
310 + * @param array $args Array of arguments for registering a post type.
311 + * @param string $post_type Post type key.
312 + * @return array Modified arguments.
307 313 */
308 -function forumax_enable_forum_rest_api() {
309 - $post_type_obj = get_post_type_object( 'forum' );
310 - if ( $post_type_obj ) {
311 - $post_type_obj->show_in_rest = true;
314 +function forumax_fix_post_type_args( $args, $post_type ) {
315 + $post_types_config = array(
316 + 'forum' => array(
317 + 'rest_base' => 'forums',
318 + 'labels' => array(
319 + 'name' => __( 'Forums', 'bbpress' ),
320 + 'singular_name' => __( 'Forum', 'bbpress' ),
321 + ),
322 + ),
323 + 'topic' => array(
324 + 'rest_base' => 'topics',
325 + 'labels' => array(
326 + 'name' => __( 'Topics', 'bbpress' ),
327 + 'singular_name' => __( 'Topic', 'bbpress' ),
328 + ),
329 + ),
330 + );
331 +
332 + if ( ! isset( $post_types_config[ $post_type ] ) ) {
333 + return $args;
312 334 }
335 +
336 + $config = $post_types_config[ $post_type ];
337 +
338 + // Force full REST API support for Gutenberg.
339 + $args['show_in_rest'] = true;
340 + $args['rest_base'] = $config['rest_base'];
341 + $args['rest_controller_class'] = 'WP_REST_Posts_Controller';
342 +
343 + // Set explicit label property (singular string).
344 + $args['label'] = $config['labels']['name'];
345 +
346 + // Ensure thumbnail support is included.
347 + if ( ! empty( $args['supports'] ) && is_array( $args['supports'] ) ) {
348 + if ( ! in_array( 'thumbnail', $args['supports'], true ) ) {
349 + $args['supports'][] = 'thumbnail';
350 + }
351 + } else {
352 + $args['supports'] = array( 'title', 'editor', 'revisions', 'thumbnail' );
353 + }
354 +
355 + // Merge labels to prevent Gutenberg "Document" fallback.
356 + if ( ! empty( $args['labels'] ) && is_array( $args['labels'] ) ) {
357 + $args['labels'] = array_merge( $args['labels'], $config['labels'] );
358 + } else {
359 + $args['labels'] = $config['labels'];
360 + }
361 +
362 + return $args;
313 363 }
314 -add_action( 'init', 'forumax_enable_forum_rest_api', 20 );
364 +add_filter( 'register_post_type_args', 'forumax_fix_post_type_args', 99, 2 );
315 365
316 366 /**
367 + * Grant bbPress post type capabilities to WordPress administrators.
368 + *
369 + * Gutenberg requests the post type REST endpoint with context=edit, which
370 + * checks custom capabilities like edit_forums and edit_topics. WordPress
371 + * administrators may not have these caps unless bbPress has explicitly
372 + * assigned them. This filter dynamically grants the required caps to
373 + * any user who can manage_options (i.e. administrators).
374 + *
375 + * @param array $allcaps All capabilities for the user.
376 + * @param array $caps Required capabilities being checked.
377 + * @param array $args Additional arguments passed to the check.
378 + * @return array Modified capabilities array.
379 + */
380 +function forumax_grant_bbpress_caps_to_admins( $allcaps, $caps, $args ) {
381 + // Only grant to users who can manage options (administrators).
382 + if ( empty( $allcaps['manage_options'] ) ) {
383 + return $allcaps;
384 + }
385 +
386 + // bbPress forum and topic capabilities needed for REST API access.
387 + $bbpress_caps = array(
388 + 'edit_forums',
389 + 'edit_others_forums',
390 + 'publish_forums',
391 + 'read_private_forums',
392 + 'read_hidden_forums',
393 + 'delete_forums',
394 + 'delete_others_forums',
395 + 'edit_topics',
396 + 'edit_others_topics',
397 + 'publish_topics',
398 + 'read_private_topics',
399 + 'delete_topics',
400 + 'delete_others_topics',
401 + );
402 +
403 + foreach ( $bbpress_caps as $cap ) {
404 + $allcaps[ $cap ] = true;
405 + }
406 +
407 + return $allcaps;
408 +}
409 +add_filter( 'user_has_cap', 'forumax_grant_bbpress_caps_to_admins', 10, 3 );
410 +
411 +/**
317 412 * Mutual Deactivation of Forumax and bbp-core plugins
318 413 */
319 414 add_action( 'activated_plugin', function( $plugin ) {
320 415 if ( ! function_exists( 'is_plugin_active' ) ) {
@@ -369,11 +464,19 @@
369 464 ] );
370 465 }, 20 ); // Priority 20 to run after theme's widgets_init
371 466
372 467
468 +/**
469 + * Add title and thumbnail support for bbPress forum and topic post types.
470 + *
471 + * Ensures the title field and featured image meta box are available
472 + * in the WordPress admin editor for both post types.
473 + */
373 474 add_action( 'init', function () {
374 - add_post_type_support( 'forum', 'thumbnail' );
375 - add_post_type_support( 'topic', 'thumbnail' );
475 + add_post_type_support( 'forum', 'title' );
476 + add_post_type_support( 'forum', 'thumbnail' );
477 + add_post_type_support( 'topic', 'title' );
478 + add_post_type_support( 'topic', 'thumbnail' );
376 479 }, 25 );
377 480
378 481
379 482 /**
@@ -494,8 +597,20 @@
494 597 */
495 598 function forumax_get_topic_count_by_status( $status = 'publish', $parent_id = false ) {
496 599 global $wpdb;
497 600
601 + // Sanitize parameters for cache key
602 + $cache_status = sanitize_key( $status );
603 + $cache_parent = ( false !== $parent_id && is_numeric( $parent_id ) ) ? (int) $parent_id : 0;
604 +
605 + // Check transient cache
606 + $cache_key = 'frmx_topic_count_' . $cache_status . '_' . $cache_parent;
607 + $count = get_transient( $cache_key );
608 +
609 + if ( false !== $count ) {
610 + return (int) $count;
611 + }
612 +
498 613 $status = esc_sql( $status );
499 614 $where = "WHERE post_type = 'topic' AND post_status = '{$status}'";
500 615
501 616 if ( false !== $parent_id && is_numeric( $parent_id ) ) {
@@ -503,6 +618,84 @@
503 618 }
504 619
505 620 $count = $wpdb->get_var( "SELECT COUNT(*) FROM {$wpdb->posts} {$where}" );
506 621
622 + // Set transient cache for 1 hour
623 + set_transient( $cache_key, (int) $count, HOUR_IN_SECONDS );
624 +
507 625 return (int) $count;
508 626 }
627 +
628 +/**
629 + * Get unanswered topics count.
630 + *
631 + * @return int The number of unanswered topics.
632 + */
633 +function forumax_get_unanswered_topics_count() {
634 + $cache_key = 'frmx_unanswered_topics_count';
635 + $count = wp_cache_get( $cache_key, 'forumax' );
636 +
637 + if ( false !== $count ) {
638 + return $count;
639 + }
640 +
641 + global $wpdb;
642 + $count = $wpdb->get_var(
643 + "SELECT COUNT(*) FROM {$wpdb->posts} p
644 + LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = '_bbp_reply_count'
645 + WHERE p.post_type = 'topic'
646 + AND p.post_status = 'publish'
647 + AND (pm.meta_value IS NULL OR pm.meta_value = '0')"
648 + );
649 +
650 + wp_cache_set( $cache_key, $count, 'forumax', HOUR_IN_SECONDS );
651 + return absint( $count );
652 +}
653 +
654 +/**
655 + * Get recent unanswered topics.
656 + *
657 + * @param int $limit Number of topics to retrieve.
658 + * @return array Array of WP_Post objects.
659 + */
660 +function forumax_get_recent_unanswered_topics( $limit = 5 ) {
661 + $args = [
662 + 'post_type' => 'topic',
663 + 'post_status' => 'publish',
664 + 'posts_per_page' => $limit,
665 + 'orderby' => 'date',
666 + 'order' => 'DESC',
667 + 'meta_query' => [
668 + 'relation' => 'OR',
669 + [
670 + 'key' => '_bbp_reply_count',
671 + 'value' => '0',
672 + 'compare' => '=',
673 + ],
674 + [
675 + 'key' => '_bbp_reply_count',
676 + 'compare' => 'NOT EXISTS',
677 + ],
678 + ],
679 + ];
680 +
681 + return get_posts( $args );
682 +}
683 +
684 +/**
685 + * Invalidate unanswered topics cache.
686 + */
687 +function forumax_invalidate_unanswered_topics_cache() {
688 + wp_cache_delete( 'frmx_unanswered_topics_count', 'forumax' );
689 +}
690 +add_action( 'bbp_new_reply', 'forumax_invalidate_unanswered_topics_cache' );
691 +add_action( 'bbp_deleted_reply', 'forumax_invalidate_unanswered_topics_cache' );
692 +add_action( 'bbp_trash_reply', 'forumax_invalidate_unanswered_topics_cache' );
693 +add_action( 'bbp_untrash_reply', 'forumax_invalidate_unanswered_topics_cache' );
694 +add_action( 'bbp_spam_reply', 'forumax_invalidate_unanswered_topics_cache' );
695 +add_action( 'bbp_unspam_reply', 'forumax_invalidate_unanswered_topics_cache' );
696 +add_action( 'bbp_new_topic', 'forumax_invalidate_unanswered_topics_cache' );
697 +add_action( 'bbp_deleted_topic', 'forumax_invalidate_unanswered_topics_cache' );
698 +add_action( 'bbp_trash_topic', 'forumax_invalidate_unanswered_topics_cache' );
699 +add_action( 'bbp_untrash_topic', 'forumax_invalidate_unanswered_topics_cache' );
700 +add_action( 'bbp_spam_topic', 'forumax_invalidate_unanswered_topics_cache' );
701 +add_action( 'bbp_unspam_topic', 'forumax_invalidate_unanswered_topics_cache' );