[buddypress-trac] [BuddyPress Trac] #9328: Feature Request: Add query filter hooks to `BP_Messages_Thread::get_current_threads_for_user()`
buddypress-trac
noreply at wordpress.org
Fri Feb 6 00:01:24 UTC 2026
#9328: Feature Request: Add query filter hooks to
`BP_Messages_Thread::get_current_threads_for_user()`
-------------------------+-----------------------------
Reporter: indigetal | Owner: (none)
Type: enhancement | Status: new
Priority: normal | Milestone: Awaiting Review
Component: Core | Version: 14.4.0
Severity: normal | Keywords:
-------------------------+-----------------------------
#### The Gap
BuddyPress's activity component has excellent query-level extensibility:
```php
// From BP_Activity_Activity::get() — lines 666, 682
$where_conditions = apply_filters( 'bp_activity_get_where_conditions',
$where_conditions, $r, $select_sql, $from_sql, $join_sql );
$join_sql = apply_filters( 'bp_activity_get_join_sql', $join_sql, $r,
$select_sql, $from_sql, $where_sql );
```
These filters allow any addon to inject WHERE clauses and JOINs into the
main activity query without modifying core. BuddyBoss's moderation system,
for example, hooks into `bp_activity_get_where_conditions` to hide
suspended content — all from addon-level code.
The messages component has **no equivalent**.
`BP_Messages_Thread::get_current_threads_for_user()` builds its SQL in a
`$sql` array (lines 790–794) and executes it directly:
```php
$sql['select'] = 'SELECT m.thread_id, MAX(m.date_sent) AS date_sent';
$sql['from'] = "FROM {$bp->messages->table_name_recipients} r INNER JOIN
{$bp->messages->table_name_messages} m ON m.thread_id = r.thread_id
{$meta_query_sql['join']}";
$sql['where'] = "WHERE {$deleted_sql} {$user_id_sql} {$sender_sql}
{$type_sql} {$search_sql} {$meta_query_sql['where']}";
$sql['misc'] = "GROUP BY m.thread_id ORDER BY date_sent DESC
{$pag_sql}";
$thread_ids = $wpdb->get_results( implode( ' ', $sql ) );
```
The only filter (`bp_messages_thread_current_threads`) fires AFTER the
query on the fully-constructed result set (line 841) — meaning addons must
filter in PHP, not SQL. This is:
1. **A performance problem** — filtering in PHP means fetching rows from
the database that will be discarded, and constructing full
`BP_Messages_Thread` objects for threads that are then thrown away. This
gets worse as thread count grows.
2. **An extensibility gap** — addons that need custom thread filtering
(archiving, priority inbox, moderation, read/unread management) have no
clean way to modify the query
3. **Inconsistent with the activity API** — activity has comprehensive
pre-query filters; messages doesn't
#### Proposed Change
Add filter hooks to `get_current_threads_for_user()` before query
execution, following the pattern established by
`BP_Activity_Activity::get()`:
```php
// After building $sql array (around line 794):
/**
* Filters the WHERE SQL for the current threads query.
*
* @since {next_version}
*
* @param string $where_sql Current WHERE clause.
* @param array $r Parsed query arguments.
* @param string $select_sql Current SELECT clause.
* @param string $from_sql Current FROM clause (includes JOINs).
*/
$sql['where'] = apply_filters( 'bp_messages_thread_get_where_conditions',
$sql['where'], $r, $sql['select'], $sql['from'] );
/**
* Filters the FROM/JOIN SQL for the current threads query.
*
* @since {next_version}
*
* @param string $from_sql Current FROM clause (includes JOINs).
* @param array $r Parsed query arguments.
* @param string $select_sql Current SELECT clause.
* @param string $where_sql Current WHERE clause.
*/
$sql['from'] = apply_filters( 'bp_messages_thread_get_join_sql',
$sql['from'], $r, $sql['select'], $sql['where'] );
```
**Note on parameter style:** In `BP_Activity_Activity::get()`, the WHERE
conditions are passed as an array (joined to a string after the filter),
whereas in the messages method they are already a string. This proposal
preserves the existing messages code structure and filters the string
directly, which is the minimal-change approach. If BP maintainers prefer,
the messages SQL could also be refactored to use an array of conditions
for parity with activity — but filtering the string is sufficient for all
the use cases described below.
#### Scope
- ~12 lines added to one file (`class-bp-messages-thread.php`)
- Zero behavioral change — the filters pass through existing values by
default
- Follows the pattern established by the activity component's existing
filters
- The existing `bp_messages_thread_current_threads` post-query filter
continues to work as-is
#### What This Enables for Addons
With these hooks, addon plugins can implement:
- **Message archiving** — Add `is_hidden` column to
`bp_messages_recipients`, filter `WHERE` to exclude `r.is_hidden = 1`
- **Message soft-delete** — Add `is_deleted` column to
`bp_messages_messages`, filter `FROM`/`JOIN` to exclude deleted messages
from thread listing
- **Content moderation** — Inject suspend/block conditions into thread
queries
- **Priority inbox** — Filter by custom meta or thread properties
- **Group messaging** — Filter threads by group membership context
None of these features require core changes — they just need the ability
to modify the query, which activity already provides but messages doesn't.
#### Prior Art
BuddyBoss Platform needed exactly these extension points. Because the
hooks don't exist in BuddyPress core, BuddyBoss had to:
1. **Restructure `get_current_threads_for_user()`** entirely — they
replaced it with a delegating call to a new `get_threads_for_user()`
method containing ~400 lines of rewritten SQL logic
2. **Add `is_hidden` and `is_deleted` columns** directly into the
restructured query conditions
3. **Add their own filter hooks** —
`bp_messages_recipient_get_where_conditions` and
`bp_messages_recipient_get_join_sql` — with signatures functionally
identical to what this proposal suggests
The fact that BuddyBoss independently arrived at the same solution (pre-
query filter hooks on the messages SQL) validates the need. If these hooks
had existed in BuddyPress core, BuddyBoss could have achieved the same
result from addon-level code without forking the class.
I'm happy to submit a PR for this change.
--
Ticket URL: <https://buddypress.trac.wordpress.org/ticket/9328>
BuddyPress Trac <http://buddypress.org/>
BuddyPress Trac
More information about the buddypress-trac
mailing list