You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
We reviewed changes in 9f5d2e2...3ea3602 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.
Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
maybe_unlock_post() now checks gated-action membership and resolves each post type’s private-read capability. Gated content selection uses a direct query for enabled private or password-protected items, with tests covering access control and grouping behavior.
Changes
Gated content access handling
Layer / File(s)
Summary
Access control and gated-action resolution classes/controllers/FrmGatedContentController.php
Private-post checks use the resolved post type capability, and token/404 handling applies only to items included in published gated actions.
Gated item selection and typing classes/models/FrmGatedContentAction.php, classes/views/frm-form-actions/*
get_posts() uses a fixed database query for enabled post types and private or password-protected statuses, while related annotations use grouped object entries.
sequenceDiagram
participant WordPressQuery
participant FrmGatedContentController
participant GatedActionPosts
participant FrmGatedTokenHelper
WordPressQuery->>FrmGatedContentController: resolve post request
FrmGatedContentController->>GatedActionPosts: check gated-action membership
GatedActionPosts-->>FrmGatedContentController: matching action or no match
FrmGatedContentController->>FrmGatedTokenHelper: validate token
FrmGatedTokenHelper-->>FrmGatedContentController: token result
FrmGatedContentController-->>WordPressQuery: preserve access or force 404
Make the CPT capability test reach the capability branch.
This test never registers a published gated action containing $post. At Line 158, has_gated_action_for_item() therefore returns early before $post_type_obj->cap->read_private_posts is evaluated; a regression to hard-coded read_private_posts would still pass. Add an action containing frm_gc_test_book and the created post ID before invoking the controller.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/phpunit/misc/test_FrmGatedContentController.php` around lines 140 -
158, Update the test setup before FrmGatedContentController::maybe_unlock_post()
to create and publish a gated action containing the frm_gc_test_book post and
its ID. Ensure has_gated_action_for_item() finds this action so execution
reaches the CPT capability check using the subscriber’s read_private_books
capability.
Avoid scanning all gated actions on every singular request.
maybe_unlock_post() performs this lookup before checking whether the post is private/password-protected or whether an access code is present. Every normal singular page therefore runs the action query, and cache misses can load each published action individually. Cache the membership result or defer the lookup until gated-access handling is needed.
Also applies to: 228-242
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@classes/controllers/FrmGatedContentController.php` around lines 163 - 179,
Update maybe_unlock_post() so it checks whether the post requires gated-access
handling—private, password-protected, or carrying an access code—before calling
has_gated_action_for_item(). Avoid querying gated actions for ordinary public
posts, while preserving the existing early return for items without an active
gated action once the lookup is needed.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@tests/phpunit/misc/test_FrmGatedContentController.php`:
- Around line 140-158: Update the test setup before
FrmGatedContentController::maybe_unlock_post() to create and publish a gated
action containing the frm_gc_test_book post and its ID. Ensure
has_gated_action_for_item() finds this action so execution reaches the CPT
capability check using the subscriber’s read_private_books capability.
---
Nitpick comments:
In `@classes/controllers/FrmGatedContentController.php`:
- Around line 163-179: Update maybe_unlock_post() so it checks whether the post
requires gated-access handling—private, password-protected, or carrying an
access code—before calling has_gated_action_for_item(). Avoid querying gated
actions for ordinary public posts, while preserving the existing early return
for items without an active gated action once the lookup is needed.
ℹ️ Review info⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: c83768b9-cb4f-4e01-83b0-7e13de936dc1
📥 Commits
Reviewing files that changed from the base of the PR and between fc97e5c and 3ea7865.
❌ Patch coverage is 60.00000% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 26.26%. Comparing base (c3d0460) to head (3ea3602). ⚠️ Report is 204 commits behind head on master.
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@classes/models/FrmGatedContentAction.php`:
- Around line 201-208: Update the post query or filtering logic in the selector
using FrmDb::get_results so private posts are included only when the current
user has the corresponding private-read capability for each post type. Preserve
published-post inclusion and ensure unauthorized private custom-post-type
entries are excluded before autocomplete values are encoded.
In `@tests/phpunit/forms/test_FrmGatedContentAction.php`:
- Around line 115-129: Update the test around FrmGatedContentAction::get_posts()
to store the callback passed to add_filter('frm_gated_content_item_types'), then
remove only that callback with remove_filter() in a finally block so cleanup
runs even when the assertion or setup throws; do not use remove_all_filters().
- Around line 17-21: Resolve the PHPCS formatting failures in the affected test
methods: group each consecutive assignment without blank lines around the post
creation, grouped results, and ID extraction statements, and reformat the keyed
arrays near the later test setup so each value begins on its own line. Preserve
the existing test logic while applying the project’s spacing and multiline array
conventions.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
Push a commit to this branch (recommended)
Create a new PR with the fixes
ℹ️ Review info⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 96c80435-15c8-4118-8788-9958a978c571
📥 Commits
Reviewing files that changed from the base of the PR and between 3ea7865 and 6f3ceff.
#!/bin/bashset -euo pipefail
file="./classes/models/FrmGatedContentAction.php"echo"--- classes/models/FrmGatedContentAction.php lines 188-230 ---"
sed -n '188,230p'"$file"echoecho"--- classes/models/FrmGatedContentAction.php lines 1-100 ---"
sed -n '1,100p'"$file"echoecho"--- Search for FmrgGatedContentAction::get_posts calls / fmbldr-gated-content usage ---"
python3 - <<'PY'import pathlib, re, jsonroots = [pathlib.Path('classes/models/FrmGatedContentAction.php'), pathlib.Path('tests/phpunit/forms/test_FrmGatedContentAction.php')]for p in roots: if p.exists(): print(f'FILE {p}') txt = p.read_text(encoding='utf-8', errors='replace') for line in range(1, len(txt.splitlines())+1): if 'FrmGatedContentAction' in txt.splitlines()[line-1] or 'get_posts' in txt.splitlines()[line-1] or 'fmbldr-gated-content' in txt.splitlines()[line-1]: print(f'{line}\t{txt.splitlines()[line-1]}')PYechoecho"--- JavaScript file candidates containing fmbldr-gated-content: ---"
python3 - <<'PY'import pathlibfor p in pathlib.Path('.').rglob('*'): if not p.is_file(): continue if '.min.' in p.name or 'node_modules' in p.parts or 'vendor' in p.parts: continue try: txt = p.read_text(encoding='utf-8', errors='replace') except Exception: continue if 'fmbldr-gated-content' in txt or 'frm_gated_content' in txt: print(p)PY
#!/bin/bashset -euo pipefail
file="./classes/controllers/FrmFormActionsController.php"echo"--- lines 158-195 from FrmFormActionsController.php ---"
sed -n '158,195p'"$file"| awk '{printf "%d\t%s\n", NR+158-1, $0}'echoecho"--- lines 635-675 from FrmFormActionsController.php ---"
sed -n '635,675p'"$file"| awk '{printf "%d\t%s\n", NR+635-1, $0}'echoecho"--- FrmGatedContentAction::get_posts_autocomplete_source ---"
sed -n '234,260p'"./classes/models/FrmGatedContentAction.php"| awk '{printf "%d\t%s\n", NR+234-1, $0}'echoecho"--- read-only summary of post query/filter semantics ---"
python3 - <<'PY'from pathlib import Pathimport repath = Path('classes/models/FrmGatedContentAction.php')text = path.read_text(encoding='utf-8')m_query = re.search(r"\$raw_posts\s*=\s*FrmDb::get_results\([^;]+", text, re.S)m_filter = re.search(r"foreach\s*\(\s*\$raw_posts\s+as\s+\$post\s*\)\s*\{(?P<body>.*?)(?=\n\t\})", text, re.S)print("query_uses_posts_table:", bool(m_query))if m_query: print("query_uses_private_status:", "post_status' => array( 'publish', 'private' )" in m_query.group(0))print("filter_matches_raw_rows:", "$raw_posts" in filter.group(0) if "filter" in dir() else False)if m_filter: print("filters_private_without_capability:", "private' !== $post->post_status" in m_filter.group("body") and "current_user_can" not in m_filter.group(0))PY
Repository: Strategy11/formidable-forms
Length of output: 4121
Filter the private post selector by read capability.
get_posts() queries /posts for both publish and private rows, then excludes only non-private public posts. This causes every private post in enabled post types to be encoded into the autocomplete selector, so users who can edit forms but cannot read a custom CPT’s private posts can select unauthorized private content. Apply the corresponding private-read capability check before including private rows in the selector.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@classes/models/FrmGatedContentAction.php` around lines 201 - 208, Update the
post query or filtering logic in the selector using FrmDb::get_results so
private posts are included only when the current user has the corresponding
private-read capability for each post type. Preserve published-post inclusion
and ensure unauthorized private custom-post-type entries are excluded before
autocomplete values are encoded.
remove_all_filters( 'frm_gated_content_item_types' ) can delete callbacks registered by other tests or extensions, causing order-dependent failures. Store the test callback and remove it with remove_filter() in a finally block.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/phpunit/forms/test_FrmGatedContentAction.php` around lines 115 - 129,
Update the test around FrmGatedContentAction::get_posts() to store the callback
passed to add_filter('frm_gated_content_item_types'), then remove only that
callback with remove_filter() in a finally block so cleanup runs even when the
assertion or setup throws; do not use remove_all_filters().
remove_all_filters( 'frm_gated_content_item_types' ) can remove callbacks registered by other tests or extensions, causing order-dependent failures. Store the callback, remove it with remove_filter(), and perform cleanup in finally so exceptions do not leak the filter.
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@tests/phpunit/forms/test_FrmGatedContentAction.php` around lines 119 - 133,
Update the filter setup in the test around FrmGatedContentAction::get_posts() to
store the callback passed to add_filter, then remove only that callback with
remove_filter('frm_gated_content_item_types', ...). Wrap the get_posts()
execution in a finally block so the test-specific filter is always cleaned up,
including when an exception occurs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Duplicate comments:
In `@tests/phpunit/forms/test_FrmGatedContentAction.php`:
- Around line 119-133: Update the filter setup in the test around
FrmGatedContentAction::get_posts() to store the callback passed to add_filter,
then remove only that callback with
remove_filter('frm_gated_content_item_types', ...). Wrap the get_posts()
execution in a finally block so the test-specific filter is always cleaned up,
including when an exception occurs.
ℹ️ Review info⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: 3c5e47e6-9186-4f58-b776-d78c50c5eb42
📥 Commits
Reviewing files that changed from the base of the PR and between 6f3ceff and 3ea3602.
🚧 Files skipped from review as they are similar to previous changes (2)
classes/controllers/FrmGatedContentController.php
classes/models/FrmGatedContentAction.php
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fix #3203 and https://secure.helpscout.net/conversation/3398946279/255863
Summary by CodeRabbit