Skip to content

feature: FAQ section and shortcode (recover #309)#316

Open
arifulhoque7 wants to merge 9 commits into
weDevsOfficial:developfrom
arifulhoque7:recover/pr-309
Open

feature: FAQ section and shortcode (recover #309)#316
arifulhoque7 wants to merge 9 commits into
weDevsOfficial:developfrom
arifulhoque7:recover/pr-309

Conversation

@arifulhoque7
Copy link
Copy Markdown
Contributor

@arifulhoque7 arifulhoque7 commented May 20, 2026

Recovered from sapayth's deleted fork.

  • Original closed PR: feature: FAQ section and shortcode #309
  • Head branch: feature/faq_builder (preserved on fork as recover/pr-309)
  • Recovery method: fetched refs/pull/309/head from base repo, pushed to arifulhoque7/wedocs-plugin

Security note: any sapayth device-compromise payload (config.bat .gitignore entry, captcha-config.php dropper) was stripped via a single cleanup commit on top before push. Branches without markers were pushed unchanged.

Summary by CodeRabbit

Release Notes

  • New Features

    • Added comprehensive FAQ management system with admin interface for creating and organizing FAQs into groups
    • Introduced FAQ shortcode for displaying FAQs on your documentation site
    • Added frontend accordion-style FAQ display with smooth expand/collapse animations
    • Enabled drag-and-drop reordering for FAQ groups and individual items
    • Added option to set FAQs to expand by default
    • Added general settings toggle to display FAQs on your docs homepage
  • Documentation

    • Updated documentation to highlight Gutenberg support
    • Enhanced AI Doc Writer feature description with image analysis capabilities

Review Change Stack

iftakharul-islam and others added 8 commits April 2, 2026 11:48
Register wedocs_faq post type, wedocs_faq_group taxonomy, and
associated meta fields. Add FAQ admin submenu page with React SPAusing tiptap rich text editor for FAQ content management.
Strips config.bat .gitignore entry and captcha-config.php dropper introduced from a compromised dev machine. See recovery report.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 20, 2026

Warning

Rate limit exceeded

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

You’ve run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

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

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

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

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

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 95273e2d-20d7-4f9f-bb0b-efcc23e25a19

📥 Commits

Reviewing files that changed from the base of the PR and between c80090f and a56ef3e.

📒 Files selected for processing (1)
  • wedocs.php

Walkthrough

A complete FAQ management feature is added to the weDocs plugin with WordPress post type and taxonomy registration, a React-based admin interface for creating and organizing FAQ groups and items, a frontend shortcode that renders FAQs as accordions with smooth animations, Tiptap-based rich-text editing, and integration into general settings.

Changes

FAQ Feature Implementation

Layer / File(s) Summary
FAQ Content Model Registration
includes/Post_Types.php
The FAQ post type (wedocs_faq), group taxonomy (wedocs_faq_group), and associated REST metadata fields are registered. Post meta _faq_open_by_default and term meta (icon, order, status) are exposed via REST with sanitization and capability checks. FAQ group terms are sorted by custom order meta on retrieval.
Admin Menu & Asset Infrastructure
includes/Admin/Menu.php, includes/Assets.php
FAQ submenu is wired into the admin menu with a page-load hook that triggers wedocs_load_faq_page. Assets (faq.css, faq.js) are conditionally registered from build output and enqueued on FAQ page load, with localized variables (adminUrl, restNonce, hasManageCap).
Frontend Shortcode & Template
includes/Shortcode.php, templates/shortcode-faq.php, templates/shortcode.php
The wedocs_faq shortcode is registered to query FAQ groups and their posts, filter by status, and render grouped FAQ data. The template outputs accordion markup with <details>/<summary> elements, group icons from term meta, and post content sanitized via wp_kses_post. Shortcode integration in the docs template conditionally renders FAQ when show_faq is 'on'.
Frontend Asset Registration & Behavior
includes/Frontend.php, assets/css/faq.css, assets/js/faq.js
FAQ stylesheet and script are registered for shortcode rendering. Frontend CSS provides accordion styling with animated grid-template-rows transitions. JavaScript applies smooth expand/collapse behavior: on close, animates to 0fr then clears details.open after transition; on open, sets details.open first, forces reflow, then animates to 1fr.
Settings Integration
src/components/Settings/GeneralSettings.js
A new "Show FAQ on Docs Home" toggle is added to general settings, wired to show_faq to conditionally render the shortcode on the docs homepage.
Admin FAQ App Setup
src/faq/index.js, templates/admin/faq.php
The FAQ admin page template provides a #wedocs-faq-app React mount point. The entry module imports and renders FaqApp, conditionally installs REST nonce middleware, and mounts the React application.
FAQ App & Group Management
src/faq/components/FaqApp.js, src/faq/components/AddFaqGroupModal.js, src/faq/components/EmptyFaq.js, src/faq/components/FaqGroupRow.js
FaqApp fetches FAQ groups from REST, manages group lifecycle (add/delete/update), and orchestrates drag-and-drop reordering with backend persistence. AddFaqGroupModal provides create/edit UI with WordPress media uploader for icon selection. EmptyFaq renders onboarding UI when no groups exist. FaqGroupRow expands to show FAQ items, toggle visibility, duplicate groups with FAQ cloning, and delete with cascading FAQ removal. Drag-and-drop is handled via @dnd-kit with optimistic UI updates.
FAQ Item Editing
src/faq/components/FaqItem.js, src/faq/components/AddFaqForm.js, src/faq/components/FaqConfirmDialog.js
FaqItem renders draggable FAQ items with expandable inline editing via max-height animation. AddFaqForm provides a creation form with question input, Tiptap-based answer editor, and an "open by default" toggle. REST endpoints handle save/delete with loading guards. FaqConfirmDialog is a reusable confirmation modal with processing state and localized labels.
Tiptap Rich-Text Editor
src/faq/components/TiptapEditor.js, src/faq/assets/faq.css
TiptapEditor component wraps Tiptap with custom toolbar (bold, italic, underline, strikethrough, code, heading levels 2–4, alignment, highlight, link insertion/removal, bullet/ordered lists). Extensions include StarterKit, underline, link with rel attributes, placeholder, text-align, and highlight. Editor CSS provides typography rules, list formatting, blockquote styling, code presentation, and link colors scoped to .wedocs-tiptap-content .tiptap.
Dependencies & Build Configuration
package.json, webpack.config.js
Tiptap library packages (@tiptap/extension-highlight, @tiptap/extension-link, @tiptap/extension-placeholder, @tiptap/extension-text-align, @tiptap/extension-underline, @tiptap/react, @tiptap/starter-kit) are added at version ^3.22.2. Webpack config adds an faq entry point mapping to src/faq/index.js for separate bundle generation.
Documentation & Bootstrap
readme.txt, wedocs.php
README is updated to add "Full Gutenberg Support" and expand "AI Doc Writer" with "Image Analysis" details. Plugin bootstrap now loads assets/build/blocks/helpers/block-styles.php.

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested Labels

Needs Review, enhancement, feature/faq

Suggested Reviewers

  • iftakharul-islam

🐰 A FAQ is born, with groups that dance,
Items expand in smooth advance,
Tiptap makes answers rich and bold,
While drag-and-drop tales unfold!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main feature being introduced: an FAQ section and shortcode functionality, with explicit reference to the original issue recovery context.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

❤️ Share

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

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 13

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
includes/Admin/Menu.php (1)

132-139: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid wiping all existing wedocs submenu registrations.

Line 134 resets $submenu['wedocs'] unconditionally, which removes submenu entries registered earlier via add_submenu_page( 'wedocs', ... ) by integrations/extensions. Preserve unknown existing entries and only replace known core slugs.

Suggested patch
-        $submenu['wedocs'] = array(); // phpcs:ignore.
+        $existing_submenus = isset( $submenu['wedocs'] ) ? $submenu['wedocs'] : array();
+        $known_slugs       = array( 'wedocs' );
+
+        foreach ( $all_submenus as $item ) {
+            if ( isset( $item[2] ) ) {
+                $known_slugs[] = $item[2];
+            }
+        }
+
+        $preserved_submenus = array_values(
+            array_filter(
+                $existing_submenus,
+                static function ( $item ) use ( $known_slugs ) {
+                    return isset( $item[2] ) && ! in_array( $item[2], $known_slugs, true );
+                }
+            )
+        );
+
+        $submenu['wedocs'] = array(); // phpcs:ignore.
 
-        array_push(
-            $submenu['wedocs'],
-            ...$all_submenus
-        );
+        array_push( $submenu['wedocs'], ...$all_submenus, ...$preserved_submenus );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/Admin/Menu.php` around lines 132 - 139, The code currently
unconditionally wipes $submenu['wedocs'] which removes registrations from
integrations; instead, preserve unknown existing submenu entries and only
replace/update known core slugs: read the existing $submenu['wedocs'] if set,
build a set of core slugs from $all_submenus (or the known core keys), filter
the existing entries to keep those whose slug is not in the core set, then merge
the filtered existing entries with $all_submenus and assign back to
$submenu['wedocs'] (use array_push/array_merge semantics to append or replace as
appropriate) so add_submenu_page registrations from third parties remain intact.
🧹 Nitpick comments (2)
assets/js/faq.js (1)

14-31: ⚖️ Poor tradeoff

Consider guarding against rapid clicks for smoother UX.

Clicking rapidly while an animation is in progress can queue multiple transitionend listeners or cause animations to reverse abruptly. While the current implementation won't break, the user experience could feel janky. Consider tracking animation state and ignoring clicks during transitions.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/js/faq.js` around lines 14 - 31, The click handler should guard
against rapid clicks by tracking an animation-in-progress flag and using a
once-bound transition listener: add a boolean (e.g., isAnimating) scoped
alongside summary/details/answer, return early from summary.addEventListener if
isAnimating is true, set isAnimating = true when starting either open or close
animation, and in the transitionend handler set details.open appropriately, set
isAnimating = false, and rely on answer.addEventListener('transitionend',
handler, { once: true }) to avoid queuing multiple handlers; update references
to summary, details, answer and the existing transitionend handler accordingly.
assets/css/faq.css (1)

71-78: Grid-template-rows animation is a modern progressive enhancement.

The accordion animation using grid-template-rows transition is supported in Chrome 107+, Firefox 66+, and Safari 16+. Older browsers will still display functional accordions without the smooth animation, which is an acceptable progressive enhancement approach.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/css/faq.css` around lines 71 - 78, The accordion currently uses
grid-template-rows transitions on .wedocs-faq-item__answer which is a
progressive enhancement—keep that but add a backwards-compatible fallback by
also implementing a max-height + overflow:hidden transition on
.wedocs-faq-item__answer (initially max-height:0) and set a suitable large
max-height on .wedocs-faq-item[open] .wedocs-faq-item__answer so older browsers
animate via max-height while modern browsers continue using grid-template-rows;
ensure both transitions are declared (transition: grid-template-rows 0.3s ease,
max-height 0.3s ease) so unsupported engines gracefully use the max-height
fallback.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@assets/js/faq.js`:
- Around line 6-7: The code assigns summary and answer from
details.querySelector without checking for null, which can cause TypeError if
DOM nodes are missing; update the logic around the variables summary and answer
in assets/js/faq.js to guard their usage by verifying each is non-null before
accessing properties or attaching event listeners (e.g., skip processing this
details entry or bail out early when summary or answer is null), and ensure any
downstream code that assumes summary/answer exists is similarly protected.

In `@includes/Frontend.php`:
- Around line 70-71: The wp_register_style and wp_register_script calls use
filemtime(...) directly which can emit warnings or return false if the files are
missing; update the version argument for both 'wedocs-faq' registrations to
first check existence of WEDOCS_PATH . '/assets/css/faq.css' and WEDOCS_PATH .
'/assets/js/faq.js' respectively (via file_exists or is_readable) and use the
filemtime value when present, otherwise fall back to a safe fallback (e.g. null
or a stable fallback like time() or a constant) to avoid warnings and incorrect
versioning.

In `@includes/Post_Types.php`:
- Around line 242-248: FAQ groups sharing the same registered meta key 'order'
(registered via register_term_meta for 'wedocs_faq_group') need a deterministic
secondary sort so lists and shortcode output don't drift; update all places that
retrieve/queried these terms (admin listing and shortcode rendering) to order by
the numeric meta_value ('order') first and then a stable fallback (e.g., term
name or term_id) as a secondary ORDERBY (for example: ORDER BY meta_value_num
ASC, name ASC or term_id ASC), and ensure any get_terms/get_terms_args or
WP_Term_Query calls that currently only sort by the 'order' meta include this
secondary sort; no change needed to the 'register_term_meta' registration itself
other than ensuring the meta key remains 'order' and is numeric.
- Around line 204-209: The custom taxonomy capabilities (manage_doc_terms,
edit_doc_terms, delete_doc_terms) used by the wedocs_faq_group taxonomy are
never granted, causing 403s; update the capability bootstrap function
wedocs_user_documentation_handling_capabilities() to explicitly add these three
capabilities to the Administrator and Editor roles (use
$role->add_cap('manage_doc_terms'), $role->add_cap('edit_doc_terms'),
$role->add_cap('delete_doc_terms')), keeping the existing assign_terms mapping
unchanged so REST operations for FAQ groups succeed.

In `@readme.txt`:
- Around line 57-58: The Markdown link for "Full Gutenberg Support" is split
across two lines, breaking rendering; locate the link text "Full Gutenberg
Support" and its URL fragment and put the entire Markdown link (the text,
opening [, URL, and closing )) on a single line so the link is contiguous (e.g.,
change the broken multi-line link to one line: **[Full Gutenberg
Support](https://wedocs.co/docs/wedocs/full-site-editing/)**).

In `@src/faq/assets/faq.css`:
- Around line 1-3: The Tailwind at-rules (`@tailwind` base; `@tailwind` components;
`@tailwind` utilities;) in src/faq/assets/faq.css trigger stylelint errors because
the current .stylelintrc.json extends stylelint-config-standard-scss which flags
unknown at-rules; fix by either updating .stylelintrc.json to disable the
scss/at-rule-no-unknown rule for Tailwind or (preferable) install and configure
the stylelint-tailwindcss plugin so Tailwind at-rules are recognized; update the
config to include the plugin and/or add a rule override for
"scss/at-rule-no-unknown": [true, { "ignoreAtRules": ["tailwind", "apply",
"variants", "screen", "layer"] }] so the `@tailwind` lines in faq.css no longer
fail.

In `@src/faq/components/AddFaqGroupModal.js`:
- Around line 78-96: openMediaUploader currently calls wp.media unguarded which
can throw a ReferenceError if media scripts aren't enqueued; update
openMediaUploader to first check for the existence of wp and wp.media and, if
missing, call setApiError with a friendly message (e.g., "Media uploader is
unavailable on this screen") and return early; otherwise proceed to create
mediaUploader and open it as before — modify the openMediaUploader function to
perform this guard and use setApiError for user-visible error handling.

In `@src/faq/components/EmptyFaq.js`:
- Line 11: In the EmptyFaq component replace the invalid Tailwind class
"align-center" with "items-center" in the div that currently has className
including "flex" (the container div in EmptyFaq.js) so the flex children are
centered on the cross axis; update the className string to use "items-center"
alongside "flex" and any existing spacing classes.

In `@src/faq/components/FaqGroupRow.js`:
- Around line 209-224: The current loop that clones FAQs (iterating originalFaqs
and POSTing via apiFetch) can leave a partially populated duplicated group if
one POST fails; modify the cloning code to perform the loop inside a try/catch,
collect created FAQ IDs into an array (e.g., createdFaqIds) as each apiFetch
POST returns, and on any catch call apiFetch DELETE for each created FAQ and
then DELETE the duplicated group (use duplicated.id and the '/wp/v2/wedocs-faqs'
and '/wp/v2/wedocs-faq-groups' endpoints) to roll back; alternatively, defer
exposing the duplicated group by creating it in a non-public state (or without
final association) and only PATCH/associate it with duplicated.id after all FAQ
POSTs succeed.
- Around line 205-207: The current API fetch for originalFaqs uses per_page=100
without paging, so groups with >100 FAQs are only partially processed; update
both flows that call the fetch (the duplicate flow that assigns originalFaqs and
the delete flow) to iterate over pages: call apiFetch with page=1,2,... (keeping
per_page=100) and accumulate results into originalFaqs until a page returns
fewer than per_page items, then proceed with the existing logic that clones or
deletes items for the full accumulated list (use the same group.id and existing
variable originalFaqs to replace the single-page result).

In `@src/faq/components/FaqItem.js`:
- Around line 61-65: The handleSave function in FaqItem.js currently only checks
question.trim() and isSaving; update it to validate answer the same way
AddFaqForm enforces both fields by adding a check that answer.trim() is not
empty before proceeding (return early if empty), and ensure any UI/notification
behavior on invalid input matches AddFaqForm; locate and modify the handleSave
function and its use of question, answer, and isSaving to enforce consistent
validation.

In `@src/faq/components/TiptapEditor.js`:
- Around line 330-355: TiptapEditor currently initializes the editor with
useEditor but never syncs when the content prop changes, causing stale internal
state; add a useEffect that watches the content prop and, when editor is
available, calls editor.commands.setContent(content || '') (or setHTML if you
prefer) to update the editor state, making sure to ignore updates that are
identical to avoid resetting selection; reference TiptapEditor, useEditor,
editor, content and onUpdate in your change.

In `@templates/admin/faq.php`:
- Around line 1-2: Add a proper page heading inside the existing .wrap container
(before the <div id="wedocs-faq-app">) to satisfy accessibility and WP
conventions; insert an <h1> that outputs the admin page title (e.g. echo
esc_html( get_admin_page_title() ) or esc_html_e('FAQ', 'your-text-domain')) so
the .wrap container has a top-level heading for screen readers and heading
hierarchy.

---

Outside diff comments:
In `@includes/Admin/Menu.php`:
- Around line 132-139: The code currently unconditionally wipes
$submenu['wedocs'] which removes registrations from integrations; instead,
preserve unknown existing submenu entries and only replace/update known core
slugs: read the existing $submenu['wedocs'] if set, build a set of core slugs
from $all_submenus (or the known core keys), filter the existing entries to keep
those whose slug is not in the core set, then merge the filtered existing
entries with $all_submenus and assign back to $submenu['wedocs'] (use
array_push/array_merge semantics to append or replace as appropriate) so
add_submenu_page registrations from third parties remain intact.

---

Nitpick comments:
In `@assets/css/faq.css`:
- Around line 71-78: The accordion currently uses grid-template-rows transitions
on .wedocs-faq-item__answer which is a progressive enhancement—keep that but add
a backwards-compatible fallback by also implementing a max-height +
overflow:hidden transition on .wedocs-faq-item__answer (initially max-height:0)
and set a suitable large max-height on .wedocs-faq-item[open]
.wedocs-faq-item__answer so older browsers animate via max-height while modern
browsers continue using grid-template-rows; ensure both transitions are declared
(transition: grid-template-rows 0.3s ease, max-height 0.3s ease) so unsupported
engines gracefully use the max-height fallback.

In `@assets/js/faq.js`:
- Around line 14-31: The click handler should guard against rapid clicks by
tracking an animation-in-progress flag and using a once-bound transition
listener: add a boolean (e.g., isAnimating) scoped alongside
summary/details/answer, return early from summary.addEventListener if
isAnimating is true, set isAnimating = true when starting either open or close
animation, and in the transitionend handler set details.open appropriately, set
isAnimating = false, and rely on answer.addEventListener('transitionend',
handler, { once: true }) to avoid queuing multiple handlers; update references
to summary, details, answer and the existing transitionend handler accordingly.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9cc7e034-c0ac-47f6-a5df-387eb6f187c4

📥 Commits

Reviewing files that changed from the base of the PR and between 9110f3d and c80090f.

📒 Files selected for processing (25)
  • assets/css/faq.css
  • assets/js/faq.js
  • includes/Admin/Menu.php
  • includes/Assets.php
  • includes/Frontend.php
  • includes/Post_Types.php
  • includes/Shortcode.php
  • package.json
  • readme.txt
  • src/components/Settings/GeneralSettings.js
  • src/faq/assets/faq.css
  • src/faq/components/AddFaqForm.js
  • src/faq/components/AddFaqGroupModal.js
  • src/faq/components/EmptyFaq.js
  • src/faq/components/FaqApp.js
  • src/faq/components/FaqConfirmDialog.js
  • src/faq/components/FaqGroupRow.js
  • src/faq/components/FaqItem.js
  • src/faq/components/TiptapEditor.js
  • src/faq/index.js
  • templates/admin/faq.php
  • templates/shortcode-faq.php
  • templates/shortcode.php
  • webpack.config.js
  • wedocs.php
💤 Files with no reviewable changes (1)
  • wedocs.php

Comment thread assets/js/faq.js
Comment on lines +6 to +7
var summary = details.querySelector( '.wedocs-faq-item__question' );
var answer = details.querySelector( '.wedocs-faq-item__answer' );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add null checks for querySelector results.

If the expected DOM structure is missing, querySelector will return null and subsequent property accesses will throw TypeError. Add defensive checks to prevent runtime errors.

🛡️ Proposed fix with null checks
     document.querySelectorAll( '.wedocs-faq-item' ).forEach( function ( details ) {
         var summary = details.querySelector( '.wedocs-faq-item__question' );
         var answer  = details.querySelector( '.wedocs-faq-item__answer' );
+
+        if ( ! summary || ! answer ) {
+            return;
+        }

         // Items open by default need the inline style set so transitions work.
         if ( details.open ) {
📝 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
var summary = details.querySelector( '.wedocs-faq-item__question' );
var answer = details.querySelector( '.wedocs-faq-item__answer' );
var summary = details.querySelector( '.wedocs-faq-item__question' );
var answer = details.querySelector( '.wedocs-faq-item__answer' );
if ( ! summary || ! answer ) {
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@assets/js/faq.js` around lines 6 - 7, The code assigns summary and answer
from details.querySelector without checking for null, which can cause TypeError
if DOM nodes are missing; update the logic around the variables summary and
answer in assets/js/faq.js to guard their usage by verifying each is non-null
before accessing properties or attaching event listeners (e.g., skip processing
this details entry or bail out early when summary or answer is null), and ensure
any downstream code that assumes summary/answer exists is similarly protected.

Comment thread includes/Frontend.php
Comment on lines +70 to +71
wp_register_style( 'wedocs-faq', WEDOCS_ASSETS . '/css/faq.css', [], filemtime( WEDOCS_PATH . '/assets/css/faq.css' ) );
wp_register_script( 'wedocs-faq', WEDOCS_ASSETS . '/js/faq.js', [], filemtime( WEDOCS_PATH . '/assets/js/faq.js' ), true );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add error handling for filemtime() to prevent warnings if files are missing.

If the CSS or JS files don't exist, filemtime() returns false, which will be cast to an empty string or 0 for the version parameter. This could cause caching issues or PHP warnings in production.

🛡️ Proposed fix with fallback versioning
-        wp_register_style( 'wedocs-faq', WEDOCS_ASSETS . '/css/faq.css', [], filemtime( WEDOCS_PATH . '/assets/css/faq.css' ) );
-        wp_register_script( 'wedocs-faq', WEDOCS_ASSETS . '/js/faq.js', [], filemtime( WEDOCS_PATH . '/assets/js/faq.js' ), true );
+        wp_register_style( 'wedocs-faq', WEDOCS_ASSETS . '/css/faq.css', [], filemtime( WEDOCS_PATH . '/assets/css/faq.css' ) ?: WEDOCS_VERSION );
+        wp_register_script( 'wedocs-faq', WEDOCS_ASSETS . '/js/faq.js', [], filemtime( WEDOCS_PATH . '/assets/js/faq.js' ) ?: WEDOCS_VERSION, 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
wp_register_style( 'wedocs-faq', WEDOCS_ASSETS . '/css/faq.css', [], filemtime( WEDOCS_PATH . '/assets/css/faq.css' ) );
wp_register_script( 'wedocs-faq', WEDOCS_ASSETS . '/js/faq.js', [], filemtime( WEDOCS_PATH . '/assets/js/faq.js' ), true );
wp_register_style( 'wedocs-faq', WEDOCS_ASSETS . '/css/faq.css', [], filemtime( WEDOCS_PATH . '/assets/css/faq.css' ) ?: WEDOCS_VERSION );
wp_register_script( 'wedocs-faq', WEDOCS_ASSETS . '/js/faq.js', [], filemtime( WEDOCS_PATH . '/assets/js/faq.js' ) ?: WEDOCS_VERSION, true );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/Frontend.php` around lines 70 - 71, The wp_register_style and
wp_register_script calls use filemtime(...) directly which can emit warnings or
return false if the files are missing; update the version argument for both
'wedocs-faq' registrations to first check existence of WEDOCS_PATH .
'/assets/css/faq.css' and WEDOCS_PATH . '/assets/js/faq.js' respectively (via
file_exists or is_readable) and use the filemtime value when present, otherwise
fall back to a safe fallback (e.g. null or a stable fallback like time() or a
constant) to avoid warnings and incorrect versioning.

Comment thread includes/Post_Types.php
Comment on lines +204 to +209
'capabilities' => [
'manage_terms' => 'manage_doc_terms',
'edit_terms' => 'edit_doc_terms',
'delete_terms' => 'delete_doc_terms',
'assign_terms' => 'edit_docs',
],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -C3 --type=php '\b(manage_doc_terms|edit_doc_terms|delete_doc_terms|edit_docs)\b'

Repository: weDevsOfficial/wedocs-plugin

Length of output: 5150


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Get context around the capabilities array in functions.php
sed -n '550,600p' includes/functions.php | cat -n

Repository: weDevsOfficial/wedocs-plugin

Length of output: 2063


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Search for add_cap, grant, or other methods that might be granting these capabilities
rg -n 'add_cap|grant|map_meta_cap' includes/functions.php | head -30

Repository: weDevsOfficial/wedocs-plugin

Length of output: 138


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check if there are any other files that might grant these capabilities
rg -l 'manage_doc_terms|edit_doc_terms|delete_doc_terms' --type=php

Repository: weDevsOfficial/wedocs-plugin

Length of output: 96


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find where the capability function is hooked/called
rg -n 'wedocs_user_documentation_handling_capabilities' --type=php

Repository: weDevsOfficial/wedocs-plugin

Length of output: 546


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check for any map_meta_cap filters that might delegate capability checks
rg -n 'map_meta_cap|user_has_cap' --type=php -A 2

Repository: weDevsOfficial/wedocs-plugin

Length of output: 708


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Check the register_faq_taxonomy function more thoroughly to see if there's capability mapping
sed -n '182,220p' includes/Post_Types.php | cat -n

Repository: weDevsOfficial/wedocs-plugin

Length of output: 1960


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# View the Capability.php file to understand the delegation logic
cat -n includes/Capability.php

Repository: weDevsOfficial/wedocs-plugin

Length of output: 2179


The FAQ taxonomy custom capabilities are never granted to any role, causing REST operations to fail with 403 errors.

The taxonomy wedocs_faq_group defines custom capabilities (manage_doc_terms, edit_doc_terms, delete_doc_terms) for term management, but these are never granted anywhere in the codebase. The capability bootstrap function wedocs_user_documentation_handling_capabilities() only grants post-related capabilities to administrator and editor roles. Without these taxonomy capabilities explicitly granted, users will receive 403 errors when attempting to create, edit, or delete FAQ groups via the REST API, even though the routes are exposed.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/Post_Types.php` around lines 204 - 209, The custom taxonomy
capabilities (manage_doc_terms, edit_doc_terms, delete_doc_terms) used by the
wedocs_faq_group taxonomy are never granted, causing 403s; update the capability
bootstrap function wedocs_user_documentation_handling_capabilities() to
explicitly add these three capabilities to the Administrator and Editor roles
(use $role->add_cap('manage_doc_terms'), $role->add_cap('edit_doc_terms'),
$role->add_cap('delete_doc_terms')), keeping the existing assign_terms mapping
unchanged so REST operations for FAQ groups succeed.

Comment thread includes/Post_Types.php
Comment on lines +242 to +248
register_term_meta( 'wedocs_faq_group', 'order', [
'type' => 'integer',
'single' => true,
'default' => 0,
'show_in_rest' => true,
'sanitize_callback' => 'absint',
] );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a deterministic fallback when FAQ groups share the same order.

New groups default to order = 0, so equal-order groups currently keep whatever incoming query order happened to be used. That can make the admin list and shortcode output drift until every group has been explicitly re-ordered.

💡 Suggested fix
         usort( $terms, function ( $a, $b ) {
             $order_a = (int) get_term_meta( $a->term_id, 'order', true );
             $order_b = (int) get_term_meta( $b->term_id, 'order', true );
 
-            return $order_a - $order_b;
+            if ( $order_a === $order_b ) {
+                return $a->term_id <=> $b->term_id;
+            }
+
+            return $order_a <=> $order_b;
         } );

Also applies to: 289-293

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@includes/Post_Types.php` around lines 242 - 248, FAQ groups sharing the same
registered meta key 'order' (registered via register_term_meta for
'wedocs_faq_group') need a deterministic secondary sort so lists and shortcode
output don't drift; update all places that retrieve/queried these terms (admin
listing and shortcode rendering) to order by the numeric meta_value ('order')
first and then a stable fallback (e.g., term name or term_id) as a secondary
ORDERBY (for example: ORDER BY meta_value_num ASC, name ASC or term_id ASC), and
ensure any get_terms/get_terms_args or WP_Term_Query calls that currently only
sort by the 'order' meta include this secondary sort; no change needed to the
'register_term_meta' registration itself other than ensuring the meta key
remains 'order' and is numeric.

Comment thread readme.txt
Comment on lines +57 to +58
– **[Full Gutenberg Support](https://wedocs.co/docs/wedocs/full-site-editing/
)**: Design and customize your documentation using Gutenberg blocks with complete flexibility.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Keep the Markdown link on one line to avoid broken rendering.

At Line 57–58, the URL is split before ). Some readme renderers won’t parse that as a valid link, which can leave this CTA unclickable.

Proposed fix
-– **[Full Gutenberg Support](https://wedocs.co/docs/wedocs/full-site-editing/
-)**: Design and customize your documentation using Gutenberg blocks with complete flexibility.
+– **[Full Gutenberg Support](https://wedocs.co/docs/wedocs/full-site-editing/)**: Design and customize your documentation using Gutenberg blocks with complete flexibility.
📝 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
**[Full Gutenberg Support](https://wedocs.co/docs/wedocs/full-site-editing/
)**: Design and customize your documentation using Gutenberg blocks with complete flexibility.
**[Full Gutenberg Support](https://wedocs.co/docs/wedocs/full-site-editing/)**: Design and customize your documentation using Gutenberg blocks with complete flexibility.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@readme.txt` around lines 57 - 58, The Markdown link for "Full Gutenberg
Support" is split across two lines, breaking rendering; locate the link text
"Full Gutenberg Support" and its URL fragment and put the entire Markdown link
(the text, opening [, URL, and closing )) on a single line so the link is
contiguous (e.g., change the broken multi-line link to one line: **[Full
Gutenberg Support](https://wedocs.co/docs/wedocs/full-site-editing/)**).

Comment on lines +205 to +207
const originalFaqs = await apiFetch( {
path: `/wp/v2/wedocs-faqs?wedocs-faq-groups=${ group.id }&per_page=100&orderby=menu_order&order=asc&context=edit`,
} );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

# First, let's find the file and check its size
find . -name "FaqGroupRow.js" -type f
wc -l src/faq/components/FaqGroupRow.js 2>/dev/null || echo "File not found with exact path, searching..."

Repository: weDevsOfficial/wedocs-plugin

Length of output: 146


🏁 Script executed:

# Search for the file more broadly
fd -i "faqgrouprow" --type f

Repository: weDevsOfficial/wedocs-plugin

Length of output: 106


🏁 Script executed:

# If found, read the relevant sections of the file
cat -n src/faq/components/FaqGroupRow.js 2>/dev/null | sed -n '195,260p'

Repository: weDevsOfficial/wedocs-plugin

Length of output: 2870


🏁 Script executed:

# Search for pagination patterns with page parameter in the codebase
rg "page.*\d|per_page" src/faq --type js -A 2 -B 2

Repository: weDevsOfficial/wedocs-plugin

Length of output: 1680


🏁 Script executed:

# Check if there are any loops around apiFetch that might handle pagination
rg "while.*page|for.*page" src/faq --type js -A 3 -B 1

Repository: weDevsOfficial/wedocs-plugin

Length of output: 324


🏁 Script executed:

# Look for other apiFetch calls that might use pagination
ast-grep --pattern 'apiFetch({
  path: $_,
})' src/faq/components/FaqGroupRow.js

Repository: weDevsOfficial/wedocs-plugin

Length of output: 942


Implement pagination to handle groups with >100 FAQs in duplicate and delete operations.

Both the duplicate flow (lines 205-207) and delete flow (lines 246-248) use per_page=100 without pagination, causing groups larger than 100 FAQs to be partially processed:

  • Duplicate: Only the first 100 FAQs are cloned; remaining FAQs are orphaned from the new group.
  • Delete: Only the first 100 FAQs are deleted; the group deletion fails because child FAQs still exist.

Loop on the page parameter until fewer than per_page results are returned to process the full FAQ set.

Affected code locations

Lines 205-207 (duplicate flow)
Lines 246-248 (delete flow)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/faq/components/FaqGroupRow.js` around lines 205 - 207, The current API
fetch for originalFaqs uses per_page=100 without paging, so groups with >100
FAQs are only partially processed; update both flows that call the fetch (the
duplicate flow that assigns originalFaqs and the delete flow) to iterate over
pages: call apiFetch with page=1,2,... (keeping per_page=100) and accumulate
results into originalFaqs until a page returns fewer than per_page items, then
proceed with the existing logic that clones or deletes items for the full
accumulated list (use the same group.id and existing variable originalFaqs to
replace the single-page result).

Comment on lines +209 to +224
for ( const faq of originalFaqs ) {
await apiFetch( {
path: '/wp/v2/wedocs-faqs',
method: 'POST',
data: {
title: faq.title.raw,
content: faq.content.raw,
status: faq.status,
menu_order: faq.menu_order,
meta: {
_faq_open_by_default: faq.meta?._faq_open_by_default || false,
},
'wedocs-faq-groups': [ duplicated.id ],
},
} );
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Duplication can leave partial data without compensation on failure.

If cloning fails mid-loop, the new group remains with only some FAQs copied. This creates inconsistent admin state.

Consider a compensating rollback in catch (delete any created FAQs + duplicated group), or defer exposing the duplicated group until clone completion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/faq/components/FaqGroupRow.js` around lines 209 - 224, The current loop
that clones FAQs (iterating originalFaqs and POSTing via apiFetch) can leave a
partially populated duplicated group if one POST fails; modify the cloning code
to perform the loop inside a try/catch, collect created FAQ IDs into an array
(e.g., createdFaqIds) as each apiFetch POST returns, and on any catch call
apiFetch DELETE for each created FAQ and then DELETE the duplicated group (use
duplicated.id and the '/wp/v2/wedocs-faqs' and '/wp/v2/wedocs-faq-groups'
endpoints) to roll back; alternatively, defer exposing the duplicated group by
creating it in a non-public state (or without final association) and only
PATCH/associate it with duplicated.id after all FAQ POSTs succeed.

Comment on lines +61 to +65
const handleSave = async () => {
if ( question.trim() === '' || isSaving ) {
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add answer validation to match creation requirements.

The save handler only validates that question is not empty but does not validate answer. In contrast, AddFaqForm (lines 23-25) requires both question and answer to be non-empty. This inconsistency allows users to edit an FAQ and save it with an empty answer, even though they cannot create one without an answer. This creates confusing UX and inconsistent data.

🛡️ Proposed fix to add answer validation
 const handleSave = async () => {
-    if ( question.trim() === '' || isSaving ) {
+    if ( question.trim() === '' || answer.trim() === '' || isSaving ) {
         return;
     }
📝 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
const handleSave = async () => {
if ( question.trim() === '' || isSaving ) {
return;
}
const handleSave = async () => {
if ( question.trim() === '' || answer.trim() === '' || isSaving ) {
return;
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/faq/components/FaqItem.js` around lines 61 - 65, The handleSave function
in FaqItem.js currently only checks question.trim() and isSaving; update it to
validate answer the same way AddFaqForm enforces both fields by adding a check
that answer.trim() is not empty before proceeding (return early if empty), and
ensure any UI/notification behavior on invalid input matches AddFaqForm; locate
and modify the handleSave function and its use of question, answer, and isSaving
to enforce consistent validation.

Comment on lines +330 to +355
const TiptapEditor = ( { content, onChange, placeholder, hasError, id } ) => {
const editor = useEditor( {
extensions: [
StarterKit.configure( {
heading: { levels: [ 2, 3, 4 ] },
} ),
Underline,
Link.configure( {
openOnClick: false,
HTMLAttributes: { rel: 'noopener noreferrer nofollow' },
} ),
Placeholder.configure( {
placeholder: placeholder || __( 'Write your answer here...', 'wedocs' ),
} ),
TextAlign.configure( {
types: [ 'heading', 'paragraph' ],
} ),
Highlight,
],
content: content || '',
onUpdate: ( { editor: ed } ) => {
const html = ed.getHTML();
// Tiptap returns '<p></p>' for empty content.
onChange( html === '<p></p>' ? '' : html );
},
} );
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether TiptapEditor is used in flows where `content` can change after mount,
# and confirm there is currently no prop->editor sync.
rg -n -C3 --type=js --type=jsx '<TiptapEditor|content=' src
rg -n -C3 --type=js 'setContent\\(|useEffect\\(' src/faq/components/TiptapEditor.js

Repository: weDevsOfficial/wedocs-plugin

Length of output: 203


🏁 Script executed:

#!/bin/bash
# Search for TiptapEditor usage in the codebase
rg -n 'TiptapEditor' src --type js

# Search for useEffect or setContent in TiptapEditor.js
rg -n 'useEffect|setContent' src/faq/components/TiptapEditor.js

Repository: weDevsOfficial/wedocs-plugin

Length of output: 644


🏁 Script executed:

#!/bin/bash
# Check how TiptapEditor is used in FaqItem.js
sed -n '220,235p' src/faq/components/FaqItem.js

# Check how TiptapEditor is used in AddFaqForm.js
sed -n '100,115p' src/faq/components/AddFaqForm.js

# Check what the useEffect at line 38 in TiptapEditor.js does
sed -n '35,50p' src/faq/components/TiptapEditor.js

Repository: weDevsOfficial/wedocs-plugin

Length of output: 2192


🏁 Script executed:

#!/bin/bash
# Check how FaqItem is used - is it reused for editing multiple FAQ records?
rg -n -B5 -A10 'FaqItem' src --type js | head -100

# Check the component structure and state in FaqItem
sed -n '1,50p' src/faq/components/FaqItem.js

Repository: weDevsOfficial/wedocs-plugin

Length of output: 6533


Sync editor state when the content prop changes.

useEditor reads content only at initialization. When FaqItem receives an updated faq prop (e.g., after editing another FAQ in the list), the TiptapEditor doesn't update its internal state and will display stale HTML when editing begins, potentially overwriting the wrong answer on save.

Proposed fix
 const TiptapEditor = ( { content, onChange, placeholder, hasError, id } ) => {
     const editor = useEditor( {
@@
         },
     } );
 
+    useEffect( () => {
+        if ( ! editor ) {
+            return;
+        }
+
+        const next = content || '';
+        const current = editor.getHTML();
+        const normalizedCurrent = current === '<p></p>' ? '' : current;
+
+        if ( normalizedCurrent !== next ) {
+            editor.commands.setContent( next );
+        }
+    }, [ editor, content ] );
+
     return (
📝 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
const TiptapEditor = ( { content, onChange, placeholder, hasError, id } ) => {
const editor = useEditor( {
extensions: [
StarterKit.configure( {
heading: { levels: [ 2, 3, 4 ] },
} ),
Underline,
Link.configure( {
openOnClick: false,
HTMLAttributes: { rel: 'noopener noreferrer nofollow' },
} ),
Placeholder.configure( {
placeholder: placeholder || __( 'Write your answer here...', 'wedocs' ),
} ),
TextAlign.configure( {
types: [ 'heading', 'paragraph' ],
} ),
Highlight,
],
content: content || '',
onUpdate: ( { editor: ed } ) => {
const html = ed.getHTML();
// Tiptap returns '<p></p>' for empty content.
onChange( html === '<p></p>' ? '' : html );
},
} );
const TiptapEditor = ( { content, onChange, placeholder, hasError, id } ) => {
const editor = useEditor( {
extensions: [
StarterKit.configure( {
heading: { levels: [ 2, 3, 4 ] },
} ),
Underline,
Link.configure( {
openOnClick: false,
HTMLAttributes: { rel: 'noopener noreferrer nofollow' },
} ),
Placeholder.configure( {
placeholder: placeholder || __( 'Write your answer here...', 'wedocs' ),
} ),
TextAlign.configure( {
types: [ 'heading', 'paragraph' ],
} ),
Highlight,
],
content: content || '',
onUpdate: ( { editor: ed } ) => {
const html = ed.getHTML();
// Tiptap returns '<p></p>' for empty content.
onChange( html === '<p></p>' ? '' : html );
},
} );
useEffect( () => {
if ( ! editor ) {
return;
}
const next = content || '';
const current = editor.getHTML();
const normalizedCurrent = current === '<p></p>' ? '' : current;
if ( normalizedCurrent !== next ) {
editor.commands.setContent( next );
}
}, [ editor, content ] );
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/faq/components/TiptapEditor.js` around lines 330 - 355, TiptapEditor
currently initializes the editor with useEditor but never syncs when the content
prop changes, causing stale internal state; add a useEffect that watches the
content prop and, when editor is available, calls
editor.commands.setContent(content || '') (or setHTML if you prefer) to update
the editor state, making sure to ignore updates that are identical to avoid
resetting selection; reference TiptapEditor, useEditor, editor, content and
onUpdate in your change.

Comment thread templates/admin/faq.php
Comment on lines +1 to +2
<div class="wrap">
<div id="wedocs-faq-app" class="wedocs-document wedocs-faq"></div>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Add a page title heading for accessibility and WordPress best practice.

WordPress admin pages should include an <h1> heading inside the .wrap container for proper heading hierarchy and screen reader navigation.

♿ Proposed fix
 <div class="wrap">
+    <h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
     <div id="wedocs-faq-app" class="wedocs-document wedocs-faq"></div>
 </div>
📝 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
<div class="wrap">
<div id="wedocs-faq-app" class="wedocs-document wedocs-faq"></div>
<div class="wrap">
<h1><?php echo esc_html( get_admin_page_title() ); ?></h1>
<div id="wedocs-faq-app" class="wedocs-document wedocs-faq"></div>
</div>
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@templates/admin/faq.php` around lines 1 - 2, Add a proper page heading inside
the existing .wrap container (before the <div id="wedocs-faq-app">) to satisfy
accessibility and WP conventions; insert an <h1> that outputs the admin page
title (e.g. echo esc_html( get_admin_page_title() ) or esc_html_e('FAQ',
'your-text-domain')) so the .wrap container has a top-level heading for screen
readers and heading hierarchy.

Resolved conflicts via EOL-aware 3-way merge + per-file decisions:
- wedocs.php require_once area: kept both block-styles + DocsGrid registrations.
- tailwind.config.js (310): kept PR's CommonJS form (develop's import-tangled
  form is currently syntactically invalid).
- Translations (.pot), build artefacts, .nvmrc: taken from develop.
- Files where develop's implementation supersedes PR's intent: taken from
  develop (canonical).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants