Skip to content

Rock gated content#3088

Open
truongwp wants to merge 129 commits into
masterfrom
rock-gated-content
Open

Rock gated content#3088
truongwp wants to merge 129 commits into
masterfrom
rock-gated-content

Conversation

@truongwp

@truongwp truongwp commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Related PR: https://github.com/Strategy11/formidable-pro/pull/6451

Summary by CodeRabbit

  • New Features

    • Gated Content action: configure gated items, generate timed access tokens, unlock private/passworded posts, and shortcode to render gated links or raw tokens
    • Admin UX: dynamic item rows, autocomplete for many items, copy-shortcode support, and helper shortcode references in the form editor
  • Tests

    • PHPUnit coverage for token generation, validation, resolution, and controller behavior
  • Chores

    • Database schema updated to track gated tokens

Review Change Stack

@coderabbitai

coderabbitai Bot commented Apr 27, 2026

Copy link
Copy Markdown
Contributor

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a gated-content form action with token generation/storage/validation, DB table and migrations, admin UI/JS and styles, shortcode rendering, query hooks to unlock private/passworded posts, hook wiring, and unit/integration tests.

Changes

Gated Content Form Action Feature

Layer / File(s) Summary
Core Data Models and Action
classes/models/FrmGatedItem.php, classes/models/FrmGatedToken.php, classes/models/FrmGatedContentAction.php
Value objects for gated items and tokens, plus FrmGatedContentAction implementing the gated_content form action, post selectors, shortcodes, and settings sanitization.
Token Generation & Validation System
classes/helpers/FrmGatedTokenHelper.php
Generates 32-character raw tokens, hashes and persists rows, manages per-request/transient caches, validates tokens via URL→cookie→user→filter chain, handles cookies and membership caching, and provides cleanup.
Database Schema & Versioning
classes/models/FrmMigrate.php, classes/helpers/FrmAppHelper.php
Adds frm_gated_tokens table and bumps plugin DB version to 106; uninstall drops the table.
Post Access Control & Query Filtering
classes/controllers/FrmGatedContentController.php
Includes private posts in main singular queries when a token validates, unlocks password-protected posts for a validated token (bypasses password check only for that post), strips access_code via redirect, and forces 404 for unauthorized private posts; clears caches on action updates/deletes.
Shortcode Handler & Display
classes/controllers/FrmGatedContentShortcodeController.php
Implements [frm_gated_content] shortcode with modes access_token, url, and link, supporting single or list outputs and safe escaping.
Admin Settings UI & Templates
classes/views/frm-form-actions/_gated_content_settings.php, classes/views/frm-form-actions/_gated_content_item_row.php, classes/views/frm-form-actions/_gated_content_shortcodes.php, resources/scss/admin/components/form/_form-actions.scss
Admin UI for configuring gated items, item row template, shortcode reference, autocomplete for large post lists, and styles for layout and copy controls.
Client-side Admin Logic
js/src/admin/admin.js
Manages dynamic gated-content item rows: type activation, reindexing, deterministic per-row IDs, file-field filtering, and shortcode copy UX with fallback.
Hook Registration & Controller Wiring
classes/controllers/FrmFormActionsController.php, classes/controllers/FrmHooksController.php, classes/controllers/FrmFormsController.php
Registers the gated_content action and wires daily token cleanup, action triggers, query/post hooks, save/delete handlers, shortcode callback, and passes form_id into helper shortcode generation.
Token Helper Unit Tests
tests/phpunit/helpers/test_FrmGatedTokenHelper.php
Covers generation format/persistence/caching, validate_access_code behavior, expiry handling, and multi-source token resolution including filter fallback.
Controller Integration Tests
tests/phpunit/misc/test_FrmGatedContentController.php
Tests that action triggers generate tokens and respect configured events (e.g., payment-success).

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

run tests

Suggested reviewers

  • garretlaxton
  • Crabcyborg

Poem

🐰 I hopped through tokens, keys in paw,
I tucked a shortcode by the door,
Private posts now find a way,
Links and tokens lead the day,
A rabbit cheers the code once more.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'Rock gated content' is vague and generic, using unclear phrasing that does not convey specific information about the changeset despite implementing substantial gated content functionality. Consider revising the title to be more descriptive, such as 'Add gated content feature with token validation' or 'Implement gated content access control system' to better communicate the main changes.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 95.51% which is sufficient. The required threshold is 80.00%.
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.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch rock-gated-content

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@deepsource-io

deepsource-io Bot commented Apr 27, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in 4d7b13f...cdd8856 on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

Important

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.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
PHP Jul 1, 2026 8:41a.m. Review ↗
JavaScript Jul 1, 2026 8:41a.m. Review ↗

Important

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.

Comment thread js/src/admin/admin.js Outdated
Comment thread js/src/admin/admin.js Outdated
Comment thread js/src/admin/admin.js Outdated
const copyBtn = event.target.closest( '.frm_gc_copy_shortcode' );
if ( copyBtn ) {
const text = copyBtn.dataset.frmCopy;
if ( navigator.clipboard && navigator.clipboard.writeText ) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Prefer using an optional chain expression instead, as it's more concise and easier to read


The optional chaining operator can be used to perform null checks before accessing a property, or calling a function.

Comment thread classes/controllers/FrmGatedContentController.php Outdated
Comment thread classes/controllers/FrmGatedContentController.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
FrmFormActionsController::trigger_actions( 'payment-success', $form_id, $entry_id );

$raw_token = FrmGatedTokenHelper::get_raw_token_for_action( $action_id );
$this->assertNotNull(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Call to an undefined method test_FrmGatedContentController::assertNotNull()


The method you are trying to call is not defined, which can result in a fatal error.

Comment thread tests/phpunit/misc/test_FrmGatedContentController.php Outdated
* @covers FrmGatedContentController::trigger
*/
public function test_payment_success_event_skips_non_matching_action() {
$form_id = $this->factory->form->create();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Access to an undefined property test_FrmGatedContentController::$factory


The property you are trying to access is not defined and will cause unexpected behavior when used.

*/
public function test_payment_success_event_skips_non_matching_action() {
$form_id = $this->factory->form->create();
$entry_id = $this->factory->entry->create( array( 'form_id' => $form_id ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Access to an undefined property test_FrmGatedContentController::$factory


The property you are trying to access is not defined and will cause unexpected behavior when used.


FrmFormActionsController::trigger_actions( 'payment-success', $form_id, $entry_id );

$this->assertNull(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Call to an undefined method test_FrmGatedContentController::assertNull()


The method you are trying to call is not defined, which can result in a fatal error.

* @param array $atts Shortcode attributes.
* @return string Shortcode output, or empty string when no token is available.
*/
public static function shortcode( $atts ) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`shortcode` has a cyclomatic complexity of 19 with "High" risk


A function with high cyclomatic complexity can be hard to understand and
maintain. Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A higher cyclomatic complexity indicates
that the function has more decision points and is more complex.

Comment thread classes/controllers/FrmGatedContentController.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
FrmFormActionsController::trigger_actions( 'payment-success', $form_id, $entry_id );

$raw_token = FrmGatedTokenHelper::get_raw_token_for_action( $action_id );
$this->assertNotNull(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Call to an undefined method test_FrmGatedContentController::assertNotNull()


The method you are trying to call is not defined, which can result in a fatal error.

Comment thread tests/phpunit/misc/test_FrmGatedContentController.php Outdated
* @covers FrmGatedContentController::trigger
*/
public function test_payment_success_event_skips_non_matching_action() {
$form_id = $this->factory->form->create();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Access to an undefined property test_FrmGatedContentController::$factory


The property you are trying to access is not defined and will cause unexpected behavior when used.

*/
public function test_payment_success_event_skips_non_matching_action() {
$form_id = $this->factory->form->create();
$entry_id = $this->factory->entry->create( array( 'form_id' => $form_id ) );

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Access to an undefined property test_FrmGatedContentController::$factory


The property you are trying to access is not defined and will cause unexpected behavior when used.


FrmFormActionsController::trigger_actions( 'payment-success', $form_id, $entry_id );

$this->assertNull(

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Call to an undefined method test_FrmGatedContentController::assertNull()


The method you are trying to call is not defined, which can result in a fatal error.

Comment thread classes/views/frm-form-actions/_gated_content_item_row.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
Comment thread classes/controllers/FrmFormsController.php
Comment thread classes/controllers/FrmGatedContentController.php Outdated
Comment thread classes/models/FrmGatedToken.php Outdated
Comment thread classes/views/frm-form-actions/_gated_content_item_row.php Outdated
Comment thread classes/views/frm-form-actions/_gated_content_item_row.php Outdated
Comment thread js/src/admin/admin.js Outdated
Comment thread js/src/admin/admin.js Outdated
Comment thread tests/phpunit/helpers/test_FrmGatedTokenHelper.php Outdated
Comment thread tests/phpunit/helpers/test_FrmGatedTokenHelper.php Outdated
Comment thread .htaccess
Comment thread classes/helpers/FrmGatedTokenHelper.php Outdated
*/
private static function get_token_transient_key( $action_id ) {
$user_id = get_current_user_id();
$scope = $user_id ? (string) $user_id : hash( 'sha256', FrmAppHelper::get_ip_address() );

@Crabcyborg Crabcyborg Jun 30, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

@truongwp People on the same internet network could use the same IP address.

Is there more we can add here to help ensure uniqueness? Like user agent?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

If we add the user agent check, the same user using different browsers won't work.

);

$this->assertNotNull( $row, 'Token row not found in DB.' );
$this->assertSame( $this->action_id, (int) $row->action_id );

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Call to an undefined method test_FrmGatedTokenHelper::assertSame()


The method you are trying to call is not defined, which can result in a fatal error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants