Skip to content

Conversation

@sapayth
Copy link
Member

@sapayth sapayth commented Sep 19, 2025

fixes #156

User Story
As a site admin,
I want to add a “Quick Search” block to my documentation pages,
So that readers can instantly search and access relevant documentation (sections, articles, or popular docs) without leaving the page.

Summary by CodeRabbit

  • New Features

    • Added “weDocs – Quick Search” block with a modal, live search, and keyboard shortcut (Cmd/Ctrl+K).
    • Configurable sources (None, Sections, Articles, Helpful) with adjustable count and optional result icons.
    • Extensive styling controls for search box and modal, plus result highlighting.
  • Improvements

    • Accessible modal with ARIA, keyboard navigation, and screen reader updates.
    • Expanded frontend CSS utilities and components; integrated Quick Search initialization on load.
  • Chores

    • Set project Node.js version to 18.
    • Updated asset manifests, versions, and build metadata.

@coderabbitai
Copy link

coderabbitai bot commented Sep 19, 2025

Walkthrough

Introduces a new server-rendered “Quick Search” block with PHP render and AJAX search, templates, and editor UI. Adds a dynamic block render loader. Refactors data store into modular docs/settings stores. Updates build artifacts, CSS utilities, and asset manifests/versions. Adds Node version file. Minor dependency tweak adds wp-data.

Changes

Cohort / File(s) Summary
Environment config
/.nvmrc
New Node version file specifying 18.
Asset manifests and versions
/assets/build/block.asset.php, /assets/build/frontend.asset.php, /assets/build/index.asset.php, /assets/build/print.asset.php, /assets/build/store.asset.php
Version hashes updated; block.asset.php adds wp-data to dependencies; others unchanged structurally.
Frontend build artifacts
/assets/build/frontend.css, /assets/build/frontend.js, /assets/build/print.css, /assets/build/print.js, /assets/build/index.css
Generated headers/source maps added; webpack bootstrap added for CSS bundles; large CSS additions including modal, badges, steps, utilities, and animations.
QuickSearch block (build + source + templates + wiring)
/assets/build/blocks/QuickSearch/*, /src/blocks/QuickSearch/*, /src/blocks/QuickSearch/templates/*, /includes/Ajax.php, /assets/js/frontend.js, /src/blocks/index.js
Adds block metadata, attributes, edit/save components, server render with helpers, templates (empty-state, item, results), AJAX search endpoint, frontend init hook, and build outputs.
Dynamic render loader
/wedocs.php
Adds init-time loader to require each block’s render.php under assets/build/blocks/*; replaces single hard-coded include.
Data store modularization
/assets/build/store.js
Replaces monolithic store with modular docs/settings stores (actions, controls, reducers, resolvers, selectors) and registers both.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • Add Promotional Banner to weDocs Dashboard #209 — Touches promo-notice and store logic similar to the modular store changes (actions/controls like dismissPromoNotice and isProLoaded gating).
  • Add docs grid #203 — Alters block registration/render loading in wedocs.php, related to this PR’s dynamic render loader and new block addition.

Suggested reviewers

  • iftakharul-islam

Poem

A bunny taps “⌘K” with cheer,
A modal blooms, the docs appear.
With badges bright and steps that spin,
I sniff the queries, dive right in.
New stores are tidy, renders load—
Hop, search, and find along the road! 🐇🔎

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Linked Issues Check ⚠️ Warning The PR implements a Quick Search feature (block, templates, AJAX handler) and a client-store refactor, but it does not satisfy the explicit requirements of linked issue #156 because there are no package.json or lockfile updates for fast-xml-parser/is-svg nor code adaptations to v4 APIs, and it does not provide explicit, verifiable migration-focused fixes or tests for issue #190 — the store refactor may help reactivity but the diff lacks targeted migration fixes or test evidence that "migrated docs reactivity" is resolved. Add the dependency updates (fast-xml-parser v4.2.7 and is-svg v4.4.0) with corresponding package-lock/yarn-lock changes and adapt code to the v4 API (plus CI/tests for XML/SVG paths), and either provide targeted changes and automated tests that reproduce-and-fix the migrated-docs reactivity for #190 or split the store/refactor into a focused PR that includes those verifications before marking the linked issues as fixed.
Out of Scope Changes Check ⚠️ Warning This PR contains substantial additions beyond the linked-issue scope (a full Quick Search feature, many new templates, large CSS and built-asset changes, .nvmrc, and multiple asset version bumps) that are not required to satisfy the stated linked issues (#156 and #190) and significantly expand the review surface. Separate concerns into focused PRs: place the Quick Search feature in its own feature PR, put dependency/security upgrades (#156) in a dedicated PR with package and code adaptations plus tests, and isolate any migration/reactivity fixes (#190) into a minimal PR with reproducible tests; also minimize or separate compiled/build artifact commits to reduce review noise.
✅ Passed checks (3 passed)
Check name Status Explanation
Title Check ✅ Passed The title "feat: block quick search" is concise and accurately describes the primary change in this PR — the addition of a Quick Search block and its supporting render/templates — making it clear and appropriate for changelog/history scanning.
Docstring Coverage ✅ Passed Docstring coverage is 81.25% which is sufficient. The required threshold is 80.00%.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.


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

@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: 15

🧹 Nitpick comments (29)
assets/js/frontend.js (1)

266-271: Security nit: add rel="noopener noreferrer" to _blank links.
Prevents tabnabbing and removes window.opener linkage.

-          <a
+          <a
             href="${ url }"
             target="_blank"
+            rel="noopener noreferrer"
             class="${ bootstrapTemplate + tailwindTemplate }doc-search-hit-result"
           >
assets/build/frontend.css (1)

1-3: Source maps in production: confirm policy.
Header and /*# sourceMappingURL=frontend.css.map*/ added. Either ship the .map file or strip the comment in release to avoid 404s and reduce asset size.

Also applies to: 1223-1224

assets/build/print.css (1)

1-3: Source maps in production: confirm policy.
Same as frontend.css—ensure .map is shipped or the comment is removed for releases.

Also applies to: 185-186

src/blocks/QuickSearch/templates/empty-state.php (1)

22-22: Consider escaping the icon output.

The icon is output directly without escaping. If this contains user-controlled content, it could pose an XSS risk.

-            <?php echo $icon; ?>
+            <?php echo wp_kses( $icon, wp_kses_allowed_html( 'post' ) ); ?>
src/blocks/QuickSearch/templates/search-item.php (1)

27-29: Security: Consider validating the permalink URL.

While esc_url() is used, the URL comes from $doc['permalink'] which could potentially contain unsafe URLs like javascript: schemes.

-     onclick="window.open('<?php echo esc_url( $permalink ); ?>', '_blank')">
+     onclick="window.open('<?php echo esc_url( $permalink, ['http', 'https'] ); ?>', '_blank')">
src/blocks/QuickSearch/save.js (1)

90-94: Consider improving the keyboard shortcut icon.

The current SVG shows an "X" pattern rather than the typical command key symbol. Consider using a more appropriate icon for keyboard shortcuts.

-                        <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
-                            <path d="M9 9l6 6m0-6l-6 6"/>
-                        </svg>
+                        <svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor">
+                            <path d="M6 4h4c1.45 0 3 1.69 3 3.5 0 1.41-.91 2.72-2 3.25V14c.58.45 1 1.27 1 2.25C12 17.31 10.31 19 8.5 19H4c-.83 0-1.5-.67-1.5-1.5v-11C2.5 5.67 3.17 5 4 5h2V4z"/>
+                        </svg>
assets/build/index.css (3)

2006-2015: Duplicate @Keyframes spin definitions detected.

There are two @keyframes spin blocks in the CSS, which could cause conflicts. The static analysis tool correctly identified this duplication.

Remove one of the duplicate @keyframes spin definitions to avoid potential conflicts:

-@keyframes spin {
-
-  to {
-    transform: rotate(360deg);
-  }
-}

Also applies to: 4108-4116


1913-1914: Handle duplicate property declarations.

The static analysis tool identified duplicate transition-property and grid-template-columns declarations that could cause unexpected behavior.

Review and consolidate the duplicate property declarations to ensure consistent styling behavior.

Also applies to: 2259-2260


6332-6335: External carousel library CSS causing parse errors.

The included react-responsive-carousel CSS is causing multiple parse errors in the static analysis tool. Consider extracting this to a separate CSS file or reviewing if it's needed.

+/* External carousel library styles - consider extracting to separate file */
-/*!************************************************************************************************************************************************************************************************************************!*\
-  !*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[2].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[2].use[2]!./node_modules/react-responsive-carousel/lib/styles/carousel.min.css ***!
-  \************************************************************************************************************************************************************************************************************************/
assets/build/store.js (1)

321-330: Wrap switch case declarations in blocks to prevent scope leakage.

The variables setDocState and isNotInParent can leak to other switch cases. This matches the static analysis findings.

Apply this fix to properly scope the declarations:

-    case 'SET_DOC':
-      const setDocState = {
+    case 'SET_DOC': {
+      const setDocState = {
         ...state,
         docs: [...state.docs, action.doc]
       };
       const isNotInParent = !state.parents.some(parent => parent?.id === action?.doc?.id);
       if (!action.doc.parent && isNotInParent) {
         setDocState.parents = [{
           ...action.doc
         }, ...state.parents];
       }
       return setDocState;
+    }
src/blocks/QuickSearch/style.scss (1)

1-8: Consider scoping the editor panel styles more specifically.

The CSS selector .components-grid.components-tools-panel.block-editor-panel-color-gradient-settings is quite generic and could affect other blocks' color panels. Consider adding a more specific parent selector to avoid unintended side effects.

Apply this fix to scope the styles to your block:

+.wedocs-quick-search-editor {
   .components-grid.components-tools-panel.block-editor-panel-color-gradient-settings {
       padding: 0;
       margin-bottom: 1rem;
   }
+}
wedocs.php (1)

184-195: Add error handling for the block loader.

Consider adding error handling to gracefully handle cases where a render file might be malformed.

Apply this improvement:

 public function load_block_render_files() {
     $blocks_dir = plugin_dir_path( __FILE__ ) . 'assets/build/blocks/';
     if ( is_dir( $blocks_dir ) ) {
         $block_dirs = glob( $blocks_dir . '*', GLOB_ONLYDIR );
         foreach ( $block_dirs as $block_dir ) {
             $render_file = $block_dir . '/render.php';
             if ( file_exists( $render_file ) ) {
-                require_once $render_file;
+                try {
+                    require_once $render_file;
+                } catch ( \Exception $e ) {
+                    error_log( 'weDocs: Failed to load block render file: ' . $render_file . ' - ' . $e->getMessage() );
+                }
             }
         }
     }
 }
src/blocks/QuickSearch/block.json (1)

35-37: Validate helpfulDocsCount range.

Consider adding min/max constraints for the helpfulDocsCount attribute to prevent unreasonable values.

You might want to add validation in your edit.js component to ensure this value stays within a reasonable range (e.g., 1-50).

includes/Ajax.php (1)

320-321: Consider using a more robust template path resolution.

The hardcoded relative path could break if the plugin structure changes.

Use the plugin constants for more reliable path resolution:

-            $template_path = plugin_dir_path( __FILE__ ) . '../src/blocks/QuickSearch/templates/search-results.php';
+            $template_path = WEDOCS_PATH . '/src/blocks/QuickSearch/templates/search-results.php';
src/blocks/QuickSearch/templates/search-results.php (2)

58-75: Clickable row: add noopener/noreferrer and keyboard/ARIA support.

Opening new tabs without noopener allows reverse‑tabnabbing; divs aren’t keyboard‑accessible.

Apply:

-            <div class="flex items-start cursor-pointer transition-colors"
+            <div class="flex items-start cursor-pointer transition-colors"
                  style="
@@
-                 onmouseover="this.style.backgroundColor='#F3F4F6'"
-                 onmouseout="this.style.backgroundColor='<?php echo esc_js( $modal_styles['listItemBackgroundColor'] ?? 'transparent' ); ?>'"
-                 onclick="window.open('<?php echo esc_url( $permalink ); ?>', '_blank')">
+                 onmouseover="this.style.backgroundColor='#F3F4F6'"
+                 onmouseout="this.style.backgroundColor='<?php echo esc_js( $modal_styles['listItemBackgroundColor'] ?? 'transparent' ); ?>'"
+                 role="link"
+                 tabindex="0"
+                 onkeydown="if(event.key==='Enter'||event.key===' '){window.open('<?php echo esc_url( $permalink ); ?>','_blank','noopener,noreferrer');event.preventDefault();}"
+                 onclick="window.open('<?php echo esc_url( $permalink ); ?>', '_blank','noopener,noreferrer')">

49-55: Optional: Pass $query into the template explicitly.

This template uses $query implicitly. Make it an explicit arg from the render/AJAX loader to avoid hidden globals.

src/blocks/QuickSearch/edit.js (5)

103-104: Remove stray console.log in production.

Apply:

-                            console.log('Updating search box placeholder:', newPlaceholder);

45-63: Remove unused searchBoxStyle object.

It’s never referenced.

Apply:

-    const searchBoxStyle = {
-        backgroundColor: searchBoxStyles.backgroundColor,
-        borderColor: searchBoxStyles.borderColor,
-        borderWidth: searchBoxStyles.borderWidth,
-        borderRadius: searchBoxStyles.borderRadius,
-        paddingTop: searchBoxStyles.padding.top,
-        paddingRight: searchBoxStyles.padding.right,
-        paddingBottom: searchBoxStyles.padding.bottom,
-        paddingLeft: searchBoxStyles.padding.left,
-        marginTop: searchBoxStyles.margin.top,
-        marginRight: searchBoxStyles.margin.right,
-        marginBottom: searchBoxStyles.margin.bottom,
-        marginLeft: searchBoxStyles.margin.left,
-        fontSize: searchBoxStyles.fontSize,
-        fontWeight: searchBoxStyles.fontWeight,
-        letterSpacing: searchBoxStyles.letterSpacing,
-        lineHeight: searchBoxStyles.lineHeight,
-        color: searchBoxStyles.placeholderColor,
-    };

83-91: Remove unused colorOptions.

Apply:

-    const colorOptions = [
-        { name: 'Default', color: '#9CA3AF' },
-        { name: 'Black', color: '#000000' },
-        { name: 'White', color: '#FFFFFF' },
-        { name: 'Gray', color: '#6B7280' },
-        { name: 'Blue', color: '#3B82F6' },
-        { name: 'Red', color: '#EF4444' },
-        { name: 'Green', color: '#10B981' },
-    ];

262-263: Fix className typo.

Apply:

-                    <p className="'mb-0'">{__('The styling will be shown in the frontend, not in the editor', 'wedocs')}</p>
+                    <p className="mb-0">{__('The styling will be shown in the frontend, not in the editor', 'wedocs')}</p>

380-385: Use a unique input id and proper boolean for disabled.

Duplicate IDs are possible if multiple blocks exist; also React props should use boolean for disabled.

Apply:

-import { Fragment } from '@wordpress/element';
+import { Fragment } from '@wordpress/element';
+import { useInstanceId } from '@wordpress/compose';
@@
-    const blockProps = useBlockProps();
+    const blockProps = useBlockProps();
+    const inputId = useInstanceId( Edit, 'wedocs-quick-search' );
@@
-                            <input
-                                id="wedocs-quick-search"
+                            <input
+                                id={ inputId }
@@
-                                disabled="disabled"
+                                disabled
assets/build/blocks/QuickSearch/render.php (4)

411-418: Add rel="noopener noreferrer" to external links.

Prevents reverse‑tabnabbing.

Apply:

-                        <a href="<?php echo esc_url( $item['permalink'] ); ?>" 
+                        <a href="<?php echo esc_url( $item['permalink'] ); ?>" 
                            class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium mr-2 mb-2 transition-colors hover:opacity-80"
                            style="background-color: <?php echo esc_attr( $modal_styles['docLabelColor'] ?? '#3B82F6' ); ?>20; color: <?php echo esc_attr( $modal_styles['docLabelColor'] ?? '#3B82F6' ); ?>;"
-                           target="_blank">
+                           target="_blank" rel="noopener noreferrer">

620-624: Honor the configured list item background color when clearing selection.

Avoid hard‑coded #F9FAFB.

Apply:

-                    item.style.backgroundColor = '#F9FAFB';
+                    item.style.backgroundColor = '<?php echo esc_js( $modal_styles['listItemBackgroundColor'] ?? '#F9FAFB' ); ?>';

33-52: Parity with src/ logic: validate doc types in get_modal_docs_data.

The build version doesn’t validate section/article IDs and marks “helpful” without deriving the actual type. Port the stricter checks from src/blocks/QuickSearch/render.php.

Also applies to: 66-75, 118-127


343-764: Race condition on rapid input: last‑response wins.

Out‑of‑order AJAX responses can overwrite newer results. Use AbortController or a monotonically increasing request id to drop stale responses.

I can patch this if you want.

src/blocks/QuickSearch/render.php (4)

466-471: Add rel="noopener noreferrer" to chips links.

Apply:

-                        <a href="<?php echo esc_url( $item['permalink'] ); ?>" 
+                        <a href="<?php echo esc_url( $item['permalink'] ); ?>" 
                            class="inline-flex items-center rounded-full px-2 py-1 text-xs font-medium mr-2 mb-2 transition-colors hover:opacity-80 no-underline"
                            style="background-color: <?php echo esc_attr( $modal_styles['docLabelColor'] ?? '#3B82F6' ); ?>20; color: <?php echo esc_attr( $modal_styles['docLabelColor'] ?? '#3B82F6' ); ?>;"
-                           target="_blank">
+                           target="_blank" rel="noopener noreferrer">

677-681: Honor configured background when clearing selection.

Apply:

-                    item.style.backgroundColor = '#F9FAFB';
+                    item.style.backgroundColor = '<?php echo esc_js( $modal_styles['listItemBackgroundColor'] ?? '#F9FAFB' ); ?>';

722-729: Dead code: highlightSearchTerms is defined but unused.

Remove or wire it to template rendering to avoid duplication with PHP highlighting.


300-304: Out‑of‑order AJAX responses can override newer results.

Add AbortController or a request counter to drop stale responses.

I can patch with a minimal let currentController pattern if you’d like.

Also applies to: 561-574

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7d2fc7e and 6419b10.

⛔ Files ignored due to path filters (10)
  • assets/build/block.js.map is excluded by !**/*.map
  • assets/build/frontend.css.map is excluded by !**/*.map
  • assets/build/frontend.js.map is excluded by !**/*.map
  • assets/build/index.css.map is excluded by !**/*.map
  • assets/build/index.js.map is excluded by !**/*.map
  • assets/build/print.css.map is excluded by !**/*.map
  • assets/build/print.js.map is excluded by !**/*.map
  • assets/build/store.js.map is excluded by !**/*.map
  • assets/build/style-block.css.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (28)
  • .nvmrc (1 hunks)
  • assets/build/block.asset.php (1 hunks)
  • assets/build/blocks/QuickSearch/block.json (1 hunks)
  • assets/build/blocks/QuickSearch/render.php (1 hunks)
  • assets/build/frontend.asset.php (1 hunks)
  • assets/build/frontend.css (2 hunks)
  • assets/build/frontend.js (1 hunks)
  • assets/build/index.asset.php (1 hunks)
  • assets/build/index.css (42 hunks)
  • assets/build/print.asset.php (1 hunks)
  • assets/build/print.css (2 hunks)
  • assets/build/print.js (1 hunks)
  • assets/build/store.asset.php (1 hunks)
  • assets/build/store.js (1 hunks)
  • assets/js/frontend.js (1 hunks)
  • includes/Ajax.php (2 hunks)
  • src/blocks/QuickSearch/attributes.js (1 hunks)
  • src/blocks/QuickSearch/block.json (1 hunks)
  • src/blocks/QuickSearch/edit.js (1 hunks)
  • src/blocks/QuickSearch/index.js (1 hunks)
  • src/blocks/QuickSearch/render.php (1 hunks)
  • src/blocks/QuickSearch/save.js (1 hunks)
  • src/blocks/QuickSearch/style.scss (1 hunks)
  • src/blocks/QuickSearch/templates/empty-state.php (1 hunks)
  • src/blocks/QuickSearch/templates/search-item.php (1 hunks)
  • src/blocks/QuickSearch/templates/search-results.php (1 hunks)
  • src/blocks/index.js (1 hunks)
  • wedocs.php (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
src/blocks/QuickSearch/attributes.js (2)
src/blocks/QuickSearch/edit.js (1)
  • attributes (17-27)
src/blocks/QuickSearch/save.js (1)
  • attributes (4-17)
src/blocks/QuickSearch/index.js (2)
src/blocks/QuickSearch/save.js (1)
  • Save (3-99)
src/blocks/QuickSearch/edit.js (1)
  • Edit (14-431)
includes/Ajax.php (1)
wedocs.php (1)
  • template_path (317-319)
src/blocks/QuickSearch/edit.js (2)
src/blocks/QuickSearch/save.js (3)
  • blockProps (23-25)
  • attributes (4-17)
  • searchBoxStyle (27-47)
src/blocks/QuickSearch/attributes.js (1)
  • attributes (3-89)
src/blocks/QuickSearch/render.php (4)
assets/build/blocks/QuickSearch/render.php (3)
  • get_modal_docs_data (22-131)
  • render_wedocs_quick_search (139-765)
  • wedocs_block_quick_search_get_template (230-243)
assets/js/frontend.js (1)
  • article (74-74)
src/blocks/QuickSearch/attributes.js (1)
  • attributes (3-89)
includes/Frontend.php (2)
  • Frontend (10-179)
  • enqueue_assets (113-118)
src/blocks/QuickSearch/save.js (2)
src/blocks/QuickSearch/attributes.js (1)
  • attributes (3-89)
src/blocks/QuickSearch/edit.js (3)
  • attributes (17-27)
  • blockProps (15-15)
  • searchBoxStyle (45-63)
assets/build/blocks/QuickSearch/render.php (4)
src/blocks/QuickSearch/render.php (3)
  • get_modal_docs_data (55-182)
  • render_wedocs_quick_search (190-822)
  • wedocs_block_quick_search_get_template (284-297)
src/blocks/QuickSearch/attributes.js (1)
  • attributes (3-89)
wedocs.php (2)
  • template_path (317-319)
  • WeDocs (55-329)
includes/Frontend.php (2)
  • Frontend (10-179)
  • enqueue_assets (113-118)
🪛 Biome (2.1.2)
assets/build/index.css

[error] 1913-1913: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.

transition-property is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


[error] 2259-2259: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.

grid-template-columns is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


[error] 6335-6335: Unexpected value or character.

Expected one of:

(parse)


[error] 6335-6335: Unexpected value or character.

Expected one of:

(parse)


[error] 6335-6335: Unexpected value or character.

Expected one of:

(parse)


[error] 6335-6335: Unexpected value or character.

Expected one of:

(parse)


[error] 6335-6335: Unexpected value or character.

Expected one of:

(parse)


[error] 6335-6335: Unexpected shorthand property flex-flow after flex-direction

(lint/suspicious/noShorthandPropertyOverrides)


[error] 6335-6335: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.

display is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


[error] 6335-6335: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.

display is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


[error] 6335-6335: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.

transition is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)

assets/build/store.js

[error] 321-324: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 325-325: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


[error] 375-375: Unsafe usage of optional chaining.

If it short-circuits with 'undefined' the evaluation will throw TypeError here:

(lint/correctness/noUnsafeOptionalChaining)


[error] 376-376: Unsafe usage of optional chaining.

If it short-circuits with 'undefined' the evaluation will throw TypeError here:

(lint/correctness/noUnsafeOptionalChaining)

🔇 Additional comments (36)
assets/build/frontend.asset.php (1)

1-1: LGTM: version bump only.
No behavior change; cache-busting updated.

assets/build/store.asset.php (1)

1-1: LGTM: deps + version look correct.
wp-api-fetch and wp-data align with the modular stores.

assets/build/print.asset.php (1)

1-1: LGTM: version bump only.
No functional change.

assets/build/index.asset.php (1)

1-1: LGTM: deps unchanged, version updated.
Matches broader asset rebuild.

assets/js/frontend.js (1)

1-1: Verified: jQuery dependency present for frontend.js
includes/Frontend.php registers 'wedocs-scripts' with ['jquery','wedocs-anchorjs'] and enqueues it; no change required.

.nvmrc (1)

1-1: Ensure CI uses Node 18.
.nvmrc is set to 18 but no GitHub Actions workflows were found under .github/workflows; confirm your CI config (GitHub Actions: .github/workflows/*.yml, CircleCI: .circleci/config.yml, GitLab: .gitlab-ci.yml, Jenkinsfile, etc.) is pinned to Node 18 to avoid build mismatches.

assets/build/block.asset.php (1)

1-1: Dependency update aligns with QuickSearch block features.

The addition of 'wp-data' dependency correctly supports the new QuickSearch block's WordPress data integration requirements, as the block implements modal functionality and needs to access WordPress data stores.

assets/build/print.js (1)

1-28: Standard Webpack module runtime wrapper.

The Webpack bootstrap runtime and ES module tagging are standard build artifacts and function correctly.

src/blocks/QuickSearch/templates/empty-state.php (3)

10-12: LGTM! Proper security guard.

The ABSPATH check correctly prevents direct access to the template file.


14-16: LGTM! Proper variable initialization.

The null-coalescing operators provide sensible defaults and prevent undefined variable errors.


26-28: LGTM! Proper output escaping.

Both the CSS color value and the message text are properly escaped for security.

assets/build/frontend.js (1)

1-28: Standard Webpack module runtime wrapper.

The Webpack bootstrap runtime for frontend.less matches the pattern in print.js and is correctly implemented.

src/blocks/QuickSearch/templates/search-item.php (4)

12-14: LGTM! Proper security guard.

The ABSPATH check correctly prevents direct access to the template file.


23-24: LGTM! Robust title handling.

The code correctly handles both string and array forms of the title and provides a safe fallback for the permalink.


28-29: LGTM! Proper output escaping.

All dynamic CSS values are properly escaped with esc_attr() and have sensible fallback defaults.

Also applies to: 32-32, 40-40


45-45: Alpha transparency implementation looks correct.

The 20 suffix creates a 20% alpha transparency effect for the badge background by appending to the hex color value.

src/blocks/QuickSearch/save.js (4)

19-21: LGTM! Conditional rendering pattern.

The early return when hideBlock is true follows React best practices.


27-47: LGTM! Comprehensive style object construction.

The searchBoxStyle object correctly maps all styling attributes from searchBoxStyles and includes CSS custom properties for dynamic styling.


49-70: LGTM! Well-structured CSS variables.

The modalStyle object creates a comprehensive set of CSS custom properties that align with the QuickSearch modal styling requirements.


74-84: LGTM! Proper data attribute structure.

The data attributes correctly pass configuration values to the frontend JavaScript for modal functionality.

src/blocks/QuickSearch/attributes.js (1)

1-91: LGTM! Comprehensive attribute schema.

The attributes object provides a complete and well-structured schema for the QuickSearch block with sensible defaults for all configuration options including styling, content sources, and UI preferences.

assets/build/index.css (4)

908-932: New DaisyUI component styles added correctly.

The .badge and .kbd component styles follow DaisyUI patterns for displaying status information and keyboard shortcuts respectively.


2146-2199: Modal system implementation looks comprehensive.

The modal styles with .modal, .!modal variants, and interaction states provide a complete modal dialog system as expected from DaisyUI components.


2256-2298: Steps widget implementation matches DaisyUI patterns.

The .steps component with grid layout and progress indicators aligns with standard step-by-step UI patterns.


3299-6330: LGTM! Comprehensive wedocs-document utility classes.

The extensive collection of responsive utility classes provides excellent coverage for the documentation layout system with proper breakpoint support and consistent spacing/typography scales.

assets/build/store.js (1)

1-1228: LGTM! The modular store architecture refactor looks clean.

The webpack-generated bundle correctly implements the modular data store architecture with separate docs and settings stores. The refactored approach improves code organization and maintainability.

src/blocks/index.js (1)

3-3: LGTM!

The QuickSearch block import is properly added to the blocks index file.

wedocs.php (1)

170-195: Excellent implementation of the dynamic block loader!

The load_block_render_files() method provides a clean, scalable approach for auto-loading block render files. This eliminates the need for manual includes for each new block.

src/blocks/QuickSearch/index.js (1)

1-27: LGTM! The block registration is properly configured.

The QuickSearch block registration follows WordPress block development best practices with proper attributes, editor/save components, and metadata.

src/blocks/QuickSearch/block.json (1)

1-101: LGTM! The block manifest is well-structured.

The block.json properly defines the QuickSearch block with comprehensive attributes and appropriate defaults. The schema version and API version are up-to-date.

includes/Ajax.php (2)

43-45: LGTM! The QuickSearch AJAX registration is correct.

The AJAX actions are properly registered for both authenticated and non-authenticated users.


259-338: Good implementation with proper security checks!

The quick_search method correctly validates nonces, sanitizes inputs, and provides flexible output formats.

src/blocks/QuickSearch/templates/search-results.php (1)

89-91: Alpha suffix on hex may fail for 3‑digit colors.

Appending 20 assumes 6‑digit hex. Consider computing rgba() from hex to avoid invalid CSS when a 3‑digit color is provided.

Do you want a small helper to convert hex→rgba with alpha=0.125? I can provide it.

src/blocks/QuickSearch/edit.js (1)

166-173: PanelColorSettings: pass palette directly, not as nested group.

colors should be an array of { name, color }. Use colors={themeColors || []}.

Apply:

-                        <PanelColorSettings
-                            colors={[
-                                {
-                                    colors: themeColors,
-                                    name: __('Theme', 'wedocs'),
-                                }
-                            ]}
+                        <PanelColorSettings
+                            colors={ themeColors || [] }

And similarly in the “Search Modal Styling” section.

Please verify in your target WP version. If you rely on grouped palettes, we can switch to ColorPalette with groups.

Also applies to: 263-270

assets/build/blocks/QuickSearch/block.json (1)

67-95: Keep modalStyles defaults aligned with src attributes.

Missing listItemBackgroundColor (used by templates) and optional listItemIconBackgroundColor.

Apply:

       "default": {
@@
-        "listItemBorderRadius": "4px"
+        "listItemBorderRadius": "4px",
+        "listItemBackgroundColor": "#F9FAFB"
       }

Optionally add:

+        "listItemIconBackgroundColor": "transparent"

Please rebuild after updating.

assets/build/blocks/QuickSearch/render.php (1)

246-248: Nonce verified in AJAX handler. quick_search() in includes/Ajax.php calls check_ajax_referer('wedocs-ajax') (line 260), so server‑side nonce verification is present.

Comment on lines +1 to +96
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "wedocs/quick-search",
"version": "1.0.0",
"title": "weDocs - Quick Search",
"icon": "search",
"category": "widgets",
"description": "Add a quick search block that opens a modal with documentation search",
"supports": {
"html": false
},
"render": "file:./render.php",
"attributes": {
"searchBoxPlaceholder": {
"type": "string",
"default": "Quick search..."
},
"modalPlaceholder": {
"type": "string",
"default": "Search documentation"
},
"modalDocsSource": {
"type": "string",
"default": "helpful"
},
"sectionIds": {
"type": "string",
"default": ""
},
"articleIds": {
"type": "string",
"default": ""
},
"helpfulDocsCount": {
"type": "number",
"default": 10
},
"searchBoxStyles": {
"type": "object",
"default": {
"placeholderColor": "#9CA3AF",
"iconColor": "#6B7280",
"commandKeyColor": "#6B7280",
"backgroundColor": "#FFFFFF",
"borderColor": "#D1D5DB",
"borderWidth": "1px",
"borderRadius": "8px",
"padding": {
"top": "12px",
"right": "16px",
"bottom": "12px",
"left": "16px"
},
"margin": {
"top": "0px",
"right": "0px",
"bottom": "0px",
"left": "0px"
},
"fontSize": "16px",
"fontWeight": "400",
"letterSpacing": "0px",
"lineHeight": "1.5"
}
},
"modalStyles": {
"type": "object",
"default": {
"placeholderColor": "#9CA3AF",
"searchIconColor": "#6B7280",
"backgroundColor": "#FFFFFF",
"fieldTextColor": "#111827",
"listItemIconColor": "#3B82F6",
"listItemTextColor": "#111827",
"docLabelColor": "#3B82F6",
"sectionLabelColor": "#3B82F6",
"listItemPadding": {
"top": "12px",
"right": "16px",
"bottom": "12px",
"left": "16px"
},
"listItemMargin": {
"top": "0px",
"right": "0px",
"bottom": "0px",
"left": "0px"
},
"listItemBorderColor": "#E5E7EB",
"listItemBorderWidth": "1px",
"listItemBorderRadius": "4px"
}
}
}
} No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

🧩 Analysis chain

Rebuild assets after schema/render changes.

The build and src differ (e.g., showIconInResults, type validation). After updating schema and render, rebuild to keep assets/build in sync.


🏁 Script executed:

#!/bin/bash
rg -n "showIconInResults" src/ assets/build/ | cat
rg -n "wedocs_is_section_doc|wedocs_is_article_doc" assets/build/blocks/QuickSearch/render.php

Length of output: 1000


Rebuild assets — src and assets/build are out of sync (missing showIconInResults).

Rebuild the block assets so assets/build/blocks/QuickSearch/block.json matches src.

  • src/blocks/QuickSearch/block.json (defines showIconInResults) and src/blocks/QuickSearch/{attributes.js, edit.js, save.js, render.php} reference it.
  • assets/build/blocks/QuickSearch/block.json (current built file) does not include showIconInResults.
  • assets/build/blocks/QuickSearch/render.php references data-show-icon-in-results (see occurrences around lines where grep found matches).

Comment on lines +14 to +38
"attributes": {
"searchBoxPlaceholder": {
"type": "string",
"default": "Quick search..."
},
"modalPlaceholder": {
"type": "string",
"default": "Search documentation"
},
"modalDocsSource": {
"type": "string",
"default": "helpful"
},
"sectionIds": {
"type": "string",
"default": ""
},
"articleIds": {
"type": "string",
"default": ""
},
"helpfulDocsCount": {
"type": "number",
"default": 10
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Add missing showIconInResults attribute.

The editor exposes it; without schema here it won’t persist.

Apply:

   "attributes": {
+    "showIconInResults": {
+      "type": "boolean",
+      "default": true
+    },
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"attributes": {
"searchBoxPlaceholder": {
"type": "string",
"default": "Quick search..."
},
"modalPlaceholder": {
"type": "string",
"default": "Search documentation"
},
"modalDocsSource": {
"type": "string",
"default": "helpful"
},
"sectionIds": {
"type": "string",
"default": ""
},
"articleIds": {
"type": "string",
"default": ""
},
"helpfulDocsCount": {
"type": "number",
"default": 10
},
"attributes": {
"showIconInResults": {
"type": "boolean",
"default": true
},
"searchBoxPlaceholder": {
"type": "string",
"default": "Quick search..."
},
"modalPlaceholder": {
"type": "string",
"default": "Search documentation"
},
"modalDocsSource": {
"type": "string",
"default": "helpful"
},
"sectionIds": {
"type": "string",
"default": ""
},
"articleIds": {
"type": "string",
"default": ""
},
"helpfulDocsCount": {
"type": "number",
"default": 10
},
🤖 Prompt for AI Agents
In assets/build/blocks/QuickSearch/block.json around lines 14 to 38, the
attributes schema is missing the editor-exposed showIconInResults attribute so
its value won't persist; add a new attribute entry under "attributes" named
"showIconInResults" with "type": "boolean" and a sensible default (e.g., true)
so the editor value is stored and restored.

Comment on lines +210 to +219
// Build data attributes
$data_attributes = [
'data-placeholder="' . esc_attr( $search_box_placeholder ) . '"',
'data-modal-placeholder="' . esc_attr( $modal_placeholder ) . '"',
'data-modal-docs-source="' . esc_attr( $modal_docs_source ) . '"',
'data-section-ids="' . esc_attr( $section_ids ) . '"',
'data-article-ids="' . esc_attr( $article_ids ) . '"',
'data-helpful-docs-count="' . esc_attr( $helpful_docs_count ) . '"',
];
$data_attributes_string = implode( ' ', $data_attributes );
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Wire showIconInResults through data attributes and AJAX.

Build file misses this attribute; src version has it. Keep build in sync.

Apply:

-    $helpful_docs_count = $attributes['helpfulDocsCount'] ?? 10;
+    $helpful_docs_count = $attributes['helpfulDocsCount'] ?? 10;
+    $show_icon_in_results = $attributes['showIconInResults'] ?? true;
@@
-        'data-helpful-docs-count="' . esc_attr( $helpful_docs_count ) . '"',
+        'data-helpful-docs-count="' . esc_attr( $helpful_docs_count ) . '"',
+        'data-show-icon-in-results="' . esc_attr( $show_icon_in_results ? 'true' : 'false' ) . '"',

And in JS:

-                const requestData = {
+                const requestData = {
                     action: 'wedocs_quick_search',
                     query: query,
                     per_page: '10',
                     format: 'html',
                     modal_styles: JSON.stringify(modalStyles),
+                    show_icon_in_results: trigger.getAttribute('data-show-icon-in-results') === 'true',
                     _wpnonce: weDocs_Vars.nonce
                 };

Also applies to: 606-616

🤖 Prompt for AI Agents
In assets/build/blocks/QuickSearch/render.php around lines 210-219 (and
similarly update the block render area around lines 606-616), the data attribute
for showIconInResults is missing; add a 'data-show-icon-in-results="' .
esc_attr( $show_icon_in_results ) . '"' entry to the $data_attributes array so
the built markup includes the flag, and ensure the same variable is propagated
into any AJAX payload/response code paths in this file (the block render and the
AJAX data assembly sections) so the frontend receives and can read the attribute
via JS.

Comment on lines +322 to +339
/* Modal Styles */
.wedocs-quick-search-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}

.wedocs-quick-search-modal.active {
display: flex;
}
</style>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Modal overlay should be fixed-position, not absolute.

position: absolute won’t cover the viewport reliably. Use fixed.

Apply:

-        .wedocs-quick-search-modal {
+        .wedocs-quick-search-modal {
             display: none;
-            position: absolute;
+            position: fixed;
             top: 0;
             left: 0;
             width: 100%;
             height: 100%;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* Modal Styles */
.wedocs-quick-search-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}
.wedocs-quick-search-modal.active {
display: flex;
}
</style>
/* Modal Styles */
.wedocs-quick-search-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}
.wedocs-quick-search-modal.active {
display: flex;
}
</style>
🤖 Prompt for AI Agents
In assets/build/blocks/QuickSearch/render.php around lines 322 to 339, the modal
overlay currently uses position: absolute which can fail to cover the viewport;
change it to position: fixed and ensure it spans the viewport by using top: 0;
left: 0; right: 0; bottom: 0 (or width: 100%; height: 100%), keep the
background-color and z-index as-is, and retain the .active rule that switches
display to flex so the modal centers correctly.

Comment on lines +345 to +349
const trigger = document.querySelector('.wedocs-quick-search-trigger');

if (!trigger) return;

// Create modal dynamically
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Support multiple block instances on a page.

document.querySelector binds only the first trigger. Iterate triggers and guard re‑init.

Apply:

-        const trigger = document.querySelector('.wedocs-quick-search-trigger');
-
-        if (!trigger) return;
+        const triggers = document.querySelectorAll('.wedocs-quick-search-trigger:not([data-qs-enhanced="1"])');
+        if (!triggers.length) return;
+        triggers.forEach((trigger) => {
+        trigger.setAttribute('data-qs-enhanced','1');

And add a closing }); just before the IIFE ends.

-    })();
+    })();
+    // end foreach
+    });

If you prefer strict scoping, I can switch this to document.currentScript scoping.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In assets/build/blocks/QuickSearch/render.php around lines 345-349, the code
uses document.querySelector which only binds the first
.wedocs-quick-search-trigger; change to select all triggers
(document.querySelectorAll) and iterate them, creating/attaching the modal and
event listeners per trigger while guarding against double initialization (e.g.,
set a data-initialized attribute or add a marker class before wiring). Ensure
the modal creation is scoped per instance (unique IDs or closed-over variables)
and that any shared handlers reference the correct instance. Finally, add the
missing closing "});" just before the IIFE ends to properly close the
iteration/initialization block.

Comment on lines +20 to +44
function wedocs_is_parent_doc( $doc_id ) {
return (int) wp_get_post_parent_id( $doc_id ) === 0;
}

/**
* Check if a docs post is a section (child of a parent doc)
*
* @param int $doc_id Post ID
* @return bool True if section, false otherwise
*/
function wedocs_is_section_doc( $doc_id ) {
$parent_id = wp_get_post_parent_id( $doc_id );
return $parent_id > 0 && wedocs_is_parent_doc( $parent_id );
}

/**
* Check if a docs post is an article (child of a section)
*
* @param int $doc_id Post ID
* @return bool True if article, false otherwise
*/
function wedocs_is_article_doc( $doc_id ) {
$parent_id = wp_get_post_parent_id( $doc_id );
return $parent_id > 0 && wedocs_is_section_doc( $parent_id );
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Guard helper declarations with function_exists.

Prevents fatal re‑declarations if helpers are defined elsewhere.

Apply:

-function wedocs_is_parent_doc( $doc_id ) {
-    return (int) wp_get_post_parent_id( $doc_id ) === 0;
-}
+if ( ! function_exists( 'wedocs_is_parent_doc' ) ) {
+    function wedocs_is_parent_doc( $doc_id ) {
+        return (int) wp_get_post_parent_id( $doc_id ) === 0;
+    }
+}
@@
-function wedocs_is_section_doc( $doc_id ) {
+if ( ! function_exists( 'wedocs_is_section_doc' ) ) {
+function wedocs_is_section_doc( $doc_id ) {
     $parent_id = wp_get_post_parent_id( $doc_id );
     return $parent_id > 0 && wedocs_is_parent_doc( $parent_id );
 }
+}
@@
-function wedocs_is_article_doc( $doc_id ) {
+if ( ! function_exists( 'wedocs_is_article_doc' ) ) {
+function wedocs_is_article_doc( $doc_id ) {
     $parent_id = wp_get_post_parent_id( $doc_id );
     return $parent_id > 0 && wedocs_is_section_doc( $parent_id );
 }
+}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function wedocs_is_parent_doc( $doc_id ) {
return (int) wp_get_post_parent_id( $doc_id ) === 0;
}
/**
* Check if a docs post is a section (child of a parent doc)
*
* @param int $doc_id Post ID
* @return bool True if section, false otherwise
*/
function wedocs_is_section_doc( $doc_id ) {
$parent_id = wp_get_post_parent_id( $doc_id );
return $parent_id > 0 && wedocs_is_parent_doc( $parent_id );
}
/**
* Check if a docs post is an article (child of a section)
*
* @param int $doc_id Post ID
* @return bool True if article, false otherwise
*/
function wedocs_is_article_doc( $doc_id ) {
$parent_id = wp_get_post_parent_id( $doc_id );
return $parent_id > 0 && wedocs_is_section_doc( $parent_id );
}
if ( ! function_exists( 'wedocs_is_parent_doc' ) ) {
function wedocs_is_parent_doc( $doc_id ) {
return (int) wp_get_post_parent_id( $doc_id ) === 0;
}
}
/**
* Check if a docs post is a section (child of a parent doc)
*
* @param int $doc_id Post ID
* @return bool True if section, false otherwise
*/
if ( ! function_exists( 'wedocs_is_section_doc' ) ) {
function wedocs_is_section_doc( $doc_id ) {
$parent_id = wp_get_post_parent_id( $doc_id );
return $parent_id > 0 && wedocs_is_parent_doc( $parent_id );
}
}
/**
* Check if a docs post is an article (child of a section)
*
* @param int $doc_id Post ID
* @return bool True if article, false otherwise
*/
if ( ! function_exists( 'wedocs_is_article_doc' ) ) {
function wedocs_is_article_doc( $doc_id ) {
$parent_id = wp_get_post_parent_id( $doc_id );
return $parent_id > 0 && wedocs_is_section_doc( $parent_id );
}
}
🤖 Prompt for AI Agents
In src/blocks/QuickSearch/render.php around lines 20 to 44, the three helper
functions (wedocs_is_parent_doc, wedocs_is_section_doc, wedocs_is_article_doc)
must be guarded to avoid fatal redeclaration: wrap each function declaration in
an if ( ! function_exists( 'function_name' ) ) { ... } check so the function is
only declared when it doesn't already exist, leaving the existing logic and
docblocks intact.

Comment on lines +376 to +392
/* Modal Styles */
.wedocs-quick-search-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}

.wedocs-quick-search-modal.active {
display: flex;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use fixed overlay for the modal.

Same as build file.

Apply:

-        .wedocs-quick-search-modal {
+        .wedocs-quick-search-modal {
             display: none;
-            position: absolute;
+            position: fixed;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/* Modal Styles */
.wedocs-quick-search-modal {
display: none;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}
.wedocs-quick-search-modal.active {
display: flex;
}
/* Modal Styles */
.wedocs-quick-search-modal {
display: none;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.5);
z-index: 9999;
justify-content: center;
align-items: center;
}
.wedocs-quick-search-modal.active {
display: flex;
}
🤖 Prompt for AI Agents
In src/blocks/QuickSearch/render.php around lines 376 to 392, the modal overlay
currently uses position: absolute which can misplace the overlay; change it to
position: fixed (keep top: 0; left: 0; width: 100%; height: 100%;
background-color: rgba(0,0,0,0.5); z-index: 9999; justify-content: center;
align-items: center) so the overlay covers the viewport consistently, and retain
the .active display:flex rule.

Comment on lines +397 to +405
<script>
(function() {
const trigger = document.querySelector('.wedocs-quick-search-trigger');

if (!trigger) return;

// Create modal dynamically
const modal = document.createElement('div');
modal.className = 'wedocs-quick-search-modal wedocs-document';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Support multiple block instances.

Scope per trigger (or guard re‑init) as in build suggestion.

I can mirror the data-qs-enhanced + loop pattern here as well for consistency.

Also applies to: 818-821

🤖 Prompt for AI Agents
In src/blocks/QuickSearch/render.php around lines 397 to 405, the script
currently selects a single .wedocs-quick-search-trigger and creates a global
modal, which breaks when there are multiple block instances; change to
querySelectorAll and loop over each trigger, scoping modal creation and event
handlers per-trigger, and add a data-qs-enhanced guard (e.g., skip triggers
already enhanced) to avoid double-init; apply the same pattern to the similar
code at lines 818-821 so each block instance gets its own modal and handlers and
re-initialization is prevented.

Comment on lines +28 to +41
$is_parent = $doc['parent'] === 0;
$is_section = $doc['parent'] > 0 && ! $is_parent;
$is_article = $doc['parent'] > 0 && $is_section;

$doc_type = 'Doc';
$doc_type_color = $modal_styles['docLabelColor'] ?? '#3B82F6';

if ( $is_section ) {
$doc_type = 'Section';
$doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
} elseif ( $is_article ) {
$doc_type = 'Article';
$doc_type_color = $modal_styles['articleLabelColor'] ?? '#8B5CF6';
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix unreachable “Article” branch and make type detection robust.

$is_article mirrors $is_section, so the elseif ($is_article) never runs. Prefer using an explicit $doc['type'] when provided, and fall back to parent heuristics.

Apply:

-            // Determine document type and styling
-            $is_parent = $doc['parent'] === 0;
-            $is_section = $doc['parent'] > 0 && ! $is_parent;
-            $is_article = $doc['parent'] > 0 && $is_section;
-
-            $doc_type = 'Doc';
-            $doc_type_color = $modal_styles['docLabelColor'] ?? '#3B82F6';
-
-            if ( $is_section ) {
-                $doc_type = 'Section';
-                $doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
-            } elseif ( $is_article ) {
-                $doc_type = 'Article';
-                $doc_type_color = $modal_styles['articleLabelColor'] ?? '#8B5CF6';
-            }
+            // Determine document type and styling (prefer explicit type)
+            $parent = isset($doc['parent']) ? (int) $doc['parent'] : 0;
+            $type   = isset($doc['type']) ? strtolower((string) $doc['type']) : null;
+
+            if ($type === 'section') {
+                $doc_type = 'Section';
+                $doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
+            } elseif ($type === 'article') {
+                $doc_type = 'Article';
+                $doc_type_color = $modal_styles['articleLabelColor'] ?? '#8B5CF6';
+            } elseif ($parent === 0) {
+                $doc_type = 'Doc';
+                $doc_type_color = $modal_styles['docLabelColor'] ?? '#3B82F6';
+            } else {
+                // Unknown child: default to Section styling
+                $doc_type = 'Section';
+                $doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
+            }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$is_parent = $doc['parent'] === 0;
$is_section = $doc['parent'] > 0 && ! $is_parent;
$is_article = $doc['parent'] > 0 && $is_section;
$doc_type = 'Doc';
$doc_type_color = $modal_styles['docLabelColor'] ?? '#3B82F6';
if ( $is_section ) {
$doc_type = 'Section';
$doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
} elseif ( $is_article ) {
$doc_type = 'Article';
$doc_type_color = $modal_styles['articleLabelColor'] ?? '#8B5CF6';
}
// Determine document type and styling (prefer explicit type)
$parent = isset($doc['parent']) ? (int) $doc['parent'] : 0;
$type = isset($doc['type']) ? strtolower((string) $doc['type']) : null;
if ($type === 'section') {
$doc_type = 'Section';
$doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
} elseif ($type === 'article') {
$doc_type = 'Article';
$doc_type_color = $modal_styles['articleLabelColor'] ?? '#8B5CF6';
} elseif ($parent === 0) {
$doc_type = 'Doc';
$doc_type_color = $modal_styles['docLabelColor'] ?? '#3B82F6';
} else {
// Unknown child: default to Section styling
$doc_type = 'Section';
$doc_type_color = $modal_styles['sectionLabelColor'] ?? '#10B981';
}

Comment on lines +44 to +55
$title = is_array( $doc['title'] ) ? $doc['title']['rendered'] : $doc['title'];
$permalink = $doc['permalink'] ?? '#';

// Highlight search terms in title
$highlighted_title = $title;
if ( ! empty( $query ) && strlen( $query ) >= 2 ) {
$highlighted_title = preg_replace(
'/(' . preg_quote( $query, '/' ) . ')/i',
'<mark class="bg-yellow-200 px-1 rounded">$1</mark>',
$title
);
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Escape title before highlighting to prevent XSS; allow only .

Currently echoing $highlighted_title without escaping risks HTML injection via titles.

Apply:

-            // Get document title
-            $title = is_array( $doc['title'] ) ? $doc['title']['rendered'] : $doc['title'];
+            // Get and escape document title
+            $raw_title = is_array( $doc['title'] ) ? ( $doc['title']['rendered'] ?? '' ) : ( $doc['title'] ?? '' );
+            $safe_title = esc_html( $raw_title );
@@
-            $highlighted_title = $title;
+            $highlighted_title = $safe_title;
             if ( ! empty( $query ) && strlen( $query ) >= 2 ) {
                 $highlighted_title = preg_replace(
                     '/(' . preg_quote( $query, '/' ) . ')/i',
                     '<mark class="bg-yellow-200 px-1 rounded">$1</mark>',
-                    $title
+                    $safe_title
                 );
             }
@@
-                        <?php echo $highlighted_title; ?>
+                        <?php echo wp_kses( $highlighted_title, [ 'mark' => [ 'class' => [] ] ] ); ?>

Also applies to: 86-86

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