-
Couldn't load subscription status.
- Fork 96
feat: block quick search #229
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Conversation
WalkthroughIntroduces 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
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing touches
🧪 Generate unit tests
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.
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. Comment |
There was a problem hiding this 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 removeswindow.openerlinkage.- <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.mapis 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 likejavascript: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 spinblocks in the CSS, which could cause conflicts. The static analysis tool correctly identified this duplication.Remove one of the duplicate
@keyframes spindefinitions 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-propertyandgrid-template-columnsdeclarations 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-carouselCSS 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
setDocStateandisNotInParentcan 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-settingsis 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
helpfulDocsCountattribute 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
$queryimplicitly. 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 unusedsearchBoxStyleobject.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 unusedcolorOptions.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" + disabledassets/build/blocks/QuickSearch/render.php (4)
411-418: Addrel="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 withsrc/logic: validate doc types inget_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
AbortControlleror a monotonically increasing request id to drop stale responses.I can patch this if you want.
src/blocks/QuickSearch/render.php (4)
466-471: Addrel="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:highlightSearchTermsis 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
AbortControlleror a request counter to drop stale responses.I can patch with a minimal
let currentControllerpattern if you’d like.Also applies to: 561-574
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (10)
assets/build/block.js.mapis excluded by!**/*.mapassets/build/frontend.css.mapis excluded by!**/*.mapassets/build/frontend.js.mapis excluded by!**/*.mapassets/build/index.css.mapis excluded by!**/*.mapassets/build/index.js.mapis excluded by!**/*.mapassets/build/print.css.mapis excluded by!**/*.mapassets/build/print.js.mapis excluded by!**/*.mapassets/build/store.js.mapis excluded by!**/*.mapassets/build/style-block.css.mapis excluded by!**/*.mappackage-lock.jsonis 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-fetchandwp-dataalign 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
20suffix 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
hideBlockis true follows React best practices.
27-47: LGTM! Comprehensive style object construction.The
searchBoxStyleobject correctly maps all styling attributes fromsearchBoxStylesand includes CSS custom properties for dynamic styling.
49-70: LGTM! Well-structured CSS variables.The
modalStyleobject 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
.badgeand.kbdcomponent styles follow DaisyUI patterns for displaying status information and keyboard shortcuts respectively.
2146-2199: Modal system implementation looks comprehensive.The modal styles with
.modal,.!modalvariants, and interaction states provide a complete modal dialog system as expected from DaisyUI components.
2256-2298: Steps widget implementation matches DaisyUI patterns.The
.stepscomponent 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
20assumes 6‑digit hex. Consider computingrgba()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.
colorsshould be an array of{ name, color }. Usecolors={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: KeepmodalStylesdefaults aligned with src attributes.Missing
listItemBackgroundColor(used by templates) and optionallistItemIconBackgroundColor.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.
| { | ||
| "$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 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 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.phpLength 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).
| "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 | ||
| }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| "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.
| // 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 ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| /* 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> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| /* 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.
| const trigger = document.querySelector('.wedocs-quick-search-trigger'); | ||
|
|
||
| if (!trigger) return; | ||
|
|
||
| // Create modal dynamically |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| 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 ); | ||
| } |
There was a problem hiding this comment.
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.
| 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.
| /* 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; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| /* 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.
| <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'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| $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'; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
| $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'; | |
| } |
| $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 | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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
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
Improvements
Chores