Skip to content

Usage tracking for test mode in Lite - #2941

Merged
Crabcyborg merged 7 commits into
masterfrom
test-mode-usage-tracking
Aug 7, 2026
Merged

Usage tracking for test mode in Lite#2941
Crabcyborg merged 7 commits into
masterfrom
test-mode-usage-tracking

Conversation

@truongwp

@truongwp truongwp commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

This tracks the number of times user views the test mode without the add-on installed and with the chat form.

This is tracked in the flows data with the format:

[view_test_mode] => Array
    (
        [no_addon] => 1
        [chat_form] => 2
    )

Summary by CodeRabbit

  • Enhancements
    • Test mode now records views of chat-enabled forms.
    • Test mode now records when the required addon is unavailable.
  • New Features
    • The Test Mode interface now supports additional form-action controls, allowing extended actions to appear alongside the enabled form actions.
  • Documentation
    • Clarified usage tracking behavior for test mode activity.

@coderabbitai

coderabbitai Bot commented Feb 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds usage tracking for chat-form and missing-addon test-mode views. Adds a frm_testmode_form_actions action hook to the enabled form actions container.

Changes

Test mode UI & usage tracking

Layer / File(s) Summary
Test-mode usage tracking
classes/controllers/FrmTestModeController.php, classes/controllers/FrmUsageController.php
Records view_test_mode events for chat forms and unavailable test mode addons. Clarifies the update_flows_data docblock.
Test-mode form actions extension hook
classes/views/test-mode/container.php
Adds do_action( 'frm_testmode_form_actions', $form_actions ) inside the enabled form actions container.

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

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding usage tracking for test mode in the Lite version.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% 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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test-mode-usage-tracking

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 Feb 5, 2026

Copy link
Copy Markdown

DeepSource Code Review

We reviewed changes in f0b2e9e...31d79d9 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 Aug 7, 2026 7:54p.m. Review ↗
JavaScript Aug 7, 2026 7:54p.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.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@classes/controllers/FrmUsageController.php`:
- Line 18: The class constant declaration "private const FLOWS_ACTION_NAME" in
FrmUsageController causes a PHP 7.0 parse error because visibility on constants
is supported only from PHP 7.1; change the declaration to a plain const
FLOWS_ACTION_NAME (remove the "private" visibility) inside the
FrmUsageController class (or alternatively update project PHP requirement to
>=7.1), ensuring all references to FLOWS_ACTION_NAME continue to work.

Comment thread classes/controllers/FrmUsageController.php Outdated
@truongwp truongwp removed the run tests label Feb 5, 2026
@truongwp
truongwp requested a review from Crabcyborg February 5, 2026 15:32
?>
</select>

<?php

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 This is for the add-on tracking?

Can we add a new hook here instead so we can move this logic into the add-on?

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.

Can we use $enabled to check, like we did with other test mode add-on features?

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 Like the hook is only called if $enabled is true?

That would be fine.

Otherwise I'm not sure if I follow.

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.

@Crabcyborg No. I meant we won't need to add a hook there, just check if ( $enabled ) { foreach ... }. Because that file contains many test mode add-ons code.

@Crabcyborg Crabcyborg Jun 3, 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

I just think there's a difference.

This file is intended to use the whole UI, as it's shown in Lite as disabled placeholders.

And these inputs are only used when the add-on is actually active, and have no visual benefit for being in Lite.

Since they only impact the add-on, it would be nice if we only needed to modify the add-on when we needed to make changes.

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.

Ok. I added the hook and moved the code to the add-on.

*
* @param array $form_actions
*/
do_action( 'frm_testmode_form_actions', $form_actions );

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Variable $form_actions might not be defined


A variable has been used but not defined, which may result in warnings during program execution. This can also cause bugs since the intended usage scope of the variable is not known.

@Crabcyborg Crabcyborg added this to the 6.32 milestone Jun 4, 2026
@Crabcyborg Crabcyborg modified the milestones: 6.32, 6.33 Jun 16, 2026
@Crabcyborg Crabcyborg modified the milestones: 6.33, 6.34 Jul 14, 2026
@Crabcyborg Crabcyborg modified the milestones: 6.34, 6.35 Aug 7, 2026

@Crabcyborg Crabcyborg left a comment

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.

Thank you @truongwp!

🚀

@Crabcyborg Crabcyborg modified the milestones: 6.35, 6.34 Aug 7, 2026
@coderabbitai

coderabbitai Bot commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Note

GitHub couldn't provide a complete incremental comparison for this pull request, so CodeRabbit is performing a full review instead. This review may take a little longer.

@coderabbitai coderabbitai Bot left a comment

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.

Actionable comments posted: 2

🤖 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/controllers/FrmTestModeController.php`:
- Around line 99-100: Make the usage-counter update invoked by
FrmUsageController::update_flows_data concurrency-safe by replacing its separate
read/increment/write sequence with an atomic increment or concurrency-safe
storage operation. Preserve both view_test_mode call sites in
FrmTestModeController while ensuring concurrent events cannot overwrite each
other or undercount the counter.
- Around line 99-100: Update the test-mode tracking in FrmTestModeController
around render_testing_mode_container() so
FrmUsageController::update_flows_data() runs only for the initial preview
request, not AJAX error redraws or success renders. Use the existing request
context or preview-specific condition to gate the 'view_test_mode'/'chat_form'
update while preserving the container rendering behavior.
🪄 Autofix

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: d05c1fed-a227-4066-b5b4-f84aab1dbe2f

📥 Commits

Reviewing files that changed from the base of the PR and between f0b2e9e and 31d79d9.

📒 Files selected for processing (3)
  • classes/controllers/FrmTestModeController.php
  • classes/controllers/FrmUsageController.php
  • classes/views/test-mode/container.php
🚧 Files skipped from review as they are similar to previous changes (2)
  • classes/controllers/FrmUsageController.php
  • classes/views/test-mode/container.php

Comment on lines +99 to +100
// Track view test mode with chat form.
FrmUsageController::update_flows_data( 'view_test_mode', 'chat_form' );

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.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Make usage-counter updates concurrency-safe.

At Lines [99-100] and [148-151], both new events use FrmUsageController::update_flows_data(). That method reads the flows option, increments the value, and writes it back in separate operations. Concurrent test-mode views can overwrite each other and undercount view_test_mode.

Update the counter atomically, or use storage that supports concurrent increments, before relying on these new call sites.

Also applies to: 148-151

🧰 Tools
🪛 ast-grep (0.45.0)

[warning] 100-100: Avoid side effects in a file that defines symbols
Context: echo '

' . esc_html__( 'Test Mode is currently not supported for conversational forms.', 'formidable' ) . '
';
Note: [CWE-710] Improper Adherence to Coding Standards.

(no-side-effect)

🤖 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/FrmTestModeController.php` around lines 99 - 100, Make
the usage-counter update invoked by FrmUsageController::update_flows_data
concurrency-safe by replacing its separate read/increment/write sequence with an
atomic increment or concurrency-safe storage operation. Preserve both
view_test_mode call sites in FrmTestModeController while ensuring concurrent
events cannot overwrite each other or undercount the counter.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 5 \
  -e "frm_test_mode" \
  -e "maybe_add_test_mode_container" \
  -e "render_testing_mode_container" \
  --glob '*.php' .

Repository: Strategy11/formidable-forms

Length of output: 10698


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== FrmFormsController load hook section =="
sed -n '490,550p' classes/controllers/FrmFormsController.php

echo
echo "== FrmTestModeController relevant method sections =="
sed -n '1,180p' classes/controllers/FrmTestModeController.php

echo
echo "== Ajax references to frm_filter_final_form and test mode =="
rg -n -C 3 \
  -e "frm_filter_final_form" \
  -e "testmode|test_mode" \
  -e "do_action\\(\\s*['\"]wp_ajax_" \
  --glob '*.php' classes || true

echo
echo "== Action/filter registration and AJAX callback candidates =="
rg -n -C 4 \
  -e "add_action\\(\\s*['\"]wp_ajax|add_filter\\(\\s*['\"]wp_ajax" \
  -e "FrmFormsController::" \
  --glob '*.php' classes/controllers classes || true

Repository: Strategy11/formidable-forms

Length of output: 50384


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== Formidable testmode URL/query references in JS =="
rg -n -C 3 \
  -e "testmode|/testmode|frm_test_mode|frm_forms_preview|iframe|src|new URL|URL\\(" \
  --glob '*.js' --glob '*.php' --glob '*.jsx' --glob '*.tsx' .

echo
echo "== frm_filter_final_form usages =="
rg -n -C 2 'frm_filter_final_form' --glob '*.php' .

echo
echo "== FrmFormsController render show_form outline/sections =="
ast-grep outline classes/controllers/FrmFormsController.php --match show_form --view expanded || true
sed -n '2460,2555p' classes/controllers/FrmFormsController.php

Repository: Strategy11/formidable-forms

Length of output: 50384


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== frm_filter_final_form usages (limited) =="
rg -n \
  -e "frm_filter_final_form" \
  --glob '*.php' classes .

echo
echo "== Targeted testmode query-string references in PHP source =="
rg -n \
  -e "testmode|frm_forms_preview|frm_forms_trash|wp_ajax_nopriv|wp_ajax_.*preview" \
  --glob '*.php' classes/controllers/FrmFormsController.php classes/controllers/FrmHooksController.php

echo
echo "== FrmEntriesAJAXSubmitController ajax hook =="
sed -n '1,120p' classes/controllers/FrmEntriesAJAXSubmitController.php || true

Repository: Strategy11/formidable-forms

Length of output: 5969


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== Show form and route relevant sections =="
rg -n \
  -e "public static function show_form|public static function route|function get_form_shortcode" \
  classes/controllers/FrmFormsController.php

sed -n '1980,2100p' classes/controllers/FrmFormsController.php
sed -n '2480,2545p' classes/controllers/FrmFormsController.php

echo
echo "== Testmode JS references across tracked JS files only =="
python3 - <<'PY'
import os, pathlib, re
patterns = [re.compile(r'\btestmode\b'), re.compile(r'/testmode\b'), re.compile(r'frm_test_mode\b'), re.compile(r'frm_forms_preview\b')]
for f in pathlib.Path('.').rglob('*'):
    if f.is_file() and f.suffix.lower() in {'.js','.jsx','.ts','.tsx'} and '.git' not in f.parts:
        try:
            text = f.read_text(encoding='utf-8')
        except Exception:
            continue
        if any(p.search(text) for p in patterns):
            print(f)
PY

echo
echo "== Minimal deterministic filter call probe =="
python3 - <<'PY'
# Reads the controller source and reports hook context around each apply_filter/add_filter call for frm_filter_final_form.
from pathlib import Path
p = Path('classes/controllers/FrmFormsController.php')
lines = p.read_text().splitlines()
for i,l in enumerate(lines, 1):
    if 'frm_filter_final_form' in l:
        start=max(1,i-4); end=min(len(lines),i+4)
        print(f'--- lines {start}-{end} ---')
        for n in range(start,end+1):
            print(f'{n}: {lines[n-1]}')
PY

Repository: Strategy11/formidable-forms

Length of output: 7116


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== Testmode JS references with line numbers =="
python3 - <<'PY'
import os, pathlib, re
source_paths = [p for p in pathlib.Path('.').rglob('*') if p.is_file() and p.suffix.lower() in {'.js','.jsx','.ts','.tsx'} and '.git' not in p.parts]
for f in source_paths:
    try:
        lines = f.read_text(encoding='utf-8').splitlines()
    except Exception:
        continue
    hits = [i for i,l in enumerate(lines, 1) if any(x in l for x in ('testmode','/testmode','frm_test_mode','frm_forms_preview'))]
    if hits:
        print(f'FILE: {f}')
        for i in hits:
            print(f'{i}: {lines[i-1]}')
PY

echo
echo "== Full route/show_form call path around preview AJAX =="
sed -n '2159,2260p' classes/controllers/FrmFormsController.php
sed -n '2495,2555p' classes/controllers/FrmFormsController.php

Repository: Strategy11/formidable-forms

Length of output: 50384


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== Ajax form action and testmode URL generation =="
sed -n '1005,1075p' js/formidable.js
sed -n '1020,1065p' js/formidable.min.js

echo
echo "== Ajax preview form generation in PHP controllers/helpers =="
rg -n -C 4 \
  -e "do_action\\(\\s*['\"]wp_ajax_|register_ajax|ajax_hooks|frm_after_form" \
  --glob '*.php' classes/js classes/controllers classes || true

echo
echo "== Formidable core register_ajax occurrences =="
rg -n -C 3 \
  -e "register_ajax|add_action\\(\\s*['\"]wp_ajax_|add_filter\\(\\s*['\"]wp_ajax_" \
  --glob '*.php' classes/controllers/FrmFormsController.php classes/helpers/FrmFormsHelper.php 2>/dev/null || true

Repository: Strategy11/formidable-forms

Length of output: 5403


Gate test-mode usage tracking to preview-only requests.

The frm_filter_final_form listener runs from show_form(), which is used by ajax preview, error redraws, and AJAX success returns. Those repeated AJAX renders also hit render_testing_mode_container() when testmode is present, so each render can increment view_test_mode. Track only the initial preview render, or gate the update by request context.

🧰 Tools
🪛 ast-grep (0.45.0)

[warning] 100-100: Avoid side effects in a file that defines symbols
Context: echo '

' . esc_html__( 'Test Mode is currently not supported for conversational forms.', 'formidable' ) . '
';
Note: [CWE-710] Improper Adherence to Coding Standards.

(no-side-effect)

🤖 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/FrmTestModeController.php` around lines 99 - 100, Update
the test-mode tracking in FrmTestModeController around
render_testing_mode_container() so FrmUsageController::update_flows_data() runs
only for the initial preview request, not AJAX error redraws or success renders.
Use the existing request context or preview-specific condition to gate the
'view_test_mode'/'chat_form' update while preserving the container rendering
behavior.

@Crabcyborg
Crabcyborg merged commit cb79093 into master Aug 7, 2026
32 of 34 checks passed
@Crabcyborg
Crabcyborg deleted the test-mode-usage-tracking branch August 7, 2026 20:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants