Skip to content

Support Forums: use the topic ID passed to user_can_resolve() - #856

Closed
obenland wants to merge 3 commits into
WordPress:trunkfrom
obenland:topic-resolution-topic-id
Closed

Support Forums: use the topic ID passed to user_can_resolve()#856
obenland wants to merge 3 commits into
WordPress:trunkfrom
obenland:topic-resolution-topic-id

Conversation

@obenland

@obenland obenland commented Sep 1, 2026

Copy link
Copy Markdown
Member

Topic_Resolution\Plugin::user_can_resolve() takes a $topic_id argument and then discards it on the next line, replacing it with bbp_get_topic_id(). It has done that since the method was introduced in [3797]. The result is that the method reports on whichever topic the current request is rendering, not the one the caller asked about.

That is fine for the two callers that read the topic from the page anyway, but Hooks::handle_extra_reply_actions() and Plugin::topic_resolution_handler() both pass an ID that came in with the request, and the answer they get back doesn't correspond to it.

This passes the argument through to bbp_get_topic_id(), which returns it when it's a usable number and otherwise falls back to the displayed topic, so callers that legitimately pass nothing behave as before. It also swaps get_post() for bbp_get_topic(), so an ID that points at some other post type can no longer match on post_author.

Directory_Compat::user_can_resolve(), which filters the result, has the same mismatch in a different form: it ignores $topic_id entirely and answers from $this->authors, $this->contributors, and $this->support_reps, all populated from the plugin or theme loaded for the current request. So the answer for a topic belonging to one plugin could be decided by another plugin's author list. The filter now returns early unless the topic carries the term for the loaded object, which is the same condition under which check_topic_for_compat() loads that object in the first place.

Testing instructions

  1. Open a topic you authored in a forum with topic resolution enabled. The "Reply and mark as resolved" checkbox should appear, and using it should still resolve the topic.
  2. Open a topic authored by someone else. The checkbox should not appear, and the status should render as text rather than as the update form.
  3. As a plugin author, confirm you can still resolve topics in your own plugin's support forum, and that the status is read-only on topics belonging to other plugins.
  4. As a moderator, confirm both remain editable.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved topic resolution permission checks to ensure actions apply only to the correct support forum.
    • Added safer handling for missing or invalid topic information.
    • Resolution permissions now correctly evaluate the requested topic, including when working outside the currently displayed topic.

The `$topic_id` argument was overwritten with `bbp_get_topic_id()`, so the
check always evaluated the topic being displayed rather than the one it was
asked about. Resolve the topic from the passed ID, falling back to the
displayed one when none is given, and use `bbp_get_topic()` so a non-topic
ID can't satisfy the author comparison.

The directory compat filter has the same mismatch: it grants authors,
contributors, and support reps permission based on the plugin or theme
loaded for the current request, without regard for which topic is being
checked. Limit it to topics that belong to that plugin or theme.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings September 1, 2026 18:30
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Core Committers: Use this line as a base for the props when committing in SVN:

Props obenland.

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes topic-resolution authorization to consistently evaluate permissions against the topic ID provided by callers (falling back to the displayed topic only when no usable ID is provided), preventing mismatches when actions are triggered from request data.

Changes:

  • Pass the $topic_id argument through to bbp_get_topic_id( $topic_id ) and fetch the topic via bbp_get_topic() to ensure authorization is evaluated against a real topic.
  • In Support Forums directory compat filtering, ensure the compat-derived author/contributor/support-rep lists only affect resolution permissions when the topic actually belongs to the compat object.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
wordpress.org/public_html/wp-content/plugins/wporg-bbp-topic-resolution/inc/class-plugin.php Ensures user_can_resolve() evaluates permission against the requested topic ID (with safe fallback) and only matches against topic posts.
wordpress.org/public_html/wp-content/plugins/support-forums/inc/class-directory-compat.php Guards the compat permission override so it only applies when the topic is tagged for the currently loaded compat object.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +466 to +470
// The compat object is loaded from the request, not from $topic_id.
$terms = get_the_terms( $topic_id, $this->taxonomy() );
if ( empty( $terms ) || is_wp_error( $terms ) || ! in_array( (string) $this->slug(), wp_list_pluck( $terms, 'slug' ), true ) ) {
return $retval;
}
@coderabbitai

coderabbitai Bot commented Sep 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Team

Run ID: 173019a3-b418-4e04-b68a-12c0458392b0

📥 Commits

Reviewing files that changed from the base of the PR and between 2048215 and 619f1f9.

📒 Files selected for processing (2)
  • wordpress.org/public_html/wp-content/plugins/support-forums/inc/class-support-compat.php
  • wordpress.org/public_html/wp-content/plugins/wporg-bbp-topic-resolution/inc/class-plugin.php

Included review availability: Your plan provides up to 8 included reviews per hour; 6 remain after this review.


📝 Walkthrough

Walkthrough

Topic resolution now validates the submitted topic’s forum, targets the requested topic for authorization, and verifies compatibility taxonomy ownership with strict forum ID handling.

Changes

Topic resolution authorization

Layer / File(s) Summary
Resolve the authorization topic
wordpress.org/public_html/wp-content/plugins/wporg-bbp-topic-resolution/inc/class-plugin.php
The handler validates the submitted topic’s forum instead of the viewed forum. user_can_resolve() uses the provided topic ID, falls back to the displayed topic, and loads it with bbp_get_topic().
Validate compat topic ownership
wordpress.org/public_html/wp-content/plugins/support-forums/inc/class-directory-compat.php, wordpress.org/public_html/wp-content/plugins/support-forums/inc/class-support-compat.php
user_can_resolve() checks the topic terms for the active compat slug. Explicit forum IDs use strict integer comparison against the reviews forum ID.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 619f1

This is a localized correction to use the requested topic ID when determining resolution permissions; no actionable merge-blocking risk remains after normal checks and review.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 3 files.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the main change: making user_can_resolve() use the passed topic ID. It is concise and directly related to the pull request objectives.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

obenland and others added 2 commits September 1, 2026 13:51
`Support_Compat::is_enabled_on_forum()` read the passed forum ID and then
overwrote its answer from the current request, so on a single topic or view
the argument had no effect at all. Return early when one is supplied, which
also makes the existing call in `handle_extra_reply_actions()` mean what it
says.

`topic_resolution_handler()` had the same mismatch: it asked whether
resolution was enabled before it read `$_POST['topic_id']`, and so answered
for the forum being viewed. Move the check below the topic lookup and pass
that topic's forum.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`$forum_id` can arrive as a numeric string, so cast it rather than relying
on a loose comparison against the integer constant.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@bazza bazza closed this in a3c32fe Sep 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants