Skip to content

root web component, make tab navigator accessible as web component#2502

Merged
Crabcyborg merged 20 commits into
masterfrom
feature/make-style-elements-accessbile-as-web-components
Jan 5, 2026
Merged

root web component, make tab navigator accessible as web component#2502
Crabcyborg merged 20 commits into
masterfrom
feature/make-style-elements-accessbile-as-web-components

Conversation

@Liviu-p
Copy link
Copy Markdown
Contributor

@Liviu-p Liviu-p commented Sep 22, 2025

@Liviu-p Liviu-p changed the title cleanup, removed unused functions, check when the web component is vi… root web component, make tab navigator accessible as web component Sep 22, 2025
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Sep 22, 2025

Warning

Rate limit exceeded

@Crabcyborg has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 15 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 47ef7f6 and 29e5cc4.

📒 Files selected for processing (1)
  • classes/controllers/FrmFormsController.php

Walkthrough

This PR introduces a new web components module for tab navigation and refactors admin script dependency management. It adds a private helper function in FrmAppController for centralizing script dependencies, extends FrmFormsController with an optional template path parameter, establishes a web components base class infrastructure with a tab navigator component, and updates build configuration to support web components bundling.

Changes

Cohort / File(s) Summary
Script Dependency Management
classes/controllers/FrmAppController.php
Added private static get_admin_js_dependencies() helper to centralize JavaScript dependencies for admin assets; registered new formidable-web-components script with dependency on formidable_admin.
Template Configuration
classes/controllers/FrmFormsController.php
Extended mb_tags_box() with optional $template_path parameter (default: 'default') to allow custom template files; updated rendering logic to conditionally include custom or default templates.
Web Components Base Infrastructure
js/src/web-components/frm-web-component.js
Added abstract base class frmWebComponent extending HTMLElement with lifecycle hooks (initOptions, loadStyle, render, afterViewInit), shadow DOM support, and visibility gating via IntersectionObserver.
Web Components Bundled Module
js/formidable-web-components.js
New self-contained module exporting frmWebComponent, frmTabsNavigator (tab strip logic with RTL support), and frmTabNavigatorComponent (composed web component); includes embedded CSS for tab layout and animations.
Tab Navigator Component
js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js
Added frmTabNavigatorComponent class with 10 methods (initView, afterViewInit, setInitialUnderlineWidth, getTabDelimiter, getTabs, getTabContainer, createTabHeading, createTabContainer, getTabUnderline) to construct and manage tab UI structure.
Tab Navigator Styling
js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.css, js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.scss
New stylesheets defining flex-based tab layout, active state styling, underline animations, slide-track transitions, and responsive/RTL-aware positioning for tab navigator component.
Web Components Registration
js/src/web-components/index.js
Imports frmTabNavigatorComponent and registers it as custom element frm-tab-navigator-component via customElements.define().
Build Configuration
webpack.config.js
Added glob-based dynamic SCSS entries for web components; registered new formidable-web-components entry pointing to ./js/src/web-components/index.js; extended CSS handling to process -component.css files separately with raw-loader.
Admin Styling Update
resources/scss/admin/components/panel/_options-panel.scss
Extended selector from #frm-options-panel h3 to include .frm-collapsible class to apply consistent heading/panel styling.
Admin Public API
js/src/admin/admin.js
Exposed maybeCollapseSettings method in the public interface of frmAdminBuildJS export.
Ignore Configuration
.eslintignore
Added js/formidable-web-components.js to ESLint ignore list.

Sequence Diagram(s)

sequenceDiagram
    participant DOM as DOM Tree
    participant Component as frmTabNavigatorComponent
    participant WebComp as frmWebComponent
    participant Observer as IntersectionObserver
    participant Renderer as DOM Renderer

    DOM->>Component: connectedCallback()
    Component->>WebComp: render()
    WebComp->>Component: initView()
    Component->>Renderer: Build wrapper, headings, containers
    Renderer->>WebComp: Append style + view to shadowRoot
    WebComp->>Observer: whenElementBecomesVisible()
    Observer->>Observer: Wait for visibility
    Observer->>WebComp: Element visible
    WebComp->>Component: afterViewInit(wrapper)
    Component->>Component: setInitialUnderlineWidth(wrapper)
    Component->>DOM: Set underline width on active tab
    Renderer->>DOM: Complete render cycle
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested labels

action: needs qa

Suggested reviewers

  • lauramekaj1

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately describes the main objective of the PR: creating a root web component and making a tab navigator accessible as a web component, which aligns with the significant new files (frmWebComponent base class, frmTabNavigatorComponent, web component infrastructure) and config changes.
Description check ✅ Passed The description is directly related to the changeset, mentioning the addition of a new tab navigator style for mb_adv_info and referencing a related PR, which connects to the new tab navigator web component implementation and FrmFormsController changes.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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 and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 9

🧹 Nitpick comments (16)
js/src/web-components/index.js (1)

1-3: Guard against double registration of custom element.

customElements.define throws if the tag is already defined (can happen with duplicated enqueues or if Pro also registers). Add a defensive check.

Apply:

 import { frmTabNavigatorComponent } from './frm-tab-navigator-component/frm-tab-navigator-component';

-customElements.define( 'frm-tab-navigator-component', frmTabNavigatorComponent );
+const TAG = 'frm-tab-navigator-component';
+if ( window.customElements && ! customElements.get( TAG ) ) {
+	customElements.define( TAG, frmTabNavigatorComponent );
+}
css/admin/frm-settings-components.js (1)

1-6: Remove empty webpack JS stub css/admin/frm-settings-components.js

No-op bootstrap emitted for the SCSS-only webpack entry and unused. Evidence: webpack.config.js defines the SCSS entry 'admin/frm-settings-components' -> resources/scss/admin/frm-settings-components.scss (webpack.config.js:42); the repo tracks css/admin/frm-settings-components.js but ripgrep finds no references; FrmAppController only registers the CSS (css/admin/frm-settings-components.css) at classes/controllers/FrmAppController.php:803. Delete css/admin/frm-settings-components.js and configure webpack/MiniCssExtractPlugin to avoid emitting JS stubs for CSS-only entries; verify nothing enqueues that JS.

css/font_icons.js (1)

1-6: Remove css/font_icons.js (empty webpack bootstrap)

css/font_icons.js is an empty webpack bootstrap (104 bytes) and unreferenced; the SCSS entry is resources/scss/font_icons.scss → css/font_icons.css (enqueued in classes/controllers/FrmElementorController.php). Delete css/font_icons.js and adjust webpack.config.js (around lines ~138–142 — RemoveEmptyScriptsPlugin / MiniCssExtractPlugin) to prevent emitting JS for SCSS-only entries.

css/frm_admin.js (1)

1-6: Delete stray empty webpack bootstrap JS emitted next to CSS.
css/frm_admin.js contains only an empty webpack bootstrap wrapper (small autogenerated) — delete the file and update the build config so SCSS entries don’t emit JS.

resources/scss/admin/components/panel/_options-panel.scss (1)

60-65: Respect reduced‑motion users.

Disable transitions when prefers-reduced-motion is set.

Apply this diff:

   &:hover {
     color: var(--grey-700);
     background-color: #fff;
     box-shadow: var(--box-shadow-sm);
   }
 }
+
+@media (prefers-reduced-motion: reduce) {
+  #frm-options-panel h3,
+  .frm-collapsible {
+    transition: none;
+  }
+  #frm-options-panel h3 .frmsvg,
+  .frm-collapsible .frmsvg {
+    transition: none;
+  }
+}
classes/controllers/FrmFormsController.php (1)

1608-1608: Document and suppress the “unused” $class param (used by included views).

Prevents PHPMD noise while clarifying intent.

Apply this diff:

-	public static function mb_tags_box( $form_id, $class = '', $template = 'default' ) {
+	/**
+	 * Render the advanced info box.
+	 *
+	 * @param int|string $form_id
+	 * @param string     $class    Used by included templates for additional CSS classes.
+	 * @param string     $template 'default'|'new-tab-navigator'
+	 *
+	 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+	 */
+	public static function mb_tags_box( $form_id, $class = '', $template = 'default' ) {
js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.css (1)

103-130: Honor prefers‑reduced‑motion and add focus visibility.

Small a11y win; avoids unnecessary animation.

Apply this diff:

 .frm-tabs-slide-track > div.frm-active {
   opacity: 1;
   transition: 0.35s opacity linear;
 }
+
+@media (prefers-reduced-motion: reduce) {
+  .frm-tabs-slide-track { transition: none; }
+  .frm-tabs-delimiter .frm-tabs-active-underline { transition: none; }
+}
+
+.frm-tabs-navs ul li:focus-visible {
+  outline: 2px solid var(--primary-500);
+  outline-offset: 2px;
+}
webpack.config.js (2)

104-111: Prefer webpack 5 asset modules over raw-loader.

Removes an extra dependency and aligns with modern webpack.

Apply this diff:

-      {
-        test: /\.css$/i,
-        use: ['style-loader', 'css-loader'],
-		exclude: /-component\.css$/
-      },
-	  {
-		test: /-component\.css$/i,
-		use: ['raw-loader']
-	  },
+      {
+        test: /\.css$/i,
+        use: ['style-loader', 'css-loader'],
+        exclude: /-component\.css$/i
+      },
+      {
+        test: /-component\.css$/i,
+        type: 'asset/source'
+      },

106-106: Case-insensitive exclude.

Match the -component.css pattern regardless of case.

Apply this diff:

-		exclude: /-component\.css$/
+		exclude: /-component\.css$/i
js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js (2)

96-99: Add basic ARIA/keyboard affordances to tabs.

Enables tab focus and assists screen readers.

Apply this diff:

-		return `<li class="${className}">${tab.getAttribute( 'data-tab-title' )}</li>`;
+		return `<li class="${className}" role="tab" aria-selected="${index === 0}" tabindex="0">${tab.getAttribute( 'data-tab-title' )}</li>`;

118-120: Handle non‑shadow DOM in getTabUnderline().

Prevents null dereference when data-shadow-dom="false".

Apply this diff:

-		return this.shadowRoot.querySelector( '.frm-tabs-active-underline' );
+		const root = this.useShadowDom ? this.shadowRoot : this;
+		return root ? root.querySelector( '.frm-tabs-active-underline' ) : null;
js/src/web-components/frm-web-component.js (2)

24-26: Guard against undefined componentStyle.

Avoid inserting the literal string "undefined" into the DOM.

-		style.textContent = this.componentStyle;
+		style.textContent = this.componentStyle || '';

20-22: Correct JSDoc return type.

The method returns a style element, not a string.

-	* @return string
+	* @return {HTMLStyleElement}
js/formidable-web-components.js (3)

206-207: Remove hard-coded data-initial-width="123".

This causes a visible jump and magic number. Compute from the active tab or omit and let afterViewInit set it.

-      return "<div class=\"frm-tabs-delimiter\">\n\t\t\t<span data-initial-width=\"123\" class=\"frm-tabs-active-underline frm-first\"></span>\n\t\t</div>";
+      return "<div class=\"frm-tabs-delimiter\">\n\t\t\t<span class=\"frm-tabs-active-underline frm-first\"></span>\n\t\t</div>";

268-271: getTabUnderline breaks without Shadow DOM.

Query the correct root based on data-shadow-dom.

-      return this.shadowRoot.querySelector('.frm-tabs-active-underline');
+      var root = this.useShadowDom ? this.shadowRoot : this;
+      return root.querySelector('.frm-tabs-active-underline');

57-58: Unnecessary preventDefault on

  • clicks.

    No default action to prevent; safe to remove.

  • 📜 Review details

    Configuration used: CodeRabbit UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between eb8e9f7 and 45a4550.

    ⛔ Files ignored due to path filters (2)
    • js/formidable-settings-components.js.map is excluded by !**/*.map, !**/*.map
    • package.json is excluded by !**/*.json
    📒 Files selected for processing (14)
    • classes/controllers/FrmAppController.php (1 hunks)
    • classes/controllers/FrmFormsController.php (2 hunks)
    • classes/views/shared/mb_adv_info_new.php (1 hunks)
    • css/admin/frm-settings-components.js (1 hunks)
    • css/font_icons.js (1 hunks)
    • css/frm_admin.js (1 hunks)
    • js/formidable-web-components.js (1 hunks)
    • js/formidable_admin.js (1 hunks)
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.css (1 hunks)
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js (1 hunks)
    • js/src/web-components/frm-web-component.js (1 hunks)
    • js/src/web-components/index.js (1 hunks)
    • resources/scss/admin/components/panel/_options-panel.scss (1 hunks)
    • webpack.config.js (2 hunks)
    🧰 Additional context used
    🧬 Code graph analysis (7)
    classes/controllers/FrmFormsController.php (2)
    js/admin/applications.js (1)
    • template (54-54)
    classes/helpers/FrmAppHelper.php (2)
    • FrmAppHelper (6-4622)
    • plugin_path (58-60)
    js/src/web-components/frm-web-component.js (1)
    webpack.config.js (1)
    • entries (26-45)
    js/src/web-components/index.js (1)
    js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js (1)
    • frmTabNavigatorComponent (5-122)
    classes/controllers/FrmAppController.php (1)
    classes/helpers/FrmAppHelper.php (1)
    • plugin_url (65-68)
    js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js (2)
    js/src/web-components/frm-web-component.js (1)
    • frmWebComponent (1-107)
    js/src/components/class-tabs-navigator.js (1)
    • frmTabsNavigator (1-89)
    classes/views/shared/mb_adv_info_new.php (6)
    classes/helpers/FrmAppHelper.php (2)
    • FrmAppHelper (6-4622)
    • show_search_box (1536-1591)
    classes/models/FrmField.php (2)
    • FrmField (6-1501)
    • is_no_save_field (1168-1170)
    classes/helpers/FrmFormsHelper.php (3)
    • FrmFormsHelper (6-1999)
    • insert_opt_html (615-665)
    • insert_code_html (686-709)
    classes/helpers/FrmHtmlHelper.php (2)
    • FrmHtmlHelper (9-124)
    • echo_dropdown_option (50-57)
    classes/helpers/FrmShortcodeHelper.php (2)
    • FrmShortcodeHelper (9-141)
    • get_contextual_codes (73-80)
    classes/controllers/FrmFormsController.php (1)
    • advanced_helpers (1640-1670)
    js/formidable-web-components.js (1)
    webpack.config.js (1)
    • entries (26-45)
    🪛 PHPMD (2.15.0)
    classes/controllers/FrmFormsController.php

    1608-1608: Avoid unused parameters such as '$class'. (undefined)

    (UnusedFormalParameter)

    🪛 Biome (2.1.2)
    js/formidable-web-components.js

    [error] 15-15: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 135-135: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 144-144: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 145-145: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 147-147: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 287-287: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 297-297: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 299-299: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 301-301: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 302-302: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)

    🔇 Additional comments (9)
    js/formidable_admin.js (1)

    11333-11333: Public export looks good; mind the this binding.

    maybeCollapseSettings relies on this being the collapsible header element. When exposing it publicly, ensure external code calls it as an event handler (e.g., el.addEventListener('click', frmAdminBuild.maybeCollapseSettings)) or with .call(el, event) to maintain the expected context.

    Optionally harden the export to accept an explicit context:

    -        maybeCollapseSettings,
    +        // Preserve expected context whether used as a listener or called directly.
    +        maybeCollapseSettings: function(ctx) {
    +          return ctx ? maybeCollapseSettings.call(ctx) : maybeCollapseSettings.call(this);
    +        },

    Please confirm the new web component uses it with the correct context (listener or .call), so this.classList and this.nextElementSibling remain valid.

    resources/scss/admin/components/panel/_options-panel.scss (1)

    12-13: Selector expansion LGTM.

    Including .frm-collapsible shares styling consistently with panel headings.

    js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.css (1)

    1-130: Solid base styles for the tab navigator.

    Structure and state styles read well.

    webpack.config.js (2)

    37-38: New entry looks correct and matches the admin registration.


    1-175: Verify raw-loader availability

    • webpack.config.js (root) contains a rule matching /-component.css$/i that uses "raw-loader".
    • No package.json found in the repo root to confirm the dependency — either add "raw-loader" to devDependencies or remove/replace its usage (e.g., use webpack asset/source) and update the config accordingly.
    classes/controllers/FrmFormsController.php (1)

    1608-1635: Template switch is safe and backward compatible

    Search found one call site: classes/views/frm-forms/mb_insert_fields.php (line 9) — it calls mb_tags_box($id) so the default template remains in use. No change required; to opt this view into the new template, call mb_tags_box($id, '', 'new-tab-navigator').

    classes/views/shared/mb_adv_info_new.php (1)

    6-6: Verify ID uniqueness for taxonomy-linkcategory.

    This ID is common in WP admin. Ensure no duplicate IDs exist on the page to avoid CSS/JS collisions.

    js/formidable-web-components.js (2)

    354-356: afterViewInit receives the host, not the wrapper (mirrors src bug).

    This is the compiled artifact of the base-class issue; fix in src and rebuild.


    391-393: IntersectionObserver observing ShadowRoot (compiled).

    Same as src: observe the host element; fix in src and rebuild.

    Comment thread classes/controllers/FrmAppController.php
    Comment thread classes/views/shared/mb_adv_info_new.php Outdated
    Comment thread js/formidable-web-components.js Outdated
    Comment thread js/formidable-web-components.js Outdated
    Comment thread js/formidable-web-components.js Outdated
    Comment thread js/src/web-components/frm-web-component.js
    Comment thread js/src/web-components/frm-web-component.js Outdated
    Comment thread classes/controllers/FrmFormsController.php Outdated
    Copy link
    Copy Markdown
    Contributor

    @coderabbitai coderabbitai Bot left a comment

    Choose a reason for hiding this comment

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

    Actionable comments posted: 0

    🧹 Nitpick comments (2)
    js/src/admin/admin.js (1)

    11429-11429: Public API relies on this binding; make it safe to call imperatively.

    maybeCollapseSettings expects this to be the header element. As a public export, calling it directly (e.g., frmAdminBuild.maybeCollapseSettings()) or passing it around can throw (no classList on the wrong this). Either document usage (“use as an event handler or call with .call(el)”) or make it accept an argument and fall back to this.

    Apply this refactor to make it robust for both event handler and direct calls:

    -	function maybeCollapseSettings() {
    -		/*jshint validthis:true */
    -		this.classList.toggle( 'frm-collapsed' );
    -
    -		// Toggles the "aria-expanded" attribute
    -		const expanded = this.getAttribute( 'aria-expanded' ) === 'true' || false;
    -		this.setAttribute( 'aria-expanded', ! expanded );
    -
    -		addSlideAnimationCssVars( this.nextElementSibling );
    -	}
    +	/**
    +	 * Toggle settings section collapse (safe for event handlers and direct calls).
    +	 * @param {Event|HTMLElement} targetOrEvent
    +	 */
    +	function maybeCollapseSettings( targetOrEvent ) {
    +		/*jshint validthis:true */
    +		const el = (this && this.nodeType === 1)
    +			? this
    +			: (targetOrEvent && (targetOrEvent.currentTarget || targetOrEvent.target || targetOrEvent));
    +		if ( ! el || ! el.classList ) {
    +			return;
    +		}
    +		el.classList.toggle( 'frm-collapsed' );
    +		const expanded = el.getAttribute( 'aria-expanded' ) === 'true';
    +		el.setAttribute( 'aria-expanded', String( ! expanded ) );
    +		addSlideAnimationCssVars( el.nextElementSibling );
    +	}

    Please confirm new call sites (e.g., in web components) either:

    • add listeners: header.addEventListener('click', frmAdminBuild.maybeCollapseSettings), or
    • call imperatively: frmAdminBuild.maybeCollapseSettings(headerEl).
    classes/controllers/FrmFormsController.php (1)

    1608-1608: Update docblock for new param and suppress PHPMD for $class

    Document $template_path and suppress the UnusedFormalParameter warning since $class may be consumed in the included template.

    -	/**
    -	 * @param int|string $form_id
    -	 * @param string     $class
    -	 * @return void
    -	 */
    +	/**
    +	 * @param int|string $form_id
    +	 * @param string     $class         CSS class passed through to the included template.
    +	 * @param string     $template_path Absolute path to a PHP template to include; pass 'default' (or empty) to use core template.
    +	 * @return void
    +	 * @SuppressWarnings(PHPMD.UnusedFormalParameter)
    +	 */
     	public static function mb_tags_box( $form_id, $class = '', $template_path = 'default' ) {
    📜 Review details

    Configuration used: CodeRabbit UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between 2925c79 and 2e6a8a8.

    ⛔ Files ignored due to path filters (1)
    • js/formidable-settings-components.js.map is excluded by !**/*.map, !**/*.map
    📒 Files selected for processing (2)
    • classes/controllers/FrmFormsController.php (2 hunks)
    • js/src/admin/admin.js (1 hunks)
    🧰 Additional context used
    🧬 Code graph analysis (1)
    classes/controllers/FrmFormsController.php (1)
    classes/helpers/FrmAppHelper.php (2)
    • FrmAppHelper (6-4623)
    • plugin_path (58-60)
    🪛 PHPMD (2.15.0)
    classes/controllers/FrmFormsController.php

    1608-1608: Avoid unused parameters such as '$class'. (undefined)

    (UnusedFormalParameter)

    🔇 Additional comments (1)
    classes/controllers/FrmFormsController.php (1)

    1629-1635: Harden template_path handling to avoid LFI and brittle includes

    Finding: only call site in this repo is classes/views/frm-forms/mb_insert_fields.php:9 — FrmFormsController::mb_tags_box($id) — no third arg passed, so current risk is low.
    Action: apply the proposed hardening (use realpath, restrict to allowed dirs, require .php) and add the path_is_in_allowed_dirs helper as suggested.
    Verify: confirm Views add‑on or any other add‑ons do not call mb_tags_box with user-controlled paths; if they must, require absolute plugin paths or extend frm_tags_box_allowed_template_dirs via the provided filter.

    Comment thread js/src/web-components/frm-web-component.js Outdated
    Comment thread js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js Outdated
    Comment thread js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js Outdated
    …webpack to compile the scss to css files that may be available in web-components folder
    Copy link
    Copy Markdown
    Contributor

    @coderabbitai coderabbitai Bot left a comment

    Choose a reason for hiding this comment

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

    Actionable comments posted: 4

    🧹 Nitpick comments (2)
    js/formidable-web-components.js (2)

    1-1: Avoid magic width "123" for underline.

    Remove hardcoded data-initial-width; fallback to first tab width.

    Apply in src and rebuild:

    -  getTabDelimiter() {
    -    var wrap = document.createElement('div'), underline = document.createElement('span');
    -    underline.setAttribute('data-initial-width', '123');
    +  getTabDelimiter() {
    +    var wrap = document.createElement('div'), underline = document.createElement('span');
         underline.classList.add('frm-tabs-active-underline', 'frm-first');
         wrap.className = 'frm-tabs-delimiter';
         wrap.appendChild(underline);
         return wrap;
       }
    -  initDefaultSlideTrackerWidth() {
    -    if (this.slideTrackLine.dataset.initialWidth) {
    -      this.slideTrackLine.style.width = `${this.slideTrackLine.dataset.initialWidth}px`;
    -    }
    -  }
    +  initDefaultSlideTrackerWidth() {
    +    if (this.slideTrackLine.dataset.initialWidth) {
    +      this.slideTrackLine.style.width = `${this.slideTrackLine.dataset.initialWidth}px`;
    +    } else if (this.navs && this.navs.length) {
    +      this.slideTrackLine.style.width = this.navs[0].clientWidth + 'px';
    +    }
    +  }

    1-1: Resilience: Recalculate underline on resize.

    Optional but improves UX when admin resizes the window or nav font changes.

    Apply in src and rebuild:

    -  initView() {
    +  initView() {
         this.tabs = this.querySelectorAll('.frm-tab');
         if (this.tabs.length === 0) return null;
         var wrap = document.createElement('div');
         wrap.classList.add('frm-tabs-wrapper');
         wrap.appendChild(this.getTabDelimiter());
         wrap.appendChild(this.getTabs());
         wrap.appendChild(this.getTabContainer());
    -    new TabsNavigator(wrap);
    +    this._tabsNavigator = new TabsNavigator(wrap);
         return wrap;
       }
    -  afterViewInit(wrap) {
    -    this.setInitialUnderlineWidth(wrap);
    -  }
    +  afterViewInit(wrap) {
    +    this.setInitialUnderlineWidth(wrap);
    +    var self = this;
    +    this._onResize = function () {
    +      self.setInitialUnderlineWidth(wrap);
    +      var active = wrap.querySelector('li.frm-active');
    +      if (active && self._tabsNavigator) {
    +        var index = Array.from(wrap.querySelectorAll('.frm-tabs-navs li')).indexOf(active);
    +        self._tabsNavigator.initSlideTrackUnderline(active, index);
    +      }
    +    };
    +    window.addEventListener('resize', this._onResize, { passive: true });
    +  }
    -  disconnectedCallback() {}
    +  disconnectedCallback() {
    +    if (this._onResize) {
    +      window.removeEventListener('resize', this._onResize);
    +      this._onResize = null;
    +    }
    +  }
    📜 Review details

    Configuration used: CodeRabbit UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between 2e6a8a8 and 8714067.

    ⛔ Files ignored due to path filters (2)
    • package-lock.json is excluded by !**/package-lock.json, !**/*.json
    • package.json is excluded by !**/*.json
    📒 Files selected for processing (6)
    • js/formidable-web-components.js (1 hunks)
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.css (1 hunks)
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js (1 hunks)
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.scss (1 hunks)
    • js/src/web-components/frm-web-component.js (1 hunks)
    • webpack.config.js (3 hunks)
    🚧 Files skipped from review as they are similar to previous changes (3)
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.css
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js
    • webpack.config.js
    🧰 Additional context used
    🧬 Code graph analysis (1)
    js/src/web-components/frm-web-component.js (1)
    webpack.config.js (1)
    • entries (37-59)
    🪛 Biome (2.1.2)
    js/formidable-web-components.js

    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: This variable is used before its declaration.

    The variable is declared here:

    (lint/correctness/noInvalidUseBeforeDeclaration)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)


    [error] 1-1: Do not reassign a function declaration.

    Reassigned here.

    Use a local variable instead.

    (lint/suspicious/noFunctionAssign)

    ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
    • GitHub Check: PHP 7.4 tests in WP trunk
    • GitHub Check: PHP 8 tests in WP trunk
    • GitHub Check: Run PHP Syntax inspection (8.3)
    • GitHub Check: Cypress
    🔇 Additional comments (6)
    js/src/web-components/frm-web-component.js (2)

    38-45: Fix afterViewInit root parameter

    When Shadow DOM is active, afterViewInit receives the host element instead of the shadow root, so any DOM queries in subclasses fail. Pass the wrapper you already computed so components can find their content.

    -		this.whenElementBecomesVisible().then( () => {
    -			this.afterViewInit( this );
    -		});
    +		this.whenElementBecomesVisible().then( () => {
    +			this.afterViewInit( wrapper );
    +		});

    72-75: Observe the host element with IntersectionObserver

    IntersectionObserver.observe throws when given a ShadowRoot (it expects an Element/Document), so Shadow DOM components crash here. Just observe the custom element itself; visibility works for both shadow and light DOM cases.

    -			const element = this.useShadowDom ? this.shadowRoot : this;
    -
    -			observer.observe( element );
    +			observer.observe( this );
    js/formidable-web-components.js (4)

    1-1: Fix: NodeList.filter misuse in initSlideTrackUnderline (runtime break).

    .filter() on NodeList returns an array; later treated as an Element. Use Array.from(...).find(...). Add a guard.

    Apply in src and rebuild:

    -  initSlideTrackUnderline(nav, index) {
    -    this.slideTrackLine.classList.remove('frm-first', 'frm-last');
    -    var activeNav = void 0 !== nav ? nav : this.navs.filter(function (nav) {
    -      return nav.classList.contains('frm-active');
    -    });
    -    var x = this.isRTL
    -      ? -(activeNav.parentElement.offsetWidth - activeNav.offsetLeft - activeNav.offsetWidth)
    -      : activeNav.offsetLeft;
    -    this.slideTrackLine.style.transform = `translateX(${x}px)`;
    -    this.slideTrackLine.style.width = activeNav.clientWidth + 'px';
    -  }
    +  initSlideTrackUnderline(nav, index) {
    +    this.slideTrackLine.classList.remove('frm-first', 'frm-last');
    +    var activeNav = typeof nav !== 'undefined'
    +      ? nav
    +      : Array.from(this.navs).find(function (li) { return li.classList.contains('frm-active'); });
    +    if (!activeNav) return;
    +    var x = this.isRTL
    +      ? -(activeNav.parentElement.offsetWidth - activeNav.offsetLeft - activeNav.offsetWidth)
    +      : activeNav.offsetLeft;
    +    this.slideTrackLine.style.transform = `translateX(${x}px)`;
    +    this.slideTrackLine.style.width = activeNav.clientWidth + 'px';
    +  }

    1-1: A11y: Add role="tablist" to the UL.

    Required for screen readers.

    Apply in src and rebuild:

    -  getTabs() {
    +  getTabs() {
         var wrapper = document.createElement('div'), ul = document.createElement('ul');
         wrapper.className = 'frm-tabs-navs';
    +    ul.setAttribute('role', 'tablist');
         wrapper.appendChild(ul);
         Array.from(this.tabs).forEach((tab, index) => { ul.appendChild(this.createTabHeading(tab, index)); });
         return wrapper;
       }

    1-1: A11y: Make tabs focusable and identify them as tabs; add Enter/Space keyboard support.

    Add role, tabindex, aria-selected; update on activation; support Enter/Space.

    Apply in src and rebuild:

    -  createTabHeading(tab, index) {
    -    var className = index === 0 ? 'frm-active' : '', li = document.createElement('li');
    -    li.className = className;
    -    li.innerText = tab.getAttribute('data-tab-title');
    -    return li;
    -  }
    +  createTabHeading(tab, index) {
    +    var isActive = index === 0;
    +    var li = document.createElement('li');
    +    li.className = isActive ? 'frm-active' : '';
    +    li.setAttribute('role', 'tab');
    +    li.setAttribute('tabindex', isActive ? '0' : '-1');
    +    li.setAttribute('aria-selected', isActive ? 'true' : 'false');
    +    li.id = (this.id ? this.id + '-tab-' + index : 'frm-tab-' + index);
    +    li.innerText = tab.getAttribute('data-tab-title');
    +    return li;
    +  }
    -  init() {
    +  init() {
         var _this = this;
         if (this.wrapper !== null && this.navs.length && this.slideTrackLine !== null && this.slideTrack !== null && this.slides.length) {
           this.initDefaultSlideTrackerWidth();
           this.navs.forEach(function (nav, index) {
             nav.addEventListener('click', function (event) {
               return _this.onNavClick(event, index);
             });
    +        nav.addEventListener('keydown', function (e) {
    +          if (e.key === 'Enter' || e.key === ' ') {
    +            e.preventDefault();
    +            _this.onNavClick({ currentTarget: nav, preventDefault: function () {} }, index);
    +          }
    +        });
           });
         }
       }
    -  onNavClick(event, index) {
    +  onNavClick(event, index) {
         var nav = event.currentTarget;
         event.preventDefault();
         this.removeActiveClassnameFromNavs();
         nav.classList.add('frm-active');
    +    // A11y: update aria-selected and tabindex
    +    this.navs.forEach(function (li, i) {
    +      li.setAttribute('aria-selected', i === index ? 'true' : 'false');
    +      li.setAttribute('tabindex', i === index ? '0' : '-1');
    +    });
    +    if (nav.focus) { nav.focus(); }
         this.initSlideTrackUnderline(nav, index);
         this.changeSlide(index);
         var anchor = nav.querySelector('a');
         if (anchor && anchor.id === 'frm_insert_fields_tab' && !anchor.closest('#frm_adv_info')) {
           window.frmAdminBuild?.clearSettingsBox?.();
         }
       }

    1-1: Verification: Ensure fixes are applied in src (not only the bundle) and lint excludes built files.

    Search for NodeList.filter on NodeList, missing ARIA roles, and keyboard handlers in src. Also make sure the linter ignores compiled bundles.

    Run:

    Comment thread js/formidable-web-components.js Outdated
    @Crabcyborg Crabcyborg added this to the 6.25 milestone Oct 9, 2025
    @codecov
    Copy link
    Copy Markdown

    codecov Bot commented Oct 9, 2025

    Codecov Report

    ❌ Patch coverage is 0% with 24 lines in your changes missing coverage. Please review.
    ✅ Project coverage is 27.35%. Comparing base (bb46a61) to head (d64c6eb).
    ⚠️ Report is 35 commits behind head on master.

    Files with missing lines Patch % Lines
    classes/controllers/FrmAppController.php 0.00% 19 Missing ⚠️
    classes/controllers/FrmFormsController.php 0.00% 5 Missing ⚠️
    Additional details and impacted files
    @@            Coverage Diff            @@
    ##             master    #2502   +/-   ##
    =========================================
      Coverage     27.35%   27.35%           
    - Complexity     8668     8674    +6     
    =========================================
      Files           142      142           
      Lines         29228    29243   +15     
    =========================================
    + Hits           7995     8000    +5     
    - Misses        21233    21243   +10     

    ☔ View full report in Codecov by Sentry.
    📢 Have feedback on the report? Share it here.

    🚀 New features to boost your workflow:
    • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
    • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

    Copy link
    Copy Markdown
    Contributor

    @coderabbitai coderabbitai Bot left a comment

    Choose a reason for hiding this comment

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

    Actionable comments posted: 0

    ♻️ Duplicate comments (1)
    classes/controllers/FrmAppController.php (1)

    686-687: Web components are registered but not loaded; add as a dep to settings bundle

    formidable-web-components is only registered and never enqueued. formidable-settings-components should depend on it so the custom element is defined when settings UI runs. This was flagged earlier and is still pending.

    Apply this diff:

    - wp_register_script( 'formidable-settings-components', $plugin_url . '/js/formidable-settings-components.js', array( 'formidable_admin' ), $version, true );
    + wp_register_script(
    +   'formidable-settings-components',
    +   $plugin_url . '/js/formidable-settings-components.js',
    +   array( 'formidable_admin', 'formidable-web-components' ),
    +   $version,
    +   true
    + );

    Optional: For clarity, consider registering formidable_admin before formidable-web-components in admin_js().

    Also applies to: 815-816

    🧹 Nitpick comments (4)
    classes/controllers/FrmFormsController.php (2)

    1628-1634: Improve error handling for missing template files.

    The current implementation silently falls back to the default template when a custom template file doesn't exist. While this provides robustness, it could mask configuration errors or deployment issues.

    Consider logging a notice when falling back to the default:

     if ( 'default' === $template_path || ! file_exists( $template_path ) ) {
    +    if ( 'default' !== $template_path ) {
    +        // Log when falling back due to missing file
    +        error_log( 'Formidable: Custom template not found: ' . $template_path . '. Using default.' );
    +    }
         include FrmAppHelper::plugin_path() . '/classes/views/shared/mb_adv_info.php';
         return;
     }
     
    +if ( ! is_readable( $template_path ) ) {
    +    error_log( 'Formidable: Custom template not readable: ' . $template_path . '. Using default.' );
    +    include FrmAppHelper::plugin_path() . '/classes/views/shared/mb_adv_info.php';
    +    return;
    +}
    +
     include $template_path;

    1608-1608: Sanitize the $template_path to prevent arbitrary file inclusion.

    Currently mb_tags_box() is only invoked with the default value, so there’s no immediate risk. To future-proof, resolve and validate the path before including:

    $base      = realpath( FrmAppHelper::plugin_path() );
    $real_path = realpath( $template_path );
    if ( ! $real_path
      || strpos( $real_path, $base ) !== 0
      || ! is_readable( $real_path )
    ) {
        include $base . '/classes/views/shared/mb_adv_info.php';
        return;
    }
    include $real_path;
    css/admin/frm-settings-components.css (1)

    1-1: Please avoid duplicating the entire minified ruleset

    This addition repeats the whole existing stylesheet (just to tweak the first selector), so we now ship two identical copies of the same rules. That bloats the asset and doubles future maintenance overhead. Instead, adjust only the selector that needs the .js variant—either by editing the original SCSS source or appending a single rule for the new case—so the shared declarations stay defined once.

    classes/controllers/FrmAppController.php (1)

    775-803: Replace placeholder @SInCE

    Update @since x.x with the correct plugin version for this release to keep docs accurate.

    📜 Review details

    Configuration used: CodeRabbit UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between 6872973 and d64c6eb.

    ⛔ Files ignored due to path filters (3)
    • js/formidable-settings-components.js.map is excluded by !**/*.map, !**/*.map
    • package-lock.json is excluded by !**/package-lock.json, !**/*.json
    • package.json is excluded by !**/*.json
    📒 Files selected for processing (4)
    • classes/controllers/FrmAppController.php (2 hunks)
    • classes/controllers/FrmFormsController.php (2 hunks)
    • css/admin/frm-settings-components.css (1 hunks)
    • js/src/admin/admin.js (1 hunks)
    🧰 Additional context used
    🧬 Code graph analysis (2)
    classes/controllers/FrmFormsController.php (1)
    classes/helpers/FrmAppHelper.php (2)
    • FrmAppHelper (6-4617)
    • plugin_path (58-60)
    classes/controllers/FrmAppController.php (1)
    classes/helpers/FrmAppHelper.php (3)
    • plugin_url (65-68)
    • FrmAppHelper (6-4617)
    • is_style_editor_page (1940-1959)
    🪛 PHPMD (2.15.0)
    classes/controllers/FrmFormsController.php

    1608-1608: Avoid unused parameters such as '$class'. (undefined)

    (UnusedFormalParameter)

    ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (4)
    • GitHub Check: Cypress
    • GitHub Check: PHP 7.4 tests in WP trunk
    • GitHub Check: PHP 8 tests in WP trunk
    • GitHub Check: Run PHP Syntax inspection (8.3)
    🔇 Additional comments (2)
    js/src/admin/admin.js (1)

    11436-11436: API surface update looks good

    Exporting the existing maybeCollapseSettings helper makes sense and keeps the original behavior intact.

    classes/controllers/FrmAppController.php (1)

    692-692: Good refactor: centralized admin JS dependencies

    Moving deps into get_admin_js_dependencies() improves maintainability. LGTM.

    @Crabcyborg Crabcyborg modified the milestones: 6.25, 6.25.1 Oct 14, 2025
    @Crabcyborg Crabcyborg modified the milestones: 6.25.1, 6.26 Nov 3, 2025
    @Crabcyborg Crabcyborg modified the milestones: 6.26, 6.27 Dec 8, 2025
    Copy link
    Copy Markdown
    Contributor

    @coderabbitai coderabbitai Bot left a comment

    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/FrmFormsController.php:
    - Line 1719: The docblock for mb_tags_box is missing a @param for the new
    $template_path parameter; update the phpdoc above the mb_tags_box method to
    include a @param string $template_path description, and if possible add a scalar
    type hint to the method signature (e.g., string $template_path) to improve type
    safety while ensuring backward compatibility.
    
    ♻️ Duplicate comments (1)
    classes/controllers/FrmAppController.php (1)

    719-720: Verify if 'formidable-settings-components' needs 'formidable-web-components' as a dependency.

    Based on the past review comment, if formidable-settings-components uses the custom elements registered by formidable-web-components (e.g., frm-tab-navigator-component), it should declare it as a dependency to ensure the custom element is defined before the settings code runs.

    Run the following script to check if the settings components bundle references the web components:

    #!/bin/bash
    # Description: Check if formidable-settings-components uses web components
    
    # Check if the built settings components file references the custom element
    if [ -f js/formidable-settings-components.js ]; then
      echo "Checking formidable-settings-components.js for web component usage:"
      rg -n "frm-tab-navigator-component|frmTabNavigatorComponent|customElements" js/formidable-settings-components.js || echo "No web component references found"
    else
      echo "Built file js/formidable-settings-components.js not found"
    fi
    
    # Check source files that might be bundled into settings components
    echo ""
    echo "Checking source files for web component usage:"
    fd -e js -e jsx . js/src --exec rg -l "frm-tab-navigator-component|frmTabNavigatorComponent" {} \;
    📜 Review details

    Configuration used: Organization UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between b8e274c and 48c2e59.

    📒 Files selected for processing (4)
    • .eslintignore
    • classes/controllers/FrmAppController.php
    • classes/controllers/FrmFormsController.php
    • css/frm_admin.css
    🧰 Additional context used
    🧬 Code graph analysis (2)
    classes/controllers/FrmAppController.php (1)
    classes/helpers/FrmAppHelper.php (3)
    • plugin_url (65-68)
    • FrmAppHelper (6-5054)
    • is_style_editor_page (2128-2147)
    classes/controllers/FrmFormsController.php (3)
    classes/helpers/FrmAppHelper.php (2)
    • FrmAppHelper (6-5054)
    • plugin_path (58-60)
    stripe/helpers/FrmTransLiteAppHelper.php (1)
    • plugin_path (11-13)
    stripe/helpers/FrmStrpLiteAppHelper.php (1)
    • plugin_path (16-18)
    🪛 GitHub Actions: Inspections
    classes/controllers/FrmFormsController.php

    [error] 1-1: PHP CS Fixer: Found 1 file with issues (phpdoc_add_missing_param_annotation) in 494 files; missing @param annotation in FrmFormsController.php. The command 'vendor/bin/php-cs-fixer fix --dry-run --verbose' failed with exit code 8.

    🪛 GitHub Check: PHPStan
    classes/controllers/FrmFormsController.php

    [failure] 1719-1719:
    Method FrmFormsController::mb_tags_box() has parameter $template_path with no type specified.

    🪛 PHPMD (2.15.0)
    classes/controllers/FrmFormsController.php

    1719-1719: Avoid unused parameters such as '$class'. (undefined)

    (UnusedFormalParameter)

    ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
    • GitHub Check: PHP 7.4 tests in WP 6.9
    • GitHub Check: PHP 8 tests in WP 6.9
    • GitHub Check: Cypress
    🔇 Additional comments (4)
    .eslintignore (1)

    14-14: LGTM!

    The addition of js/formidable-web-components.js to the ESLint ignore list is appropriate, as this is a generated/built file consistent with other ignored assets in the project.

    classes/controllers/FrmFormsController.php (1)

    1740-1746: LGTM! Template path logic is correct.

    The conditional logic correctly handles both the default template path and custom template paths, with proper fallback behavior when the custom path doesn't exist.

    classes/controllers/FrmAppController.php (2)

    812-839: LGTM! Well-structured dependency management helper.

    The new get_admin_js_dependencies() method effectively centralizes dependency management and conditionally includes wp-color-picker only when editing styles, which is a good optimization.


    725-725: Good refactoring to use the dependency helper.

    Replacing the hard-coded dependency array with the new helper method improves maintainability and enables conditional dependency loading.

    Comment thread classes/controllers/FrmFormsController.php
    Copy link
    Copy Markdown
    Contributor

    @coderabbitai coderabbitai Bot left a comment

    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/FrmFormsController.php:
    - Around line 1716-1720: The mb_tags_box method signature and docblock should
    declare $template_path as a string: update the PHPDoc to replace "@param mixed
    $template_path" with "@param string $template_path" and add a string type hint
    to the method signature (public static function mb_tags_box(int $form_id, string
    $class = '', string $template_path = 'default')) while keeping existing defaults
    and other param types intact; locate the mb_tags_box function to apply these
    changes and run a quick static check to ensure no signature conflicts.
    
    🧹 Nitpick comments (1)
    js/src/admin/admin.js (1)

    5755-5765: Exporting maybeCollapseSettings looks correct; be mindful of this binding

    Exposing maybeCollapseSettings on frmAdminBuildJS is reasonable and should be backward compatible. The function expects this to be the header element (h3/h4) and uses this.nextElementSibling, so external callers should either:

    • use it directly as an event handler (el.addEventListener('click', frmAdminBuild.maybeCollapseSettings)), or
    • call it with Function.prototype.call/apply (frmAdminBuild.maybeCollapseSettings.call(el)),

    to avoid this being window/undefined in strict contexts.

    If you expect wider reuse, consider a thin wrapper that accepts the header element as an explicit parameter (e.g., collapseSettings(headerEl)), and internally delegates to the existing function.

    Also applies to: 11252-11273

    📜 Review details

    Configuration used: Organization UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between 48c2e59 and c4faf5b.

    📒 Files selected for processing (5)
    • classes/controllers/FrmFormsController.php
    • js/src/admin/admin.js
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js
    • js/src/web-components/frm-web-component.js
    • js/src/web-components/index.js
    🚧 Files skipped from review as they are similar to previous changes (3)
    • js/src/web-components/index.js
    • js/src/web-components/frm-web-component.js
    • js/src/web-components/frm-tab-navigator-component/frm-tab-navigator-component.js
    🧰 Additional context used
    🪛 PHPMD (2.15.0)
    classes/controllers/FrmFormsController.php

    1720-1720: Avoid unused parameters such as '$class'. (undefined)

    (UnusedFormalParameter)

    ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
    • GitHub Check: Cypress
    • GitHub Check: PHP 7.4 tests in WP 6.9
    • GitHub Check: PHP 8 tests in WP 6.9
    🔇 Additional comments (2)
    js/src/admin/admin.js (1)

    1924-1931: JSDoc for frm_deny_drop_in_repeater filter now matches runtime signature

    The updated @param {boolean} denyDropInRepeater correctly documents the first argument passed to wp.hooks.applyFilters( 'frm_deny_drop_in_repeater', false, draggable ). No runtime impact; doc improvement looks good.

    classes/controllers/FrmFormsController.php (1)

    1741-1746: No security vulnerability exists. The method mb_tags_box() is only called from protected admin pages with the default $template_path value ('default'), and there is no mechanism for user input to reach this parameter. The code is already secured by capability checks that terminate execution with wp_die() if the user lacks the required 'frm_edit_forms' permission, and is not exposed to untrusted input.

    Likely an incorrect or invalid review comment.

    Comment thread classes/controllers/FrmFormsController.php Outdated
    Copy link
    Copy Markdown
    Contributor

    @coderabbitai coderabbitai Bot left a comment

    Choose a reason for hiding this comment

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

    Actionable comments posted: 0

    ♻️ Duplicate comments (1)
    classes/controllers/FrmFormsController.php (1)

    1716-1722: Add string type hint to $template_path parameter.

    The method signature lacks a string type hint for $template_path, though the docblock documents it as a string and the parameter has a string default value. Adding the type hint aligns with PHP best practices and improves type safety.

    Additionally, replace the @since x.x placeholder on line 1718 with the actual version number (likely 6.27 based on the current release being 6.26.1).

    Proposed fix
     	/**
     	 * @param int|string $form_id
     	 * @param string     $class
     	 * @param string     $template_path The path to a template file to use instead of the default.
     	 *
    -	 * @since x.x Added $template_path parameter.
    +	 * @since 6.27 Added $template_path parameter.
     	 *
     	 * @return void
     	 */
    -	public static function mb_tags_box( $form_id, $class = '', $template_path = 'default' ) {
    +	public static function mb_tags_box( $form_id, $class = '', string $template_path = 'default' ) {

    The $class parameter is used within the included template file (mb_adv_info.php), so it should not be removed.

    🧹 Nitpick comments (1)
    classes/controllers/FrmFormsController.php (1)

    1743-1748: Consider adding path validation if custom template paths are used.

    The code currently lacks validation beyond file_exists() when including custom template paths, which could theoretically allow path traversal if a caller passes user-controlled input to $template_path. However, in the current implementation, the only call site uses the default parameter and no custom paths are passed.

    If this function is intended to support custom template paths in the future, add validation:

    • Use realpath() to verify the path resolves within an allowed directory (e.g., plugin directory)
    • Validate file extension to ensure only PHP files are included
    • Or restrict to a whitelist of allowed template paths

    For now, this is a minor defensive hardening suggestion rather than a critical issue.

    📜 Review details

    Configuration used: Organization UI

    Review profile: CHILL

    Plan: Pro

    📥 Commits

    Reviewing files that changed from the base of the PR and between c4faf5b and 64d8506.

    📒 Files selected for processing (1)
    • classes/controllers/FrmFormsController.php
    🧰 Additional context used
    🪛 PHPMD (2.15.0)
    classes/controllers/FrmFormsController.php

    1722-1722: Avoid unused parameters such as '$class'. (undefined)

    (UnusedFormalParameter)

    ⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
    • GitHub Check: Cypress
    • GitHub Check: PHP 8 tests in WP 6.9
    • GitHub Check: PHP 7.4 tests in WP 6.9

    Copy link
    Copy Markdown
    Contributor

    @Crabcyborg Crabcyborg left a comment

    Choose a reason for hiding this comment

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

    Thanks @Liviu-p!

    I got this up to date with master, and made some small changes to get it passing the workflows.

    I think this is good to merge now.

    🚀

    @Crabcyborg Crabcyborg merged commit 8f06fd5 into master Jan 5, 2026
    16 checks passed
    @Crabcyborg Crabcyborg deleted the feature/make-style-elements-accessbile-as-web-components branch January 5, 2026 17:50
    stephywells pushed a commit that referenced this pull request Apr 4, 2026
    …accessbile-as-web-components
    
    root web component, make tab navigator accessible as web component
    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