-
Notifications
You must be signed in to change notification settings - Fork 92
Feat/pro block settings #257
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
WalkthroughDeletes many compiled build artifacts, adds numerous new source-based Gutenberg blocks, helpers, and UI controls/components, wraps DocsGrid render functions with redeclaration guards, and updates asset registration and webpack/package configuration. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
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: 79
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
webpack.config.js (1)
71-75: Avoid duplicate MiniCssExtractPlugin.@wordpress/scripts already injects MiniCssExtractPlugin. A second instance can cause conflicts. Reuse the existing one unless you have a specific need.
Apply this diff:
- plugins: [ - ...defaultConfig.plugins, - new MiniCSSExtractPlugin( { - filename: '[name].css', - chunkFilename: '[id].css', - } ), - ], + plugins: [ ...defaultConfig.plugins ],
🧹 Nitpick comments (98)
assets/build/style-block-rtl.css (2)
1-1: Reconsider extensive use of!importantflags.The CSS contains numerous
!importantdeclarations (e.g.,background-color:var(--field-color) !important), which typically indicates CSS architecture or specificity issues. Using!importantbroadly can make the codebase harder to maintain and override.Review the specificity of selectors and consider restructuring to rely on proper selector hierarchy instead of
!important. For example:/* Instead of: */ .wp-block-wedocs-wedocs-search .wedocs-search-input .search-field { background-color: var(--field-color) !important; } /* Consider: */ .wp-block-wedocs-wedocs-search .wedocs-search-input .search-field { background-color: var(--field-color); }This requires ensuring the selector specificity is sufficient without needing
!important.
1-1: Consider build artifact exclusion from version control.Build artifacts are typically auto-generated and should not be committed to version control. If this file is generated during the build process, it should be excluded via
.gitignoreand regenerated as part of CI/CD.Verify that
assets/build/is excluded from.gitignoreand that the build pipeline regenerates these files. This keeps the repository clean and ensures artifacts stay in sync with source.src/blocks/components/SpacingControl.js (3)
26-68: Consider extracting the duplicated BoxControl configuration.The Padding and Margin sections share identical configuration (units, allowReset, resetValues). Extract this into a shared helper or constant to improve maintainability.
Example refactor:
+const SPACING_BOX_CONFIG = { + units: [ + { value: 'px', label: 'px' }, + { value: 'em', label: 'em' }, + { value: 'rem', label: 'rem' }, + { value: '%', label: '%' } + ], + allowReset: true, + resetValues: { + top: '0px', + right: '0px', + bottom: '0px', + left: '0px' + } +}; + const SpacingControl = ({ // ... props }) => { return ( <PanelBody title={label} initialOpen={false}> {showPadding && ( <> <BoxControl label={__('Padding', 'wedocs')} values={paddingValue} onChange={onPaddingChange} - units={[ - { value: 'px', label: 'px' }, - { value: 'em', label: 'em' }, - { value: 'rem', label: 'rem' }, - { value: '%', label: '%' } - ]} - allowReset={true} - resetValues={{ - top: '0px', - right: '0px', - bottom: '0px', - left: '0px' - }} + {...SPACING_BOX_CONFIG} /> <Spacer marginTop={4} marginBottom={4} /> </> )} {showMargin && ( <> <BoxControl label={__('Margin', 'wedocs')} values={marginValue} onChange={onMarginChange} - units={[ - { value: 'px', label: 'px' }, - { value: 'em', label: 'em' }, - { value: 'rem', label: 'rem' }, - { value: '%', label: '%' } - ]} - allowReset={true} - resetValues={{ - top: '0px', - right: '0px', - bottom: '0px', - left: '0px' - }} + {...SPACING_BOX_CONFIG} /> <Spacer marginTop={4} marginBottom={4} /> </> )} </PanelBody> ); };
77-77: Consider consistent default value handling.The
gapValueuses an inline fallback ('10px') whilepaddingValueandmarginValuehave default values in the props destructuring. For consistency, consider adding a default forgapValuein the props definition (line 18).
74-85: Note: API inconsistency with custom UnitControl.This component uses WordPress's experimental
UnitControl(value as a string like'10px'), while the codebase also has a customUnitControlatsrc/blocks/CustomControls/UnitControl.jswith a different API (separatevalueandunitprops). Consider documenting when to use each or standardizing on one approach to avoid confusion.src/blocks/commonControls/DisplayControls.js (1)
26-47: Consider extracting styles to a stylesheet.While inline styles work, extracting them to a dedicated CSS file or using a CSS-in-JS solution would improve maintainability and allow for better reusability across components.
readme.md (1)
26-39: Remove misleading Mozart configuration comment from readme.md.This commented JSON block references "WPMUDEV\PluginTest" and includes
google/apiclient, but verification shows: the weDocs project has no Mozart configuration incomposer.json, andgoogle/apiclientis not used anywhere in the codebase. This appears to be accidentally copied from another project and should be deleted to avoid confusion.src/blocks/TableOfContents/editor.scss (1)
18-24: Consider the UX implications ofcursor: defaulton links.The TOC list links have
cursor: defaultbut still show a hover color change. This creates an inconsistent user experience where the visual feedback (color change on hover) suggests interactivity, but the cursor doesn't change to indicate a clickable element.If these links are not meant to be clickable in the editor (which seems to be the intent), consider either:
- Removing the hover color change to match the non-interactive cursor, or
- Using
pointer-events: noneto completely disable interaction and remove the need for hover styles.Apply this diff to remove hover styles for consistency:
.toc-content { .toc-list { li a { cursor: default; - - &:hover { - color: #0073aa; - } + pointer-events: none; } } }assets/build/blocks/TableOfContents/style-index.css (2)
1-1: Typo in custom property name (sytle → style) and likely wrong binding.color uses var(--list-item-sytle, inherit). Rename to a clear token (e.g., --toc-link-color) across LTR/RTL CSS and JS, and bind it to listColor (not container background).
1-1: Nit: prefer ::before/::after.Use double-colon pseudo-elements for modern CSS.
src/blocks/commonControls/TypographyControls.js (2)
255-270: Use undefined on reset instead of null to truly clear values.Block serialization treats undefined as “absent”; null may persist and complicate style builders. Prefer undefined.
Apply this diff:
- fontFamily: null, - fontSize: null, - fontAppearance: null, - lineHeight: null, - letterSpacing: null, - textDecoration: null, - textTransform: null, + fontFamily: undefined, + fontSize: undefined, + fontAppearance: undefined, + lineHeight: undefined, + letterSpacing: undefined, + textDecoration: undefined, + textTransform: undefined,
49-66: Reduce repetition with a small helper.setAttributes blocks repeat. Extract a setTypographyForDevice(key, value) helper to cut noise and mistakes.
Example:
+ const setTypographyForDevice = (key, value) => { + setAttributes({ + typographyControls: { + ...typographyControls, + [device]: { + ...typographyControls[device], + [key]: value, + }, + }, + }); + }; ... - onChange={(value) => { setAttributes({ ... }) }} + onChange={(value) => setTypographyForDevice('fontFamily', value)}Also applies to: 90-107, 111-144, 149-165, 167-201, 204-242
webpack.config.js (4)
19-20: Use content hashing (or path) for emitted assets to avoid collisions and aid caching.images/[name][ext] can overwrite when names repeat. Prefer contenthash or preserve subpaths.
Apply one:
- assetModuleFilename: 'images/[name][ext]', + assetModuleFilename: 'images/[name].[contenthash:8][ext]',or:
- assetModuleFilename: 'images/[name][ext]', + assetModuleFilename: '[path][name][ext]',
24-31: Broaden filter to include webp/avif; otherwise rules conflict.Default WP Scripts rules often match webp/avif; your filter leaves them, causing overlap.
Apply this diff:
- return !testString.match(/jpg|jpeg|png|gif|svg|bmp|ico/i); + return !testString.match(/jpg|jpeg|png|gif|svg|bmp|ico|webp|avif/i);
48-59: Brittle SVG routing by substring match.Checking pathData.filename.includes('assets/fonts') can fail with alternate paths. Use include/exclude with resolved paths, or a dedicated fonts rule before SVG images.
Example:
- if (pathData.filename.includes('assets/fonts')) { return 'fonts/[name][ext]'; } + // In rules: put a fonts-first rule with `test: /\.svg$/i, include: path.resolve(__dirname, 'assets/fonts')` + // and a second svg rule for images with `exclude` pointing to the fonts dir.
78-94: Make devServer host configurable.Hardcoding host 'wedocs.test' can block other devs. Read from env with a safe default.
Example:
- host: 'wedocs.test', + host: process.env.DEV_HOST || 'localhost', + port: parseInt(process.env.DEV_PORT || '8886', 10),src/blocks/components/TypographyControl.js (3)
54-70: Use theme/gutenberg font families, not a hard‑coded list.Pull families via useSettings('typography.fontFamilies') to respect theme.json and user fonts; fall back gracefully for classic themes.
Example snippet:
import { useSettings } from '@wordpress/block-editor'; const ff = useSettings( 'typography.fontFamilies' ); const themeFonts = ff?.[0]?.theme ?? []; const customFonts = ff?.[0]?.custom ?? []; const options = [{ label: __('Default','wedocs'), value: 'default' }, ...themeFonts, ...customFonts];
116-127: UnitControl defaults should be empty/undefined, not 'normal'.UnitControl expects numeric+unit (or empty). Use placeholders and treat undefined as “inherit/normal” in style builders.
Apply this diff:
- value={value.lineHeight || 'normal'} + value={value.lineHeight} ... - value={value.letterSpacing || 'normal'} + value={value.letterSpacing}Then handle “normal” in CSS generation (fallback when undefined).
Also applies to: 130-140
32-33: Open by default only when needed.Initial open Panels can be noisy. Consider initialOpen prop controlled by caller or keep it closed by default for consistency with other panels.
assets/build/blocks/TableOfContents/style-index-rtl.css (1)
1-1: Typo in custom property (sytle) and binding.Rename var(--list-item-sytle) to --toc-link-color (or similar) and align with JS to source from listColor, not container background.
src/blocks/helpers/README.md (1)
1-120: Add minimum WP/Gutenberg versions and SSR registration snippet.Include a short “Compatibility” section (min WP and Gutenberg) and a code snippet showing register_block_type with render_callback using these helpers for dynamic blocks. Helps adopters avoid guesswork.
assets/build/block.js (1)
1-1: Do not lint/review minified build artifacts; exclude assets/build from linters and code review.Biome “noRedeclare / use-before-declare” errors are from minification. Add assets/build to .eslintignore/.biomeignore and CI excludes. Prefer reviewing source files with sourcemaps.
Example .biomeignore/.eslintignore entry:
assets/build/**src/blocks/commonControls/AlignmentControls.js (2)
30-76: DRY the four nearly identical handlersReduce repetition and accidental divergence by using a generic updater.
Example:
-const handleDirectionAlignmentChange = (value) => { /* ...direction... */ }; -const handleTextAlignmentChange = (value) => { /* ...textAlign... */ }; -const handleHorizontalAlignmentChange = (value) => { /* ...justifyContent... */ }; -const handleVerticalAlignmentChange = (value) => { /* ...alignItems... */ }; +const updateAlignment = (key) => (value) => + setAttributes({ + alignmentControls: { + ...alignmentControls, + [device]: { + ...currentAlignment, + [key]: value, + }, + }, + }); + +const handleDirectionAlignmentChange = updateAlignment('direction'); +const handleTextAlignmentChange = updateAlignment('textAlign'); +const handleHorizontalAlignmentChange = updateAlignment('justifyContent'); +const handleVerticalAlignmentChange = updateAlignment('alignItems');
196-219: Prefer removing keys over saving nulls on ResetPersisting null bloats attribute storage and requires extra null checks. Remove the keys for the current device instead.
- onClick={() => { - setAttributes({ - alignmentControls: { - ...alignmentControls, - [device]: { - ...currentAlignment, - textAlign: null, - alignItems: null, - justifyContent: null, - direction: null, - }, - }, - }); - }} + onClick={() => { + const { textAlign, alignItems, justifyContent, direction, ...rest } = currentAlignment || {}; + setAttributes({ + alignmentControls: { + ...alignmentControls, + [device]: rest, + }, + }); + }}Ensure downstream CSS generation handles missing keys (undefined) correctly.
src/blocks/components/BackgroundControl.js (2)
15-27: Default onChange handlers to no-ops to prevent crashesIf a parent omits a handler, RadioControl/TextControl/MediaUpload will call undefined.
-const BackgroundControl = ({ +const BackgroundControl = ({ label, backgroundType = 'classic', - onBackgroundTypeChange, + onBackgroundTypeChange = () => {}, backgroundColor, - onBackgroundColorChange, + onBackgroundColorChange = () => {}, backgroundGradient, - onBackgroundGradientChange, + onBackgroundGradientChange = () => {}, backgroundImage = {}, - onBackgroundImageChange, + onBackgroundImageChange = () => {}, showGradient = true, showImage = true }) => {
31-39: Optional UX polish: clear opposite-type state on switchAvoid stale values when toggling type.
- onChange={onBackgroundTypeChange} + onChange={(type) => { + onBackgroundTypeChange(type); + if (type === 'classic') onBackgroundGradientChange?.(''); + if (type === 'gradient') onBackgroundColorChange?.(''); + }}Also, when selecting an image, consider fallback alt (media.alt || media.title || '').
Also applies to: 57-66, 69-107
src/blocks/commonControls/DimensionsControls.js (2)
98-154: Consistency: consider supplying explicit units to UnitControlDimensionControl.js defines units; this component leaves defaults. Aligning units across both improves UX and predictability.
Example:
<UnitControl __next40pxDefaultSize label={__('Fixed', 'wedocs')} value={currentDimensions.width || ''} + units={[ { value: 'px', label: 'px' }, { value: '%', label: '%' }, { value: 'em', label: 'em' }, { value: 'rem', label: 'rem' } ]}Repeat for min/max width/height.
Also applies to: 171-227
230-258: Prefer removing keys over saving nulls on ResetSame rationale as AlignmentControls.
- [device]: { - ...currentDimensions, - width: null, - minWidth: null, - maxWidth: null, - height: null, - minHeight: null, - maxHeight: null, - padding: null, - margin: null, - blockSpacing: null, - }, +[device]: ((d) => { + const { + width, minWidth, maxWidth, + height, minHeight, maxHeight, + padding, margin, blockSpacing, + ...rest + } = d || {}; + return rest; +})(currentDimensions),src/blocks/components/DimensionControl.js (1)
8-16: Default onChange handlers to no-opsPrevents accidental crashes if a parent forgets a handler.
-const DimensionControl = ({ +const DimensionControl = ({ label, widthValue, - onWidthChange, + onWidthChange = () => {}, heightValue, - onHeightChange, + onHeightChange = () => {}, showHeight = true, linkValues = false }) => {assets/build/print-rtl.css (4)
39-40: Remove duplicate border declarationOnly the latter applies; drop the first to avoid confusion.
- border: 1px solid #ccc; - border: 1px solid rgba(0, 0, 0, 0.15); + border: 1px solid rgba(0, 0, 0, 0.15);
36-37: Deduplicate white-spaceThe second overrides the first. Keep pre-wrap for readability in print.
- white-space: pre; - white-space: pre-wrap; + white-space: pre-wrap;
55-56: Resolve conflicting font-size declarationsfont-size appears twice; only last wins. Keep the intended value (15px shown later) and remove the earlier one.
- font-size: 18px; line-height: 1.2em; border-radius: 50px; color: #fff; background: #3197d1; vertical-align: baseline; white-space: nowrap; - font-size: 15px; + font-size: 15px;Also applies to: 62-62
141-144: Drop duplicate selectorSame selector listed twice.
-a:not(.anchorjs-link)::after, -a:not(.anchorjs-link)::after { +a:not(.anchorjs-link)::after { content: ' (' attr(href) ')'; }src/blocks/TableOfContents/style.scss (3)
63-67: Use logical properties to support RTLReplace left-specific properties with logical ones.
- border-left: 3px solid #0073aa; - padding-left: 10px; + border-inline-start: 3px solid #0073aa; + padding-inline-start: 10px;
133-135: Respect reduced motion preferencesAvoid forced smooth scrolling when users prefer reduced motion.
html.smooth-scroll { scroll-behavior: smooth; } +@media (prefers-reduced-motion: reduce) { + html.smooth-scroll { + scroll-behavior: auto; + } +}
137-151: Avoid non-localizable CSS-generated contentThe loading message is hardcoded via
content:and can’t be localized/accessibility-announced. Prefer rendering this text in markup with an ARIA live region.src/blocks/commonControls/ColorsControls.js (1)
17-17: Remove unused props
isTextColor,isBackgroundColor,isLinkColorare declared but unused. Drop them or implement conditional rendering.assets/build/blocks/DocsGrid/index.js (2)
1-1: Avoidper_page: -1REST queries in editorFetching all docs/sections/articles can be slow on large sites. Paginate or limit plus on-demand fetch to improve editor perf.
1-1: Consider excluding built assets from PRsMinified bundles create noisy diffs and false-positive lint. Commit sources and rely on build steps or attach artifacts on releases.
assets/build/frontend-rtl.css (2)
508-516: Conflictingfont-sizedeclarations
font-sizeis set to 18px then 15px for the same selector; the latter wins. Remove one for clarity.- font-size: 18px; line-height: 1.2em; border-radius: 50px; color: #fff; background: #3197d1; vertical-align: baseline; white-space: nowrap; - font-size: 15px; + font-size: 15px;
164-168: Preferoverflow: autofor hit list
overflow: scrollalways shows scrollbars;autoavoids visual noise.- overflow: scroll; + overflow: auto;src/blocks/Contributors/edit-old.js (4)
10-23: Prune unused imports
RangeControlandButtonGroupappear unused. Remove to reduce bundle size.
66-71:currentPostis computed but unusedEither wire it into preview/data fetching or remove it.
92-100: Avatar border radius used but not configurable here
roundedusesattributes.avatarBorderRadius, but this UI doesn’t expose a control to set it. Add a UnitControl or remove the dependency.
28-29: Removeedit-old.js— it's unused and superseded byedit.js.Verification confirms
src/blocks/Contributors/index.jsimports from./edit(notedit-old), and there are no references toedit-old.jsanywhere in the codebase. The file appears to be legacy code that was fully replaced byedit.js. Keeping it risks maintenance burden and accidental edits to the wrong file.src/blocks/helpers/block-styles.php (3)
141-149: Gradient is overridden by image; support layered backgrounds.Currently background-image gets set twice; the URL wins and gradient is lost. Compose a single declaration:
- if ($background_type === 'gradient' && $background_gradient) { - $styles[] = 'background-image: ' . esc_attr($background_gradient); - } - if (isset($background_image['url']) && !empty($background_image['url'])) { - $styles[] = 'background-image: url(' . esc_url($background_image['url']) . ')'; - $styles[] = 'background-size: cover'; - $styles[] = 'background-position: center'; - } + $images = []; + if ($background_type === 'gradient' && $background_gradient) { + $images[] = esc_attr($background_gradient); + } + if (!empty($background_image['url'])) { + $images[] = 'url(' . esc_url($background_image['url']) . ')'; + $styles[] = 'background-size: cover'; + $styles[] = 'background-position: center'; + } + if ($images) { + $styles[] = 'background-image: ' . implode(', ', $images); + }Also applies to: 145-149
236-242: Avoid dropping legitimate “0” values in styles_to_css.array_filter without a callback treats "0" as empty. Use strlen to keep "margin: 0" strings intact (future-proofing).
- return implode('; ', array_filter($styles)); + return implode('; ', array_filter($styles, 'strlen'));
290-311: Broaden sanitizer to modern CSS functions.calc(), clamp(), min(), max(), and var() are common in block styles. Consider supporting them to avoid stripping valid input. Example approach (illustrative):
- if (preg_match('/^(-?\d*\.?\d+)([a-z%]+)?$/i', $value, $matches)) { + if (preg_match('/^(-?\d*\.?\d+)([a-z%]+)?$/i', $value, $matches)) { ... - } + } elseif (preg_match('/^(calc|clamp|min|max)\(.+\)$/i', $value) || preg_match('/^var\(--[a-z0-9\-\_]+\)$/i', $value)) { + return $value; + }src/blocks/commonControls/BackgroundImageControls.js (1)
18-19: Hoist static constants outside the component.Move ALLOWED_MEDIA_TYPES to module scope to avoid re-allocating on every render.
-const BackgroundImageControls = ({ attributes, setAttributes, device }) => { - const { backgroundImageControls } = attributes; - const currentBackgroundImage = backgroundImageControls[device] || {}; - - const ALLOWED_MEDIA_TYPES = ['image']; +const ALLOWED_MEDIA_TYPES = [ 'image' ]; +const BackgroundImageControls = ({ attributes, setAttributes, device }) => { + const { backgroundImageControls } = attributes; + const currentBackgroundImage = backgroundImageControls[device] || {};src/blocks/AdvanceContributors/edit-old.js (3)
151-161: Use WordPress date i18n utilities for preview date.Respect site locale/timezone for the editor preview.
-import { useSelect } from '@wordpress/data'; +import { useSelect } from '@wordpress/data'; +import { dateI18n, getSettings as getDateSettings } from '@wordpress/date'; ... - <span style={dateStyle}> - {attributes.datePrefix} {new Date().toLocaleDateString('en-US', { - year: 'numeric', - month: 'long', - day: 'numeric' - })} - </span> + <span style={dateStyle}> + { attributes.datePrefix } { dateI18n( getDateSettings().formats.date || 'F j, Y', Date.now() ) } + </span>
292-320: Capture media ID with background image for better caching and REST usage.Store id alongside url/alt to allow size switching and consistent serialization.
- onSelect={(media) => setAttributes({ - backgroundImage: { url: media.url, alt: media.alt } - })} + onSelect={(media) => setAttributes({ + backgroundImage: { id: media.id, url: media.url, alt: media.alt } + })}If server render uses IDs for responsive sources, ensure schema accepts backgroundImage.id.
33-49: Consider centralizing style generation via the new PHP helpers (parity).Inline editor styles duplicate logic now present in src/blocks/helpers/block-styles.php. A small utility mirroring the helper on the client would reduce drift and bugs.
Happy to sketch a tiny JS style-builder to keep parity with wedocs_build_* helpers.
src/blocks/AdvanceContributors/index.js (1)
12-16: Update comment to match inline implementation.The comment references
./save.jsbut the save function is defined inline. Since this block uses server-side rendering (returningnull), consider either:
- Removing the comment, or
- Updating it to reflect the inline implementation
/** - * @see ./save.js + * Server-side rendered block - save returns null */ save: () => null,src/blocks/TableOfContents/index.js (1)
29-35: Remove trailing whitespace.Clean up the trailing whitespace at the end of the file.
registerBlockType( metadata.name, { /** * @see ./edit.js */ edit: Edit, } ); -src/blocks/Contributors/save.js (1)
1-11: Remove unusedblockPropsvariable.Since this is a server-rendered block that returns
null, theuseBlockProps.save()call andblockPropsvariable are unnecessary and can be removed. The import can also be removed.-import { useBlockProps } from '@wordpress/block-editor'; - const Save = () => { - const blockProps = useBlockProps.save(); - // Since this is a dynamic block that uses PHP rendering, // we return null to let the server-side render function handle the output return null; }; export default Save;src/blocks/TableOfContents/controls/ListItems.js (1)
18-22: Remove commented-out code.The commented-out
ColorsControlsblock should either be implemented or removed. Leaving commented code in production decreases maintainability.src/blocks/Contributors/style.scss (1)
105-108: Consider removing !important if possible.The
!importantflags on lines 106-107 for avatar sizing may indicate specificity issues. If possible, increase selector specificity instead to avoid!important..contributor-avatar { // Smaller avatars on mobile img, .default-icon { width: 28px; height: 28px; } }If these rules are being overridden elsewhere, consider refactoring the CSS architecture rather than using
!important.src/blocks/Contributors/index.js (1)
19-41: Consider extracting icon styles to constants.The inline styles for the PRO badge could be extracted to named constants for better maintainability and reusability if this pattern is used across multiple blocks.
const PRO_BADGE_STYLES = { badge: { position: 'absolute', top: '22px', right: '-2px', background: '#4f47e6', color: 'white', fontSize: '9px', padding: '2px 3px', borderRadius: '3px', fontWeight: 'bold', lineHeight: 1 }, wrapper: { position: 'relative', display: 'inline-block' } }; icon: { src: () => ( <span style={PRO_BADGE_STYLES.wrapper}> <Icon icon={starFilled} /> <span style={PRO_BADGE_STYLES.badge}>PRO</span> </span> ), }wedocs.php (1)
185-185: Remove or uncomment the AdvanceContributors block.Line 185 has the
AdvanceContributorsblock commented out. Either enable it or remove the comment to keep the codebase clean.assets/build/blocks/DocsGrid/render.php (3)
10-37: Prefix or scope helper function to avoid global collisions.get_pagination_style_tag() is unprefixed and global. Prefer wedocs_get_pagination_style_tag(), or make it a private helper inside render_wedocs_docs_grid(). The new function_exists guard helps but namespacing is safer.
183-183: Remove unused variables or implement their usage.$total_pages and $total_articles are declared but never used. Either remove them or render pagination/article counts. This also silences PHPMD warnings.
Also applies to: 228-228
184-206: Inline <script>: consider enqueueing and optional chaining support.Move the toggle JS to an enqueued script or wp_add_inline_script attached to the block handle to play well with CSP and caching. Also verify that optional chaining (?.) meets your supported browsers for front-end visitors.
Would you confirm your browser support baseline and whether CSP is enforced on typical installs?
src/blocks/TableOfContents/ColorsControls.js (1)
21-28: Prefer stable APIs to fetch theme palettes.Consider using useSetting for palettes/gradients to avoid unsafe WP APIs and the eslint disable.
Example:
import { useSetting } from '@wordpress/block-editor'; const themeColors = useSetting( 'color.palette' ) || []; const themeGradients = useSetting( 'color.gradients' ) || [];If other controls already use useSetting (e.g., BorderAndShadowControls.js), align for consistency.
assets/build/blocks/Contributors/style-index-rtl.css (1)
1-1: Scope note: avoid cross-component bleed.This stylesheet also targets
.contributors-tab-system .components-button-group. Ensure this file is only enqueued where needed, or move editor-only styles to the editor stylesheet to avoid front-end collisions.src/blocks/components/ShadowControl.js (3)
5-7: Avoid confusion with local UnitControl by renaming the WP import.You already have a custom UnitControl in the codebase. Rename the WP import to clarify intent.
- __experimentalUnitControl as UnitControl, + __experimentalUnitControl as WPUnitControl,And update usages:
- <UnitControl ... + <WPUnitControl ...Confirm no other imports in this file shadow the same name.
Also applies to: 41-51, 55-64, 69-78, 83-92
16-21: Defensive: guard onShadowChange.If onShadowChange is omitted, updateShadow will throw. Either require it or no-op guard:
- const updateShadow = (key, newValue) => { - onShadowChange({ + const updateShadow = (key, newValue) => { + (onShadowChange || (() => {}))({ ...shadowValue, [key]: newValue }); };
96-106: API check: PanelColorSettings deprecation.PanelColorSettings has been phased out in favor of ToolsPanel/ColorGradientControl in newer WP. If you target recent core, plan a follow-up to migrate.
assets/build/blocks/AdvanceContributors/block.json (1)
1-16: Missing textdomain in block.jsonConsider adding "textdomain": "wedocs" to enable proper i18n tooling for strings in metadata.
src/blocks/components/BorderControl.js (2)
26-41: Reset width/color when switching to “None”If users set width/color then choose “None”, stale styles may persist downstream.
Apply:
- onChange={onBorderStyleChange} + onChange={(newStyle) => { + onBorderStyleChange(newStyle); + if (newStyle === 'none') { + onBorderWidthChange({}); + onBorderColorChange(undefined); + } + }}
87-96: PanelColorSettings is deprecated in newer WP; consider ToolsPanel/ColorPaletteFuture-proof by migrating to ColorSettings within ToolsPanel or use block-editor color support if applicable.
src/blocks/Contributors/render.php (1)
12-18: Unused parameters + missing $post guardSilence analyzers and avoid fatals on non-singular contexts.
- function render_wedocs_contributors_block($attributes, $content, $block) { - // Get the current post - $post = get_post(); + function render_wedocs_contributors_block($attributes, $content, $block) { + // Silence unused params + unset($content, $block); + // Get the current post + $post = get_post(); + if ( ! $post ) { + return ''; + }Also applies to: 19-39
assets/build/blocks/AdvanceContributors/style-index-rtl.css (1)
1-1: Contrast media query value and legacy prefix
- prefers-contrast: high is non-standard; use "more" for broader support.
- The -o-object-fit prefix is obsolete.
Apply:
-@media(prefers-contrast: high){ +@media(prefers-contrast: more){And drop "-o-object-fit: cover".
src/blocks/AdvanceContributors/style.scss (3)
64-75: Add visible focus styles for keyboard users.Anchors only style :hover. Include :focus-visible for parity and WCAG compliance.
.contributor-name { transition: color 0.3s ease; text-decoration: none; + outline: none; + &:focus-visible { + outline: 2px solid currentColor; + outline-offset: 2px; + text-decoration: underline; + } }
49-61: Use CSS variables instead of hard-coded brand colors.Replace fixed hex with theme variables to improve theming and dark-mode harmony.
- .default-icon { - background-color: #0073aa; - color: white; + .default-icon { + --wedocs-accent: var(--wp--preset--color--primary, #0073aa); + --wedocs-on-accent: var(--wp--preset--color--background, #fff); + background-color: var(--wedocs-accent); + color: var(--wedocs-on-accent); } @@ - .contributor-item { - .contributor-avatar .default-icon { - background-color: #4a90a4; - } - } + .contributor-item .contributor-avatar .default-icon { + background-color: color-mix(in oklab, var(--wedocs-accent) 70%, black); + }Also applies to: 151-156
103-109: Avoid !important; raise specificity instead.!important makes overrides harder. Prefer a more specific selector or block-scoped size token.
- img, .default-icon { - width: 28px !important; - height: 28px !important; - } + img, .default-icon { + width: 28px; + height: 28px; + }If collisions occur, scope via
.wedocs-contributors .contributors-container .contributor-item .contributor-avatar imgrather than using!important.assets/build/blocks/TableOfContents/view.js (1)
1-1: Scope heading search to the nearest content container; reduce O(n²) and support H6.
- Limit to the block’s nearest article/content container to avoid cross-picking headings from the whole page.
- Replace
Array.from(list).indexOf(node)with the loop index.- Initialize counters up to H6.
- const c=document.querySelector(".entry-content, .post-content, main, .content")||document.body + const c = t.closest("article, .entry-content, .post-content, main, .content") || document.body; @@ - const i={1:0,2:0,3:0,4:0,5:0}; + const i={1:0,2:0,3:0,4:0,5:0,6:0}; @@ - t.forEach(function(e){ - const l=parseInt(e.tagName.charAt(1)) + t.forEach(function(e, idx){ + const l = Math.min(6, parseInt(e.tagName.charAt(1), 10) || 2); @@ - const a = e.id || "toc-heading-"+Array.from(t).indexOf(e); + const a = e.id || "toc-heading-" + idx;src/blocks/DocsGrid/render.php (4)
183-183: Remove or use$total_pages; currently unused.Either render pagination or drop the variable. See next comment for adding pagination.
- $total_pages = $docs_query->max_num_pages; + $total_pages = $docs_query->max_num_pages; // Use below if pagination is enabled.
42-53: Wire up pagination rendering and style variables.Attributes include pagination settings but output is missing; also
get_pagination_style_tag()is never used.@@ - $show_view_details = $attributes['showViewDetails'] ?? true; + $show_view_details = $attributes['showViewDetails'] ?? true; + $enable_pagination = $attributes['enablePagination'] ?? false; @@ - // Query docs with pagination + // Query docs with pagination $docs_query = new WP_Query($args); @@ - echo $toggle_script; - // Output hover styles - echo $hover_styles; + // Pagination CSS variables + echo get_pagination_style_tag( $attributes ); + echo $toggle_script; + echo $hover_styles; @@ - </div> - </div> + </div> + </div> + <?php if ( $enable_pagination && $docs_per_page !== 'all' && $total_pages > 1 ) : ?> + <nav class="wedocs-docs-grid__pagination" aria-label="<?php esc_attr_e('Docs navigation', 'wedocs'); ?>"> + <?php + echo paginate_links( array( + 'total' => $total_pages, + 'current' => max( 1, (int) $current_page ), + 'type' => 'list', + 'prev_text' => __('Previous', 'wedocs'), + 'next_text' => __('Next', 'wedocs'), + ) ); + ?> + </nav> + <?php endif; ?> <?php return ob_get_clean();Also applies to: 158-171, 210-213, 319-323
256-257: Compose inline styles once and escape as a whole.Avoid mixing escaped and raw CSS fragments inside the attribute.
- <h4 class="wedocs-docs-grid__section-title" - style="<?php echo esc_attr($title_style); ?> display: flex; justify-content: space-between; align-items: center;"> + <?php $section_title_style = trim($title_style . ' display:flex; justify-content:space-between; align-items:center;'); ?> + <h4 class="wedocs-docs-grid__section-title" style="<?php echo esc_attr( $section_title_style ); ?>">
228-228: Remove$total_articlesor implement usage.Declared but never used.
- $total_articles = 0; + // $total_articles reserved for future use; remove if not needed.src/blocks/commonControls/BorderAndShadowControls.js (3)
123-131: Avoid boolean className.Passing false can stringify to "false". Use a conditional string.
- className={isOpen && 'is-open'} + className={isOpen ? 'is-open' : undefined}
215-237: Reset to undefined/null to fall back cleanly.Setting empty objects keeps truthy values around. Prefer null/undefined to fully reset.
- border: {}, - borderRadius: null, - boxShadow: {}, + border: undefined, + borderRadius: undefined, + boxShadow: undefined,
35-46: Confirm boxShadow key naming consistency.This control uses { x, y, blur, spread, color, inset }. Ensure all consumers/readers (renderers/styles) expect these keys (not horizontal/vertical). If not, map keys at the boundary.
src/blocks/Contributors/block.json (1)
27-30: Potential contrast issue for titleColor default.Title defaults to #fff while backgroundColor defaults to #f9f9f9; visually OK, but if a theme sets a white background it may become invisible. Consider a darker default (e.g., #111).
src/blocks/TableOfContents/Inspector.js (1)
19-77: Unify textdomain with the block’s domain (“wedocs”).Strings use 'dynamic-table-of-contents-block-wp' while block.json declares 'wedocs'. Aligning domains improves translation loading.
- __('TOC Title', 'dynamic-table-of-contents-block-wp') + __('TOC Title', 'wedocs') # Apply to all __() calls in this file.Also applies to: 94-223
assets/build/blocks/Contributors/render.php (2)
290-306: Small UX/accessibility hardening on avatar rendering.- $output .= '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($contributor->display_name) . '" style="' . wedocs_styles_to_css($avatar_styles) . '">'; + $output .= '<img src="' . esc_url($avatar_url) . '" alt="' . esc_attr($contributor->display_name) . '" loading="lazy" decoding="async" style="' . wedocs_styles_to_css($avatar_styles) . '">'; ... - $output .= '<div class="default-icon" style="' . wedocs_styles_to_css($icon_styles) . '">'; + $output .= '<div class="default-icon" aria-hidden="true" style="' . wedocs_styles_to_css($icon_styles) . '">';
12-12: Silence PHPMD UnusedFormalParameter for $content and $block.WP render callbacks accept ($attributes, $content, $block) even if unused. Prefix unused params to signal intent.
- function render_wedocs_contributors_block($attributes, $content, $block) { + function render_wedocs_contributors_block($attributes, $_content = null, $_block = null) {Alternatively, add a PHPMD ignore for these params.
src/blocks/TableOfContents/edit.js (1)
154-163: Typo in CSS custom property name."--list-item-sytle" → "--list-item-style" (or remove if unused). Typo prevents styles from applying.
- "--list-item-sytle": containerBackgroundColor, + "--list-item-style": containerBackgroundColor,src/blocks/TableOfContents/view.js (3)
57-61: Avoid assembling HTML with strings; build DOM nodes to reduce XSS/escaping risk.Even with textContent, innerHTML concatenation is fragile. Prefer createElement/append with textContent.
Example replacement for this block:
- const tocHTML = generateTOCHTML(headings, supportedHeadings, showHierarchy, showNumbering); - const tocContent = tocBlock.querySelector('.toc-content'); - tocContent.innerHTML = tocHTML; + const tocContent = tocBlock.querySelector('.toc-content'); + tocContent.innerHTML = ''; + tocContent.appendChild( + generateTOCListElement(headings, supportedHeadings, showHierarchy, showNumbering) + );…with a new generateTOCListElement that returns a UL element constructed via createElement.
150-160: Add a11y state to collapsible behavior.Toggle aria-expanded on the title and aria-hidden on the content; announce via role="button".
- if (title && content) { - title.addEventListener('click', function() { - title.classList.toggle('collapsed'); - content.classList.toggle('collapsed'); - }); - } + if (title && content) { + title.setAttribute('role', 'button'); + title.setAttribute('aria-controls', 'toc-content'); + title.setAttribute('aria-expanded', 'true'); + content.id = 'toc-content'; + title.addEventListener('click', function() { + const expanded = title.getAttribute('aria-expanded') === 'true'; + title.setAttribute('aria-expanded', String(!expanded)); + title.classList.toggle('collapsed'); + content.classList.toggle('collapsed'); + content.setAttribute('aria-hidden', String(expanded)); + }); + }
217-236: Preserve URL hash on smooth scroll.Currently prevents default without updating history, so deep links don’t work. Push the hash after scrolling.
if (targetElement) { const offsetTop = targetElement.offsetTop - 80; // Account for sticky headers @@ } else { // Fallback smooth scroll animateScrollTo(offsetTop, 600); } + // Update hash without jump + history.replaceState(null, '', '#' + targetId); }src/blocks/AdvanceContributors/edit.js (2)
164-179: Parallelize manual user fetch to reduce editor latency.Serial await in a loop is slow with many users. Use Promise.all and filter nulls.
- if (attributes.selectedContributors.length > 0) { - for (const userId of attributes.selectedContributors) { - try { - const user = await wp.apiFetch({ - path: `/wp/v2/users/${userId}?context=edit` - }); - if (user) { - contributors.push(user); - } - } catch (error) { - console.warn(`Could not fetch user ${userId}:`, error); - } - } - } + if (attributes.selectedContributors.length > 0) { + const fetched = await Promise.all( + attributes.selectedContributors.map((userId) => + wp.apiFetch({ path: `/wp/v2/users/${userId}?context=edit` }).catch((e) => { + console.warn(`Could not fetch user ${userId}:`, e); + return null; + }) + ) + ); + contributors.push(...fetched.filter(Boolean)); + }
193-221: Minor: also dedupe against the main author when merging revisions.You already track contributorIds; ensure main author is included initially to avoid duplicates.
- const contributorIds = [currentPost.author]; + const contributorIds = [currentPost.author];This is correct as written. Please verify that get users for both main author and revisions do not produce duplicates in displayContributors. If duplicates appear, add a final Map by id when setting state:
- setActualContributors(contributors); + const uniq = Array.from(new Map(contributors.map(u => [u.id || u.ID, u])).values()); + setActualContributors(uniq);src/blocks/TableOfContents/render.php (1)
14-44: Emit styles via wp_add_inline_style and traverse nested blocks.
- Printing a raw <style> in wp_head is brittle. Prefer wp_add_inline_style against an enqueued handle.
- parse_blocks() only inspects top-level blocks; recurse innerBlocks to style nested TOCs.
- add_action( 'wp_head', 'wedocs_dynamic_table_of_contents_inline_styles' ); + add_action( 'wp_enqueue_scripts', 'wedocs_dynamic_table_of_contents_inline_styles', 20 ); @@ - $blocks = parse_blocks( $post->post_content ); - $styles = ''; - foreach ( $blocks as $block ) { + $blocks = parse_blocks( $post->post_content ); + $styles = ''; + $walker = function( $blocks ) use ( &$styles ) { + foreach ( $blocks as $block ) { + if ( 'wedocs/table-of-contents' === ( $block['blockName'] ?? '' ) ) { + $attributes = $block['attrs'] ?? array(); + $block_id = $attributes['blockId'] ?? ''; + if ( $block_id ) { + $styles .= wedocs_generate_toc_styles( $attributes, $block_id ); + } + } + if ( ! empty( $block['innerBlocks'] ) ) { + $walker( $block['innerBlocks'] ); + } + } + }; + $walker( $blocks ); @@ - if ( ! empty( $styles ) ) { - echo '<style id="dynamic-toc-styles">' . $styles . '</style>'; - } + if ( ! empty( $styles ) ) { + // Ensure 'wedocs-toc' (or actual handle) is registered/enqueued beforehand. + wp_add_inline_style( 'wedocs-toc', $styles ); + }Also applies to: 25-37, 39-44
src/blocks/helpers/block-helpers.js (4)
23-31: Gradient overwritten by image; honor backgroundType.When backgroundType is 'gradient', subsequent backgroundImage url() assignment overrides it. Gate the image path by type.
- if (attributes.backgroundImage?.url) { + if (attributes.backgroundType !== 'gradient' && attributes.backgroundImage?.url) { styles.backgroundImage = `url(${attributes.backgroundImage.url})`; styles.backgroundSize = 'cover'; styles.backgroundPosition = 'center'; }
250-267: Allow common CSS functions (calc, var, clamp).Current validator rejects calc()/var()/clamp(). Broaden acceptance to typical safe patterns.
- const regex = /^(-?\d*\.?\d+)([a-z%]+)?$/i; + const functionOk = /^(calc|var|clamp)\(/i.test(value.trim()); + if (functionOk) return true; + const regex = /^(-?\d*\.?\d+)([a-z%]+)?$/i;
374-390: Guard for SSR/Node usage.Accessing window breaks SSR/tests. Add typeof window check and default false.
-export const isBreakpoint = (breakpoint) => { - const breakpoints = getBreakpoints(); - const width = window.innerWidth; +export const isBreakpoint = (breakpoint) => { + if (typeof window === 'undefined') return false; + const breakpoints = getBreakpoints(); + const width = window.innerWidth;
231-241: Expose cancel() on debounce for cleanup in effects.Helps avoid stray timers.
export const debounce = (func, wait) => { let timeout; - return function executedFunction(...args) { + const debounced = function executedFunction(...args) { const later = () => { clearTimeout(timeout); func(...args); }; clearTimeout(timeout); timeout = setTimeout(later, wait); }; + debounced.cancel = () => clearTimeout(timeout); + return debounced; };
assets/build/block.js
Outdated
| @@ -1 +1 @@ | |||
| (()=>{"use strict";var e,t={418:(e,t,o)=>{var l=o(609),a=Symbol.for("react.element"),r=(Symbol.for("react.fragment"),Object.prototype.hasOwnProperty),n=l.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED.ReactCurrentOwner,i={key:!0,ref:!0,__self:!0,__source:!0};t.jsx=function(e,t,o){var l,d={},s=null,c=null;for(l in void 0!==o&&(s=""+o),void 0!==t.key&&(s=""+t.key),void 0!==t.ref&&(c=t.ref),t)r.call(t,l)&&!i.hasOwnProperty(l)&&(d[l]=t[l]);if(e&&e.defaultProps)for(l in t=e.defaultProps)void 0===d[l]&&(d[l]=t[l]);return{$$typeof:a,type:e,key:s,ref:c,props:d,_owner:n.current}}},706:(e,t,o)=>{e.exports=o(418)},445:(e,t,o)=>{var l=o(609);const a=window.wp.blocks,r=window.wp.i18n,n=window.wp.primitives;var i=o(706);const d=(0,i.jsx)(n.SVG,{viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:(0,i.jsx)(n.Path,{d:"M12 8c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm0 6.5c-1.4 0-2.5-1.1-2.5-2.5s1.1-2.5 2.5-2.5 2.5 1.1 2.5 2.5-1.1 2.5-2.5 2.5zM12.8 3h-1.5v3h1.5V3zm-1.6 18h1.5v-3h-1.5v3zm6.8-9.8v1.5h3v-1.5h-3zm-12 0H3v1.5h3v-1.5zm9.7 5.6 2.1 2.1 1.1-1.1-2.1-2.1-1.1 1.1zM8.3 7.2 6.2 5.1 5.1 6.2l2.1 2.1 1.1-1.1zM5.1 17.8l1.1 1.1 2.1-2.1-1.1-1.1-2.1 2.1zM18.9 6.2l-1.1-1.1-2.1 2.1 1.1 1.1 2.1-2.1z"})}),s=(0,i.jsx)(n.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,i.jsx)(n.Path,{fillRule:"evenodd",d:"M10.289 4.836A1 1 0 0111.275 4h1.306a1 1 0 01.987.836l.244 1.466c.787.26 1.503.679 2.108 1.218l1.393-.522a1 1 0 011.216.437l.653 1.13a1 1 0 01-.23 1.273l-1.148.944a6.025 6.025 0 010 2.435l1.149.946a1 1 0 01.23 1.272l-.653 1.13a1 1 0 01-1.216.437l-1.394-.522c-.605.54-1.32.958-2.108 1.218l-.244 1.466a1 1 0 01-.987.836h-1.306a1 1 0 01-.986-.836l-.244-1.466a5.995 5.995 0 01-2.108-1.218l-1.394.522a1 1 0 01-1.217-.436l-.653-1.131a1 1 0 01.23-1.272l1.149-.946a6.026 6.026 0 010-2.435l-1.148-.944a1 1 0 01-.23-1.272l.653-1.131a1 1 0 011.217-.437l1.393.522a5.994 5.994 0 012.108-1.218l.244-1.466zM14.929 12a3 3 0 11-6 0 3 3 0 016 0z",clipRule:"evenodd"})}),c=window.wp.element,u=window.wp.blockEditor,p=window.wp.components,g=({label:e,value:t,unit:o,onValueChange:a,onUnitChange:n})=>(0,l.createElement)(p.Flex,null,(0,l.createElement)(p.FlexBlock,null,(0,l.createElement)(p.TextControl,{label:e,value:parseInt(t),onChange:e=>a(e)})),(0,l.createElement)(p.FlexItem,null,(0,l.createElement)(p.SelectControl,{label:(0,r.__)("Unit","wedocs"),value:o,options:[{label:"px",value:"px"},{label:"%",value:"%"}],onChange:e=>n(e)}))),m=({selected:e,options:t,onChange:o})=>(0,l.createElement)(p.BaseControl,null,(0,l.createElement)("div",{className:"radio-image-control-options"},t.map((t=>(0,l.createElement)("div",{key:t.value,className:"radio-image-option"},(0,l.createElement)("input",{type:"radio",id:`radio-image-${t.value}`,value:t.value,checked:e===t.value,onChange:e=>o(e.target.value)}),(0,l.createElement)("label",{htmlFor:`radio-image-${t.value}`},t.icon&&(0,l.createElement)("i",{className:`dashicons ${t.icon}`}),t.img&&(0,l.createElement)("img",{src:t.img,alt:t.label}),t?.svg)))))),b={hideSearch:{type:"boolean",default:!1},searchWidth:{type:"number",default:50},widthUnit:{type:"string",default:"%"},placeholder:{type:"string",default:(0,r.__)("Search for a top or question","wedocs")},alignment:{type:"string",default:"right"},bgColor:{type:"string",default:"#FFFFFF"},hoverColor:{type:"string",default:"#FFFFFF"},padding:{type:"object",default:{top:14,left:22,right:22,bottom:14}},margin:{type:"object",default:{top:0,left:0,right:0,bottom:0}},borderColor:{type:"string",default:"#cccccc"},borderType:{type:"string",default:"solid"},borderWidth:{type:"number",default:1},borderRadius:{type:"number",default:30},iconColor:{type:"string",default:"#FFFFFF"},iconBgColor:{type:"string",default:"#3b82f6"},iconHoverColor:{type:"string",default:"#2563eb"},svgHoverColor:{type:"string",default:"#FFFFFF"},btnPadding:{type:"object",default:{top:24,left:26,right:26,bottom:24}},btnPosition:{type:"object",default:{top:0,right:0,bottom:10}},btnRadius:{type:"number",default:30}};(0,a.registerBlockType)("wedocs/wedocs-search",{attributes:b,save:({attributes:e})=>{const{margin:t,bgColor:o,padding:a,btnRadius:r,alignment:n,iconColor:i,widthUnit:d,hoverColor:s,borderType:p,hideSearch:g,btnPadding:m,searchWidth:b,btnPosition:h,placeholder:_,borderColor:v,borderWidth:C,iconBgColor:w,borderRadius:f,svgHoverColor:E,iconHoverColor:x}=e;if(g)return;const y={display:"flex",justifyContent:n},B={border:`${C}px ${p} ${v}`,paddingTop:a?.top,paddingLeft:a?.left,paddingRight:a?.right,borderRadius:`${f}px`,paddingBottom:a?.bottom,"--field-color":o,"--field-bg-color":s},S={top:h?.top,left:h?.left,right:h?.right,bottom:h?.bottom,height:"auto",paddingTop:m?.top,paddingLeft:m?.left,borderRadius:r,paddingRight:m?.right,paddingBottom:m?.bottom,"--field-icon-color":i,"--field-btn-bg-color":w,"--field-icon-hover-color":E,"--field-btn-bg-hover-color":x};return(0,l.createElement)(c.Fragment,null,(0,l.createElement)("form",{method:"get",role:"search",action:weDocsBlockVars?.siteUrl,...u.useBlockProps.save({className:"search-form wedocs-search-form"})},(0,l.createElement)("div",{style:y},(0,l.createElement)("div",{className:"wedocs-search-input",style:{width:b+d,marginTop:t?.top,marginLeft:t?.left,marginRight:t?.right,marginBottom:t?.bottom}},(0,l.createElement)("input",{name:"s",type:"search",style:B,className:"search-field",placeholder:_}),(0,l.createElement)("input",{type:"hidden",name:"post_type",value:"docs"}),(0,l.createElement)("button",{type:"submit",style:S,className:"search-submit"},(0,l.createElement)("svg",{width:"15",height:"16",fill:"none"},(0,l.createElement)("path",{fillRule:"evenodd",d:"M11.856 10.847l2.883 2.883a.89.89 0 0 1 0 1.257c-.173.174-.401.261-.629.261s-.455-.087-.629-.261l-2.883-2.883c-1.144.874-2.532 1.353-3.996 1.353a6.56 6.56 0 0 1-4.671-1.935c-2.576-2.575-2.576-6.765 0-9.341C3.179.934 4.839.247 6.603.247s3.424.687 4.671 1.935a6.56 6.56 0 0 1 1.935 4.67 6.55 6.55 0 0 1-1.353 3.995zM3.189 3.439c-1.882 1.882-1.882 4.945 0 6.827.912.912 2.124 1.414 3.414 1.414s2.502-.502 3.414-1.414 1.414-2.124 1.414-3.413-.502-2.502-1.414-3.413-2.124-1.414-3.414-1.414-2.502.502-3.414 1.414z"})))))))},edit:({attributes:e,setAttributes:t})=>{const o=(0,u.useBlockProps)(),{margin:a,bgColor:n,padding:i,btnRadius:b,alignment:h,iconColor:_,widthUnit:v,hoverColor:C,borderType:w,hideSearch:f,btnPadding:E,searchWidth:x,btnPosition:y,placeholder:B,borderColor:S,borderWidth:k,iconBgColor:F,borderRadius:P,svgHoverColor:R,iconHoverColor:T}=e;console.log("editor panel:",n);const M=[{value:"left",label:(0,r.__)("Align left","wedocs"),svg:(0,l.createElement)("svg",{width:"24",height:"25",fill:"none",strokeWidth:"2",strokeLinecap:"round",stroke:"left"===h?"#007cba":"#939494",strokeLinejoin:"round"},(0,l.createElement)("path",{d:"M8 9.462h12m-12 6h6m-10-9v12"}))},{value:"center",label:(0,r.__)("Align center","wedocs"),svg:(0,l.createElement)("svg",{width:"24",height:"25",fill:"none",strokeWidth:"2",strokeLinecap:"round",stroke:"center"===h?"#007cba":"#939494",strokeLinejoin:"round"},(0,l.createElement)("path",{d:"M18 9.462H6m8.99 6h-6"}),(0,l.createElement)("path",{d:"M12 6.462v12"}))},{value:"right",label:(0,r.__)("Align right","wedocs"),svg:(0,l.createElement)("svg",{width:"24",height:"25",fill:"none",strokeWidth:"2",strokeLinecap:"round",stroke:"right"===h?"#007cba":"#939494",strokeLinejoin:"round"},(0,l.createElement)("path",{d:"M16 9.462H4m12 6h-6m10-9v12"}))}],[N,D]=(0,c.useState)(!1),[O,$]=(0,c.useState)(!1),[L,A]=(0,c.useState)(!1),H={display:"flex",justifyContent:h},j={border:`${k}px ${w} ${S}`,paddingTop:i?.top,background:N?C:n,paddingLeft:i?.left,paddingRight:i?.right,borderRadius:`${P}px`,paddingBottom:i?.bottom},I={top:y?.top,left:y?.left,right:y?.right,bottom:y?.bottom,height:"auto",background:L?T:F,paddingTop:E?.top,paddingLeft:E?.left,borderRadius:b,paddingRight:E?.right,paddingBottom:E?.bottom},V=[{label:(0,r.__)("Solid","wedocs"),value:"solid"},{label:(0,r.__)("Dotted","wedocs"),value:"dotted"},{label:(0,r.__)("Dashed","wedocs"),value:"dashed"},{label:(0,r.__)("Double","wedocs"),value:"double"},{label:(0,r.__)("Groove","wedocs"),value:"groove"},{label:(0,r.__)("Ridge","wedocs"),value:"ridge"},{label:(0,r.__)("Inset","wedocs"),value:"inset"},{label:(0,r.__)("Outset","wedocs"),value:"outset"},{label:(0,r.__)("None","wedocs"),value:"none"},{label:(0,r.__)("Hidden","wedocs"),value:"hidden"}];return(0,l.createElement)(c.Fragment,null,(0,l.createElement)(u.InspectorControls,null,(0,l.createElement)(p.PanelBody,null,(0,l.createElement)(p.ToggleControl,{checked:f,className:"wedocs-search-toggle",label:(0,r.__)("Disable Block","wedocs"),onChange:e=>t({hideSearch:e})})),!f&&(0,l.createElement)(c.Fragment,null,(0,l.createElement)(p.PanelBody,{title:(0,r.__)("Color Settings","wedocs"),icon:d,initialOpen:!1,className:"wedocs-search-color-settings"},(0,l.createElement)(u.PanelColorSettings,{colors:[{name:"Sweet",color:"#F43F5E"},{name:"Orange",color:"#F97316"},{name:"Yellow",color:"#FACC15"},{name:"Purple",color:"#8B5CF6"},{name:"Light Blue",color:"#3B82F6"},{name:"Light Green",color:"#10B981"}],colorSettings:[{value:n,label:(0,r.__)("Field Background Color","wedocs"),onChange:e=>t({bgColor:e})},{value:C,label:(0,r.__)("Field Hover Color","wedocs"),onChange:e=>t({hoverColor:e})},{value:S,label:(0,r.__)("Border Color","wedocs"),onChange:e=>t({borderColor:e})},{value:_,label:(0,r.__)("Icon Color","wedocs"),onChange:e=>t({iconColor:e})},{value:F,label:(0,r.__)("Button Color","wedocs"),onChange:e=>t({iconBgColor:e})},{value:T,label:(0,r.__)("Button Hover Color","wedocs"),onChange:e=>t({iconHoverColor:e})},{value:R,label:(0,r.__)("Icon Hover Color","wedocs"),onChange:e=>t({svgHoverColor:e})}]})),(0,l.createElement)(p.PanelBody,{title:(0,r.__)("Search Bar Settings","wedocs"),icon:s},(0,l.createElement)(g,{unit:v,value:x,label:(0,r.__)("Field Width","wedocs"),onUnitChange:e=>t({widthUnit:e}),onValueChange:e=>t({searchWidth:e?parseInt(e):0})}),(0,l.createElement)(p.TextControl,{value:B,label:(0,r.__)("Placeholder","wedocs"),placeholder:(0,r.__)("Search bar placeholder","wedocs"),onChange:e=>t({placeholder:e})}),(0,l.createElement)("p",{style:{fontSize:11}},(0,r.__)("POSITION","wedocs")),(0,l.createElement)(m,{selected:h,options:M,onChange:e=>t({alignment:e})}),(0,l.createElement)(p.__experimentalBoxControl,{resetValues:{top:"14px",left:"22px",right:"22px",bottom:"14px"},values:i,label:(0,r.__)("Field Padding","wedocs"),onChange:e=>t({padding:e})}),(0,l.createElement)(p.__experimentalBoxControl,{resetValues:{top:"0px",left:"0px",right:"0px",bottom:"0px"},values:a,label:(0,r.__)("Field Margin","wedocs"),onChange:e=>t({margin:e})}),(0,l.createElement)(p.RangeControl,{min:0,max:10,value:k,label:(0,r.__)("Border Width","wedocs"),onChange:e=>t({borderWidth:e})}),(0,l.createElement)(p.RangeControl,{min:0,max:100,value:P,label:(0,r.__)("Border Radius","wedocs"),onChange:e=>t({borderRadius:e})}),(0,l.createElement)(p.SelectControl,{value:w,options:V,label:(0,r.__)("Border Type","wedocs"),onChange:e=>t({borderType:e})}),(0,l.createElement)(p.__experimentalBoxControl,{resetValues:{top:"24px",left:"26px",right:"26px",bottom:"24px"},values:E,label:(0,r.__)("Button Padding","wedocs"),onChange:e=>t({btnPadding:e})}),(0,l.createElement)(p.__experimentalBoxControl,{resetValues:{top:"0px",right:"0px",bottom:"10px"},values:y,label:(0,r.__)("Button Margin","wedocs"),onChange:e=>t({btnPosition:e})}),(0,l.createElement)(p.RangeControl,{min:0,max:100,value:b,label:(0,r.__)("Button Radius","wedocs"),onChange:e=>t({btnRadius:e})})))),(0,l.createElement)("div",{...o,style:H},(0,l.createElement)("div",{className:"wedocs-editor-search-input",style:{width:x+v,marginTop:a?.top,marginLeft:a?.left,marginRight:a?.right,marginBottom:a?.bottom}},(0,l.createElement)("input",{readOnly:!0,style:j,className:"search-field",placeholder:B,onMouseEnter:()=>D(!0),onMouseLeave:()=>D(!1)}),(0,l.createElement)("input",{type:"hidden",name:"post_type",value:"docs"}),(0,l.createElement)("button",{type:"submit",style:I,className:"search-submit",onMouseEnter:()=>A(!0),onMouseLeave:()=>A(!1)},(0,l.createElement)("svg",{width:"15",height:"16",fill:"none",onMouseEnter:()=>$(!0),onMouseLeave:()=>$(!1)},(0,l.createElement)("path",{fill:O?R:_,fillRule:"evenodd",d:"M11.856 10.847l2.883 2.883a.89.89 0 0 1 0 1.257c-.173.174-.401.261-.629.261s-.455-.087-.629-.261l-2.883-2.883c-1.144.874-2.532 1.353-3.996 1.353a6.56 6.56 0 0 1-4.671-1.935c-2.576-2.575-2.576-6.765 0-9.341C3.179.934 4.839.247 6.603.247s3.424.687 4.671 1.935a6.56 6.56 0 0 1 1.935 4.67 6.55 6.55 0 0 1-1.353 3.995zM3.189 3.439c-1.882 1.882-1.882 4.945 0 6.827.912.912 2.124 1.414 3.414 1.414s2.502-.502 3.414-1.414 1.414-2.124 1.414-3.413-.502-2.502-1.414-3.413-2.124-1.414-3.414-1.414-2.502.502-3.414 1.414z"})))),f&&(0,l.createElement)("div",{className:"backdrop"})))},icon:(0,l.createElement)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none"},(0,l.createElement)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8.91421 1.5H5.5C4.39543 1.5 3.5 2.39543 3.5 3.5V6.91421V9.02779V15.5C3.5 16.6046 4.39543 17.5 5.5 17.5H7.02779C6.07771 16.4385 5.5 15.0367 5.5 13.5C5.5 10.1863 8.18629 7.5 11.5 7.5C13.0367 7.5 14.4385 8.07771 15.5 9.02779V8.5V6.91421C15.5 6.38378 15.2893 5.87507 14.9142 5.5L11.5 2.08579C11.1249 1.71071 10.6162 1.5 10.0858 1.5H8.91421ZM15.5 13.5C15.5 11.2909 13.7091 9.5 11.5 9.5C9.29086 9.5 7.5 11.2909 7.5 13.5C7.5 15.7091 9.29086 17.5 11.5 17.5C12.2414 17.5 12.9364 17.2977 13.5318 16.946L14.7929 18.2071C15.1834 18.5976 15.8166 18.5976 16.2071 18.2071C16.5976 17.8166 16.5976 17.1834 16.2071 16.7929L14.946 15.5318C15.2977 14.9364 15.5 14.2414 15.5 13.5ZM11.5 11.5C12.6046 11.5 13.5 12.3954 13.5 13.5C13.5 14.0526 13.2772 14.5512 12.9142 14.9142C12.5512 15.2772 12.0526 15.5 11.5 15.5C10.3954 15.5 9.5 14.6046 9.5 13.5C9.5 12.3954 10.3954 11.5 11.5 11.5Z",fill:"#111827"})),title:(0,r.__)("weDocs - Searchbar","wedocs"),keywords:["Search","weDocs search bar","Bar"],category:"widgets",description:(0,r.__)("Simple search forms for easy user guidance for your documentation","wedocs")});const h=({attributes:e,setAttributes:t})=>{const o=e=>o=>{t({[e]:o})},a=((0,r.__)("Solid","wedocs"),(0,r.__)("Dashed","wedocs"),(0,r.__)("Dotted","wedocs"),(0,r.__)("None","wedocs"),[{name:"Sweet",color:"#F43F5E"},{name:"Orange",color:"#F97316"},{name:"Yellow",color:"#FACC15"},{name:"Purple",color:"#8B5CF6"},{name:"Light Blue",color:"#3B82F6"},{name:"Light Green",color:"#10B981"}]);return(0,l.createElement)(l.Fragment,null,(0,l.createElement)(p.PanelBody,{title:(0,r.__)("Grid Styles","wedocs"),icon:"admin-appearance",initialOpen:!1},(0,l.createElement)("label",null,(0,r.__)("Colors","wedocs")),(0,l.createElement)(u.PanelColorSettings,{colors:a,colorSettings:[{value:e.docTitleColor,label:(0,r.__)("Doc Title Color","wedocs"),onChange:e=>o("docTitleColor")(e)},{value:e.docChildrenActiveColor,label:(0,r.__)("Doc Children Active Color","wedocs"),onChange:e=>o("docChildrenActiveColor")(e)},{value:e.borderColor,label:(0,r.__)("Border Color","wedocs"),onChange:e=>o("borderColor")(e)}]}),(0,l.createElement)(p.__experimentalBoxControl,{label:(0,r.__)("Grid Padding","wedocs"),values:e.gridPadding,onChange:o("gridPadding")}),(0,l.createElement)(p.__experimentalBoxControl,{label:(0,r.__)("Grid Margin","wedocs"),values:e.gridMargin,onChange:o("gridMargin")}),(0,l.createElement)(p.SelectControl,{label:(0,r.__)("Border Type","wedocs"),value:e.borderType,options:[{label:(0,r.__)("Solid","wedocs"),value:"solid"},{label:(0,r.__)("Dashed","wedocs"),value:"dashed"},{label:(0,r.__)("Dotted","wedocs"),value:"dotted"},{label:(0,r.__)("None","wedocs"),value:"none"}],onChange:e=>t({borderType:e})}),(0,l.createElement)(p.SelectControl,{label:(0,r.__)("Border Width","wedocs"),value:e.borderWidth,options:[{label:"0px",value:"0px"},{label:"1px",value:"1px"},{label:"2px",value:"2px"},{label:"3px",value:"3px"},{label:"4px",value:"4px"},{label:"5px",value:"5px"}],onChange:e=>t({borderWidth:e})}),(0,l.createElement)(p.SelectControl,{label:(0,r.__)("Border Radius","wedocs"),value:e.borderRadius,options:[{label:"0px",value:"0px"},{label:"4px",value:"4px"},{label:"8px",value:"8px"},{label:"12px",value:"12px"},{label:"16px",value:"16px"},{label:"20px",value:"20px"}],onChange:e=>t({borderRadius:e})})),(0,l.createElement)(p.PanelBody,{title:(0,r.__)("Button Styles","wedocs"),icon:"admin-appearance",initialOpen:!1},(0,l.createElement)("label",null,(0,r.__)("Button Colors","wedocs")),(0,l.createElement)(u.PanelColorSettings,{colors:a,colorSettings:[{value:e.buttonColor,label:(0,r.__)("Button Color","wedocs"),onChange:e=>o("buttonColor")(e)},{value:e.buttonHoverColor,label:(0,r.__)("Button Hover Color","wedocs"),onChange:e=>o("buttonHoverColor")(e)},{value:e.buttonTextColor,label:(0,r.__)("Button Text Color","wedocs"),onChange:e=>o("buttonTextColor")(e)},{value:e.buttonHoverTextColor,label:(0,r.__)("Button Hover Text Color","wedocs"),onChange:e=>o("buttonHoverTextColor")(e)}]}),(0,l.createElement)(p.__experimentalBoxControl,{label:(0,r.__)("Button Padding","wedocs"),values:e.buttonPadding,onChange:o("buttonPadding")}),(0,l.createElement)(p.__experimentalBoxControl,{label:(0,r.__)("Button Margin","wedocs"),values:e.buttonMargin,onChange:o("buttonMargin")}),(0,l.createElement)(p.SelectControl,{label:(0,r.__)("Button Border Radius","wedocs"),value:e.buttonBorderRadius,options:[{label:"0px",value:"0px"},{label:"4px",value:"4px"},{label:"8px",value:"8px"},{label:"12px",value:"12px"},{label:"16px",value:"16px"},{label:"20px",value:"20px"}],onChange:e=>t({buttonBorderRadius:e})}),(0,l.createElement)("div",{className:"wedocs-color-control"},(0,l.createElement)("label",null,(0,r.__)("Button Text","wedocs")),(0,l.createElement)(p.TextControl,{value:e.buttonText,onChange:o("buttonText")}))))},_=JSON.parse('{"UU":"wedocs/wedocs-docs-grid"}');(0,a.registerBlockType)(_.UU,{edit:({attributes:e,setAttributes:t})=>{const o=(0,u.useBlockProps)(),{useSelect:a}=wp.data,[n,i]=(0,c.useState)(1),[d,g]=(0,c.useState)(!1),{hideDocGrid:m,docStyle:b,docsPerPage:_,excludeDocs:v,order:C,orderBy:w,sectionsPerDoc:f,articlesPerSection:E,showDocArticle:x,keepArticlesCollapsed:y,showViewDetails:B,gridPadding:S,gridMargin:k,docTitleColor:F,docChildrenActiveColor:P,borderType:R,borderRadius:T,borderWidth:M,borderColor:N,buttonBorderRadius:D,buttonPadding:O,buttonMargin:$,buttonColor:L,buttonHoverColor:A,buttonTextColor:H,buttonText:j,buttonHoverTextColor:I}=e,V=[{label:"All",value:"all"},...Array.from({length:10},((e,t)=>({label:String(t+1),value:String(t+1)})))],W=[{label:(0,r.__)("weDocs Order","wedocs"),value:"menu_order"},{label:(0,r.__)("ID","wedocs"),value:"id"},{label:(0,r.__)("Name","wedocs"),value:"title"}],z=[{label:(0,r.__)("Ascending","wedocs"),value:"asc"},{label:(0,r.__)("Descending","wedocs"),value:"desc"}],U=[{label:"All",value:"all"},...Array.from({length:10},((e,t)=>({label:String(t+1),value:String(t+1)})))],{pages:G,sections:Y,articles:Z}=a((e=>{const{getEntityRecords:t}=e("core"),o=t("postType","docs",{status:"publish",per_page:-1,parent:0,orderby:w,order:C}),l=o?t("postType","docs",{status:"publish",parent_in:o.map((e=>e.id)),per_page:-1}):null,a=l?t("postType","docs",{status:"publish",parent_in:l.map((e=>e.id)),per_page:-1}):null;return{pages:o,sections:l,articles:a}}),[w,C]),q=(e=>{if("all"===_)return e;const t=parseInt(_),o=(n-1)*t,l=o+t;return e.slice(o,l)})((()=>{if(!G||!Y||!Z)return[];let e=[...G];return v&&v.length>0&&(e=e.filter((e=>!v.includes(e.id.toString())))),e=e.map((e=>{let t=Y.filter((t=>t.parent===e.id));"all"!==f&&(t=t.slice(0,parseInt(f))),t=t.map((e=>{let t=Z.filter((t=>t.parent===e.id));return"all"!==E&&(t=t.slice(0,parseInt(E))),{...e,articles:t}}));const o=t.reduce(((e,t)=>e+t.articles.length),0);return{...e,sections:t,articleCount:o}})),e})()),J=G?G.reduce(((e,t)=>(e[t.id]=t.title.rendered,e)),{}):{},K=(G&&G.map((e=>({value:e.id.toString(),label:e.title.rendered}))),e=>o=>{t({[e]:o})}),Q=v?v.map((e=>J[e]||e)):[];return(0,l.createElement)(c.Fragment,null,(0,l.createElement)(u.InspectorControls,null,(0,l.createElement)(p.PanelBody,{title:(0,r.__)("Doc Grid Settings","wedocs"),icon:s,initialOpen:!1},(0,l.createElement)(p.SelectControl,{value:b,options:[{label:"1x1",value:"1x1"},{label:"1x2",value:"1x2"}],label:(0,r.__)("DOCS GRID COLUMN STYLE","wedocs"),onChange:K("docStyle")}),(0,l.createElement)(p.SelectControl,{value:_,options:V,label:(0,r.__)("Docs per page","wedocs"),onChange:K("docsPerPage")}),(0,l.createElement)(p.FormTokenField,{value:Q,suggestions:Object.values(J),label:(0,r.__)("Exclude Docs","wedocs"),onChange:e=>{const o=e.map((e=>{const t=Object.entries(J).find((([t,o])=>o===e));return t?t[0]:e}));t({excludeDocs:o})}}),(0,l.createElement)(p.SelectControl,{value:C,options:z,label:(0,r.__)("Order","wedocs"),onChange:K("order")}),(0,l.createElement)(p.SelectControl,{value:w,options:W,label:(0,r.__)("Order by","wedocs"),onChange:K("orderBy")}),(0,l.createElement)(p.SelectControl,{value:f,options:U,label:(0,r.__)("Sections per doc","wedocs"),onChange:K("sectionsPerDoc")}),(0,l.createElement)(p.SelectControl,{value:E,options:U,label:(0,r.__)("Articles per section","wedocs"),onChange:K("articlesPerSection")}),(0,l.createElement)(p.PanelRow,null,(0,l.createElement)(p.ToggleControl,{checked:x,label:(0,r.__)("Show Doc Article","wedocs"),onChange:K("showDocArticle")})),(0,l.createElement)(p.PanelRow,null,(0,l.createElement)(p.ToggleControl,{checked:y,label:(0,r.__)("Keep Article Collapsed","wedocs"),onChange:K("keepArticlesCollapsed")})),(0,l.createElement)(p.PanelRow,null,(0,l.createElement)(p.ToggleControl,{checked:B,label:(0,r.__)("Show View Details Button","wedocs"),onChange:K("showViewDetails")})))),(0,l.createElement)(u.InspectorControls,null,(0,l.createElement)(h,{attributes:e,setAttributes:t})),(0,l.createElement)("div",{...o},m?(0,l.createElement)("div",{className:"backdrop"}):(0,l.createElement)("div",{className:"wedocs-block-wrapper"},(0,l.createElement)("div",{className:`wedocs-docs-grid wedocs-docs-grid--${b}`},d?(0,l.createElement)(Spinner,null):q.map((e=>((e,t)=>(0,l.createElement)("div",{key:e.id,className:"wedocs-docs-grid__item",style:t.item},(0,l.createElement)("h3",{className:"wedocs-docs-grid__title",style:t.title},e.title.rendered),((e,t)=>e.sections?(0,l.createElement)("div",{className:"wedocs-docs-grid__sections "+(y?"is-collapsed":"")},e.sections.map((e=>(0,l.createElement)("div",{key:e.id,className:"wedocs-docs-grid__section"},(0,l.createElement)("h4",{className:"wedocs-docs-grid__section-title",style:{...t.title,display:"flex",justifyContent:"space-between",alignItems:"center"}},(0,l.createElement)("span",null,e.title.rendered),x&&e.articles&&e.articles.length>0&&(0,l.createElement)("svg",{fill:"none",viewBox:"0 0 24 24",width:"16",strokeWidth:"2",stroke:"#acb8c4",className:y?"":"active"},(0,l.createElement)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19.5 8.25l-7.5 7.5-7.5-7.5"}))),x&&!y&&e.articles&&(0,l.createElement)("ul",{className:"wedocs-docs-grid__articles"},e.articles.map((e=>(0,l.createElement)("li",{key:e.id,className:"wedocs-docs-grid__article",style:t.children},e.title.rendered))))))),0===e.sections.length&&(0,l.createElement)("span",{className:"inside"},(0,l.createElement)("svg",{fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor"},(0,l.createElement)("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"})),(0,r.__)("This document has no sections yet. Check back later or wait for the author to add content.","wedocs"))):null)(e,t),B&&(0,l.createElement)("div",{className:"wedocs-docs-grid__details"},(0,l.createElement)("span",{className:"wedocs-docs-grid__details-link",style:t.button},t.button.text))))(e,(()=>{const e=S?`${S.top} ${S.right} ${S.bottom} ${S.left}`:"",t=k?`${k.top} ${k.right} ${k.bottom} ${k.left}`:"",o=O?`${O.top} ${O.right} ${O.bottom} ${O.left}`:"",l=D||"8px",a=$?`${$.top} ${$.right} ${$.bottom} ${$.left}`:"";return{item:{padding:e,margin:t,borderStyle:R||"solid",borderWidth:M||"1px",borderColor:N||"rgba(0, 0, 0, 0.1)",borderRadius:T||"8px",backgroundColor:"#fff"},title:{color:F||"#1e1e1e"},children:{color:P||"#0073aa"},button:{padding:o,margin:a,backgroundColor:L||"#0073aa",color:H||"#ffffff",text:j||(0,r.__)("View Details","wedocs"),borderRadius:l||"8px","--hover-bg":A||"#005177","--hover-color":I||"#ffffff"}}})())))))))},save:()=>null})},609:e=>{e.exports=window.React}},o={};function l(e){var a=o[e];if(void 0!==a)return a.exports;var r=o[e]={exports:{}};return t[e](r,r.exports,l),r.exports}l.m=t,e=[],l.O=(t,o,a,r)=>{if(!o){var n=1/0;for(c=0;c<e.length;c++){o=e[c][0],a=e[c][1],r=e[c][2];for(var i=!0,d=0;d<o.length;d++)(!1&r||n>=r)&&Object.keys(l.O).every((e=>l.O[e](o[d])))?o.splice(d--,1):(i=!1,r<n&&(n=r));if(i){e.splice(c--,1);var s=a();void 0!==s&&(t=s)}}return t}r=r||0;for(var c=e.length;c>0&&e[c-1][2]>r;c--)e[c]=e[c-1];e[c]=[o,a,r]},l.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={366:0,337:0};l.O.j=t=>0===e[t];var t=(t,o)=>{var a,r,n=o[0],i=o[1],d=o[2],s=0;if(n.some((t=>0!==e[t]))){for(a in i)l.o(i,a)&&(l.m[a]=i[a]);if(d)var c=d(l)}for(t&&t(o);s<n.length;s++)r=n[s],l.o(e,r)&&e[r]&&e[r][0](),e[r]=0;return l.O(c)},o=self.webpackChunkweDocs=self.webpackChunkweDocs||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})();var a=l.O(void 0,[337],(()=>l(445)));a=l.O(a)})(); No newline at end of file | |||
| (()=>{"use strict";var e,o={684:(e,o,a)=>{a.d(o,{A:()=>n});var t=a(5573),l=a(790);const n=(0,l.jsx)(t.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,l.jsx)(t.Path,{fillRule:"evenodd",d:"M10.289 4.836A1 1 0 0111.275 4h1.306a1 1 0 01.987.836l.244 1.466c.787.26 1.503.679 2.108 1.218l1.393-.522a1 1 0 011.216.437l.653 1.13a1 1 0 01-.23 1.273l-1.148.944a6.025 6.025 0 010 2.435l1.149.946a1 1 0 01.23 1.272l-.653 1.13a1 1 0 01-1.216.437l-1.394-.522c-.605.54-1.32.958-2.108 1.218l-.244 1.466a1 1 0 01-.987.836h-1.306a1 1 0 01-.986-.836l-.244-1.466a5.995 5.995 0 01-2.108-1.218l-1.394.522a1 1 0 01-1.217-.436l-.653-1.131a1 1 0 01.23-1.272l1.149-.946a6.026 6.026 0 010-2.435l-1.148-.944a1 1 0 01-.23-1.272l.653-1.131a1 1 0 011.217-.437l1.393.522a5.994 5.994 0 012.108-1.218l.244-1.466zM14.929 12a3 3 0 11-6 0 3 3 0 016 0z",clipRule:"evenodd"})})},790:e=>{e.exports=window.ReactJSXRuntime},2317:(e,o,a)=>{var t=a(4997),l=a(7723),n=a(4715),r=a(6427),i=a(6087),s=(a(7143),a(790));const d=({attributes:e,setAttributes:o})=>(0,s.jsxs)(r.PanelBody,{title:(0,l.__)("List Items","dynamic-table-of-contents-block-wp"),initialOpen:!1,children:[(0,s.jsx)("h4",{children:(0,l.__)("TOC Container","dynamic-table-of-contents-block-wp")}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{children:(0,l.__)("Background Color","dynamic-table-of-contents-block-wp")}),(0,s.jsx)(r.ColorPicker,{color:containerBackgroundColor,onChange:e=>o({containerBackgroundColor:e})})]})]}),c=({attributes:e,setAttributes:o})=>(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(n.InspectorControls,{children:(0,s.jsxs)(r.PanelBody,{title:(0,l.__)("General","dynamic-table-of-contents-block-wp"),initialOpen:!0,children:[(0,s.jsx)(r.TextControl,{label:(0,l.__)("TOC Title","dynamic-table-of-contents-block-wp"),value:tocTitle,onChange:e=>o({tocTitle:e})}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{style:{fontWeight:"600",marginBottom:"8px",display:"block"},children:(0,l.__)("Supported Heading Tags","dynamic-table-of-contents-block-wp")}),["h1","h2","h3","h4","h5"].map(e=>(0,s.jsx)(r.CheckboxControl,{label:e.toUpperCase(),checked:supportedHeadings.includes(e),onChange:a=>{const t=a?[...supportedHeadings,e]:supportedHeadings.filter(o=>o!==e);o({supportedHeadings:t})}},e))]}),(0,s.jsx)(r.ToggleControl,{label:(0,l.__)("List Hierarchy","dynamic-table-of-contents-block-wp"),help:(0,l.__)("Indent subheadings to show hierarchy","dynamic-table-of-contents-block-wp"),checked:showHierarchy,onChange:e=>o({showHierarchy:e})}),(0,s.jsx)(r.ToggleControl,{label:(0,l.__)("List Numbering","dynamic-table-of-contents-block-wp"),help:(0,l.__)("Show numbered list instead of bullets","dynamic-table-of-contents-block-wp"),checked:showNumbering,onChange:e=>o({showNumbering:e})}),(0,s.jsx)(r.ToggleControl,{label:(0,l.__)("Collapsible on Small Devices","dynamic-table-of-contents-block-wp"),help:(0,l.__)("Make TOC collapsible on mobile devices","dynamic-table-of-contents-block-wp"),checked:collapsibleOnMobile,onChange:e=>o({collapsibleOnMobile:e})}),(0,s.jsx)(r.ToggleControl,{label:(0,l.__)("Smooth Scroll Behavior","dynamic-table-of-contents-block-wp"),checked:smoothScroll,onChange:e=>o({smoothScroll:e})}),(0,s.jsx)(r.ToggleControl,{label:(0,l.__)("Sticky Mode","dynamic-table-of-contents-block-wp"),help:(0,l.__)("Keep TOC fixed while scrolling","dynamic-table-of-contents-block-wp"),checked:stickyMode,onChange:e=>o({stickyMode:e})})]})}),(0,s.jsxs)(n.InspectorControls,{group:"styles",children:[(0,s.jsx)(d,{attributes:e,setAttributes:o}),(0,s.jsxs)(r.PanelBody,{title:(0,l.__)("Style","dynamic-table-of-contents-block-wp"),initialOpen:!1,children:[(0,s.jsx)("h4",{children:(0,l.__)("TOC Container","dynamic-table-of-contents-block-wp")}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{children:(0,l.__)("Background Color","dynamic-table-of-contents-block-wp")}),(0,s.jsx)(r.ColorPicker,{color:containerBackgroundColor,onChange:e=>o({containerBackgroundColor:e})})]}),(0,s.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Width","dynamic-table-of-contents-block-wp"),value:containerWidth,onChange:e=>o({containerWidth:e}),units:[{value:"%",label:"%"},{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]}),(0,s.jsx)(r.__experimentalBoxControl,{label:(0,l.__)("Padding","dynamic-table-of-contents-block-wp"),values:containerPadding,onChange:e=>o({containerPadding:e})}),(0,s.jsx)(r.__experimentalBoxControl,{label:(0,l.__)("Margin","dynamic-table-of-contents-block-wp"),values:containerMargin,onChange:e=>o({containerMargin:e})}),(0,s.jsx)(r.SelectControl,{label:(0,l.__)("Border Style","dynamic-table-of-contents-block-wp"),value:containerBorderStyle,options:[{label:(0,l.__)("None","dynamic-table-of-contents-block-wp"),value:"none"},{label:(0,l.__)("Solid","dynamic-table-of-contents-block-wp"),value:"solid"},{label:(0,l.__)("Dashed","dynamic-table-of-contents-block-wp"),value:"dashed"},{label:(0,l.__)("Dotted","dynamic-table-of-contents-block-wp"),value:"dotted"}],onChange:e=>o({containerBorderStyle:e})}),"none"!==containerBorderStyle&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Border Width","dynamic-table-of-contents-block-wp"),value:containerBorderWidth,onChange:e=>o({containerBorderWidth:e})}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{children:(0,l.__)("Border Color","dynamic-table-of-contents-block-wp")}),(0,s.jsx)(r.ColorPicker,{color:containerBorderColor,onChange:e=>o({containerBorderColor:e})})]})]}),(0,s.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Border Radius","dynamic-table-of-contents-block-wp"),value:containerBorderRadius,onChange:e=>o({containerBorderRadius:e})}),(0,s.jsx)("hr",{style:{margin:"20px 0"}}),(0,s.jsx)("h4",{children:(0,l.__)("TOC Title","dynamic-table-of-contents-block-wp")}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{children:(0,l.__)("Color","dynamic-table-of-contents-block-wp")}),(0,s.jsx)(r.ColorPicker,{color:titleColor,onChange:e=>o({titleColor:e})})]}),(0,s.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Font Size","dynamic-table-of-contents-block-wp"),value:titleFontSize,onChange:e=>o({titleFontSize:e})}),(0,s.jsx)(r.SelectControl,{label:(0,l.__)("Font Weight","dynamic-table-of-contents-block-wp"),value:titleFontWeight,options:[{label:"300",value:"300"},{label:"400",value:"400"},{label:"500",value:"500"},{label:"600",value:"600"},{label:"700",value:"700"},{label:"800",value:"800"}],onChange:e=>o({titleFontWeight:e})}),(0,s.jsx)("hr",{style:{margin:"20px 0"}}),(0,s.jsx)("h4",{children:(0,l.__)("TOC List","dynamic-table-of-contents-block-wp")}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{children:(0,l.__)("Color","dynamic-table-of-contents-block-wp")}),(0,s.jsx)(r.ColorPicker,{color:listColor,onChange:e=>o({listColor:e})})]}),(0,s.jsxs)("div",{style:{marginBottom:"20px"},children:[(0,s.jsx)("label",{children:(0,l.__)("Hover Color","dynamic-table-of-contents-block-wp")}),(0,s.jsx)(r.ColorPicker,{color:listHoverColor,onChange:e=>o({listHoverColor:e})})]}),(0,s.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Font Size","dynamic-table-of-contents-block-wp"),value:listFontSize,onChange:e=>o({listFontSize:e})})]})]})]}),p=JSON.parse('{"UU":"wedocs/table-of-contents"}');(0,t.registerBlockType)(p.UU,{edit:function({attributes:e,setAttributes:o,clientId:a}){const{blockId:t,tocTitle:r,supportedHeadings:d,showHierarchy:p,showNumbering:h,collapsibleOnMobile:g,containerBackgroundColor:u,containerWidth:b,containerPadding:x,containerMargin:m,containerBorderStyle:_,containerBorderWidth:v,containerBorderColor:C,containerBorderRadius:w,titleColor:y,titleFontSize:f,titleFontWeight:j,titlePadding:S,listColor:B,listHoverColor:T,listFontSize:k,smoothScroll:P,stickyMode:$,additionalCssClass:F}=e,[M,R]=(0,i.useState)([]);(0,i.useEffect)(()=>{t||o({blockId:`toc-${a}`})},[t,a,o]),(0,i.useEffect)(()=>{const e=[{level:2,text:"Introduction",id:"introduction"},{level:3,text:"Getting Started",id:"getting-started"},{level:3,text:"Basic Features",id:"basic-features"},{level:2,text:"Advanced Usage",id:"advanced-usage"},{level:3,text:"Configuration",id:"configuration"},{level:4,text:"Settings Panel",id:"settings-panel"},{level:2,text:"Conclusion",id:"conclusion"}].filter(e=>d.includes(`h${e.level}`));R(e)},[d]);const D=(0,n.useBlockProps)({className:`${F} ${$?"sticky-mode":""}`.trim(),"data-block-id":t,style:{"--list-item-sytle":u,width:b,padding:x?`${x.top} ${x.right} ${x.bottom} ${x.left}`:void 0,margin:m?`${m.top} ${m.right} ${m.bottom} ${m.left}`:void 0,borderStyle:"none"!==_?_:void 0,borderWidth:"none"!==_?v:void 0,borderColor:"none"!==_?C:void 0,borderRadius:w}});return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(c,{attributes:e,setAttributes:o}),(0,s.jsxs)("div",{...D,children:[(0,s.jsx)("div",{className:"toc-title",style:{color:y,fontSize:f,fontWeight:j,padding:S?`${S.top} ${S.right} ${S.bottom} ${S.left}`:void 0},children:r}),(0,s.jsx)("div",{className:"toc-content",style:{color:B,fontSize:k},children:((e,o,a)=>{if(0===e.length)return(0,s.jsx)("div",{className:"toc-empty-state",children:(0,s.jsx)("p",{children:(0,l.__)("No headings found. Add some headings to your content to see them here.","dynamic-table-of-contents-block-wp")})});let t=1;const n={2:0,3:0,4:0,5:0};return(0,s.jsx)("ul",{className:`toc-list ${o?"hierarchical":"flat"} ${a?"numbered":"bulleted"}`,children:e.map((e,l)=>{if(a)if(o){n[e.level]++;for(let o=e.level+1;o<=5;o++)n[o]=0}else n[e.level]=t++;const r=o?20*(e.level-2):0,i=a?o?Object.entries(n).slice(0,e.level-1).map(([e,o])=>o>0?o:"").filter(e=>e).join("."):n[e.level]:"";return(0,s.jsx)("li",{style:{marginLeft:`${r}px`},children:(0,s.jsxs)("a",{href:`#${e.id}`,className:"toc-link",children:[a&&(0,s.jsxs)("span",{className:"toc-number",children:[i,". "]}),e.text]})},l)})})})(M,p,h)}),g&&(0,s.jsx)("div",{className:"toc-mobile-notice",style:{marginTop:"10px",fontSize:"12px",opacity:.7},children:(0,l.__)("(Collapsible on mobile devices)","dynamic-table-of-contents-block-wp")})]})]})}})},4715:e=>{e.exports=window.wp.blockEditor},4997:e=>{e.exports=window.wp.blocks},5573:e=>{e.exports=window.wp.primitives},6087:e=>{e.exports=window.wp.element},6239:(e,o,a)=>{var t=a(4997),l=a(7723),n=a(4715),r=a(6427),i=a(6087),s=a(7143);const d=window.wp.coreData;var c=a(790);const p=({children:e,defaultTab:o="setup"})=>{const[a,t]=(0,i.useState)(o),n=[{key:"setup",label:(0,l.__)("Setup","wedocs"),icon:"admin-settings"},{key:"style",label:(0,l.__)("Style","wedocs"),icon:"admin-appearance"}];return(0,c.jsxs)("div",{className:"contributors-tab-system",children:[(0,c.jsx)("div",{style:{borderBottom:"1px solid #ddd",marginBottom:"16px",paddingBottom:"8px"},children:(0,c.jsx)(r.ButtonGroup,{children:n.map(e=>(0,c.jsxs)(r.Button,{variant:a===e.key?"primary":"secondary",onClick:()=>t(e.key),style:{marginRight:"4px",display:"flex",alignItems:"center",gap:"4px"},children:[(0,c.jsx)("span",{className:`dashicons dashicons-${e.icon}`,style:{fontSize:"16px"}}),e.label]},e.key))})}),(0,c.jsx)("div",{className:"tab-content",children:e.map((e,o)=>{const t=0===o?"setup":"style";return(0,c.jsx)("div",{style:{display:a===t?"block":"none"},children:e},t)})})]})},h=({label:e,value:o={},onChange:a,colorValue:t,onColorChange:i,hoverColorValue:s,onHoverColorChange:d,showHoverColor:p=!0,showLineHeight:h=!0,showLetterSpacing:g=!0,showTextTransform:u=!0,showTextDecoration:b=!0})=>{const x=(e,t)=>{a({...o,[e]:t})};return(0,c.jsxs)(r.PanelBody,{title:e,initialOpen:!1,children:[(0,c.jsx)(n.PanelColorSettings,{title:(0,l.__)("Colors","wedocs"),colorSettings:[{value:t,onChange:i,label:(0,l.__)("Text Color","wedocs")},...p?[{value:s,onChange:d,label:(0,l.__)("Hover Color","wedocs")}]:[]]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Font Family","wedocs"),value:o.fontFamily||"default",options:[{label:(0,l.__)("Default","wedocs"),value:"default"},{label:"Arial",value:"Arial, sans-serif"},{label:"Georgia",value:"Georgia, serif"},{label:"Helvetica",value:"Helvetica, sans-serif"},{label:"Times New Roman",value:'"Times New Roman", serif'},{label:"Verdana",value:"Verdana, sans-serif"},{label:"Roboto",value:"Roboto, sans-serif"},{label:"Open Sans",value:'"Open Sans", sans-serif'},{label:"Lato",value:"Lato, sans-serif"},{label:"Montserrat",value:"Montserrat, sans-serif"}],onChange:e=>x("fontFamily","default"===e?void 0:e)}),(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Font Size","wedocs"),value:o.fontSize||"14px",onChange:e=>x("fontSize",e),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"},{value:"%",label:"%"}]}),(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Font Weight","wedocs"),value:o.fontWeight||"400",options:[{label:(0,l.__)("100 - Thin","wedocs"),value:"100"},{label:(0,l.__)("200 - Extra Light","wedocs"),value:"200"},{label:(0,l.__)("300 - Light","wedocs"),value:"300"},{label:(0,l.__)("400 - Normal","wedocs"),value:"400"},{label:(0,l.__)("500 - Medium","wedocs"),value:"500"},{label:(0,l.__)("600 - Semi Bold","wedocs"),value:"600"},{label:(0,l.__)("700 - Bold","wedocs"),value:"700"},{label:(0,l.__)("800 - Extra Bold","wedocs"),value:"800"},{label:(0,l.__)("900 - Black","wedocs"),value:"900"}],onChange:e=>x("fontWeight",e)}),(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Font Style","wedocs"),value:o.fontStyle||"normal",options:[{label:(0,l.__)("Normal","wedocs"),value:"normal"},{label:(0,l.__)("Italic","wedocs"),value:"italic"},{label:(0,l.__)("Oblique","wedocs"),value:"oblique"}],onChange:e=>x("fontStyle",e)}),h&&(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Line Height","wedocs"),value:o.lineHeight||"normal",onChange:e=>x("lineHeight",e),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"",label:"unitless"}]}),g&&(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Letter Spacing","wedocs"),value:o.letterSpacing||"normal",onChange:e=>x("letterSpacing",e),units:[{value:"px",label:"px"},{value:"em",label:"em"}]}),u&&(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Text Transform","wedocs"),value:o.textTransform||"none",options:[{label:(0,l.__)("None","wedocs"),value:"none"},{label:(0,l.__)("Uppercase","wedocs"),value:"uppercase"},{label:(0,l.__)("Lowercase","wedocs"),value:"lowercase"},{label:(0,l.__)("Capitalize","wedocs"),value:"capitalize"}],onChange:e=>x("textTransform",e)}),b&&(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Text Decoration","wedocs"),value:o.textDecoration||"none",options:[{label:(0,l.__)("None","wedocs"),value:"none"},{label:(0,l.__)("Underline","wedocs"),value:"underline"},{label:(0,l.__)("Overline","wedocs"),value:"overline"},{label:(0,l.__)("Line Through","wedocs"),value:"line-through"}],onChange:e=>x("textDecoration",e)})]})},g=({label:e,paddingValue:o={},onPaddingChange:a,marginValue:t={},onMarginChange:n,showPadding:i=!0,showMargin:s=!0,showGap:d=!1,gapValue:p,onGapChange:h})=>(0,c.jsxs)(r.PanelBody,{title:e,initialOpen:!1,children:[i&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalBoxControl,{label:(0,l.__)("Padding","wedocs"),values:o,onChange:a,units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"},{value:"%",label:"%"}],allowReset:!0,resetValues:{top:"0px",right:"0px",bottom:"0px",left:"0px"}}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4})]}),s&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalBoxControl,{label:(0,l.__)("Margin","wedocs"),values:t,onChange:n,units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"},{value:"%",label:"%"}],allowReset:!0,resetValues:{top:"0px",right:"0px",bottom:"0px",left:"0px"}}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4})]}),d&&(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Gap","wedocs"),value:p||"10px",onChange:h,units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]})]}),u=({label:e,borderStyle:o="none",onBorderStyleChange:a,borderWidth:t={},onBorderWidthChange:i,borderColor:s,onBorderColorChange:d,borderRadius:p,onBorderRadiusChange:h,showIndividualSides:g=!0})=>(0,c.jsxs)(r.PanelBody,{title:e,initialOpen:!1,children:[(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Border Style","wedocs"),value:o,options:[{label:(0,l.__)("None","wedocs"),value:"none"},{label:(0,l.__)("Solid","wedocs"),value:"solid"},{label:(0,l.__)("Dashed","wedocs"),value:"dashed"},{label:(0,l.__)("Dotted","wedocs"),value:"dotted"},{label:(0,l.__)("Double","wedocs"),value:"double"},{label:(0,l.__)("Groove","wedocs"),value:"groove"},{label:(0,l.__)("Ridge","wedocs"),value:"ridge"},{label:(0,l.__)("Inset","wedocs"),value:"inset"},{label:(0,l.__)("Outset","wedocs"),value:"outset"}],onChange:a}),"none"!==o&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),g?(0,c.jsx)(r.__experimentalBoxControl,{label:(0,l.__)("Border Width","wedocs"),values:t,onChange:i,units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}],allowReset:!0,resetValues:{top:"1px",right:"1px",bottom:"1px",left:"1px"}}):(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Border Width","wedocs"),value:t.top||"1px",onChange:e=>i({top:e,right:e,bottom:e,left:e}),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),(0,c.jsx)(n.PanelColorSettings,{title:(0,l.__)("Border Color","wedocs"),colorSettings:[{value:s,onChange:d,label:(0,l.__)("Color","wedocs")}]})]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Border Radius","wedocs"),value:p||"0px",onChange:h,units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"},{value:"%",label:"%"}]})]}),b=({label:e,backgroundType:o="classic",onBackgroundTypeChange:a,backgroundColor:t,onBackgroundColorChange:i,backgroundGradient:s,onBackgroundGradientChange:d,backgroundImage:p={},onBackgroundImageChange:h,showGradient:g=!0,showImage:u=!0})=>(0,c.jsxs)(r.PanelBody,{title:e,initialOpen:!1,children:[(0,c.jsx)(r.RadioControl,{label:(0,l.__)("Background Type","wedocs"),selected:o,options:[{label:(0,l.__)("Classic","wedocs"),value:"classic"},...g?[{label:(0,l.__)("Gradient","wedocs"),value:"gradient"}]:[]],onChange:a}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),"classic"===o&&(0,c.jsx)(n.PanelColorSettings,{title:(0,l.__)("Background Color","wedocs"),colorSettings:[{value:t,onChange:i,label:(0,l.__)("Color","wedocs")}]}),"gradient"===o&&g&&(0,c.jsx)(r.TextControl,{label:(0,l.__)("Gradient CSS","wedocs"),value:s||"",onChange:d,placeholder:"linear-gradient(45deg, #ff0000, #00ff00)",help:(0,l.__)("Enter CSS gradient value","wedocs")}),u&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),(0,c.jsxs)("div",{children:[(0,c.jsx)("h4",{children:(0,l.__)("Background Image","wedocs")}),(0,c.jsx)(n.MediaUploadCheck,{children:(0,c.jsx)(n.MediaUpload,{onSelect:e=>h({url:e.url,alt:e.alt,id:e.id}),allowedTypes:["image"],value:p?.id,render:({open:e})=>(0,c.jsx)(r.Button,{onClick:e,variant:"secondary",children:p?.url?(0,l.__)("Change Image","wedocs"):(0,l.__)("Select Image","wedocs")})})}),p?.url&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalSpacer,{marginTop:2,marginBottom:2}),(0,c.jsx)(r.Button,{onClick:()=>h({url:"",alt:"",id:""}),variant:"secondary",isDestructive:!0,children:(0,l.__)("Remove Image","wedocs")})]})]})]})]}),x=({label:e,shadowValue:o={},onShadowChange:a,showToggle:t=!0})=>{var i;const s=(e,t)=>{a({...o,[e]:t})},d=null!==(i=o.enabled)&&void 0!==i&&i;return(0,c.jsxs)(r.PanelBody,{title:e,initialOpen:!1,children:[t&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.ToggleControl,{label:(0,l.__)("Enable Box Shadow","wedocs"),checked:d,onChange:e=>s("enabled",e)}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4})]}),(d||!t)&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Horizontal Offset","wedocs"),value:o.horizontal||"0px",onChange:e=>s("horizontal",e),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:3,marginBottom:3}),(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Vertical Offset","wedocs"),value:o.vertical||"2px",onChange:e=>s("vertical",e),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:3,marginBottom:3}),(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Blur Radius","wedocs"),value:o.blur||"4px",onChange:e=>s("blur",e),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:3,marginBottom:3}),(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Spread Radius","wedocs"),value:o.spread||"0px",onChange:e=>s("spread",e),units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"}]}),(0,c.jsx)(r.__experimentalSpacer,{marginTop:4,marginBottom:4}),(0,c.jsx)(n.PanelColorSettings,{title:(0,l.__)("Shadow Color","wedocs"),colorSettings:[{value:o.color||"rgba(0,0,0,0.1)",onChange:e=>s("color",e),label:(0,l.__)("Color","wedocs")}]})]})]})},m=({label:e,widthValue:o,onWidthChange:a,heightValue:t,onHeightChange:n,showHeight:i=!0,linkValues:s=!1})=>(0,c.jsxs)(r.PanelBody,{title:e,initialOpen:!1,children:[(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Width","wedocs"),value:o||"auto",onChange:e=>{a(e),s&&i&&n&&n(e)},units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"},{value:"%",label:"%"},{value:"auto",label:"auto"}]}),i&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.__experimentalSpacer,{marginTop:3,marginBottom:3}),(0,c.jsx)(r.__experimentalUnitControl,{label:(0,l.__)("Height","wedocs"),value:t||"auto",onChange:n,units:[{value:"px",label:"px"},{value:"em",label:"em"},{value:"rem",label:"rem"},{value:"%",label:"%"},{value:"auto",label:"auto"}]})]})]}),_=a.p+"images/avatar_1.png",v=(a.p,e=>{const{attributes:o,setAttributes:a}=e,[t,v]=(0,i.useState)([]),[C,w]=(0,i.useState)(!1),[y,f]=(0,i.useState)([]),[j,S]=(0,i.useState)(!1),B=window.weDocsAdminScriptVars?.isPro||!1,T=(0,n.useBlockProps)({className:`wedocs-contributors ${o.additionalCssClass}`,style:{backgroundColor:"classic"===o.backgroundType?o.backgroundColor:void 0,backgroundImage:"gradient"===o.backgroundType?o.backgroundGradient:o.backgroundImage?.url?`url(${o.backgroundImage.url})`:void 0,padding:`${o.padding.top} ${o.padding.right} ${o.padding.bottom} ${o.padding.left}`,margin:`${o.margin.top} ${o.margin.right} ${o.margin.bottom} ${o.margin.left}`,borderStyle:"none"!==o.borderStyle?o.borderStyle:void 0,borderWidth:"none"!==o.borderStyle?`${o.borderWidth.top} ${o.borderWidth.right} ${o.borderWidth.bottom} ${o.borderWidth.left}`:void 0,borderColor:"none"!==o.borderStyle?o.borderColor:void 0,borderRadius:o.borderRadius,boxShadow:o.boxShadow.enabled?`${o.boxShadow.horizontal} ${o.boxShadow.vertical} ${o.boxShadow.blur} ${o.boxShadow.spread} ${o.boxShadow.color}`:void 0}}),k=(0,s.useSelect)(e=>{const{getCurrentPostId:o,getCurrentPostType:a}=e("core/editor")||{};return o?e(d.store).getEntityRecord("postType",a(),o()):null},[]);return(0,i.useEffect)(()=>{"manual"===o.contributorDisplayMode&&(w(!0),wp.apiFetch({path:"/wp/v2/users?per_page=100&context=edit"}).then(e=>{v(e),w(!1)}).catch(()=>{w(!1)}))},[o.contributorDisplayMode]),(0,i.useEffect)(()=>{k&&(async()=>{S(!0);try{const e=[];switch(o.contributorDisplayMode){case"main_author":if(k.author){const o=await wp.apiFetch({path:`/wp/v2/users/${k.author}?context=edit`});o&&e.push(o)}break;case"manual":if(o.selectedContributors.length>0)for(const a of o.selectedContributors)try{const o=await wp.apiFetch({path:`/wp/v2/users/${a}?context=edit`});o&&e.push(o)}catch(e){console.warn(`Could not fetch user ${a}:`,e)}break;default:if(k.author){const o=await wp.apiFetch({path:`/wp/v2/users/${k.author}?context=edit`});o&&e.push(o)}if(k.id)try{const o=await wp.apiFetch({path:`/wp/v2/${k.type}/${k.id}/revisions?per_page=50`}),a=[k.author];for(const t of o)if(t.author&&!a.includes(t.author)){a.push(t.author);try{const o=await wp.apiFetch({path:`/wp/v2/users/${t.author}?context=edit`});o&&e.push(o)}catch(e){console.warn(`Could not fetch revision author ${t.author}:`,e)}}}catch(e){console.warn("Could not fetch revisions:",e)}}f(e)}catch(e){console.error("Error fetching contributors:",e),f([])}finally{S(!1)}})()},[k,o.contributorDisplayMode,o.selectedContributors]),B?(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(n.InspectorControls,{children:(0,c.jsxs)(p,{defaultTab:"setup",children:[(0,c.jsxs)(c.Fragment,{children:[(0,c.jsxs)(r.PanelBody,{title:(0,l.__)("General Settings","wedocs"),initialOpen:!0,children:[(0,c.jsx)(r.ToggleControl,{label:(0,l.__)("Show Title","wedocs"),checked:o.showTitle,onChange:e=>a({showTitle:e})}),o.showTitle&&(0,c.jsx)(r.TextControl,{label:(0,l.__)("Title","wedocs"),value:o.title,onChange:e=>a({title:e})}),(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Contributor Display","wedocs"),value:o.contributorDisplayMode,options:[{label:(0,l.__)("Show all contributors","wedocs"),value:"all"},{label:(0,l.__)("Manually select contributors","wedocs"),value:"manual"},{label:(0,l.__)("Show only main author","wedocs"),value:"main_author"}],onChange:e=>a({contributorDisplayMode:e})}),"manual"===o.contributorDisplayMode&&(0,c.jsxs)("div",{children:[(0,c.jsx)("h4",{children:(0,l.__)("Select Contributors","wedocs")}),C?(0,c.jsx)(r.Spinner,{}):(0,c.jsx)("div",{style:{maxHeight:"200px",overflowY:"auto",border:"1px solid #ddd",padding:"10px"},children:t.map(e=>(0,c.jsxs)("label",{style:{display:"block",marginBottom:"5px"},children:[(0,c.jsx)("input",{type:"checkbox",checked:o.selectedContributors.includes(e.id),onChange:t=>{const l=t.target.checked?[...o.selectedContributors,e.id]:o.selectedContributors.filter(o=>o!==e.id);a({selectedContributors:l})},style:{marginRight:"8px"}}),e.name]},e.id))})]})]}),(0,c.jsxs)(r.PanelBody,{title:(0,l.__)("Avatar Settings","wedocs"),initialOpen:!1,children:[(0,c.jsx)(r.ToggleControl,{label:(0,l.__)("Show Avatar","wedocs"),checked:o.showAvatar,onChange:e=>a({showAvatar:e})}),o.showAvatar&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.RadioControl,{label:(0,l.__)("Avatar Type","wedocs"),selected:o.avatarType,options:[{label:(0,l.__)("User Avatar","wedocs"),value:"user_avatar"},{label:(0,l.__)("Common Icon","wedocs"),value:"common_icon"}],onChange:e=>a({avatarType:e})}),(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Avatar Shape","wedocs"),value:o.avatarShape,options:[{label:(0,l.__)("Circle","wedocs"),value:"circle"},{label:(0,l.__)("Rounded","wedocs"),value:"rounded"},{label:(0,l.__)("Square","wedocs"),value:"square"}],onChange:e=>a({avatarShape:e})}),(0,c.jsx)(r.ToggleControl,{label:(0,l.__)("Hover Effect","wedocs"),checked:o.avatarHoverEffect,onChange:e=>a({avatarHoverEffect:e})})]})]}),(0,c.jsxs)(r.PanelBody,{title:(0,l.__)("Date Settings","wedocs"),initialOpen:!1,children:[(0,c.jsx)(r.ToggleControl,{label:(0,l.__)("Show Last Updated Date","wedocs"),checked:o.showLastUpdated,onChange:e=>a({showLastUpdated:e})}),o.showLastUpdated&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(r.RadioControl,{label:(0,l.__)("Date Format","wedocs"),selected:o.dateFormat,options:[{label:(0,l.__)("WordPress Default","wedocs"),value:"wp_default"},{label:(0,l.__)("Custom Format","wedocs"),value:"custom"}],onChange:e=>a({dateFormat:e})}),"custom"===o.dateFormat&&(0,c.jsx)(r.TextControl,{label:(0,l.__)("Custom Date Format","wedocs"),value:o.customDateFormat,onChange:e=>a({customDateFormat:e}),help:(0,l.__)('Use PHP date format. E.g., F j, Y for "January 1, 2023"',"wedocs")}),(0,c.jsx)(r.TextControl,{label:(0,l.__)("Date Prefix Text","wedocs"),value:o.datePrefix,onChange:e=>a({datePrefix:e})})]})]}),(0,c.jsxs)(r.PanelBody,{title:(0,l.__)("Advanced","wedocs"),initialOpen:!1,children:[(0,c.jsx)(r.TextControl,{label:(0,l.__)("Additional CSS Classes","wedocs"),value:o.additionalCssClass,onChange:e=>a({additionalCssClass:e}),help:(0,l.__)("Separate multiple classes with spaces","wedocs")}),(0,c.jsx)(r.ToggleControl,{label:(0,l.__)("Enable Schema Markup","wedocs"),checked:o.enableSchema,onChange:e=>a({enableSchema:e}),help:(0,l.__)("Output structured data for author and dateModified","wedocs")}),(0,c.jsx)(r.SelectControl,{label:(0,l.__)("Avatar Link Behavior","wedocs"),value:o.linkBehavior,options:[{label:(0,l.__)("Link to user profile","wedocs"),value:"user_profile"},{label:(0,l.__)("No link","wedocs"),value:"no_link"},{label:(0,l.__)("Custom link","wedocs"),value:"custom_link"}],onChange:e=>a({linkBehavior:e})}),"custom_link"===o.linkBehavior&&(0,c.jsx)(r.TextControl,{label:(0,l.__)("Custom Link URL","wedocs"),value:o.customLinkUrl,onChange:e=>a({customLinkUrl:e}),placeholder:"https://example.com/author"})]})]}),(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(b,{label:(0,l.__)("Container Background","wedocs"),backgroundType:o.backgroundType,onBackgroundTypeChange:e=>a({backgroundType:e}),backgroundColor:o.backgroundColor,onBackgroundColorChange:e=>a({backgroundColor:e}),backgroundGradient:o.backgroundGradient,onBackgroundGradientChange:e=>a({backgroundGradient:e}),backgroundImage:o.backgroundImage,onBackgroundImageChange:e=>a({backgroundImage:e})}),(0,c.jsx)(g,{label:(0,l.__)("Container Spacing","wedocs"),paddingValue:o.padding,onPaddingChange:e=>a({padding:e}),marginValue:o.margin,onMarginChange:e=>a({margin:e}),showGap:!0,gapValue:o.contributorGap,onGapChange:e=>a({contributorGap:e})}),(0,c.jsx)(u,{label:(0,l.__)("Container Border","wedocs"),borderStyle:o.borderStyle,onBorderStyleChange:e=>a({borderStyle:e}),borderWidth:o.borderWidth,onBorderWidthChange:e=>a({borderWidth:e}),borderColor:o.borderColor,onBorderColorChange:e=>a({borderColor:e}),borderRadius:o.borderRadius,onBorderRadiusChange:e=>a({borderRadius:e})}),(0,c.jsx)(x,{label:(0,l.__)("Container Shadow","wedocs"),shadowValue:o.boxShadow,onShadowChange:e=>a({boxShadow:e})}),o.showTitle&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(h,{label:(0,l.__)("Title Typography","wedocs"),value:o.contributorTitleTypography,onChange:e=>a({contributorTitleTypography:e}),colorValue:o.contributorTitleColor,onColorChange:e=>a({contributorTitleColor:e}),hoverColorValue:o.contributorTitleHoverColor,onHoverColorChange:e=>a({contributorTitleHoverColor:e})}),(0,c.jsx)(g,{label:(0,l.__)("Title Spacing","wedocs"),paddingValue:o.titlePadding,onPaddingChange:e=>a({titlePadding:e}),marginValue:o.titleMargin,onMarginChange:e=>a({titleMargin:e}),showGap:!1})]}),o.showAvatar&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(m,{label:(0,l.__)("Avatar Size","wedocs"),widthValue:o.avatarSize,onWidthChange:e=>a({avatarSize:e}),showHeight:!1}),(0,c.jsx)(g,{label:(0,l.__)("Avatar Spacing","wedocs"),paddingValue:o.avatarPadding,onPaddingChange:e=>a({avatarPadding:e}),marginValue:o.avatarMargin,onMarginChange:e=>a({avatarMargin:e}),showGap:!1}),(0,c.jsx)(u,{label:(0,l.__)("Avatar Border","wedocs"),borderStyle:o.avatarBorderStyle,onBorderStyleChange:e=>a({avatarBorderStyle:e}),borderWidth:o.avatarBorderWidth,onBorderWidthChange:e=>a({avatarBorderWidth:e}),borderColor:o.avatarBorderColor,onBorderColorChange:e=>a({avatarBorderColor:e}),borderRadius:o.avatarBorderRadius,onBorderRadiusChange:e=>a({avatarBorderRadius:e})}),(0,c.jsx)(x,{label:(0,l.__)("Avatar Shadow","wedocs"),shadowValue:o.avatarBoxShadow,onShadowChange:e=>a({avatarBoxShadow:e})})]}),(0,c.jsx)(h,{label:(0,l.__)("Name Typography","wedocs"),value:o.nameTypography,onChange:e=>a({nameTypography:e}),colorValue:o.nameColor,onColorChange:e=>a({nameColor:e}),hoverColorValue:o.nameHoverColor,onHoverColorChange:e=>a({nameHoverColor:e})}),(0,c.jsx)(g,{label:(0,l.__)("Name Spacing","wedocs"),paddingValue:o.namePadding,onPaddingChange:e=>a({namePadding:e}),marginValue:o.nameMargin,onMarginChange:e=>a({nameMargin:e}),showGap:!1}),o.showLastUpdated&&(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(h,{label:(0,l.__)("Date Typography","wedocs"),value:o.dateTypography,onChange:e=>a({dateTypography:e}),colorValue:o.dateColor,onColorChange:e=>a({dateColor:e}),showHoverColor:!1}),(0,c.jsx)(g,{label:(0,l.__)("Date Spacing","wedocs"),paddingValue:o.datePadding,onPaddingChange:e=>a({datePadding:e}),marginValue:o.dateMargin,onMarginChange:e=>a({dateMargin:e}),showGap:!1})]})]})]})}),(0,c.jsx)("div",{...T,children:(()=>{if(j)return(0,c.jsxs)(r.Placeholder,{icon:"groups",label:(0,l.__)("Doc Contributors","wedocs"),children:[(0,c.jsx)(r.Spinner,{}),(0,c.jsx)("div",{children:(0,l.__)("Loading contributors...","wedocs")})]});if("manual"===o.contributorDisplayMode&&0===o.selectedContributors.length)return(0,c.jsx)(r.Placeholder,{icon:"groups",label:(0,l.__)("Doc Contributors","wedocs"),instructions:(0,l.__)("Select contributors from the settings panel.","wedocs")});let e=y;e&&0!==e.length||(e=[{id:1,name:"Demo Author",avatar_urls:{48:_}}]);const a={width:o.avatarSize,height:o.avatarSize,borderRadius:"circle"===o.avatarShape?"50%":"rounded"===o.avatarShape?o.avatarBorderRadius:"0",borderStyle:"none"!==o.avatarBorderStyle?o.avatarBorderStyle:void 0,borderColor:"none"!==o.avatarBorderStyle?o.avatarBorderColor:void 0,borderWidth:"none"!==o.avatarBorderStyle?`${o.avatarBorderWidth?.top||"2px"} ${o.avatarBorderWidth?.right||"2px"} ${o.avatarBorderWidth?.bottom||"2px"} ${o.avatarBorderWidth?.left||"2px"}`:void 0,padding:`${o.avatarPadding?.top||"0px"} ${o.avatarPadding?.right||"0px"} ${o.avatarPadding?.bottom||"0px"} ${o.avatarPadding?.left||"0px"}`,margin:`${o.avatarMargin?.top||"0px"} ${o.avatarMargin?.right||"8px"} ${o.avatarMargin?.bottom||"0px"} ${o.avatarMargin?.left||"0px"}`,boxShadow:o.avatarBoxShadow?.enabled?`${o.avatarBoxShadow.horizontal} ${o.avatarBoxShadow.vertical} ${o.avatarBoxShadow.blur} ${o.avatarBoxShadow.spread} ${o.avatarBoxShadow.color}`:void 0},t={color:o.contributorTitleColor,fontSize:o.contributorTitleTypography.fontSize,fontWeight:o.contributorTitleTypography.fontWeight,fontStyle:o.contributorTitleTypography.fontStyle,fontFamily:"default"!==o.contributorTitleTypography.fontFamily?o.contributorTitleTypography.fontFamily:void 0,lineHeight:"normal"!==o.contributorTitleTypography.lineHeight?o.contributorTitleTypography.lineHeight:void 0,letterSpacing:"normal"!==o.contributorTitleTypography.letterSpacing?o.contributorTitleTypography.letterSpacing:void 0,textTransform:"none"!==o.contributorTitleTypography.textTransform?o.contributorTitleTypography.textTransform:void 0,textDecoration:"none"!==o.contributorTitleTypography.textDecoration?o.contributorTitleTypography.textDecoration:void 0,padding:`${o.titlePadding?.top||"0px"} ${o.titlePadding?.right||"0px"} ${o.titlePadding?.bottom||"10px"} ${o.titlePadding?.left||"0px"}`,margin:`${o.titleMargin?.top||"0px"} ${o.titleMargin?.right||"0px"} ${o.titleMargin?.bottom||"0px"} ${o.titleMargin?.left||"0px"}`},n={color:o.nameColor,fontSize:o.nameTypography.fontSize,fontWeight:o.nameTypography.fontWeight,fontStyle:o.nameTypography.fontStyle,fontFamily:"default"!==o.nameTypography.fontFamily?o.nameTypography.fontFamily:void 0,lineHeight:"normal"!==o.nameTypography.lineHeight?o.nameTypography.lineHeight:void 0,letterSpacing:"normal"!==o.nameTypography.letterSpacing?o.nameTypography.letterSpacing:void 0,textTransform:"none"!==o.nameTypography.textTransform?o.nameTypography.textTransform:void 0,textDecoration:"none"!==o.nameTypography.textDecoration?o.nameTypography.textDecoration:void 0,padding:`${o.namePadding?.top||"0px"} ${o.namePadding?.right||"0px"} ${o.namePadding?.bottom||"0px"} ${o.namePadding?.left||"0px"}`,margin:`${o.nameMargin?.top||"0px"} ${o.nameMargin?.right||"0px"} ${o.nameMargin?.bottom||"0px"} ${o.nameMargin?.left||"0px"}`},i={color:o.dateColor,fontSize:o.dateTypography.fontSize,fontWeight:o.dateTypography.fontWeight,fontStyle:o.dateTypography.fontStyle,fontFamily:"default"!==o.dateTypography.fontFamily?o.dateTypography.fontFamily:void 0,lineHeight:"normal"!==o.dateTypography.lineHeight?o.dateTypography.lineHeight:void 0,letterSpacing:"normal"!==o.dateTypography.letterSpacing?o.dateTypography.letterSpacing:void 0,textTransform:"none"!==o.dateTypography.textTransform?o.dateTypography.textTransform:void 0,textDecoration:"none"!==o.dateTypography.textDecoration?o.dateTypography.textDecoration:void 0,padding:`${o.datePadding?.top||"0px"} ${o.datePadding?.right||"0px"} ${o.datePadding?.bottom||"0px"} ${o.datePadding?.left||"0px"}`,margin:`${o.dateMargin?.top||"10px"} ${o.dateMargin?.right||"0px"} ${o.dateMargin?.bottom||"0px"} ${o.dateMargin?.left||"0px"}`};return(0,c.jsxs)("div",{children:[o.showTitle&&(0,c.jsx)("h3",{style:t,children:o.title}),(0,c.jsx)("div",{style:{display:"flex",alignItems:"center",flexWrap:"wrap",gap:o.contributorGap||"10px"},children:o.showAvatar&&e.map(e=>{const t=e.name||e.display_name||"Unknown",l=e.id||e.ID||Math.random();let r=_;if(e.avatar_urls&&(r=e.avatar_urls[48]||e.avatar_urls[96]||e.avatar_urls[24]),!r&&e.email)try{r=`https://www.gravatar.com/avatar/${btoa(e.email.toLowerCase().trim())}?s=48&d=identicon`}catch(e){r=_}return(0,c.jsxs)("div",{style:{display:"flex",alignItems:"center"},children:["user_avatar"===o.avatarType?(0,c.jsx)("img",{src:r,alt:t,style:a}):(0,c.jsx)("div",{style:{...a,backgroundColor:"#0073aa",display:"flex",alignItems:"center",justifyContent:"center"},children:(0,c.jsx)("svg",{width:"16",height:"16",fill:"white",viewBox:"0 0 24 24",children:(0,c.jsx)("path",{d:"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z"})})}),(0,c.jsx)("span",{style:n,children:t})]},l)})}),o.showLastUpdated&&(0,c.jsxs)("div",{style:i,children:[o.datePrefix," ",(new Date).toLocaleDateString("en-US",{year:"numeric",month:"long",day:"numeric"})]})]})})()})]}):(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(n.InspectorControls,{children:(0,c.jsx)(r.PanelBody,{title:(0,l.__)("Doc Contributors - PRO Feature","wedocs"),initialOpen:!0,children:(0,c.jsxs)("div",{style:{padding:"20px",textAlign:"center"},children:[(0,c.jsx)("div",{style:{marginBottom:"15px"},children:(0,c.jsx)("svg",{width:"48",height:"48",fill:"#4f47e6",viewBox:"0 0 20 15",children:(0,c.jsx)("path",{d:"M19.213 4.116c.003.054-.001.108-.015.162l-1.234 6.255a.56.56 0 0 1-.541.413l-7.402.036h-.003-7.402c-.257 0-.482-.171-.544-.414L.839 4.295a.53.53 0 0 1-.015-.166C.347 3.983 0 3.548 0 3.036c0-.632.528-1.145 1.178-1.145s1.178.514 1.178 1.145a1.13 1.13 0 0 1-.43.884L3.47 5.434c.39.383.932.602 1.486.602.655 0 1.28-.303 1.673-.81l2.538-3.272c-.213-.207-.345-.494-.345-.809C8.822.514 9.351 0 10 0s1.178.514 1.178 1.145c0 .306-.125.584-.327.79l.002.003 2.52 3.281c.393.512 1.02.818 1.677.818a2.11 2.11 0 0 0 1.481-.597l1.554-1.512c-.268-.21-.44-.531-.44-.892 0-.632.528-1.145 1.177-1.145S20 2.405 20 3.036c0 .498-.329.922-.787 1.079zm-1.369 8.575c0-.301-.251-.545-.561-.545H2.779c-.31 0-.561.244-.561.545V14c0 .301.251.546.561.546h14.505c.31 0 .561-.244.561-.546v-1.309z"})})}),(0,c.jsx)("h3",{style:{margin:"0 0 10px 0",fontSize:"16px",fontWeight:"600"},children:(0,l.__)("This is a PRO Feature","wedocs")}),(0,c.jsx)("p",{style:{margin:"0 0 20px 0",color:"#666",fontSize:"14px"},children:(0,l.__)("The Contributors block requires weDocs Pro to be active.","wedocs")}),(0,c.jsx)("a",{href:"https://wedocs.co/pricing/",target:"_blank",rel:"noopener noreferrer",style:{display:"inline-block",padding:"10px 20px",backgroundColor:"#4f47e6",color:"#fff",textDecoration:"none",borderRadius:"4px",fontWeight:"600",fontSize:"14px"},children:(0,l.__)("Purchase weDocs Pro","wedocs")})]})})}),(0,c.jsx)("div",{...T,children:(0,c.jsx)(r.Placeholder,{icon:(0,c.jsx)("svg",{width:"48",height:"48",fill:"#4f47e6",viewBox:"0 0 20 15",children:(0,c.jsx)("path",{d:"M19.213 4.116c.003.054-.001.108-.015.162l-1.234 6.255a.56.56 0 0 1-.541.413l-7.402.036h-.003-7.402c-.257 0-.482-.171-.544-.414L.839 4.295a.53.53 0 0 1-.015-.166C.347 3.983 0 3.548 0 3.036c0-.632.528-1.145 1.178-1.145s1.178.514 1.178 1.145a1.13 1.13 0 0 1-.43.884L3.47 5.434c.39.383.932.602 1.486.602.655 0 1.28-.303 1.673-.81l2.538-3.272c-.213-.207-.345-.494-.345-.809C8.822.514 9.351 0 10 0s1.178.514 1.178 1.145c0 .306-.125.584-.327.79l.002.003 2.52 3.281c.393.512 1.02.818 1.677.818a2.11 2.11 0 0 0 1.481-.597l1.554-1.512c-.268-.21-.44-.531-.44-.892 0-.632.528-1.145 1.177-1.145S20 2.405 20 3.036c0 .498-.329.922-.787 1.079zm-1.369 8.575c0-.301-.251-.545-.561-.545H2.779c-.31 0-.561.244-.561.545V14c0 .301.251.546.561.546h14.505c.31 0 .561-.244.561-.546v-1.309z"})}),label:(0,l.__)("Doc Contributors - PRO Feature","wedocs"),instructions:(0,l.__)("This block requires weDocs Pro to be active.","wedocs"),children:(0,c.jsx)("a",{href:"https://wedocs.co/pricing/",target:"_blank",rel:"noopener noreferrer",style:{display:"inline-block",padding:"10px 20px",backgroundColor:"#4f47e6",color:"#fff",textDecoration:"none",borderRadius:"4px",fontWeight:"600",fontSize:"14px",marginTop:"10px"},children:(0,l.__)("Purchase weDocs Pro","wedocs")})})})]})}),C=JSON.parse('{"UU":"wedocs/contributors"}');var w=a(5573);const y=(0,c.jsx)(w.SVG,{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 24 24",children:(0,c.jsx)(w.Path,{d:"M11.776 4.454a.25.25 0 01.448 0l2.069 4.192a.25.25 0 00.188.137l4.626.672a.25.25 0 01.139.426l-3.348 3.263a.25.25 0 00-.072.222l.79 4.607a.25.25 0 01-.362.263l-4.138-2.175a.25.25 0 00-.232 0l-4.138 2.175a.25.25 0 01-.363-.263l.79-4.607a.25.25 0 00-.071-.222L4.754 9.881a.25.25 0 01.139-.426l4.626-.672a.25.25 0 00.188-.137l2.069-4.192z"})});(0,t.registerBlockType)(C.UU,{edit:v,save:()=>null,icon:{src:()=>(0,c.jsxs)("span",{style:{position:"relative",display:"inline-block"},children:[(0,c.jsx)(r.Icon,{icon:y}),(0,c.jsx)("span",{style:{position:"absolute",top:"22px",right:"-2px",background:"#4f47e6",color:"white",fontSize:"9px",padding:"2px 3px",borderRadius:"3px",fontWeight:"bold",lineHeight:1},children:"PRO"})]})}})},6427:e=>{e.exports=window.wp.components},7143:e=>{e.exports=window.wp.data},7450:(e,o,a)=>{var t=a(4997),l=a(7723),n=a(5573),r=a(790);const i=(0,r.jsx)(n.SVG,{viewBox:"0 0 24 24",xmlns:"http://www.w3.org/2000/svg",children:(0,r.jsx)(n.Path,{d:"M12 8c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm0 6.5c-1.4 0-2.5-1.1-2.5-2.5s1.1-2.5 2.5-2.5 2.5 1.1 2.5 2.5-1.1 2.5-2.5 2.5zM12.8 3h-1.5v3h1.5V3zm-1.6 18h1.5v-3h-1.5v3zm6.8-9.8v1.5h3v-1.5h-3zm-12 0H3v1.5h3v-1.5zm9.7 5.6 2.1 2.1 1.1-1.1-2.1-2.1-1.1 1.1zM8.3 7.2 6.2 5.1 5.1 6.2l2.1 2.1 1.1-1.1zM5.1 17.8l1.1 1.1 2.1-2.1-1.1-1.1-2.1 2.1zM18.9 6.2l-1.1-1.1-2.1 2.1 1.1 1.1 2.1-2.1z"})});var s=a(684),d=a(6087),c=a(4715),p=a(6427);const h=({label:e,value:o,unit:a,onValueChange:t,onUnitChange:n})=>(0,r.jsxs)(p.Flex,{children:[(0,r.jsx)(p.FlexBlock,{children:(0,r.jsx)(p.TextControl,{label:e,value:parseInt(o),onChange:e=>t(e)})}),(0,r.jsx)(p.FlexItem,{children:(0,r.jsx)(p.SelectControl,{label:(0,l.__)("Unit","wedocs"),value:a,options:[{label:"px",value:"px"},{label:"%",value:"%"}],onChange:e=>n(e)})})]}),g=({selected:e,options:o,onChange:a})=>(0,r.jsx)(p.BaseControl,{children:(0,r.jsx)("div",{className:"radio-image-control-options",children:o.map(o=>(0,r.jsxs)("div",{className:"radio-image-option",children:[(0,r.jsx)("input",{type:"radio",id:`radio-image-${o.value}`,value:o.value,checked:e===o.value,onChange:e=>a(e.target.value)}),(0,r.jsxs)("label",{htmlFor:`radio-image-${o.value}`,children:[o.icon&&(0,r.jsx)("i",{className:`dashicons ${o.icon}`}),o.img&&(0,r.jsx)("img",{src:o.img,alt:o.label}),o?.svg]})]},o.value))})}),u={hideSearch:{type:"boolean",default:!1},searchWidth:{type:"number",default:50},widthUnit:{type:"string",default:"%"},placeholder:{type:"string",default:(0,l.__)("Search for a top or question","wedocs")},alignment:{type:"string",default:"right"},bgColor:{type:"string",default:"#FFFFFF"},hoverColor:{type:"string",default:"#FFFFFF"},padding:{type:"object",default:{top:14,left:22,right:22,bottom:14}},margin:{type:"object",default:{top:0,left:0,right:0,bottom:0}},borderColor:{type:"string",default:"#cccccc"},borderType:{type:"string",default:"solid"},borderWidth:{type:"number",default:1},borderRadius:{type:"number",default:30},iconColor:{type:"string",default:"#FFFFFF"},iconBgColor:{type:"string",default:"#3b82f6"},iconHoverColor:{type:"string",default:"#2563eb"},svgHoverColor:{type:"string",default:"#FFFFFF"},btnPadding:{type:"object",default:{top:24,left:26,right:26,bottom:24}},btnPosition:{type:"object",default:{top:0,right:0,bottom:10}},btnRadius:{type:"number",default:30}};(0,t.registerBlockType)("wedocs/wedocs-search",{attributes:u,save:({attributes:e})=>{const{margin:o,bgColor:a,padding:t,btnRadius:l,alignment:n,iconColor:i,widthUnit:s,hoverColor:p,borderType:h,hideSearch:g,btnPadding:u,searchWidth:b,btnPosition:x,placeholder:m,borderColor:_,borderWidth:v,iconBgColor:C,borderRadius:w,svgHoverColor:y,iconHoverColor:f}=e;if(g)return;const j={display:"flex",justifyContent:n},S={border:`${v}px ${h} ${_}`,paddingTop:t?.top,paddingLeft:t?.left,paddingRight:t?.right,borderRadius:`${w}px`,paddingBottom:t?.bottom,"--field-color":a,"--field-bg-color":p},B={top:x?.top,left:x?.left,right:x?.right,bottom:x?.bottom,height:"auto",paddingTop:u?.top,paddingLeft:u?.left,borderRadius:l,paddingRight:u?.right,paddingBottom:u?.bottom,"--field-icon-color":i,"--field-btn-bg-color":C,"--field-icon-hover-color":y,"--field-btn-bg-hover-color":f};return(0,r.jsx)(d.Fragment,{children:(0,r.jsx)("form",{method:"get",role:"search",action:weDocsBlockVars?.siteUrl,...c.useBlockProps.save({className:"search-form wedocs-search-form"}),children:(0,r.jsx)("div",{style:j,children:(0,r.jsxs)("div",{className:"wedocs-search-input",style:{width:b+s,marginTop:o?.top,marginLeft:o?.left,marginRight:o?.right,marginBottom:o?.bottom},children:[(0,r.jsx)("input",{name:"s",type:"search",style:S,className:"search-field",placeholder:m}),(0,r.jsx)("input",{type:"hidden",name:"post_type",value:"docs"}),(0,r.jsx)("button",{type:"submit",style:B,className:"search-submit",children:(0,r.jsx)("svg",{width:"15",height:"16",fill:"none",children:(0,r.jsx)("path",{fillRule:"evenodd",d:"M11.856 10.847l2.883 2.883a.89.89 0 0 1 0 1.257c-.173.174-.401.261-.629.261s-.455-.087-.629-.261l-2.883-2.883c-1.144.874-2.532 1.353-3.996 1.353a6.56 6.56 0 0 1-4.671-1.935c-2.576-2.575-2.576-6.765 0-9.341C3.179.934 4.839.247 6.603.247s3.424.687 4.671 1.935a6.56 6.56 0 0 1 1.935 4.67 6.55 6.55 0 0 1-1.353 3.995zM3.189 3.439c-1.882 1.882-1.882 4.945 0 6.827.912.912 2.124 1.414 3.414 1.414s2.502-.502 3.414-1.414 1.414-2.124 1.414-3.413-.502-2.502-1.414-3.413-2.124-1.414-3.414-1.414-2.502.502-3.414 1.414z"})})})]})})})})},edit:({attributes:e,setAttributes:o})=>{const a=(0,c.useBlockProps)(),{margin:t,bgColor:n,padding:u,btnRadius:b,alignment:x,iconColor:m,widthUnit:_,hoverColor:v,borderType:C,hideSearch:w,btnPadding:y,searchWidth:f,btnPosition:j,placeholder:S,borderColor:B,borderWidth:T,iconBgColor:k,borderRadius:P,svgHoverColor:$,iconHoverColor:F}=e;console.log("editor panel:",n);const M=[{value:"left",label:(0,l.__)("Align left","wedocs"),svg:(0,r.jsx)("svg",{width:"24",height:"25",fill:"none",strokeWidth:"2",strokeLinecap:"round",stroke:"left"===x?"#007cba":"#939494",strokeLinejoin:"round",children:(0,r.jsx)("path",{d:"M8 9.462h12m-12 6h6m-10-9v12"})})},{value:"center",label:(0,l.__)("Align center","wedocs"),svg:(0,r.jsxs)("svg",{width:"24",height:"25",fill:"none",strokeWidth:"2",strokeLinecap:"round",stroke:"center"===x?"#007cba":"#939494",strokeLinejoin:"round",children:[(0,r.jsx)("path",{d:"M18 9.462H6m8.99 6h-6"}),(0,r.jsx)("path",{d:"M12 6.462v12"})]})},{value:"right",label:(0,l.__)("Align right","wedocs"),svg:(0,r.jsx)("svg",{width:"24",height:"25",fill:"none",strokeWidth:"2",strokeLinecap:"round",stroke:"right"===x?"#007cba":"#939494",strokeLinejoin:"round",children:(0,r.jsx)("path",{d:"M16 9.462H4m12 6h-6m10-9v12"})})}],[R,D]=(0,d.useState)(!1),[H,W]=(0,d.useState)(!1),[O,N]=(0,d.useState)(!1),z={display:"flex",justifyContent:x},L={border:`${T}px ${C} ${B}`,paddingTop:u?.top,background:R?v:n,paddingLeft:u?.left,paddingRight:u?.right,borderRadius:`${P}px`,paddingBottom:u?.bottom},A={top:j?.top,left:j?.left,right:j?.right,bottom:j?.bottom,height:"auto",background:O?F:k,paddingTop:y?.top,paddingLeft:y?.left,borderRadius:b,paddingRight:y?.right,paddingBottom:y?.bottom},U=[{label:(0,l.__)("Solid","wedocs"),value:"solid"},{label:(0,l.__)("Dotted","wedocs"),value:"dotted"},{label:(0,l.__)("Dashed","wedocs"),value:"dashed"},{label:(0,l.__)("Double","wedocs"),value:"double"},{label:(0,l.__)("Groove","wedocs"),value:"groove"},{label:(0,l.__)("Ridge","wedocs"),value:"ridge"},{label:(0,l.__)("Inset","wedocs"),value:"inset"},{label:(0,l.__)("Outset","wedocs"),value:"outset"},{label:(0,l.__)("None","wedocs"),value:"none"},{label:(0,l.__)("Hidden","wedocs"),value:"hidden"}];return(0,r.jsxs)(d.Fragment,{children:[(0,r.jsxs)(c.InspectorControls,{children:[(0,r.jsx)(p.PanelBody,{children:(0,r.jsx)(p.ToggleControl,{checked:w,className:"wedocs-search-toggle",label:(0,l.__)("Disable Block","wedocs"),onChange:e=>o({hideSearch:e})})}),!w&&(0,r.jsxs)(d.Fragment,{children:[(0,r.jsx)(p.PanelBody,{title:(0,l.__)("Color Settings","wedocs"),icon:i,initialOpen:!1,className:"wedocs-search-color-settings",children:(0,r.jsx)(c.PanelColorSettings,{colors:[{name:"Sweet",color:"#F43F5E"},{name:"Orange",color:"#F97316"},{name:"Yellow",color:"#FACC15"},{name:"Purple",color:"#8B5CF6"},{name:"Light Blue",color:"#3B82F6"},{name:"Light Green",color:"#10B981"}],colorSettings:[{value:n,label:(0,l.__)("Field Background Color","wedocs"),onChange:e=>o({bgColor:e})},{value:v,label:(0,l.__)("Field Hover Color","wedocs"),onChange:e=>o({hoverColor:e})},{value:B,label:(0,l.__)("Border Color","wedocs"),onChange:e=>o({borderColor:e})},{value:m,label:(0,l.__)("Icon Color","wedocs"),onChange:e=>o({iconColor:e})},{value:k,label:(0,l.__)("Button Color","wedocs"),onChange:e=>o({iconBgColor:e})},{value:F,label:(0,l.__)("Button Hover Color","wedocs"),onChange:e=>o({iconHoverColor:e})},{value:$,label:(0,l.__)("Icon Hover Color","wedocs"),onChange:e=>o({svgHoverColor:e})}]})}),(0,r.jsxs)(p.PanelBody,{title:(0,l.__)("Search Bar Settings","wedocs"),icon:s.A,children:[(0,r.jsx)(h,{unit:_,value:f,label:(0,l.__)("Field Width","wedocs"),onUnitChange:e=>o({widthUnit:e}),onValueChange:e=>o({searchWidth:e?parseInt(e):0})}),(0,r.jsx)(p.TextControl,{value:S,label:(0,l.__)("Placeholder","wedocs"),placeholder:(0,l.__)("Search bar placeholder","wedocs"),onChange:e=>o({placeholder:e})}),(0,r.jsx)("p",{style:{fontSize:11},children:(0,l.__)("POSITION","wedocs")}),(0,r.jsx)(g,{selected:x,options:M,onChange:e=>o({alignment:e})}),(0,r.jsx)(p.__experimentalBoxControl,{resetValues:{top:"14px",left:"22px",right:"22px",bottom:"14px"},values:u,label:(0,l.__)("Field Padding","wedocs"),onChange:e=>o({padding:e})}),(0,r.jsx)(p.__experimentalBoxControl,{resetValues:{top:"0px",left:"0px",right:"0px",bottom:"0px"},values:t,label:(0,l.__)("Field Margin","wedocs"),onChange:e=>o({margin:e})}),(0,r.jsx)(p.RangeControl,{min:0,max:10,value:T,label:(0,l.__)("Border Width","wedocs"),onChange:e=>o({borderWidth:e})}),(0,r.jsx)(p.RangeControl,{min:0,max:100,value:P,label:(0,l.__)("Border Radius","wedocs"),onChange:e=>o({borderRadius:e})}),(0,r.jsx)(p.SelectControl,{value:C,options:U,label:(0,l.__)("Border Type","wedocs"),onChange:e=>o({borderType:e})}),(0,r.jsx)(p.__experimentalBoxControl,{resetValues:{top:"24px",left:"26px",right:"26px",bottom:"24px"},values:y,label:(0,l.__)("Button Padding","wedocs"),onChange:e=>o({btnPadding:e})}),(0,r.jsx)(p.__experimentalBoxControl,{resetValues:{top:"0px",right:"0px",bottom:"10px"},values:j,label:(0,l.__)("Button Margin","wedocs"),onChange:e=>o({btnPosition:e})}),(0,r.jsx)(p.RangeControl,{min:0,max:100,value:b,label:(0,l.__)("Button Radius","wedocs"),onChange:e=>o({btnRadius:e})})]})]})]}),(0,r.jsxs)("div",{...a,style:z,children:[(0,r.jsxs)("div",{className:"wedocs-editor-search-input",style:{width:f+_,marginTop:t?.top,marginLeft:t?.left,marginRight:t?.right,marginBottom:t?.bottom},children:[(0,r.jsx)("input",{readOnly:!0,style:L,className:"search-field",placeholder:S,onMouseEnter:()=>D(!0),onMouseLeave:()=>D(!1)}),(0,r.jsx)("input",{type:"hidden",name:"post_type",value:"docs"}),(0,r.jsx)("button",{type:"submit",style:A,className:"search-submit",onMouseEnter:()=>N(!0),onMouseLeave:()=>N(!1),children:(0,r.jsx)("svg",{width:"15",height:"16",fill:"none",onMouseEnter:()=>W(!0),onMouseLeave:()=>W(!1),children:(0,r.jsx)("path",{fill:H?$:m,fillRule:"evenodd",d:"M11.856 10.847l2.883 2.883a.89.89 0 0 1 0 1.257c-.173.174-.401.261-.629.261s-.455-.087-.629-.261l-2.883-2.883c-1.144.874-2.532 1.353-3.996 1.353a6.56 6.56 0 0 1-4.671-1.935c-2.576-2.575-2.576-6.765 0-9.341C3.179.934 4.839.247 6.603.247s3.424.687 4.671 1.935a6.56 6.56 0 0 1 1.935 4.67 6.55 6.55 0 0 1-1.353 3.995zM3.189 3.439c-1.882 1.882-1.882 4.945 0 6.827.912.912 2.124 1.414 3.414 1.414s2.502-.502 3.414-1.414 1.414-2.124 1.414-3.413-.502-2.502-1.414-3.413-2.124-1.414-3.414-1.414-2.502.502-3.414 1.414z"})})})]}),w&&(0,r.jsx)("div",{className:"backdrop"})]})]})},icon:(0,r.jsx)("svg",{width:"20",height:"20",viewBox:"0 0 20 20",fill:"none",children:(0,r.jsx)("path",{fillRule:"evenodd",clipRule:"evenodd",d:"M8.91421 1.5H5.5C4.39543 1.5 3.5 2.39543 3.5 3.5V6.91421V9.02779V15.5C3.5 16.6046 4.39543 17.5 5.5 17.5H7.02779C6.07771 16.4385 5.5 15.0367 5.5 13.5C5.5 10.1863 8.18629 7.5 11.5 7.5C13.0367 7.5 14.4385 8.07771 15.5 9.02779V8.5V6.91421C15.5 6.38378 15.2893 5.87507 14.9142 5.5L11.5 2.08579C11.1249 1.71071 10.6162 1.5 10.0858 1.5H8.91421ZM15.5 13.5C15.5 11.2909 13.7091 9.5 11.5 9.5C9.29086 9.5 7.5 11.2909 7.5 13.5C7.5 15.7091 9.29086 17.5 11.5 17.5C12.2414 17.5 12.9364 17.2977 13.5318 16.946L14.7929 18.2071C15.1834 18.5976 15.8166 18.5976 16.2071 18.2071C16.5976 17.8166 16.5976 17.1834 16.2071 16.7929L14.946 15.5318C15.2977 14.9364 15.5 14.2414 15.5 13.5ZM11.5 11.5C12.6046 11.5 13.5 12.3954 13.5 13.5C13.5 14.0526 13.2772 14.5512 12.9142 14.9142C12.5512 15.2772 12.0526 15.5 11.5 15.5C10.3954 15.5 9.5 14.6046 9.5 13.5C9.5 12.3954 10.3954 11.5 11.5 11.5Z",fill:"#111827"})}),title:(0,l.__)("weDocs - Searchbar","wedocs"),keywords:["Search","weDocs search bar","Bar"],category:"widgets",description:(0,l.__)("Simple search forms for easy user guidance for your documentation","wedocs")}),a(9033),a(6239),a(2317)},7723:e=>{e.exports=window.wp.i18n},9033:(e,o,a)=>{var t=a(4997),l=a(7723),n=a(684),r=a(6087),i=a(4715),s=a(6427),d=a(790);const c=({attributes:e,setAttributes:o})=>{const a=e=>a=>{o({[e]:a})},t=((0,l.__)("Solid","wedocs"),(0,l.__)("Dashed","wedocs"),(0,l.__)("Dotted","wedocs"),(0,l.__)("None","wedocs"),[{name:"Sweet",color:"#F43F5E"},{name:"Orange",color:"#F97316"},{name:"Yellow",color:"#FACC15"},{name:"Purple",color:"#8B5CF6"},{name:"Light Blue",color:"#3B82F6"},{name:"Light Green",color:"#10B981"}]);return(0,d.jsxs)(d.Fragment,{children:[(0,d.jsxs)(s.PanelBody,{title:(0,l.__)("Grid Styles","wedocs"),icon:"admin-appearance",initialOpen:!1,children:[(0,d.jsx)("label",{children:(0,l.__)("Colors","wedocs")}),(0,d.jsx)(i.PanelColorSettings,{colors:t,colorSettings:[{value:e.docTitleColor,label:(0,l.__)("Doc Title Color","wedocs"),onChange:e=>a("docTitleColor")(e)},{value:e.docChildrenActiveColor,label:(0,l.__)("Doc Children Active Color","wedocs"),onChange:e=>a("docChildrenActiveColor")(e)},{value:e.borderColor,label:(0,l.__)("Border Color","wedocs"),onChange:e=>a("borderColor")(e)}]}),(0,d.jsx)(s.__experimentalBoxControl,{label:(0,l.__)("Grid Padding","wedocs"),values:e.gridPadding,onChange:a("gridPadding")}),(0,d.jsx)(s.__experimentalBoxControl,{label:(0,l.__)("Grid Margin","wedocs"),values:e.gridMargin,onChange:a("gridMargin")}),(0,d.jsx)(s.SelectControl,{label:(0,l.__)("Border Type","wedocs"),value:e.borderType,options:[{label:(0,l.__)("Solid","wedocs"),value:"solid"},{label:(0,l.__)("Dashed","wedocs"),value:"dashed"},{label:(0,l.__)("Dotted","wedocs"),value:"dotted"},{label:(0,l.__)("None","wedocs"),value:"none"}],onChange:e=>o({borderType:e})}),(0,d.jsx)(s.SelectControl,{label:(0,l.__)("Border Width","wedocs"),value:e.borderWidth,options:[{label:"0px",value:"0px"},{label:"1px",value:"1px"},{label:"2px",value:"2px"},{label:"3px",value:"3px"},{label:"4px",value:"4px"},{label:"5px",value:"5px"}],onChange:e=>o({borderWidth:e})}),(0,d.jsx)(s.SelectControl,{label:(0,l.__)("Border Radius","wedocs"),value:e.borderRadius,options:[{label:"0px",value:"0px"},{label:"4px",value:"4px"},{label:"8px",value:"8px"},{label:"12px",value:"12px"},{label:"16px",value:"16px"},{label:"20px",value:"20px"}],onChange:e=>o({borderRadius:e})})]}),(0,d.jsxs)(s.PanelBody,{title:(0,l.__)("Button Styles","wedocs"),icon:"admin-appearance",initialOpen:!1,children:[(0,d.jsx)("label",{children:(0,l.__)("Button Colors","wedocs")}),(0,d.jsx)(i.PanelColorSettings,{colors:t,colorSettings:[{value:e.buttonColor,label:(0,l.__)("Button Color","wedocs"),onChange:e=>a("buttonColor")(e)},{value:e.buttonHoverColor,label:(0,l.__)("Button Hover Color","wedocs"),onChange:e=>a("buttonHoverColor")(e)},{value:e.buttonTextColor,label:(0,l.__)("Button Text Color","wedocs"),onChange:e=>a("buttonTextColor")(e)},{value:e.buttonHoverTextColor,label:(0,l.__)("Button Hover Text Color","wedocs"),onChange:e=>a("buttonHoverTextColor")(e)}]}),(0,d.jsx)(s.__experimentalBoxControl,{label:(0,l.__)("Button Padding","wedocs"),values:e.buttonPadding,onChange:a("buttonPadding")}),(0,d.jsx)(s.__experimentalBoxControl,{label:(0,l.__)("Button Margin","wedocs"),values:e.buttonMargin,onChange:a("buttonMargin")}),(0,d.jsx)(s.SelectControl,{label:(0,l.__)("Button Border Radius","wedocs"),value:e.buttonBorderRadius,options:[{label:"0px",value:"0px"},{label:"4px",value:"4px"},{label:"8px",value:"8px"},{label:"12px",value:"12px"},{label:"16px",value:"16px"},{label:"20px",value:"20px"}],onChange:e=>o({buttonBorderRadius:e})}),(0,d.jsxs)("div",{className:"wedocs-color-control",children:[(0,d.jsx)("label",{children:(0,l.__)("Button Text","wedocs")}),(0,d.jsx)(s.TextControl,{value:e.buttonText,onChange:a("buttonText")})]})]})]})},p=JSON.parse('{"UU":"wedocs/wedocs-docs-grid"}');(0,t.registerBlockType)(p.UU,{edit:({attributes:e,setAttributes:o})=>{const a=(0,i.useBlockProps)(),{useSelect:t}=wp.data,[p,h]=(0,r.useState)(1),[g,u]=(0,r.useState)(!1),{hideDocGrid:b,docStyle:x,docsPerPage:m,excludeDocs:_,order:v,orderBy:C,sectionsPerDoc:w,articlesPerSection:y,showDocArticle:f,keepArticlesCollapsed:j,showViewDetails:S,gridPadding:B,gridMargin:T,docTitleColor:k,docChildrenActiveColor:P,borderType:$,borderRadius:F,borderWidth:M,borderColor:R,buttonBorderRadius:D,buttonPadding:H,buttonMargin:W,buttonColor:O,buttonHoverColor:N,buttonTextColor:z,buttonText:L,buttonHoverTextColor:A}=e,U=(e,o)=>e.sections?(0,d.jsxs)("div",{className:"wedocs-docs-grid__sections "+(j?"is-collapsed":""),children:[e.sections.map(e=>(0,d.jsxs)("div",{className:"wedocs-docs-grid__section",children:[(0,d.jsxs)("h4",{className:"wedocs-docs-grid__section-title",style:{...o.title,display:"flex",justifyContent:"space-between",alignItems:"center"},children:[(0,d.jsx)("span",{children:e.title.rendered}),f&&e.articles&&e.articles.length>0&&(0,d.jsx)("svg",{fill:"none",viewBox:"0 0 24 24",width:"16",strokeWidth:"2",stroke:"#acb8c4",className:j?"":"active",children:(0,d.jsx)("path",{strokeLinecap:"round",strokeLinejoin:"round",d:"M19.5 8.25l-7.5 7.5-7.5-7.5"})})]}),f&&!j&&e.articles&&(0,d.jsx)("ul",{className:"wedocs-docs-grid__articles",children:e.articles.map(e=>(0,d.jsx)("li",{className:"wedocs-docs-grid__article",style:o.children,children:e.title.rendered},e.id))})]},e.id)),0===e.sections.length&&(0,d.jsxs)("span",{className:"inside",children:[(0,d.jsx)("svg",{fill:"none",viewBox:"0 0 24 24","stroke-width":"1.5",stroke:"currentColor",children:(0,d.jsx)("path",{"stroke-linecap":"round","stroke-linejoin":"round",d:"M11.25 11.25l.041-.02a.75.75 0 011.063.852l-.708 2.836a.75.75 0 001.063.853l.041-.021M21 12a9 9 0 11-18 0 9 9 0 0118 0zm-9-3.75h.008v.008H12V8.25z"})}),(0,l.__)("This document has no sections yet. Check back later or wait for the author to add content.","wedocs")]})]}):null,V=[{label:"All",value:"all"},...Array.from({length:10},(e,o)=>({label:String(o+1),value:String(o+1)}))],I=[{label:(0,l.__)("weDocs Order","wedocs"),value:"menu_order"},{label:(0,l.__)("ID","wedocs"),value:"id"},{label:(0,l.__)("Name","wedocs"),value:"title"}],G=[{label:(0,l.__)("Ascending","wedocs"),value:"asc"},{label:(0,l.__)("Descending","wedocs"),value:"desc"}],E=[{label:"All",value:"all"},...Array.from({length:10},(e,o)=>({label:String(o+1),value:String(o+1)}))],{pages:q,sections:J,articles:Y}=t(e=>{const{getEntityRecords:o}=e("core"),a=o("postType","docs",{status:"publish",per_page:-1,parent:0,orderby:C,order:v}),t=a?o("postType","docs",{status:"publish",parent_in:a.map(e=>e.id),per_page:-1}):null,l=t?o("postType","docs",{status:"publish",parent_in:t.map(e=>e.id),per_page:-1}):null;return{pages:a,sections:t,articles:l}},[C,v]),Z=(e=>{if("all"===m)return e;const o=parseInt(m),a=(p-1)*o,t=a+o;return e.slice(a,t)})((()=>{if(!q||!J||!Y)return[];let e=[...q];return _&&_.length>0&&(e=e.filter(e=>!_.includes(e.id.toString()))),e=e.map(e=>{let o=J.filter(o=>o.parent===e.id);"all"!==w&&(o=o.slice(0,parseInt(w))),o=o.map(e=>{let o=Y.filter(o=>o.parent===e.id);return"all"!==y&&(o=o.slice(0,parseInt(y))),{...e,articles:o}});const a=o.reduce((e,o)=>e+o.articles.length,0);return{...e,sections:o,articleCount:a}}),e})()),K=q?q.reduce((e,o)=>(e[o.id]=o.title.rendered,e),{}):{},X=(q&&q.map(e=>({value:e.id.toString(),label:e.title.rendered})),e=>a=>{o({[e]:a})}),Q=_?_.map(e=>K[e]||e):[];return(0,d.jsxs)(r.Fragment,{children:[(0,d.jsx)(i.InspectorControls,{children:(0,d.jsxs)(s.PanelBody,{title:(0,l.__)("Doc Grid Settings","wedocs"),icon:n.A,initialOpen:!1,children:[(0,d.jsx)(s.SelectControl,{value:x,options:[{label:"1x1",value:"1x1"},{label:"1x2",value:"1x2"}],label:(0,l.__)("DOCS GRID COLUMN STYLE","wedocs"),onChange:X("docStyle")}),(0,d.jsx)(s.SelectControl,{value:m,options:V,label:(0,l.__)("Docs per page","wedocs"),onChange:X("docsPerPage")}),(0,d.jsx)(s.FormTokenField,{value:Q,suggestions:Object.values(K),label:(0,l.__)("Exclude Docs","wedocs"),onChange:e=>{const a=e.map(e=>{const o=Object.entries(K).find(([o,a])=>a===e);return o?o[0]:e});o({excludeDocs:a})}}),(0,d.jsx)(s.SelectControl,{value:v,options:G,label:(0,l.__)("Order","wedocs"),onChange:X("order")}),(0,d.jsx)(s.SelectControl,{value:C,options:I,label:(0,l.__)("Order by","wedocs"),onChange:X("orderBy")}),(0,d.jsx)(s.SelectControl,{value:w,options:E,label:(0,l.__)("Sections per doc","wedocs"),onChange:X("sectionsPerDoc")}),(0,d.jsx)(s.SelectControl,{value:y,options:E,label:(0,l.__)("Articles per section","wedocs"),onChange:X("articlesPerSection")}),(0,d.jsx)(s.PanelRow,{children:(0,d.jsx)(s.ToggleControl,{checked:f,label:(0,l.__)("Show Doc Article","wedocs"),onChange:X("showDocArticle")})}),(0,d.jsx)(s.PanelRow,{children:(0,d.jsx)(s.ToggleControl,{checked:j,label:(0,l.__)("Keep Article Collapsed","wedocs"),onChange:X("keepArticlesCollapsed")})}),(0,d.jsx)(s.PanelRow,{children:(0,d.jsx)(s.ToggleControl,{checked:S,label:(0,l.__)("Show View Details Button","wedocs"),onChange:X("showViewDetails")})})]})}),(0,d.jsx)(i.InspectorControls,{children:(0,d.jsx)(c,{attributes:e,setAttributes:o})}),(0,d.jsx)("div",{...a,children:b?(0,d.jsx)("div",{className:"backdrop"}):(0,d.jsx)("div",{className:"wedocs-block-wrapper",children:(0,d.jsx)("div",{className:`wedocs-docs-grid wedocs-docs-grid--${x}`,children:g?(0,d.jsx)(Spinner,{}):Z.map(e=>((e,o)=>(0,d.jsxs)("div",{className:"wedocs-docs-grid__item",style:o.item,children:[(0,d.jsx)("h3",{className:"wedocs-docs-grid__title",style:o.title,children:e.title.rendered}),U(e,o),S&&(0,d.jsx)("div",{className:"wedocs-docs-grid__details",children:(0,d.jsx)("span",{className:"wedocs-docs-grid__details-link",style:o.button,children:o.button.text})})]},e.id))(e,(()=>{const e=B?`${B.top} ${B.right} ${B.bottom} ${B.left}`:"",o=T?`${T.top} ${T.right} ${T.bottom} ${T.left}`:"",a=H?`${H.top} ${H.right} ${H.bottom} ${H.left}`:"",t=D||"8px",n=W?`${W.top} ${W.right} ${W.bottom} ${W.left}`:"";return{item:{padding:e,margin:o,borderStyle:$||"solid",borderWidth:M||"1px",borderColor:R||"rgba(0, 0, 0, 0.1)",borderRadius:F||"8px",backgroundColor:"#fff"},title:{color:k||"#1e1e1e"},children:{color:P||"#0073aa"},button:{padding:a,margin:n,backgroundColor:O||"#0073aa",color:z||"#ffffff",text:L||(0,l.__)("View Details","wedocs"),borderRadius:t||"8px","--hover-bg":N||"#005177","--hover-color":A||"#ffffff"}}})()))})})})]})},save:()=>null})}},a={};function t(e){var l=a[e];if(void 0!==l)return l.exports;var n=a[e]={exports:{}};return o[e](n,n.exports,t),n.exports}t.m=o,e=[],t.O=(o,a,l,n)=>{if(!a){var r=1/0;for(c=0;c<e.length;c++){for(var[a,l,n]=e[c],i=!0,s=0;s<a.length;s++)(!1&n||r>=n)&&Object.keys(t.O).every(e=>t.O[e](a[s]))?a.splice(s--,1):(i=!1,n<r&&(r=n));if(i){e.splice(c--,1);var d=l();void 0!==d&&(o=d)}}return o}n=n||0;for(var c=e.length;c>0&&e[c-1][2]>n;c--)e[c]=e[c-1];e[c]=[a,l,n]},t.n=e=>{var o=e&&e.__esModule?()=>e.default:()=>e;return t.d(o,{a:o}),o},t.d=(e,o)=>{for(var a in o)t.o(o,a)&&!t.o(e,a)&&Object.defineProperty(e,a,{enumerable:!0,get:o[a]})},t.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),t.o=(e,o)=>Object.prototype.hasOwnProperty.call(e,o),(()=>{var e;t.g.importScripts&&(e=t.g.location+"");var o=t.g.document;if(!e&&o&&(o.currentScript&&"SCRIPT"===o.currentScript.tagName.toUpperCase()&&(e=o.currentScript.src),!e)){var a=o.getElementsByTagName("script");if(a.length)for(var l=a.length-1;l>-1&&(!e||!/^http(s?):/.test(e));)e=a[l--].src}if(!e)throw new Error("Automatic publicPath is not supported in this browser");e=e.replace(/^blob:/,"").replace(/#.*$/,"").replace(/\?.*$/,"").replace(/\/[^\/]+$/,"/"),t.p=e})(),(()=>{var e={4:0,204:0,366:0,687:0,484:0,631:0,380:0,337:0};t.O.j=o=>0===e[o];var o=(o,a)=>{var l,n,[r,i,s]=a,d=0;if(r.some(o=>0!==e[o])){for(l in i)t.o(i,l)&&(t.m[l]=i[l]);if(s)var c=s(t)}for(o&&o(a);d<r.length;d++)n=r[d],t.o(e,n)&&e[n]&&e[n][0](),e[n]=0;return t.O(c)},a=globalThis.webpackChunkweDocs=globalThis.webpackChunkweDocs||[];a.forEach(o.bind(null,0)),a.push=o.bind(null,a.push.bind(a))})();var l=t.O(void 0,[484,631,380,337],()=>t(7450));l=t.O(l)})(); 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
TOC link color custom property likely misbound.
The bundle sets {"--list-item-sytle": containerBackgroundColor}. That appears intended for listColor. Please adjust in the source (e.g., src/blocks/TableOfContents/edit.js) and fix the property name typo across CSS/JS.
I need to verify the source code to confirm the issue. Let me search for the TableOfContents block implementation.
[/run_scripts]
[/run_scripts]
[/run_scripts]
🏁 Script executed:
#!/bin/bash
# Find TableOfContents block source files
fd -type f -name "*.js" -path "*TableOfContents*" | head -20
fd -type f -name "*.jsx" -path "*table-of-contents*" -o -path "*toc*" | grep -v node_modules | head -20Length of output: 341
🏁 Script executed:
#!/bin/bash
# Search for the specific CSS custom property in source files
rg -n "list-item" --type=js --type=jsx -B2 -A2 | head -50
rg -n "containerBackgroundColor" --type=js --type=jsx -B3 -A3 | grep -i "style\|toc\|list" | head -50Length of output: 55
🏁 Script executed:
#!/bin/bash
# Look for TOC block edit file and check the style object
find . -type f \( -name "*edit.js" -o -name "*edit.jsx" \) | xargs grep -l "toc\|table-of-contents" -i 2>/dev/nullLength of output: 36
Now let me examine the source file to verify the CSS custom property binding:
[/run_scripts]
[/run_scripts]
🏁 Script executed:
#!/bin/bash
# View the TableOfContents edit.js file
cat ./src/blocks/TableOfContents/edit.jsLength of output: 6113
🏁 Script executed:
#!/bin/bash
# Search for the style object and CSS custom properties in edit.js
grep -n "\-\-list\|containerBackgroundColor\|listColor" ./src/blocks/TableOfContents/edit.js -A2 -B2Length of output: 695
Fix CSS custom property binding and typo in TableOfContents block.
Line 154 in src/blocks/TableOfContents/edit.js contains two errors:
- Property name typo:
--list-item-sytleshould be--list-item-style - Wrong variable: should bind
listColor(used for list text, line 184) instead ofcontainerBackgroundColor(container background)
Change:
"--list-item-sytle": containerBackgroundColor,
to:
"--list-item-style": listColor,
🧰 Tools
🪛 Biome (2.1.2)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: Shouldn't redeclare 'a'. Consider to delete it or rename it.
'a' is defined here:
(lint/suspicious/noRedeclare)
[error] 1-1: Shouldn't redeclare 'l'. Consider to delete it or rename it.
'l' is defined here:
(lint/suspicious/noRedeclare)
[error] 1-1: Shouldn't redeclare 'n'. Consider to delete it or rename it.
'n' is defined here:
(lint/suspicious/noRedeclare)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
[error] 1-1: This variable is used before its declaration.
The variable is declared here:
(lint/correctness/noInvalidUseBeforeDeclaration)
🤖 Prompt for AI Agents
In assets/build/block.js around lines 1 to 1, the inline style object for the
TableOfContents block uses a misspelled CSS custom property and binds the wrong
variable; change the entry that currently sets "--list-item-sytle" to instead
set "--list-item-style" and bind it to the list color variable used elsewhere
(replace the container background variable with the listColor variable).
| "borderAndShadowControls": { | ||
| "type": "object", | ||
| "default": { | ||
| "desktop": { | ||
| "borderStyle": "solid", | ||
| "borderWidth": { | ||
| "top": "1px", | ||
| "right": "1px", | ||
| "bottom": "1px", | ||
| "left": "1px" | ||
| }, | ||
| "borderColor": "#dddddd", | ||
| "borderRadius": { | ||
| "topLeft": "4px", | ||
| "topRight": "4px", | ||
| "bottomLeft": "4px", | ||
| "bottomRight": "4px" | ||
| }, | ||
| "boxShadow": { | ||
| "enabled": false, | ||
| "horizontal": "0px", | ||
| "vertical": "2px", | ||
| "blur": "4px", | ||
| "spread": "0px", | ||
| "color": "rgba(0,0,0,0.1)" | ||
| } | ||
| }, |
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.
Box shadow schema doesn’t match renderer expectations
Defaults use "horizontal"/"vertical", but the renderer in AdvanceContributors expects "x"/"y", so shadows will never render.
Either:
- Change defaults to x/y, or
- Update the renderer to read "horizontal"/"vertical".
If you keep schema as-is, align the PHP at Box Shadow handling. See related comment in render.php.
| case 'main_author': | ||
| $author_id = get_post_field('post_author', $post->ID); | ||
| if ($author_id) { | ||
| $author_user = get_userdata($author_id); | ||
| if ($author_user) { | ||
| $contributors[] = $author_user; | ||
| } | ||
| } | ||
| break; |
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.
$post may be null; unsafe property access
Accessing $post->ID without verifying $post will fatal on non-singular contexts or previews.
Guard before use:
- case 'main_author':
- $author_id = get_post_field('post_author', $post->ID);
+ case 'main_author':
+ if ( ! $post ) { break; }
+ $author_id = get_post_field('post_author', $post->ID);Repeat this pattern wherever $post->ID is used.
📝 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.
| case 'main_author': | |
| $author_id = get_post_field('post_author', $post->ID); | |
| if ($author_id) { | |
| $author_user = get_userdata($author_id); | |
| if ($author_user) { | |
| $contributors[] = $author_user; | |
| } | |
| } | |
| break; | |
| case 'main_author': | |
| if ( ! $post ) { break; } | |
| $author_id = get_post_field('post_author', $post->ID); | |
| if ($author_id) { | |
| $author_user = get_userdata($author_id); | |
| if ($author_user) { | |
| $contributors[] = $author_user; | |
| } | |
| } | |
| break; |
🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/render.php around lines 49 to 57, the
code accesses $post->ID without ensuring $post is non-null which will fatal in
non-singular contexts; update the case 'main_author' to first check that $post
is an object (e.g. if (!$post || !isset($post->ID)) return/continue or wrap the
block in if ($post && isset($post->ID)) { ... }), then retrieve post_author and
proceed as before; apply the same null-guard pattern to every other location in
this file that accesses $post->ID.
| // Box Shadow | ||
| if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['x'])) { | ||
| $shadow = $controls['boxShadow']; | ||
| $shadow_value = ''; | ||
| if (isset($shadow['inset']) && $shadow['inset']) { | ||
| $shadow_value .= 'inset '; | ||
| } | ||
| $shadow_value .= esc_attr($shadow['x']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['y']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['blur']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['spread']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['color']); | ||
| $rules[] = 'box-shadow: ' . $shadow_value; | ||
| } |
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.
Box shadow keys mismatch (“x/y” vs “horizontal/vertical”)
This check requires ['x'] but block attributes provide ['horizontal'] and ['vertical']; shadow never applies.
Update to:
- if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['x'])) {
+ if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['horizontal'])) {
$shadow = $controls['boxShadow'];
$shadow_value = '';
if (isset($shadow['inset']) && $shadow['inset']) {
$shadow_value .= 'inset ';
}
- $shadow_value .= esc_attr($shadow['x']) . ' ';
- $shadow_value .= esc_attr($shadow['y']) . ' ';
+ $shadow_value .= esc_attr($shadow['horizontal']) . ' ';
+ $shadow_value .= esc_attr($shadow['vertical']) . ' ';📝 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.
| // Box Shadow | |
| if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['x'])) { | |
| $shadow = $controls['boxShadow']; | |
| $shadow_value = ''; | |
| if (isset($shadow['inset']) && $shadow['inset']) { | |
| $shadow_value .= 'inset '; | |
| } | |
| $shadow_value .= esc_attr($shadow['x']) . ' '; | |
| $shadow_value .= esc_attr($shadow['y']) . ' '; | |
| $shadow_value .= esc_attr($shadow['blur']) . ' '; | |
| $shadow_value .= esc_attr($shadow['spread']) . ' '; | |
| $shadow_value .= esc_attr($shadow['color']); | |
| $rules[] = 'box-shadow: ' . $shadow_value; | |
| } | |
| // Box Shadow | |
| if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['horizontal'])) { | |
| $shadow = $controls['boxShadow']; | |
| $shadow_value = ''; | |
| if (isset($shadow['inset']) && $shadow['inset']) { | |
| $shadow_value .= 'inset '; | |
| } | |
| $shadow_value .= esc_attr($shadow['horizontal']) . ' '; | |
| $shadow_value .= esc_attr($shadow['vertical']) . ' '; | |
| $shadow_value .= esc_attr($shadow['blur']) . ' '; | |
| $shadow_value .= esc_attr($shadow['spread']) . ' '; | |
| $shadow_value .= esc_attr($shadow['color']); | |
| $rules[] = 'box-shadow: ' . $shadow_value; | |
| } |
🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/render.php around lines 229 to 242,
the box-shadow branch checks for shadow['x'] and shadow['y'] but the block
attributes provide horizontal/vertical keys, so the shadow never applies; update
the guard to check for horizontal/vertical (with fallbacks to x/y for backward
compatibility), read horizontal and vertical into local variables, then build
the shadow string using those values (preserving inset, blur, spread, color and
esc_attr usage) and only add the rule if horizontal/vertical (or their
fallbacks) are present.
| // Handle display controls for hiding on devices | ||
| $display_classes = []; | ||
| if (isset($display_controls['desktop']) && $display_controls['desktop']) { | ||
| $display_classes[] = 'wedocs-hide-desktop'; | ||
| } | ||
| if (isset($display_controls['tablet']) && $display_controls['tablet']) { | ||
| $display_classes[] = 'wedocs-hide-tablet'; | ||
| } | ||
| if (isset($display_controls['mobile']) && $display_controls['mobile']) { | ||
| $display_classes[] = 'wedocs-hide-mobile'; | ||
| } | ||
| $css_classes = array_merge($css_classes, $display_classes); | ||
|
|
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.
Hide-class logic inverted; always hides on all devices
You append wedocs-hide-{device} when the device key exists (it always does), so the block is hidden across breakpoints.
Only add hide-class when display is explicitly 'none':
- if (isset($display_controls['desktop']) && $display_controls['desktop']) {
+ if (isset($display_controls['desktop']['display']) && $display_controls['desktop']['display'] === 'none') {
$display_classes[] = 'wedocs-hide-desktop';
}
- if (isset($display_controls['tablet']) && $display_controls['tablet']) {
+ if (isset($display_controls['tablet']['display']) && $display_controls['tablet']['display'] === 'none') {
$display_classes[] = 'wedocs-hide-tablet';
}
- if (isset($display_controls['mobile']) && $display_controls['mobile']) {
+ if (isset($display_controls['mobile']['display']) && $display_controls['mobile']['display'] === 'none') {
$display_classes[] = 'wedocs-hide-mobile';
}🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/render.php around lines 333 to 345,
the current logic adds wedocs-hide-{device} whenever the device key exists
(which is always true), causing the block to be hidden on all devices; change
the checks so you only append the hide class when the display control for that
device is explicitly 'none' (e.g. isset($display_controls['desktop']) &&
$display_controls['desktop'] === 'none'), repeat for tablet and mobile, then
merge those classes into $css_classes as before.
| <Button | ||
| __next40pxDefaultSize | ||
| variant="secondary" | ||
| isDestructive | ||
| text={__('Reset All', 'block-responsive')} | ||
| style={{ | ||
| width: '100%', | ||
| justifyContent: 'center', | ||
| marginTop: '16px', | ||
| }} | ||
| onClick={() => { | ||
| setAttributes({ | ||
| colorsControls: { | ||
| ...colorsControls, | ||
| [device]: { | ||
| ...currentColors, | ||
| textColor: undefined, | ||
| backgroundColor: undefined, | ||
| linkColor: undefined, | ||
| linkHoverColor: undefined, | ||
| }, | ||
| }, | ||
| }); | ||
| }} | ||
| /> | ||
| </> |
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 children for Button label (avoid Button.text for compatibility).
Some versions of @wordpress/components don’t support the “text” prop on Button. Safer to pass children.
- <Button
+ <Button
__next40pxDefaultSize
variant="secondary"
isDestructive
- text={__('Reset All', 'block-responsive')}
style={{
width: '100%',
justifyContent: 'center',
marginTop: '16px',
}}
onClick={() => {
setAttributes({
colorsControls: {
...colorsControls,
[device]: {
...currentColors,
textColor: undefined,
backgroundColor: undefined,
linkColor: undefined,
linkHoverColor: undefined,
},
},
});
}}
/>
+ >
+ { __('Reset All', 'wedocs') }
+ </Button>📝 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.
| <Button | |
| __next40pxDefaultSize | |
| variant="secondary" | |
| isDestructive | |
| text={__('Reset All', 'block-responsive')} | |
| style={{ | |
| width: '100%', | |
| justifyContent: 'center', | |
| marginTop: '16px', | |
| }} | |
| onClick={() => { | |
| setAttributes({ | |
| colorsControls: { | |
| ...colorsControls, | |
| [device]: { | |
| ...currentColors, | |
| textColor: undefined, | |
| backgroundColor: undefined, | |
| linkColor: undefined, | |
| linkHoverColor: undefined, | |
| }, | |
| }, | |
| }); | |
| }} | |
| /> | |
| </> | |
| <Button | |
| __next40pxDefaultSize | |
| variant="secondary" | |
| isDestructive | |
| style={{ | |
| width: '100%', | |
| justifyContent: 'center', | |
| marginTop: '16px', | |
| }} | |
| onClick={() => { | |
| setAttributes({ | |
| colorsControls: { | |
| ...colorsControls, | |
| [device]: { | |
| ...currentColors, | |
| textColor: undefined, | |
| backgroundColor: undefined, | |
| linkColor: undefined, | |
| linkHoverColor: undefined, | |
| }, | |
| }, | |
| }); | |
| }} | |
| > | |
| {__('Reset All', 'block-responsive')} | |
| </Button> |
🤖 Prompt for AI Agents
In src/blocks/TableOfContents/ColorsControls.js around lines 322 to 347, the
Button currently uses the text prop which some @wordpress/components versions
don't support; replace the text prop with a child node: remove text={__('Reset
All', 'block-responsive')} and instead place the __('Reset All',
'block-responsive') string as the Button's child content (keeping all other
props and the onClick handler unchanged) so the label is passed via children for
maximum compatibility.
|
|
||
|
|
||
|
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.
Empty file with meaningless whitespace; implement like AdvanceContributors or remove entirely.
This file contains only whitespace but no actual code. For server-rendered blocks, you should either:
- Implement it like
src/blocks/AdvanceContributors/save.js(returning null with proper imports) - Remove the file entirely if not needed
The current whitespace-only content serves no purpose and creates inconsistency.
Apply this diff to implement the proper pattern:
-
-
-
+import { useBlockProps } from '@wordpress/block-editor';
+
+const Save = () => {
+ const blockProps = useBlockProps.save();
+
+ // Since this is a dynamic block that uses PHP rendering,
+ // we return null to let the server-side render function handle the output
+ return null;
+};
+
+export default Save;📝 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.
| import { useBlockProps } from '@wordpress/block-editor'; | |
| const Save = () => { | |
| const blockProps = useBlockProps.save(); | |
| // Since this is a dynamic block that uses PHP rendering, | |
| // we return null to let the server-side render function handle the output | |
| return null; | |
| }; | |
| export default Save; |
🤖 Prompt for AI Agents
In src/blocks/TableOfContents/save.js lines 1-3: the file currently contains
only whitespace; either remove the file or implement the server-rendered block
pattern used by src/blocks/AdvanceContributors/save.js — create a save.js that
imports React (if your linting requires it) and exports a default Save component
that returns null (i.e., server-rendered no-client-save), matching the project's
style and export conventions; ensure any required ESLint or module headers are
present.
| a { | ||
| text-decoration: none; | ||
| color: var(--list-item-sytle, inherit); | ||
| display: inline-block; |
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
Fix CSS custom property typo
--list-item-sytle is misspelled; it prevents the custom color from working.
Apply:
- color: var(--list-item-sytle, inherit);
+ color: var(--list-item-style, inherit);Run to find all occurrences and ensure consistency:
🏁 Script executed:
#!/bin/bash
rg -n --type=css --type=scss --type=js --type=php --no-ignore -S '\-\-list-item-sy?tle'Length of output: 28
🏁 Script executed:
#!/bin/bash
# Search for the misspelled custom property across all file types
# Using rg without the problematic type specification
rg -n -S 'list-item-sy' --glob='*.scss' --glob='*.css' --glob='*.js' --glob='*.php'Length of output: 82389
🏁 Script executed:
#!/bin/bash
# Also check the specific file mentioned in the review
cat src/blocks/TableOfContents/style.scss | grep -n 'list-item'Length of output: 47
🏁 Script executed:
#!/bin/bash
# Search for both spellings to understand which is used
rg -n 'list-item-style' --glob='*.scss' --glob='*.css' --glob='*.js' --glob='*.php'Length of output: 0
Fix CSS custom property typo in two locations
The custom property --list-item-sytle is misspelled (should be --list-item-style), preventing the custom color from being applied.
Apply the fix in:
src/blocks/TableOfContents/style.scssline 55:
- color: var(--list-item-sytle, inherit);
+ color: var(--list-item-style, inherit);src/blocks/TableOfContents/edit.jsline 154:
- "--list-item-sytle": containerBackgroundColor,
+ "--list-item-style": containerBackgroundColor,📝 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.
| a { | |
| text-decoration: none; | |
| color: var(--list-item-sytle, inherit); | |
| display: inline-block; | |
| a { | |
| text-decoration: none; | |
| color: var(--list-item-style, inherit); | |
| display: inline-block; |
🤖 Prompt for AI Agents
In src/blocks/TableOfContents/style.scss around lines 53-56 and in
src/blocks/TableOfContents/edit.js at line 154, the CSS custom property name is
misspelled as --list-item-sytle; update both occurrences to --list-item-style so
the intended custom color is applied (search for the misspelled token and
replace it with the corrected property name in both files).
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: 20
Note
Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.
♻️ Duplicate comments (43)
src/blocks/components/TabSystem.js (3)
3-3: Remove unused Spacer import.The
__experimentalSpacer as Spacerimport is never used in this component.🔎 Proposed fix
-import { Button, ButtonGroup, __experimentalSpacer as Spacer } from '@wordpress/components'; +import { Button, ButtonGroup } from '@wordpress/components';
21-38: Add accessibility attributes for tab navigation.The tab navigation is missing essential ARIA attributes for screen reader support. The ButtonGroup should have
role="tablist", and each Button should haverole="tab",aria-selected, andaria-controlsattributes.🔎 Proposed fix
- <ButtonGroup> + <ButtonGroup role="tablist" aria-label={__('Block Settings Tabs', 'wedocs')}> {tabs.map(tab => ( <Button key={tab.key} variant={activeTab === tab.key ? 'primary' : 'secondary'} onClick={() => setActiveTab(tab.key)} + role="tab" + id={`wedocs-tab-${tab.key}`} + aria-selected={activeTab === tab.key} + aria-controls={`wedocs-tabpanel-${tab.key}`} style={{ marginRight: '4px', display: 'flex', alignItems: 'center', gap: '4px' }} >
43-55: Fix children handling, duplicate keys, and add accessibility attributes.Three critical issues:
- Runtime error:
children.mapwill break when a single child is passed (React children can be an object, not an array).- Duplicate keys: All children after the first get
key="style", causing React reconciliation issues.- Missing accessibility: Tab panels need
role="tabpanel",aria-labelledby, and correspondingidattributes.🔎 Proposed fix
First, import
Childrenfrom React:-import { useState } from '@wordpress/element'; +import { useState, Children } from '@wordpress/element';Then fix the content rendering:
{/* Tab Content */} <div className="tab-content"> - {children.map((child, index) => { - const tabKey = index === 0 ? 'setup' : 'style'; - return ( - <div - key={tabKey} - style={{ - display: activeTab === tabKey ? 'block' : 'none' - }} - > - {child} - </div> - ); - })} + {Children.toArray(children).map((child, index) => { + const tabKey = index === 0 ? 'setup' : 'style'; + return ( + <div + key={`${tabKey}-${index}`} + id={`wedocs-tabpanel-${tabKey}`} + role="tabpanel" + aria-labelledby={`wedocs-tab-${tabKey}`} + style={{ + display: activeTab === tabKey ? 'block' : 'none' + }} + > + {child} + </div> + ); + })} </div>src/blocks/TableOfContents/save.js (1)
1-3: The empty file issue from the previous review remains unresolved.As noted in the previous review, this file contains only whitespace and serves no purpose. For server-rendered blocks, you should either implement it properly (returning null with proper imports like
AdvanceContributors/save.js) or remove the file entirely.assets/build/style-block-rtl.css (1)
1-1: Fix duplicatewidthproperty in source CSS.A duplicate
widthproperty declaration exists in the selector.wedocs-search-input,.wedocs-editor-search-input. Since this is a build artifact, the issue should be resolved in the source CSS file before rebuilding.🧰 Tools
🪛 Biome (2.1.2)
[error] 1-1: Duplicate properties can lead to unexpected behavior and may override previous declarations unintentionally.
Remove or rename the duplicate property to ensure consistent styling.
(lint/suspicious/noDuplicateProperties)
assets/build/block.js (1)
1-1: Address CSS custom property issue in TableOfContents source.A previous review identified a typo and incorrect variable binding in the TableOfContents block source (
src/blocks/TableOfContents/edit.jsline 154). Since this is a build artifact, fix the source and rebuild.src/blocks/Contributors/edit-old.js (1)
151-161: Preview ignores configured date format settings.The date preview uses a hardcoded
toLocaleDateStringformat and ignores thedateFormatandcustomDateFormatattributes that users can configure. This creates a mismatch between editor preview and frontend output.Since PHP date format strings are specified in the help text, consider either:
- Using
@wordpress/dateutilities with format conversion- Rendering a placeholder indicating the format will apply on frontend
src/blocks/AdvanceContributors/edit-old.js (2)
51-65: Replacewp.apiFetchwith imported@wordpress/api-fetch.This was flagged in a previous review. For bundled code, import
apiFetchdirectly for better tree-shaking and explicit dependency management.
151-161: Date format preview ignores user settings.This was flagged in a previous review. The preview hardcodes
toLocaleDateStringand ignoresdateFormat/customDateFormatattributes.assets/build/blocks/DocsGrid/index.asset.php (1)
1-1: Existing critical issue with react-jsx-runtime dependency already flagged.The incompatibility between the
react-jsx-runtimedependency (requires WP 6.6+) and the plugin's minimum WordPress requirement (5.6+) has already been identified in a previous review comment. Please address that issue before merging.includes/Assets.php (1)
85-89: Critical: Style handle enqueued without registration (duplicate issue).The
wedocs-block-styleregistration remains commented out (lines 85-89), but the style is still enqueued at lines 129 and 155. This is the same critical issue flagged in the previous review and must be resolved.Apply one of the fixes from the previous review:
Option 1: Uncomment and fix the registration:
🔎 Restore registration
- // wp_register_style( - // 'wedocs-block-style', - // $assets_url . '/build/style-block.css', - // $block_dependencies['version'] - // ); + wp_register_style( + 'wedocs-block-style', + $assets_url . '/build/style-block.css', + array(), + $block_dependencies['version'] + );Option 2: Remove all enqueue calls:
🔎 Remove enqueue calls
- wp_enqueue_style( 'wedocs-block-style' );And in
admin_enqueue:public function admin_enqueue() { - wp_enqueue_style( 'wedocs-block-style' ); - // Enqueue admin script.Also applies to: 129-129, 155-155
src/blocks/TableOfContents/controls/ListItems.js (1)
7-16: Critical: Undefined variable reference (duplicate issue).The component uses
containerBackgroundColoron line 14 without defining it. This is the same critical issue from the previous review and will cause aReferenceErrorat runtime.Apply one of the fixes from the previous review:
Option 1: Destructure from attributes:
🔎 Destructure the variable
const ListItems = ({ attributes, setAttributes }) => { + const { containerBackgroundColor } = attributes; + return ( <PanelBody title={__('List Items', 'dynamic-table-of-contents-block-wp')} initialOpen={false}>Option 2: Access via attributes:
🔎 Use attributes.containerBackgroundColor
<div style={{ marginBottom: '20px' }}> <label>{__('Background Color', 'dynamic-table-of-contents-block-wp')}</label> <ColorPicker - color={containerBackgroundColor} + color={attributes.containerBackgroundColor} onChange={(value) => setAttributes({ containerBackgroundColor: value })} />assets/build/blocks/TableOfContents/style-index.css (1)
1-1: Accessibility issue: Loading message in CSS pseudo-element (previously flagged).As noted in the previous review, the
.toc-loading .toc-content:afterrule renders "Loading headings..." via a CSS pseudo-element, which is not accessible to screen readers. This loading message should be moved to the DOM withrole="status"oraria-live="polite"to ensure it's announced by assistive technologies.assets/build/blocks/TableOfContents/style-index-rtl.css (1)
1-1: Accessibility issue: Loading message in CSS pseudo-element (previously flagged in RTL variant).The same accessibility issue noted in the LTR version applies here: the loading message in
.toc-loading .toc-content:aftershould be moved to the DOM with appropriate ARIA attributes for screen reader support.assets/build/store.js (1)
1-1: Static analysis errors remain unaddressed.The unsafe optional chaining and switch clause issues flagged by static analysis are still present in this build artifact. These were previously identified in the source files (
src/data/docs/reducer.jsaround lines 84-85). The source must be fixed and the bundle rebuilt.src/blocks/TableOfContents/ColorsControls.js (3)
17-20: Undefined colorsControls will crash the component.The destructuring of
colorsControlswithout a default value and immediate access tocolorsControls[device]will throw a TypeError ifattributes.colorsControlsis undefined.
53-53: Incorrect text domain breaks translations.The text domain
'block-responsive'should be'wedocs'to match this plugin's translation infrastructure. This issue appears throughout the file at multiple locations.Also applies to: 68-68, 108-108, 122-122, 135-135, 158-158, 174-174, 229-229, 243-243, 257-257, 280-280, 293-293, 326-326
322-347: Button.text prop may not be supported in all versions.Using the
textprop on Button can cause compatibility issues with some versions of@wordpress/components. The label should be passed as children instead.src/blocks/commonControls/TypographyControls.js (1)
28-30: Undefined typographyControls will crash the component.Destructuring without a default and accessing
typographyControls[device]will throw ifattributes.typographyControlsis undefined.src/blocks/commonControls/AlignmentControls.js (2)
26-28: Guard against undefinedalignmentControlsto avoid runtime errors
attributes.alignmentControlsmay be undefined; accessingalignmentControls[device]will throw. This was flagged in a previous review.🔎 Proposed fix
const AlignmentControls = ({ attributes, setAttributes, device }) => { - const { alignmentControls } = attributes; - const currentAlignment = alignmentControls[device] || {}; + const { alignmentControls = {} } = attributes; + const currentAlignment = alignmentControls[device] || {};
161-165: Invalid CSS value foralignItems: "space-between" is not valid
align-itemsdoes not acceptspace-between; that's ajustify-contentvalue. This will produce invalid CSS. This was flagged in a previous review.🔎 Proposed fix
<ToggleGroupControlOptionIcon - value="space-between" - label={__('Space between', 'wedocs')} + value="stretch" + label={__('Stretch', 'wedocs')} icon={justifyStretchVertical} />assets/build/blocks/DocsGrid/render.php (1)
74-82: Guard against non-array padding/margin inputsIf
$grid_paddingis not an array, accessing['top']etc. will emit "Illegal string offset" notices. This was flagged in a previous review.🔎 Proposed fix
- if ($grid_padding) { + if ( is_array( $grid_padding ) ) { $padding_style = sprintf( 'padding: %s %s %s %s;', esc_attr($grid_padding['top'] ?? '1.5rem'),Apply the same pattern to
$grid_margin,$button_padding, and$button_marginchecks.src/blocks/commonControls/DisplayControls.js (2)
50-57: Guard against undefineddisplayControlsIf
attributes.displayControlsis undefined, line 53-54 and line 61 will throw runtime errors. This was flagged in a previous review.🔎 Proposed fix
const toggleDeviceVisibility = (deviceKey) => { + const current = attributes.displayControls || {}; setAttributes({ displayControls: { - ...attributes.displayControls, - [deviceKey]: !attributes.displayControls[deviceKey], + ...current, + [deviceKey]: !current[deviceKey], }, }); }; // Render individual device control card const renderDeviceCard = ({ key, icon, label }) => { - const isHidden = attributes.displayControls[key]; + const isHidden = attributes.displayControls?.[key];Also applies to: 61-61
76-80: Addaria-labelfor accessibilityThe toggle button displays only an icon, making it inaccessible to screen reader users. This was flagged in a previous review.
🔎 Proposed fix
<Button __next40pxDefaultSize onClick={() => toggleDeviceVisibility(key)} icon={isHidden ? unseen : seen} + aria-label={ + isHidden + ? __('Show on', 'wedocs') + ' ' + key + : __('Hide on', 'wedocs') + ' ' + key + } />src/blocks/Contributors/render.php (5)
100-106: Wrong API for retrieving contributors - usesget_post_fieldinstead of post meta
get_post_field('wedocs_contributors', ...)reads a posts table column, not post meta. Formain_authorcase, this should usepost_authorfield. This was flagged in a previous review.🔎 Proposed fix
case 'main_author': - $author_id = get_post_field('wedocs_contributors', $post->ID); + if ( ! $post ) { break; } + $author_id = get_post_field('post_author', $post->ID); if ($author_id) { $contributors[] = get_userdata($author_id); } break;
120-131: Invalid contributor retrieval in 'all' case
get_post_field('wedocs_contributors', ...)returns a string column, not post meta. Callingarray_values()on it produces an array of characters, causing incorrect behavior. This was flagged in a previous review.🔎 Proposed fix
case 'all': default: // Get all contributors who have edited the post - $author_id = get_post_field('wedocs_contributors', $post->ID); - $authors = array_values($author_id); // return auhtors id. - foreach($authors as $author){ - $contributors[]= get_userdata($author); - } - - - if ($author_id && ($author_user = get_userdata($author_id))) { - $contributors[] = $author_user; - } + // Include post author first + $post_author_id = $post ? (int) get_post_field('post_author', $post->ID) : 0; + if ( $post_author_id && ($author_user = get_userdata($post_author_id)) ) { + $contributors[] = $author_user; + } + + // Get contributors from post meta + $author_ids = (array) get_post_meta($post->ID, 'wedocs_contributors', true); + foreach ( $author_ids as $uid ) { + if ( $user = get_userdata( (int) $uid ) ) { + $contributors[] = $user; + } + }
156-165: Demo fallback should not render in productionThis creates a fake "Demo Author" user on production sites when no contributors are found. This was flagged in a previous review.
🔎 Proposed fix
- if (empty($contributors)) { - // For demo purposes, add mock contributors if none found - $contributors = [ - (object) [ - 'ID' => 1, - 'display_name' => 'Demo Author', - 'user_email' => 'demo@example.com' - ] - ]; - } + if (empty($contributors)) { + return ''; + }
395-395: Return markup instead of echoingBlock render callbacks should return the output string, not echo it. Echoing can cause misplaced output. This was flagged in a previous review.
🔎 Proposed fix
- echo render_wedocs_contributors_block($attributes, $content, $block); + return render_wedocs_contributors_block($attributes, $content, $block); }Note: The
echoshould be moved outside thefunction_existsblock and removed entirely since the function already returns the output.
153-154: De-duplicate contributors list
array_filterremoves nulls but doesn't prevent duplicate users (e.g., if post author also appears in revisions). This was flagged in a previous review.🔎 Proposed fix
// Filter out invalid contributors - $contributors = array_filter($contributors); + $contributors = array_filter($contributors); + // De-duplicate by user ID + $contributors = array_values(array_reduce($contributors, function($acc, $u) { + if (is_object($u) && isset($u->ID)) { + $acc[$u->ID] = $u; + } + return $acc; + }, []));assets/build/blocks/AdvanceContributors/render.php (4)
49-57: Critical: Unsafe $post property access without null check.Lines 50 and 73 access
$post->IDwithout verifying that$postis not null. This will cause a fatal error in non-singular contexts (archives, previews, etc.).🔎 Required fix
case 'main_author': + if (!$post) { break; } $author_id = get_post_field('post_author', $post->ID);Apply the same null guard at Line 73 and anywhere else
$post->IDis accessed.Based on past review comments.
229-242: Major: Box shadow key mismatch prevents shadows from rendering.Line 230 checks for
$shadow['x']but the block attributes schema (block.json lines 284-290) provides'horizontal'and'vertical'keys. This mismatch means box shadows will never apply.🔎 Required fix
-if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['x'])) { +if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['horizontal'])) { $shadow = $controls['boxShadow']; $shadow_value = ''; if (isset($shadow['inset']) && $shadow['inset']) { $shadow_value .= 'inset '; } - $shadow_value .= esc_attr($shadow['x']) . ' '; - $shadow_value .= esc_attr($shadow['y']) . ' '; + $shadow_value .= esc_attr($shadow['horizontal']) . ' '; + $shadow_value .= esc_attr($shadow['vertical']) . ' ';Based on past review comments.
333-345: Critical: Inverted hide-class logic hides block on all devices.Lines 335-342 add
wedocs-hide-{device}classes whenever the device key exists (which is always true per the schema defaults), causing the block to be hidden across all breakpoints.🔎 Required fix
Only add hide classes when display is explicitly set to 'none':
-if (isset($display_controls['desktop']) && $display_controls['desktop']) { +if (isset($display_controls['desktop']['display']) && $display_controls['desktop']['display'] === 'none') { $display_classes[] = 'wedocs-hide-desktop'; } -if (isset($display_controls['tablet']) && $display_controls['tablet']) { +if (isset($display_controls['tablet']['display']) && $display_controls['tablet']['display'] === 'none') { $display_classes[] = 'wedocs-hide-tablet'; } -if (isset($display_controls['mobile']) && $display_controls['mobile']) { +if (isset($display_controls['mobile']['display']) && $display_controls['mobile']['display'] === 'none') { $display_classes[] = 'wedocs-hide-mobile'; }Based on past review comments.
497-499: Critical: Render file must return the generated HTML.Line 499 calls the render function but doesn't return its output to WordPress, resulting in empty block output on the frontend.
🔎 Required fix
return $output; } -render_wedocs_advance_contributors_block( $attributes, $content, $block ); +return render_wedocs_advance_contributors_block( $attributes, $content, $block );Based on past review comments.
assets/build/blocks/AdvanceContributors/block.json (1)
284-291: Schema mismatch with render.php for box shadow.The block.json schema correctly defines box shadow with
"horizontal"and"vertical"keys, but the render.php file (Line 230) checks for"x"and"y", causing shadows to never render.The fix should be applied in render.php to match this schema. See the review comment on render.php lines 229-242.
Based on past review comments.
assets/build/blocks/TableOfContents/index.js (1)
1-1: Reconsider committing minified build artifacts to the repository.This is generated build output that should not be committed to version control. See the previous comment on
assets/build/blocks/AdvanceContributors/index.jsfor the same rationale.src/blocks/commonControls/DimensionsControls.js (3)
11-14: Guard against undefineddimensionsControlsto prevent runtime errors.
dimensionsControlsmay be undefined, causingdimensionsControls[device]to throw a runtime error.🔎 Proposed fix
-const DimensionsControls = ({ attributes, setAttributes, device }) => { - const { dimensionsControls } = attributes; - const currentDimensions = dimensionsControls[device] || {}; +const DimensionsControls = ({ attributes, setAttributes, device }) => { + const { dimensionsControls = {} } = attributes; + const currentDimensions = dimensionsControls[device] || {};Based on past review comments.
15-28: Guard nested object spreads to prevent runtime errors.Spreading
currentDimensions.paddingwill throw ifpaddingis undefined.🔎 Proposed fix
const handlePaddingChange = (value) => { const newDimensionsControls = { ...dimensionsControls, [device]: { ...currentDimensions, padding: { - ...currentDimensions.padding, + ...(currentDimensions.padding ?? {}), ...value, }, }, }; setAttributes({ dimensionsControls: newDimensionsControls }); };Apply the same pattern to
handleMarginChange(lines 30-43) andhandleBlockSpacingChange(lines 45-58).Based on past review comments.
69-74: Replace-Infinitywith a supported numeric value.Gutenberg's
SpacingSizesControlexpects a finite number forminimumCustomValue. Using-Infinityis not supported and may break UI validation.🔎 Proposed fix
<SpacingSizesControl values={currentDimensions.margin || {}} onChange={handleMarginChange} label={__('Margin', 'wedocs')} - minimumCustomValue={-Infinity} + minimumCustomValue={-1000} />Alternatively, omit the prop to use the component's default minimum value.
Based on past review comments.
src/blocks/TableOfContents/style.scss (1)
53-56: Fix CSS custom property typo.The custom property name is misspelled as
--list-item-sytle(should be--list-item-style), which prevents the custom color from being applied.🔎 Proposed fix
a { text-decoration: none; - color: var(--list-item-sytle, inherit); + color: var(--list-item-style, inherit); display: inline-block; transition: color 0.2s ease;Note: According to past review comments, this typo also appears in the corresponding edit.js file where the CSS variable is set. Ensure both locations are fixed for consistency.
Based on past review comments.
src/blocks/commonControls/ColorsControls.js (1)
17-19: Add missingdeviceprop to function signature.The component references
deviceon line 19 but doesn't receive it as a prop, causingcolorsControls[device]to be undefined.🔎 Proposed fix
-const ColorsControls = ({ attributes, setAttributes, isTextColor = false, isBackgroundColor = false, isLinkColor = false }) => { - const { colorsControls } = attributes; +const ColorsControls = ({ attributes, setAttributes, device, isTextColor = false, isBackgroundColor = false, isLinkColor = false }) => { + const { colorsControls = {} } = attributes; const currentColors = colorsControls[device] || {};Additionally, consider providing a default value for
device(e.g.,device = 'desktop') if it's optional.Based on past review comments.
src/blocks/commonControls/BackgroundImageControls.js (1)
164-182: UnitControl: "auto" is invalid for__experimentalUnitControl.
__experimentalUnitControlexpects a numeric value with unit. Passing "auto" will cause validation issues. Use empty string and add explicit units.This was flagged in a previous review. The fix should use an empty string as the default and define allowed units:
<UnitControl __next40pxDefaultSize - value={currentBackgroundImage.bgWidth || 'auto'} + value={currentBackgroundImage.bgWidth ?? ''} + units={[ + { value: 'px', label: 'px' }, + { value: '%', label: '%' }, + ]} disabled={currentBackgroundImage.bgSize !== 'tile'} onChange={(value) => { ... }} placeholder={__('Auto', 'wedocs')} />src/blocks/helpers/block-styles.php (2)
58-70: CSS value sanitization function exists but is not used.The
wedocs_sanitize_css_value()function (lines 290-312) provides proper CSS value sanitization, butwedocs_build_spacing_styles()uses onlyesc_attr()which doesn't validate CSS units. This was previously flagged and the sanitization function was added, but integration is incomplete.The fix from the past review should be applied here to use
wedocs_sanitize_css_value()for padding/margin values.
81-101: Border style and radius values lack proper sanitization.This segment uses
esc_attr()for CSS values but doesn't validate against allowed units. Thewedocs_sanitize_css_value()function exists but isn't used here.
🟡 Minor comments (21)
readme.md-23-39 (1)
23-39: Clarify the purpose and placement of the Mozart configuration block.This commented-out configuration block appears to be for the Mozart dependency system, but it's unclear why this needs to be in a README file. Additionally, the namespace (
WPMUDEV_PluginTest) and classmap prefix suggest this may be example or copied configuration, not specific to weDocs.Consider:
- Moving actual configuration to proper config files (e.g.,
composer.jsonor a dedicated Mozart config file)- If this is documentation, provide context explaining what Mozart is and why weDocs uses it
- Removing the commented block if it's example code that's not relevant to this project
src/blocks/components/SpacingControl.js-73-85 (1)
73-85: Fallback logic may override intentional '0px' gap values.The expression
gapValue || '10px'on Line 77 will default to '10px' for any falsy value, including'0px',0, or''. If a developer explicitly wants to set the gap to zero, this fallback will prevent it.🔎 Proposed fix using nullish coalescing
<UnitControl label={__('Gap', 'wedocs')} - value={gapValue || '10px'} + value={gapValue ?? '10px'} onChange={onGapChange} units={[ { value: 'px', label: 'px' },This ensures only
nullorundefinedtrigger the default, allowing explicit'0px'or0values.src/blocks/components/SpacingControl.js-1-7 (1)
1-7: Update imports to use stable BoxControl and UnitControl exports.
__experimentalBoxControland__experimentalUnitControlwere promoted to stable APIs (BoxControl and UnitControl) in WordPress 6.7/6.8. Update the imports to:import { BoxControl, UnitControl } from '@wordpress/components';The
__experimentalSpacerimport should remain as-is, as Spacer has not been stabilized yet.src/blocks/commonControls/BorderAndShadowControls.js-215-237 (1)
215-237: Inconsistent reset values for different properties.The reset operation uses different values for each property:
border: {}(empty object)borderRadius: null(null)boxShadow: {}(empty object)While this works due to the fallback logic on line 97, the inconsistency could confuse maintainers.
🔎 Suggested fix for consistency
onClick={() => { setAttributes({ borderAndShadowControls: { ...borderAndShadowControls, [device]: { ...currentBorderAndShadow, - border: {}, - borderRadius: null, - boxShadow: {}, + border: undefined, + borderRadius: undefined, + boxShadow: undefined, }, }, });Or consistently use empty objects:
- borderRadius: null, + borderRadius: {},assets/build/print-rtl.css-141-144 (1)
141-144: Duplicate selectora:not(.anchorjs-link)::after.The same selector appears twice on consecutive lines. This is likely a copy-paste error.
🔎 Proposed fix
-a:not(.anchorjs-link)::after, -a:not(.anchorjs-link)::after { +a:not(.anchorjs-link)::after { content: ' (' attr(href) ')'; }src/blocks/helpers/block-helpers.js-374-389 (1)
374-389:isBreakpointwill throw in SSR/Node environments.Direct access to
window.innerWidthwithout a guard will cause aReferenceErrorduring server-side rendering or testing in Node. Add a check forwindowexistence.🔎 Proposed fix
export const isBreakpoint = (breakpoint) => { + if (typeof window === 'undefined') { + return false; + } const breakpoints = getBreakpoints(); const width = window.innerWidth;assets/build/print-rtl.css-55-62 (1)
55-62: Duplicatefont-sizedeclarations in the same rule.
font-sizeis declared twice (line 55:18px, line 62:15px). The second declaration overrides the first, making line 55 dead code. If15pxis the intended size, remove line 55.🔎 Proposed fix
.entry-content dl dt { float: right; display: inline-block; font-weight: 400; text-align: center; padding: 4px 9px; margin-bottom: 1em; - font-size: 18px; line-height: 1.2em; border-radius: 50px; color: #fff; background: #3197d1; vertical-align: baseline; white-space: nowrap; font-size: 15px;src/blocks/TableOfContents/index.js-29-34 (1)
29-34: Addsave: () => nullto the block registration.The block registration is missing the
saveproperty. Based on the pattern used in Contributors and AdvanceContributors blocks (which also use server-side rendering viarender.php), add:save: () => null,This indicates that the block content is rendered server-side rather than stored in the database.
src/blocks/commonControls/TypographyControls.js-244-271 (1)
244-271: Use children for Button label instead of text prop.The
textprop on Button may not be supported in all versions of@wordpress/components. Pass the label as children for better compatibility.🔎 Proposed fix
<Button __next40pxDefaultSize variant="secondary" isDestructive - text={__('Reset All', 'wedocs')} style={{ width: '100%', justifyContent: 'center', marginTop: '16px', }} onClick={() => { setAttributes({ typographyControls: { ...typographyControls, [device]: { ...currentTypography, fontFamily: null, fontSize: null, fontAppearance: null, lineHeight: null, letterSpacing: null, textDecoration: null, textTransform: null, }, }, }); }} -/> +> + {__('Reset All', 'wedocs')} +</Button>src/blocks/Contributors/render.php-332-332 (1)
332-332: Usewp_date()instead ofdate()for timezone-aware formatting
date()doesn't respect WordPress timezone settings. Usewp_date()for consistent timezone handling.🔎 Proposed fix
- $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); + $last_modified = $post ? get_the_modified_date($date_format_string, $post) : wp_date($date_format_string);src/blocks/Contributors/edit.js-323-327 (1)
323-327: Hardcoded date format in preview.The preview always uses
'en-US'locale and a specific format, ignoring theattributes.dateFormatandattributes.customDateFormatsettings. This creates a mismatch between the editor preview and the actual rendered output.Consider using the configured date format settings to make the preview more accurate, or add a comment explaining this is a simplified preview.
assets/build/frontend-rtl.css-508-515 (1)
508-515: Remove duplicate font-size declaration.Line 508 declares
font-size: 18pxand line 515 declaresfont-size: 15pxfor the same selector. This creates ambiguity about which size should be applied.🔎 Proposed fix
padding: 4px 9px; margin-bottom: 1em; - font-size: 18px; line-height: 1.2em; border-radius: 50px; color: #fff; background: #3197d1; vertical-align: baseline; white-space: nowrap; font-size: 15px;src/blocks/AdvanceContributors/render.php-454-454 (1)
454-454: Incorrect date fallback when post is unavailable.Line 454 uses
date($date_format_string)as fallback when$postis unavailable, which returns the current date/time rather than a meaningful post date. Consider omitting the date section entirely when the post is unavailable.🔎 Proposed fix
- $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); + $last_modified = $post ? get_the_modified_date($date_format_string, $post) : ''; + + if (!$last_modified) { + // Skip rendering date if post is unavailable + $show_last_updated = false; + }Committable suggestion skipped: line range outside the PR's diff.
src/blocks/DocsGrid/render.php-183-184 (1)
183-184: Unused variable$total_pagesand missing pagination rendering.
$total_pagesis computed but never used. Theget_pagination_style_tagfunction exists but pagination UI is not rendered. Either implement pagination or remove the unused code.Also applies to: 207-212
src/blocks/TableOfContents/edit.js-113-113 (1)
113-113: Potential negative indent when h1 is included insupportedHeadings.The counters object starts at level 2, and indent calculation
(heading.level - 2) * 20produces negative values for h1. If h1 is supported, this could cause layout issues.🔎 Proposed fix
- let counter = 1; - const counters = { 2: 0, 3: 0, 4: 0, 5: 0 }; + let counter = 1; + const counters = { 1: 0, 2: 0, 3: 0, 4: 0, 5: 0 };And for indent:
- const indent = showHierarchy ? (heading.level - 2) * 20 : 0; + const indent = showHierarchy ? Math.max(0, (heading.level - 1) * 20) : 0;Also applies to: 130-130
assets/build/blocks/Contributors/render.php-332-332 (1)
332-332: Usewp_date()instead ofdate()for WordPress timezone handling.
date()uses server timezone, not the WordPress configured timezone. Usewp_date()for consistency with WordPress settings.🔎 Proposed fix
- $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); + $last_modified = $post ? get_the_modified_date($date_format_string, $post) : wp_date($date_format_string);src/blocks/TableOfContents/edit.js-154-154 (1)
154-154: Fix typo in CSS variable name:--list-item-sytle→--list-item-style.This typo will cause the CSS variable to not match any references expecting
--list-item-style.🔎 Proposed fix
style: { - "--list-item-sytle": containerBackgroundColor, + "--list-item-style": containerBackgroundColor,src/blocks/DocsGrid/render.php-176-178 (1)
176-178: Use integer-1instead of string'-1'forposts_per_page.WP_Query expects an integer for
posts_per_page. Using a string may cause unexpected behavior.🔎 Proposed fix
} else { - $args['posts_per_page'] = '-1'; + $args['posts_per_page'] = -1; $args['paged'] = 1; }src/blocks/AdvanceContributors/edit.js-286-290 (1)
286-290: AvoidMath.random()as React key.Using
Math.random()for keys (line 289 fallback) causes React to unmount and remount components on every render, degrading performance and breaking state.🔎 Suggested fix
- const contributorId = contributor.id || contributor.ID || Math.random(); + const contributorId = contributor.id || contributor.ID || `fallback-${index}`;Note: This requires adding
indexparameter to the.map()callback.Committable suggestion skipped: line range outside the PR's diff.
src/blocks/helpers/block-styles.php-222-225 (1)
222-225: Custom styles are merged without validation.The
$args['custom']array is directly merged into styles without any sanitization. If this array contains user-controlled values, it could allow CSS injection.🔎 Suggested fix
// Custom styles if (isset($args['custom']) && is_array($args['custom'])) { - $styles = array_merge($styles, $args['custom']); + $sanitized_custom = array_map('sanitize_text_field', $args['custom']); + $styles = array_merge($styles, $sanitized_custom); }package.json-30-30 (1)
30-30: Test the build thoroughly after upgrading @wordpress/scripts to v30.The upgrade from
@wordpress/scriptsv25 to v30.15.0 includes changes to webpack, Babel, and ESLint presets. Review the changelog for breaking changes specific to your setup, run your build scripts, and verify that blocks render correctly in WordPress. The version of@wordpress/block-editordoes not need to be bumped solely based on this upgrade—WordPress packages use a dist-tag strategy (e.g.,@wordpress/block-editor@wp-6.x) for version coordination rather than strict pinning.
| @@ -0,0 +1 @@ | |||
| <?php return array('dependencies' => array('react-jsx-runtime', 'wp-block-editor', 'wp-blocks', 'wp-components', 'wp-core-data', 'wp-data', 'wp-element', 'wp-i18n', 'wp-primitives'), 'version' => 'f2d62c10206d682dc7b2'); | |||
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
🏁 Script executed:
#!/bin/bash
echo "=== Checking for build artifacts in assets/build/ ==="
if [ -d assets/build ]; then
find assets/build -type f | head -20
else
echo "assets/build/ directory not found"
fi
echo -e "\n=== Checking git status of assets/build/ ==="
git ls-files assets/build/ 2>/dev/null | head -20 || echo "No git-tracked files in assets/build/"
echo -e "\n=== Checking .gitignore for build directory exclusions ==="
if [ -f .gitignore ]; then
echo "=== Full .gitignore content ==="
cat -n .gitignore
echo ""
echo "=== Patterns matching 'build' or 'assets' ==="
grep -n "build\|dist\|assets" .gitignore || echo "No matching patterns found"
else
echo ".gitignore file not found"
fi
echo -e "\n=== Checking for build-related files (package.json, etc.) ==="
if [ -f package.json ]; then
echo "=== package.json found, checking for build scripts ==="
head -50 package.json
fi
echo -e "\n=== Git status overview for assets/build/ ==="
git status assets/build/ 2>/dev/null || echo "Git status check failed"Repository: weDevsOfficial/wedocs-plugin
Length of output: 4514
Remove build artifacts from version control and add assets/build/ to .gitignore.
The assets/build/ directory contains auto-generated files created by wp-scripts build and is currently tracked in git. These artifacts should not be committed because they:
- Cause merge conflicts when multiple developers build locally
- Bloat the repository with auto-generated content
- Create unnecessary churn in the version history
Add assets/build/ to .gitignore and regenerate these assets during the build/deployment process (e.g., via the npm run build or npm run release scripts).
🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/index.asset.php at line 1, a
generated build artifact is committed; remove all files under assets/build/ from
version control and add assets/build/ to .gitignore so generated assets aren’t
tracked. Specifically: delete the committed assets/build/ files from the repo
(git rm --cached or remove and commit), add an entry "assets/build/" to
.gitignore, and ensure the build step (npm run build/release) generates these
files during CI or deployment instead of committing them.
| @@ -0,0 +1 @@ | |||
| .contributors-tab-system .components-button-group{display:flex}.wedocs-contributors .contributors-container{display:flex;align-items:center;flex-wrap:wrap;gap:10px;margin-bottom:10px}@media(max-width: 768px){.wedocs-contributors .contributors-container{flex-direction:column;align-items:flex-start;gap:8px}}.wedocs-contributors .contributors-container .contributor-item{display:flex;align-items:center;gap:8px}@media(max-width: 768px){.wedocs-contributors .contributors-container .contributor-item{width:100%}}.wedocs-contributors .contributors-container .contributor-item .contributor-avatar{display:flex;align-items:center;justify-content:center;transition:all .3s ease}.wedocs-contributors .contributors-container .contributor-item .contributor-avatar.avatar-hover:hover{transform:scale(1.1);box-shadow:0 2px 8px rgba(0,0,0,.15)}.wedocs-contributors .contributors-container .contributor-item .contributor-avatar img{display:block;-o-object-fit:cover;object-fit:cover}.wedocs-contributors .contributors-container .contributor-item .contributor-avatar .default-icon{display:flex;align-items:center;justify-content:center;background-color:#0073aa;color:#fff}.wedocs-contributors .contributors-container .contributor-item .contributor-avatar .default-icon svg{width:60%;height:60%;fill:currentColor}.wedocs-contributors .contributors-container .contributor-item .contributor-name{transition:color .3s ease;text-decoration:none}.wedocs-contributors .contributors-container .contributor-item .contributor-name:hover{text-decoration:underline}.wedocs-contributors .contributors-container .contributor-item .contributor-name.no-link{cursor:default}.wedocs-contributors .last-updated{margin-top:10px;font-style:italic}@media(max-width: 768px){.wedocs-contributors .last-updated{margin-top:8px;font-size:.9em}}.wedocs-contributors .contributors-title{margin:0 0 10px 0;font-weight:600;font-size:16px}@media(max-width: 480px){.wedocs-contributors .contributors-container{gap:6px}.wedocs-contributors .contributors-container .contributor-item{gap:6px}.wedocs-contributors .contributors-container .contributor-item .contributor-avatar img,.wedocs-contributors .contributors-container .contributor-item .contributor-avatar .default-icon{width:28px !important;height:28px !important}.wedocs-contributors .contributors-container .contributor-item .contributor-name{font-size:.9em}.wedocs-contributors .last-updated{font-size:.8em}}@media(prefers-contrast: high){.wedocs-contributors .contributor-item .contributor-avatar{border:2px solid currentColor !important}.wedocs-contributors .contributor-item .contributor-name{text-decoration:underline}}@media(prefers-reduced-motion: reduce){.wedocs-contributors .contributor-avatar{transition:none !important}.wedocs-contributors .contributor-avatar.avatar-hover:hover{transform:none !important}.wedocs-contributors .contributor-name{transition:none !important}}@media(prefers-color-scheme: dark){.wedocs-contributors .contributor-item .contributor-avatar .default-icon{background-color:#4a90a4}}@media print{.wedocs-contributors .contributors-container{flex-direction:column;align-items:flex-start}.wedocs-contributors .contributor-item .contributor-avatar{display:none}} | |||
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
🏁 Script executed:
#!/bin/bash
# Compare LTR and RTL versions to verify they're different
echo "=== Comparing AdvanceContributors LTR and RTL files ==="
if [ -f assets/build/blocks/AdvanceContributors/style-index.css ] && [ -f assets/build/blocks/AdvanceContributors/style-index-rtl.css ]; then
echo "File sizes:"
wc -c assets/build/blocks/AdvanceContributors/style-index*.css
echo ""
echo "Diff output (first 50 lines):"
diff assets/build/blocks/AdvanceContributors/style-index.css assets/build/blocks/AdvanceContributors/style-index-rtl.css | head -50
else
echo "Files not found - listing directory:"
find assets/build/blocks/AdvanceContributors -type f -name "*.css" 2>/dev/null || echo "Directory not found"
fi
echo ""
echo "=== Checking for RTL-specific properties in AdvanceContributors RTL file ==="
if [ -f assets/build/blocks/AdvanceContributors/style-index-rtl.css ]; then
echo "Searching for directional properties:"
grep -o "padding-right\|border-right\|margin-right\|float" assets/build/blocks/AdvanceContributors/style-index-rtl.css | sort | uniq -c
else
echo "RTL file not found"
fi
echo ""
echo "=== Checking TableOfContents RTL file for reference ==="
if [ -f assets/build/blocks/TableOfContents/style-index-rtl.css ]; then
echo "Size of TableOfContents RTL file:"
wc -c assets/build/blocks/TableOfContents/style-index-rtl.css
echo ""
echo "Searching for directional properties in TableOfContents RTL:"
grep -o "padding-right\|border-right\|margin-right\|float" assets/build/blocks/TableOfContents/style-index-rtl.css | head -10
else
echo "TableOfContents RTL file not found"
fiRepository: weDevsOfficial/wedocs-plugin
Length of output: 684
RTL stylesheet is identical to LTR version and missing directional adjustments.
The style-index-rtl.css file is byte-for-byte identical to style-index.css (both 3204 bytes with no differences). RTL stylesheets require directional properties adjustments such as:
padding-rightinstead ofpadding-left(and vice versa)border-rightinstead ofborder-leftmargin-rightinstead ofmargin-left- Adjusted
floatandtext-alignvalues
The TableOfContents RTL variant correctly implements these adjustments. Apply equivalent RTL transformations to the AdvanceContributors stylesheet.
🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/style-index-rtl.css around lines 1 to
1, the RTL file is identical to the LTR stylesheet and lacks directional
mirroring; update the CSS to mirror directional properties from the LTR file —
replace left/right properties (padding-left ↔ padding-right, margin-left ↔
margin-right, border-left ↔ border-right), invert float and text-align values,
and adjust directional shorthands (e.g., margin: top right bottom left -> swap
left/right), ensure any directional transform/translateX values are negated, and
follow the same RTL adjustments used in the TableOfContents RTL variant so
layout, alignment and visual ordering are correct for right-to-left languages.
| if ( !function_exists('render_wedocs_contributors_block')){ | ||
| function render_wedocs_contributors_block($attributes, $content, $block) { |
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.
Render function called inside function_exists guard.
The echo render_wedocs_contributors_block(...) at line 395 is inside the guard, so it only executes on first load. Typically, the function should be defined inside the guard, but called outside.
🔎 Proposed fix
return $output;
- }
- echo render_wedocs_contributors_block($attributes, $content, $block);
}
+}
+
+echo render_wedocs_contributors_block($attributes, $content, $block);Also applies to: 395-396
🧰 Tools
🪛 PHPMD (2.15.0)
12-12: Avoid unused parameters such as '$content'. (undefined)
(UnusedFormalParameter)
12-12: Avoid unused parameters such as '$block'. (undefined)
(UnusedFormalParameter)
🤖 Prompt for AI Agents
In assets/build/blocks/Contributors/render.php around lines 11-12 and 395-396,
the render function call (echo render_wedocs_contributors_block(...)) is placed
inside the function_exists() guard so it only runs when the function is being
defined; move the echo call out of the guard so the guard only wraps the
function definition. Specifically, keep the if ( !
function_exists('render_wedocs_contributors_block') ) { function ... } block
as-is, then after the closing brace call echo
render_wedocs_contributors_block($attributes, $content, $block) so the function
is defined conditionally but always invoked.
| case 'all': | ||
| default: | ||
| // Get all contributors who have edited the post | ||
| $author_id = get_post_field('wedocs_contributors', $post->ID); | ||
| $authors = array_values($author_id); // return auhtors id. | ||
| foreach($authors as $author){ | ||
| $contributors[]= get_userdata($author); | ||
| } | ||
|
|
||
|
|
||
| if ($author_id && ($author_user = get_userdata($author_id))) { | ||
| $contributors[] = $author_user; | ||
| } |
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.
Logic bug: Author may be added twice in 'all' mode.
The code iterates over $authors adding each contributor, then adds the author again at lines 130-132. This can result in duplicate entries.
🔎 Proposed fix
case 'all':
default:
// Get all contributors who have edited the post
$author_id = get_post_field('wedocs_contributors', $post->ID);
- $authors = array_values($author_id); // return auhtors id.
- foreach($authors as $author){
- $contributors[]= get_userdata($author);
- }
-
-
- if ($author_id && ($author_user = get_userdata($author_id))) {
- $contributors[] = $author_user;
+ if (is_array($author_id)) {
+ foreach ($author_id as $author) {
+ $user = get_userdata($author);
+ if ($user) {
+ $contributors[] = $user;
+ }
+ }
+ } elseif ($author_id && ($author_user = get_userdata($author_id))) {
+ $contributors[] = $author_user;
}📝 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.
| case 'all': | |
| default: | |
| // Get all contributors who have edited the post | |
| $author_id = get_post_field('wedocs_contributors', $post->ID); | |
| $authors = array_values($author_id); // return auhtors id. | |
| foreach($authors as $author){ | |
| $contributors[]= get_userdata($author); | |
| } | |
| if ($author_id && ($author_user = get_userdata($author_id))) { | |
| $contributors[] = $author_user; | |
| } | |
| case 'all': | |
| default: | |
| // Get all contributors who have edited the post | |
| $author_id = get_post_field('wedocs_contributors', $post->ID); | |
| if (is_array($author_id)) { | |
| foreach ($author_id as $author) { | |
| $user = get_userdata($author); | |
| if ($user) { | |
| $contributors[] = $user; | |
| } | |
| } | |
| } elseif ($author_id && ($author_user = get_userdata($author_id))) { | |
| $contributors[] = $author_user; | |
| } |
🤖 Prompt for AI Agents
In assets/build/blocks/Contributors/render.php around lines 120 to 132, the code
appends contributors from $authors then unconditionally appends $author_user
again, causing duplicate entries; fix by removing the redundant append or
deduplicating before adding: either drop the final if-block that adds
$author_user (since it’s already added from $authors), or normalize $author_id
to an array and build $authors from it then ensure you only add each user once
(e.g., track added user IDs or filter duplicates with their IDs) before pushing
get_userdata results into $contributors.
| $author_id = get_post_field('wedocs_contributors', $post->ID); | ||
| $authors = array_values($author_id); // return auhtors 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.
Type safety: array_values() on potentially non-array value.
get_post_field('wedocs_contributors', $post->ID) may return a string, empty string, or WP_Error depending on the meta value. Calling array_values() on a non-array will cause a fatal error.
🔎 Proposed fix
- $author_id = get_post_field('wedocs_contributors', $post->ID);
- $authors = array_values($author_id); // return auhtors id.
+ $author_id = get_post_field('wedocs_contributors', $post->ID);
+ $authors = is_array($author_id) ? array_values($author_id) : [];🤖 Prompt for AI Agents
In assets/build/blocks/Contributors/render.php around lines 123-124, the code
calls array_values() directly on the result of get_post_field which may be a
WP_Error, string, or empty value; update it to first guard against WP_Error,
then normalize the value to an array before calling array_values: if
is_wp_error($author_id) return/handle error (or set $authors = []), if
is_array($author_id) use array_values($author_id), if it's a non-empty scalar
wrap it as a single-element array (e.g. $authors = [$author_id]), otherwise set
$authors = []; this ensures type safety and avoids fatal errors.
| export { | ||
| generateBlockStyles, | ||
| generateTypographyStyles, | ||
| generateSpacingStyles, | ||
| generateElementStyles, | ||
| generateCustomProperties, | ||
| debounce, | ||
| isValidCSSValue, | ||
| convertToPx, | ||
| classNames, | ||
| getBreakpoints, | ||
| isBreakpoint | ||
| } from './block-helpers'; | ||
|
|
||
| // Export default object with all helpers | ||
| export default { | ||
| generateBlockStyles, | ||
| generateTypographyStyles, | ||
| generateSpacingStyles, | ||
| generateElementStyles, | ||
| generateCustomProperties, | ||
| debounce, | ||
| isValidCSSValue, | ||
| convertToPx, | ||
| classNames, | ||
| getBreakpoints, | ||
| isBreakpoint | ||
| }; 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.
Default export references identifiers that are not in scope.
The named re-exports on lines 11-22 make the functions available to consumers of this module, but they do not bring those identifiers into the local scope of this file. The default export object (lines 26-37) references generateBlockStyles, debounce, etc., which are undefined in this file's scope.
This will cause a ReferenceError at runtime when importing the default export.
🔎 Proposed fix
-// Export all helper functions
-export {
+// Import helpers for local use
+import {
generateBlockStyles,
generateTypographyStyles,
generateSpacingStyles,
generateElementStyles,
generateCustomProperties,
debounce,
isValidCSSValue,
convertToPx,
classNames,
getBreakpoints,
isBreakpoint
} from './block-helpers';
+
+// Re-export all helper functions
+export {
+ generateBlockStyles,
+ generateTypographyStyles,
+ generateSpacingStyles,
+ generateElementStyles,
+ generateCustomProperties,
+ debounce,
+ isValidCSSValue,
+ convertToPx,
+ classNames,
+ getBreakpoints,
+ isBreakpoint
+};
// Export default object with all helpers
export default {
generateBlockStyles,Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In src/blocks/helpers/index.js around lines 11-38, the file currently only
re-exports named helpers but then attempts to reference those identifiers for a
default export (causing ReferenceError); fix this by bringing the functions into
the local scope (either with a single import { generateBlockStyles,
generateTypographyStyles, generateSpacingStyles, generateElementStyles,
generateCustomProperties, debounce, isValidCSSValue, convertToPx, classNames,
getBreakpoints, isBreakpoint } from './block-helpers' or import * as helpers
from './block-helpers'), then re-export the named symbols and create the default
export object from those locally imported identifiers (or simply export default
helpers if using namespace import). Ensure the file both exports the named
symbols and exposes a valid default object referencing identifiers that exist in
this module scope.
| // Get block attributes with proper defaults | ||
| $block_id = isset($attributes['blockId']) ? sanitize_text_field($attributes['blockId']) : 'toc-' . uniqid(); | ||
| $toc_title = isset($attributes['tocTitle']) ? sanitize_text_field($attributes['tocTitle']) : 'Table of Contents'; | ||
| $supported_headings = isset($attributes['supportedHeadings']) && is_array($attributes['supportedHeadings']) ? $attributes['supportedHeadings'] : ['h2', 'h3']; | ||
| $show_hierarchy = isset($attributes['showHierarchy']) ? (bool) $attributes['showHierarchy'] : true; | ||
| $show_numbering = isset($attributes['showNumbering']) ? (bool) $attributes['showNumbering'] : false; | ||
| $collapsible_on_mobile = isset($attributes['collapsibleOnMobile']) ? (bool) $attributes['collapsibleOnMobile'] : true; | ||
| $smooth_scroll = isset($attributes['smoothScroll']) ? (bool) $attributes['smoothScroll'] : true; | ||
| $sticky_mode = isset($attributes['stickyMode']) ? (bool) $attributes['stickyMode'] : false; | ||
| $additional_css_class = isset($attributes['additionalCssClass']) ? sanitize_text_field($attributes['additionalCssClass']) : ''; | ||
|
|
||
| // Build CSS classes | ||
| $css_classes = ['wp-block-wedocs-table-of-contents']; | ||
| if (!empty($additional_css_class)) { | ||
| $css_classes[] = esc_attr($additional_css_class); | ||
| } | ||
| if ($sticky_mode) { | ||
| $css_classes[] = 'sticky-mode'; | ||
| } | ||
| if ($collapsible_on_mobile) { | ||
| $css_classes[] = 'collapsible-mobile'; | ||
| } | ||
| if ($smooth_scroll) { | ||
| $css_classes[] = 'smooth-scroll'; | ||
| } | ||
|
|
||
| // Get block wrapper attributes | ||
| $wrapper_attributes = get_block_wrapper_attributes([ | ||
| 'class' => implode(' ', $css_classes), | ||
| 'data-block-id' => esc_attr($block_id), | ||
| 'data-supported-headings' => esc_attr(wp_json_encode($supported_headings)), | ||
| 'data-show-hierarchy' => $show_hierarchy ? 'true' : 'false', | ||
| 'data-show-numbering' => $show_numbering ? 'true' : 'false', | ||
| 'data-smooth-scroll' => $smooth_scroll ? 'true' : 'false' | ||
| ]); | ||
|
|
||
| // Apply inline styles | ||
| $inline_styles = ''; | ||
| if (!empty($attributes['containerBackgroundColor'])) { | ||
| $inline_styles .= 'background-color: ' . esc_attr($attributes['containerBackgroundColor']) . ';'; | ||
| } | ||
| if (!empty($attributes['containerWidth'])) { | ||
| $inline_styles .= 'width: ' . esc_attr($attributes['containerWidth']) . ';'; | ||
| } |
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.
Code executes at include time before $attributes is available.
Lines 109-152 run when the file is included, but $attributes isn't defined yet - it's only available when WordPress calls the render callback. This will cause PHP warnings/errors about undefined variables.
This code should either be inside the render callback or removed entirely as it duplicates logic already in render_wedocs_table_of_contents_block().
🤖 Prompt for AI Agents
In src/blocks/TableOfContents/render.php around lines 109-152, code is executing
at include time and references $attributes which is undefined until the
WordPress render callback runs; move this entire block into the
render_wedocs_table_of_contents_block() function (or delete it if it duplicates
that function) so it runs only when the render callback receives $attributes,
replace direct references to $attributes with the function's $attributes
parameter, and ensure any helper variables ($block_id, $css_classes,
$wrapper_attributes, $inline_styles, etc.) are computed inside the render
callback to avoid PHP notices and duplicate logic.
| /** | ||
| * Modern WordPress block render callback | ||
| * This function is automatically called by WordPress when the block.json has "render": "file:./render.php" | ||
| */ | ||
| // Extract attributes with defaults | ||
| $toc_title = $attributes['tocTitle'] ?? 'Table of Contents'; | ||
| $supported_headings = $attributes['supportedHeadings'] ?? ['h2', 'h3']; | ||
| $show_hierarchy = $attributes['showHierarchy'] ?? true; | ||
| $show_numbering = $attributes['showNumbering'] ?? false; | ||
| $collapsible_on_mobile = $attributes['collapsibleOnMobile'] ?? true; | ||
| $container_background_color = $attributes['containerBackgroundColor'] ?? ''; | ||
| $container_width = $attributes['containerWidth'] ?? '100%'; | ||
| $container_padding = $attributes['containerPadding'] ?? ['top' => '20px', 'right' => '20px', 'bottom' => '20px', 'left' => '20px']; | ||
| $container_margin = $attributes['containerMargin'] ?? ['top' => '0px', 'right' => '0px', 'bottom' => '20px', 'left' => '0px']; | ||
| $container_border_style = $attributes['containerBorderStyle'] ?? 'solid'; | ||
| $container_border_width = $attributes['containerBorderWidth'] ?? '1px'; | ||
| $container_border_color = $attributes['containerBorderColor'] ?? '#e0e0e0'; | ||
| $container_border_radius = $attributes['containerBorderRadius'] ?? '5px'; | ||
| $title_color = $attributes['titleColor'] ?? ''; | ||
| $title_font_size = $attributes['titleFontSize'] ?? '18px'; | ||
| $title_font_weight = $attributes['titleFontWeight'] ?? '600'; | ||
| $title_padding = $attributes['titlePadding'] ?? ['top' => '0px', 'right' => '0px', 'bottom' => '15px', 'left' => '0px']; | ||
| $list_color = $attributes['listColor'] ?? ''; | ||
| $list_hover_color = $attributes['listHoverColor'] ?? ''; | ||
| $list_font_size = $attributes['listFontSize'] ?? '14px'; | ||
| $smooth_scroll = $attributes['smoothScroll'] ?? true; | ||
| $sticky_mode = $attributes['stickyMode'] ?? false; | ||
| $additional_css_class = $attributes['additionalCssClass'] ?? ''; | ||
|
|
||
| // Build wrapper attributes | ||
| $wrapper_attributes = 'class="wp-block-wedocs-table-of-contents'; | ||
| if ($collapsible_on_mobile) { | ||
| $wrapper_attributes .= ' toc-mobile-collapsible'; | ||
| } | ||
| if ($sticky_mode) { | ||
| $wrapper_attributes .= ' toc-sticky'; | ||
| } | ||
| if (!empty($additional_css_class)) { | ||
| $wrapper_attributes .= ' ' . esc_attr($additional_css_class); | ||
| } | ||
| $wrapper_attributes .= '"'; | ||
|
|
||
| // Build inline styles | ||
| $inline_styles = ''; | ||
| if (!empty($container_background_color)) { | ||
| $inline_styles .= 'background-color: ' . esc_attr($container_background_color) . '; '; | ||
| } | ||
| $inline_styles .= 'width: ' . esc_attr($container_width) . '; '; | ||
| $inline_styles .= 'padding: ' . esc_attr($container_padding['top']) . ' ' . esc_attr($container_padding['right']) . ' ' . esc_attr($container_padding['bottom']) . ' ' . esc_attr($container_padding['left']) . '; '; | ||
| $inline_styles .= 'margin: ' . esc_attr($container_margin['top']) . ' ' . esc_attr($container_margin['right']) . ' ' . esc_attr($container_margin['bottom']) . ' ' . esc_attr($container_margin['left']) . '; '; | ||
| $inline_styles .= 'border: ' . esc_attr($container_border_width) . ' ' . esc_attr($container_border_style) . ' ' . esc_attr($container_border_color) . '; '; | ||
| $inline_styles .= 'border-radius: ' . esc_attr($container_border_radius) . '; '; | ||
|
|
||
| $toc_content = wedocs_generate_toc_content_safe($supported_headings, $show_hierarchy, $show_numbering); | ||
|
|
||
| ?> | ||
| <div <?php echo $wrapper_attributes; ?> <?php echo !empty($inline_styles) ? 'style="' . esc_attr($inline_styles) . '"' : ''; ?>> | ||
| <div class="toc-title" style="<?php echo !empty($title_color) ? 'color: ' . esc_attr($title_color) . '; ' : ''; ?>font-size: <?php echo esc_attr($title_font_size); ?>; font-weight: <?php echo esc_attr($title_font_weight); ?>; padding: <?php echo esc_attr($title_padding['top']) . ' ' . esc_attr($title_padding['right']) . ' ' . esc_attr($title_padding['bottom']) . ' ' . esc_attr($title_padding['left']); ?>;"> | ||
| <?php echo esc_html($toc_title); ?> | ||
| </div> | ||
| <div class="toc-content" style="<?php echo !empty($list_color) ? 'color: ' . esc_attr($list_color) . '; ' : ''; ?>font-size: <?php echo esc_attr($list_font_size); ?>;"> | ||
| <?php echo wp_kses_post($toc_content); ?> | ||
| </div> | ||
| </div> |
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.
Same issue: Duplicate rendering code outside of function.
This file has the identical problem as the build version - lines 375-438 contain rendering code outside of any function that will execute on every file include.
This appears to be the source file. The entire section from line 375 to end of file should be removed, as it duplicates render_wedocs_table_of_contents_block() defined above.
🤖 Prompt for AI Agents
In src/blocks/TableOfContents/render.php around lines 375 to 438 there is
duplicated block render code placed outside any function (it duplicates
render_wedocs_table_of_contents_block()), which causes it to run on every
include; remove the entire section from line 375 to the end of the file (the
duplicated rendering block) so only the previously defined
render_wedocs_table_of_contents_block() is used, and verify there are no
leftover stray PHP open/close tags or duplicated variable definitions after
removal.
| // Generate TOC HTML | ||
| const tocHTML = generateTOCHTML(headings, supportedHeadings, showHierarchy, showNumbering); | ||
| const tocContent = tocBlock.querySelector('.toc-content'); | ||
| tocContent.innerHTML = tocHTML; | ||
|
|
||
| // Add IDs to headings if they don't have them | ||
| headings.forEach(function(heading, index) { | ||
| if (!heading.id) { | ||
| heading.id = 'toc-heading-' + index; | ||
| } | ||
| }); | ||
| } |
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.
IDs are assigned to headings after TOC HTML is generated, causing broken anchor links.
The generateTOCHTML function (line 58) is called before IDs are assigned to headings (lines 63-67). When generateTOCHTML accesses heading.id on line 100, headings without existing IDs will have empty id values, and the fallback 'toc-heading-' + index won't match the IDs assigned later.
🔎 Proposed fix: Assign IDs before generating HTML
function generateTOC(tocBlock) {
const supportedHeadings = getSupportedHeadings(tocBlock);
const showHierarchy = tocBlock.dataset.showHierarchy !== 'false';
const showNumbering = tocBlock.dataset.showNumbering === 'true';
// Find all headings in the page content
const contentArea = document.querySelector('.entry-content, .post-content, main, .content') || document.body;
const headingSelector = supportedHeadings.map(h => h.toLowerCase()).join(', ');
const headings = contentArea.querySelectorAll(headingSelector);
if (headings.length === 0) {
const tocContent = tocBlock.querySelector('.toc-content');
tocContent.innerHTML = '<div class="toc-empty-state"><p>No headings found in the content.</p></div>';
return;
}
+ // Add IDs to headings BEFORE generating TOC HTML
+ headings.forEach(function(heading, index) {
+ if (!heading.id) {
+ heading.id = 'toc-heading-' + index;
+ }
+ });
+
// Generate TOC HTML
const tocHTML = generateTOCHTML(headings, supportedHeadings, showHierarchy, showNumbering);
const tocContent = tocBlock.querySelector('.toc-content');
tocContent.innerHTML = tocHTML;
-
- // Add IDs to headings if they don't have them
- headings.forEach(function(heading, index) {
- if (!heading.id) {
- heading.id = 'toc-heading-' + index;
- }
- });
}🤖 Prompt for AI Agents
In src/blocks/TableOfContents/view.js around lines 57 to 68, IDs are being added
to headings after generateTOCHTML is called, so generateTOCHTML sees empty ids
and produces broken anchors; move the headings.forEach block that assigns ids to
run before calling generateTOCHTML (or alternatively update generateTOCHTML to
generate and use fallback ids itself), then call generateTOCHTML and set
tocContent.innerHTML so the TOC uses the correct, already-assigned ids.
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: 2
🤖 Fix all issues with AI agents
In @src/blocks/TableOfContents/Inspector.js:
- Around line 113-122: The commented Advanced Panel in Inspector.js references
the attribute additionalCssClass but that variable is not included in the
attributes destructuring, which will throw a ReferenceError if the block is ever
uncommented; fix by adding additionalCssClass to the attributes destructuring
(where other attributes are pulled out, e.g., in the TableOfContentsInspector or
the functional component's props destructuring around the existing attributes
block) so additionalCssClass and its usage with setAttributes are defined and
safe to uncomment.
- Around line 10-11: Update the import so BoxControl uses the stable export:
replace __experimentalBoxControl with BoxControl in the import list (keep
__experimentalUnitControl as-is); ensure the import line now reads to include
BoxControl and __experimentalUnitControl so references to BoxControl in
Inspector.js resolve to the stable component.
🧹 Nitpick comments (1)
src/blocks/TableOfContents/Inspector.js (1)
52-53: Consider CSS classes for repeated styling patterns.Multiple inline styles are used throughout, particularly
marginBottom: '20px'which appears several times. While functional, using CSS classes would improve maintainability and consistency.Also applies to: 129-130, 181-182, 197-197, 229-229, 233-234, 241-242
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
src/blocks/TableOfContents/Inspector.jssrc/editor/AiDocWriterPanel.js
🔇 Additional comments (3)
src/editor/AiDocWriterPanel.js (1)
7-7: Import path modernization is correct.The migration from
@wordpress/edit-postto@wordpress/editoris valid. BothPluginSidebarandPluginSidebarMoreMenuItemare properly exported by@wordpress/editorv14.5.0 and will work as expected.src/blocks/TableOfContents/Inspector.js (2)
16-38: Previous critical issue resolved.The destructuring of attributes is now properly implemented. All attribute variables used throughout the component are correctly extracted here, resolving the ReferenceError that was flagged in the previous review.
56-69: Well-implemented immutable state handling.The checkbox logic correctly maintains immutability when adding or removing heading tags from the
supportedHeadingsarray.
| __experimentalBoxControl as BoxControl, | ||
| __experimentalUnitControl as UnitControl, |
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
🌐 Web query:
@wordpress/components 28.10.0 BoxControl UnitControl stable
💡 Result:
Short answer: In @wordpress/components v28.10.0 BoxControl is stable, while UnitControl remains experimental (not stabilized).
Sources:
- BoxControl documented as stable / stabilized in core updates. [1]
- UnitControl still exported as __experimentalUnitControl in the handbook (experimental). [2]
- Release/changes overview noting BoxControl stabilization and UnitControl listed among experimental-to-monitor changes. [3]
References
[1] Make WordPress Core — Updates to user‑interface components in WordPress 6.8 (stabilized BoxControl).
[2] WordPress Block Editor Handbook — UnitControl (shows __experimentalUnitControl usage).
[3] WordPress Block Editor Handbook — BoxControl (stable usage and props).
🌐 Web query:
WordPress components experimental BoxControl UnitControl release notes
💡 Result:
Short summary:
-
BoxControl: the experimental __experimentalBoxControl was stabilized and can be imported as BoxControl (not experimental) as part of the editor components changes around the WordPress 6.7 / 6.8 timeframe. [1][2]
-
UnitControl: remains an experimental component (__experimentalUnitControl) in the Block Editor handbook; its docs and usage examples are published in the developer handbook. [3]
Sources:
[1] Make WordPress Core — Editor components updates in WordPress 6.7 (stabilized BoxControl).
[2] Make WordPress Core — Updates to user‑interface components in WordPress 6.8 (40px default-size opt-in, mentions BoxControl stabilization).
[3] WordPress Block Editor Handbook — UnitControl (experimental) documentation.
🌐 Web query:
@wordpress/components BoxControl UnitControl API stability changelog
💡 Result:
Summary — API stability / changelog highlights for BoxControl and UnitControl in @wordpress/components:
-
BoxControl: stabilized (moved from __experimentalBoxControl to BoxControl) during the progressive reduction of experimental APIs (noted in WordPress 6.7 and reiterated in 6.8 release notes). [1][2]
-
UnitControl: received API/structure changes in WordPress 6.2 (className/outer wrapper behavior; removal of components-unit-control-wrapper and __unstableWrapperClassName), and later was included in the 6.8 list of controls logging deprecation warnings while adopting the new 40px default sizing opt-in. [3][1]
-
General: several components (including BoxControl and UnitControl) were part of the effort to reduce experimental exports and normalize sizing/props; consumers should prefer the stabilized exports (BoxControl, UnitControl) and follow the 40px default-size opt-in prop where noted (__next40pxDefaultSize). [1][2][3]
Sources:
[1] Make WordPress Core — “Updates to user-interface components in WordPress 6.8.”
[2] Make WordPress Core — “Updates to user-interface components in WordPress 6.7.”
[3] Make WordPress Core — “Editor Components updates in WordPress 6.2.”
Update BoxControl import to stable version.
BoxControl was stabilized in @wordpress/components (WordPress 6.7+) and can be imported directly without the experimental prefix. Update line 10 to import the stable version:
BoxControl,UnitControl correctly remains experimental and should continue using __experimentalUnitControl as it has not yet been stabilized.
🤖 Prompt for AI Agents
In @src/blocks/TableOfContents/Inspector.js around lines 10 - 11, Update the
import so BoxControl uses the stable export: replace __experimentalBoxControl
with BoxControl in the import list (keep __experimentalUnitControl as-is);
ensure the import line now reads to include BoxControl and
__experimentalUnitControl so references to BoxControl in Inspector.js resolve to
the stable component.
| {/* <PanelBody title={__('Advanced', 'dynamic-table-of-contents-block-wp')} initialOpen={false}> | ||
| <TextControl | ||
| label={__('Additional CSS class(es)', 'dynamic-table-of-contents-block-wp')} | ||
| value={additionalCssClass} | ||
| onChange={(value) => setAttributes({ additionalCssClass: value })} | ||
| help={__('Space-separated CSS classes', 'dynamic-table-of-contents-block-wp')} | ||
| /> | ||
| </PanelBody> */} |
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.
Commented code references undefined variable.
The commented Advanced panel references additionalCssClass (line 116), which is not destructured from attributes. If this code is uncommented in the future without first adding the variable to the destructuring block, it will cause a ReferenceError.
🔧 Fix if uncommenting this section
Add to the destructuring block at line 38:
listColor,
listHoverColor,
- listFontSize
+ listFontSize,
+ additionalCssClass
} = attributes;Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @src/blocks/TableOfContents/Inspector.js around lines 113 - 122, The
commented Advanced Panel in Inspector.js references the attribute
additionalCssClass but that variable is not included in the attributes
destructuring, which will throw a ReferenceError if the block is ever
uncommented; fix by adding additionalCssClass to the attributes destructuring
(where other attributes are pulled out, e.g., in the TableOfContentsInspector or
the functional component's props destructuring around the existing attributes
block) so additionalCssClass and its usage with setAttributes are defined and
safe to uncomment.
Introduces a new 'Helpful Feedback' block with customizable voting buttons, styling options, and server-side rendering for docs articles. Updates Contributors block to restrict rendering to docs post type and registers the new block in the main index.
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: 13
🤖 Fix all issues with AI agents
In @src/blocks/Contributors/render.php:
- Around line 156-165: Remove the hard-coded demo contributor array set to
$contributors when empty; instead either return empty output or show an
admin-only message. Replace the current block that assigns the mock (the array
with 'ID' => 1, 'display_name' => 'Demo Author', 'user_email' =>
'demo@example.com') with one of: 1) leave $contributors empty and
return/continue rendering nothing, 2) wrap a debug-only fallback behind a flag
like WP_DEBUG or a custom is_dev() check, or 3) display a message only to admins
using current_user_can('manage_options') before emitting any placeholder. Ensure
no mock data is present in production by removing the literal array assignment
to $contributors.
- Around line 100-151: The 'all' case mishandles wedocs_contributors as both
array and scalar causing duplicates and type errors; update the logic in the
switch 'all' branch to first retrieve and validate the contributors data from
get_post_field('wedocs_contributors', $post->ID) (ensure it exists and is an
array or decode it if stored as JSON), normalize it into an array (e.g.,
$author_ids), iterate that array to populate $contributors via get_userdata($id)
while tracking seen IDs to avoid duplicates, remove the redundant scalar check
that treats $author_id as a single ID, and then merge additional unique revision
authors into the same seen set before adding their userdata.
- Line 395: The file currently calls echo
render_wedocs_contributors_block($attributes, $content, $block) at file scope;
remove that call so the function render_wedocs_contributors_block is only
defined and not invoked on include. Ensure the function definition remains in
place and that block.json registers this function as the render callback (so
WordPress will call it with the proper $attributes, $content, $block when
rendering the block).
In @src/blocks/HelpfulFeedback/edit.js:
- Around line 104-113: The containerStyle object can throw if containerPadding
or containerMargin is undefined; update the code that builds containerStyle
(and/or create safePadding/safeMargin helper objects) to use optional chaining
or fallbacks for top/right/bottom/left (e.g., derive safe values from
containerPadding?.top ?? 0 etc.) so padding and margin string interpolation
never accesses undefined properties; apply the same defensive fallback for
containerBorderRadius and containerBorderWidth if needed to avoid runtime errors
when those props are missing.
In @src/blocks/HelpfulFeedback/render.php:
- Around line 37-38: The code reads $_COOKIE['wedocs_response'] directly;
instead retrieve and sanitize the cookie before exploding and comparing to
$post_id: get the raw cookie (e.g., via filter_input(INPUT_COOKIE,
'wedocs_response') or isset($_COOKIE['wedocs_response'])), run wp_unslash() and
sanitize_text_field() (or appropriate sanitizer), then explode into an array and
cast/clean each element (e.g., array_map('intval') or
array_map('sanitize_text_field')) before assigning to $previous and using
in_array($post_id, $previous, true) to ensure safe, type-strict comparison.
- Line 302: Replace raw translation outputs that use _e() with the escaped
helper esc_html_e() to ensure translated strings are escaped for HTML;
specifically update the calls rendering "You found this helpful", "Yes", and
"No" (the _e('You found this helpful', 'wedocs'), _e('Yes', 'wedocs'), and
_e('No', 'wedocs') usages in the HelpfulFeedback render) to use esc_html_e()
instead so translation output is safely escaped.
- Line 26: The code directly assigns $_SERVER['REMOTE_ADDR'] to $user_ip without
sanitization; change the assignment so you read the value safely (e.g., $raw_ip
= $_SERVER['REMOTE_ADDR'] ?? '';), then validate it with filter_var($raw_ip,
FILTER_VALIDATE_IP) and only assign the validated value to $user_ip (or set to
an empty string/null if invalid). Update the code around the $user_ip variable
in render.php to use this validation and avoid trusting the superglobal raw
value.
- Around line 13-19: The file contains top-level render logic that must be
wrapped in the project's standard render callback; create a function named
render_wedocs_helpful_feedback_block($attributes, $content, $block) and move the
existing code (including the get_post_type() check and ob_start()/ob_get_clean()
flow) into that function, adjust indentation, and return the buffered output
(use return ob_get_clean() instead of echo); ensure the function signature
matches other blocks so it can be used as the render callback.
In @src/blocks/HelpfulFeedback/save.js:
- Around line 1-5: Remove the unused import by deleting the "useBlockProps"
import statement at the top of the file since the Save component returns null
for server-side rendering; update the import list in
src/blocks/HelpfulFeedback/save.js so only necessary imports remain (keep the
Save function as-is returning null).
In @src/blocks/HelpfulFeedback/view.js:
- Around line 141-154: The template injects thankYouMessage directly into
thankYouContent, creating an XSS risk; fix it by escaping or encoding the
message before interpolation (e.g., create an escapeHtml utility or use a DOM
text node and textContent) and replace thankYouMessage with
escapedThankYouMessage in the thankYouContent construction; update the code that
builds thankYouContent (the template literal block) to use the escaped value and
ensure any helper is reused wherever thankYouMessage is interpolated.
In @src/blocks/HelpfulModal/render.php:
- Around line 140-151: The declared global function get_help_icon_svg can
collide with other blocks; refactor it into a uniquely namespaced/static class
method (e.g., HelpfulModal::getHelpIconSvg or HelpfulModal_get_help_icon_svg)
and move the SVG map into that class, then replace all calls to
get_help_icon_svg(...) with the new static method name to avoid function_exists
guards and unintended override; ensure the method signature and return behavior
remain the same.
In @wedocs.php:
- Around line 179-180: The code enqueues 'wedocs-admin-script' on init which can
race with Assets::register() / register_blocks() and also loads on the frontend;
change it so the script is enqueued only after registration and only in
admin/editor context by moving the enqueue call into an admin_enqueue_scripts
callback (or guard it with is_admin() || current_user_can('edit_posts')) and
ensure it runs after Assets::register() / register_blocks() so
'wedocs-admin-script' is registered before calling wp_enqueue_script.
🧹 Nitpick comments (18)
src/blocks/Contributors/render.php (1)
12-12: Optional: Consider documenting unused callback parameters.Static analysis flags
$contentand$blockas unused. While these are part of the WordPress render callback signature, consider:
- Adding
@SuppressWarningsor similar annotation if they're intentionally unused- Verifying whether
$blockcontext might be useful for future enhancements- Using
@paramdocumentation to clarify they're part of the required WordPress signaturesrc/blocks/HelpfulModal/index.js (2)
2-6: Fix inconsistent comment indentation.The JSDoc comment block has extra leading spaces before
/**, which is inconsistent with standard formatting conventions.♻️ Proposed fix
- - /** +/** * Registers a new block provided a unique name and an object defining its behavior. * * @see https://developer.wordpress.org/block-editor/reference-guides/block-api/block-registration/ */
35-35: Remove trailing whitespace.Line 35 contains trailing whitespace that should be removed for code cleanliness.
src/blocks/HelpfulModal/style.scss (1)
43-43: Consider using a lower z-index value.The z-index of
99999is extremely high and may conflict with other WordPress plugins, themes, or admin UI elements that use high z-index values. WordPress admin bar typically uses z-index around 99999-100000, which could cause overlap issues.Consider using a more moderate z-index value (e.g., 10000-50000) to reduce the likelihood of conflicts while still ensuring the modal appears above most content.
♻️ Proposed fix
- z-index: 99999; + z-index: 10000;src/blocks/HelpfulFeedback/index.js (1)
1-5: Standardize quote style for consistency.This file uses double quotes for imports, while other block files in the PR (e.g.,
src/blocks/HelpfulModal/index.js) use single quotes. For consistency across the codebase, consider standardizing on one quote style.♻️ Proposed fix
-import { registerBlockType } from "@wordpress/blocks"; -import Edit from "./edit"; -import Save from "./save"; -import metadata from "./block.json"; -import "./style.scss"; +import { registerBlockType } from '@wordpress/blocks'; +import Edit from './edit'; +import Save from './save'; +import metadata from './block.json'; +import './style.scss';src/blocks/index.js (2)
7-7: Remove trailing whitespace.Line 7 contains trailing whitespace that should be removed for code cleanliness.
8-73: Remove or document commented out imports.There are 65+ lines of commented out block imports. Consider one of the following approaches:
- If these blocks are not being developed: Remove the commented code entirely to reduce clutter and maintenance burden.
- If these are planned features: Remove the comments and track these features in GitHub issues or a project roadmap instead.
- If temporarily disabled: Add a clear comment explaining why they're disabled and when they'll be re-enabled.
Leaving large amounts of commented code in the codebase creates confusion for future maintainers and increases the risk of merge conflicts.
Example approach
If these are planned features:
-// import './Breadcrumbs'; -// import './CategoryDocs'; -// ... (63 more lines) +// Future block implementations tracked in: +// - Issue #XXX: Documentation blocks (Breadcrumbs, CategoryDocs, etc.) +// - Issue #YYY: Engagement blocks (DocRating, DocFeedback, etc.)Or simply remove them if not actively planned.
src/blocks/HelpfulFeedback/view.js (1)
123-126: Consider extracting duplicate SVG icons to a shared module.These SVG icon paths are duplicated across
view.js,edit.js, andrender.php. Extracting them to a shared constants file would improve maintainability.src/blocks/HelpfulFeedback/edit.js (1)
4-4: Unused import:RichText.
RichTextis imported but never used in this component.♻️ Remove unused import
-import { useBlockProps, InspectorControls, RichText } from '@wordpress/block-editor'; +import { useBlockProps, InspectorControls } from '@wordpress/block-editor';src/blocks/HelpfulFeedback/style.scss (1)
218-227: Consider prefixing thefadeInkeyframe name.The
fadeInkeyframe name is generic and could conflict with other stylesheets. A prefixed name likewedocs-fadeInwould prevent potential conflicts.♻️ Suggested naming
- @keyframes fadeIn { + @keyframes wedocs-fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }And update the animation reference:
- animation: fadeIn 0.3s ease-in-out; + animation: wedocs-fadeIn 0.3s ease-in-out;src/blocks/HelpfulFeedback/render.php (1)
253-255: Consider escaping vote count output for consistency.While
$yes_votesand$no_votesare cast to integers (line 29-30), it's a WordPress best practice to escape all output. Usingesc_html()would add defense-in-depth.♻️ Suggested consistency improvement
- <span class="vote-count">(<?php echo $yes_votes; ?>)</span> + <span class="vote-count">(<?php echo esc_html($yes_votes); ?>)</span>src/blocks/HelpfulModal/edit.js (2)
36-36: Unused icon imports from@wordpress/icons.
help,info, andgetIconfunction (lines 120-142) renders custom inline SVGs instead.♻️ Remove unused imports
-import { settings, help, info, email } from '@wordpress/icons'; +import { settings } from '@wordpress/icons';
28-28: Use the customBorderControlcomponent for consistency.The custom
BorderControlcomponent atsrc/blocks/components/BorderControl.jsis used in active blocks like Contributors, but HelpfulModal imports the experimental WordPress__experimentalBorderControlinstead. Update this to import from the custom components for consistency with other similar blocks.wedocs.php (5)
49-49: Consider using consistent path resolution.Line 48 uses
__DIR__while this line usesplugin_dir_path(__FILE__). Both work, but consistency improves readability.♻️ Suggested refactor for consistency
-require_once plugin_dir_path(__FILE__) . 'src/blocks/helpers/block-styles.php'; +require_once __DIR__ . '/src/blocks/helpers/block-styles.php';
186-186: Remove or document commented-out code.The commented-out
AdvanceContributorsblock suggests incomplete development. Either remove it or add a TODO comment explaining why it's disabled.
178-202: Consider enqueuing scripts only in block editor context.The
wedocs-admin-scriptis enqueued on everyinitaction, including frontend requests. For better performance, consider enqueuing it only when the block editor is loaded.♻️ Suggested improvement for editor-only enqueuing
public function register_blocks() { - // Enqueue admin script early to make weDocsAdminScriptVars available for blocks - wp_enqueue_script( 'wedocs-admin-script' ); - // Modern WordPress block registration using block.json files $block_directories = [Instead, ensure the script is enqueued via
block.jsoneditorScriptproperty or in anenqueue_block_editor_assetshook.
347-356: Prevent potential duplicate block categories.The filter always appends the 'wedocs' category without checking if it already exists, which could create duplicates if the filter runs multiple times or another plugin adds the same category.
♻️ Suggested fix to prevent duplicates
add_filter( 'block_categories_all', function( $categories, $post ) { - // Add "wedocs" category if not already there - $categories[] = array( - 'slug' => 'wedocs', - 'title' => __( 'weDocs Blocks', 'wedocs' ), - 'icon' => null, // optional, doesn't show everywhere - ); - + // Check if category already exists + $category_exists = false; + foreach ( $categories as $category ) { + if ( isset( $category['slug'] ) && $category['slug'] === 'wedocs' ) { + $category_exists = true; + break; + } + } + + // Add "wedocs" category if not already there + if ( ! $category_exists ) { + $categories[] = array( + 'slug' => 'wedocs', + 'title' => __( 'weDocs Blocks', 'wedocs' ), + 'icon' => null, + ); + } + return $categories; }, 10, 2 );
347-356: Unused$postparameter.The filter callback declares a
$postparameter but never uses it. You can either remove it or suppress the unused variable warning with@paramannotation.♻️ Option 1: Remove unused parameter
-add_filter( 'block_categories_all', function( $categories, $post ) { +add_filter( 'block_categories_all', function( $categories ) {
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (18)
src/blocks/Contributors/render.phpsrc/blocks/HelpfulFeedback/block.jsonsrc/blocks/HelpfulFeedback/edit.jssrc/blocks/HelpfulFeedback/index.jssrc/blocks/HelpfulFeedback/render.phpsrc/blocks/HelpfulFeedback/save.jssrc/blocks/HelpfulFeedback/style.scsssrc/blocks/HelpfulFeedback/view.jssrc/blocks/HelpfulModal/block.jsonsrc/blocks/HelpfulModal/edit.jssrc/blocks/HelpfulModal/editor.scsssrc/blocks/HelpfulModal/index.jssrc/blocks/HelpfulModal/render.phpsrc/blocks/HelpfulModal/save.jssrc/blocks/HelpfulModal/style.scsssrc/blocks/HelpfulModal/view.jssrc/blocks/index.jswedocs.php
✅ Files skipped from review due to trivial changes (4)
- src/blocks/HelpfulModal/save.js
- src/blocks/HelpfulModal/editor.scss
- src/blocks/HelpfulFeedback/block.json
- src/blocks/HelpfulModal/block.json
🧰 Additional context used
🧬 Code graph analysis (8)
src/blocks/HelpfulFeedback/edit.js (1)
src/blocks/CustomControls/RadioImageControl.js (1)
RadioImageControl(3-26)
src/blocks/HelpfulFeedback/view.js (2)
src/utils/menuFix.js (1)
$(2-2)assets/js/frontend.js (1)
data(163-166)
src/blocks/HelpfulModal/edit.js (2)
src/blocks/components/BorderControl.js (1)
BorderControl(11-116)src/blocks/helpers/block-helpers.js (1)
p(35-35)
src/blocks/HelpfulModal/render.php (1)
src/blocks/HelpfulModal/edit.js (1)
attributes(55-104)
src/blocks/Contributors/render.php (1)
src/blocks/helpers/block-styles.php (8)
wedocs_build_background_styles(134-152)wedocs_build_spacing_styles(58-70)wedocs_build_border_styles(81-101)wedocs_build_shadow_styles(109-123)wedocs_build_element_styles(179-228)wedocs_generate_block_id(160-162)wedocs_styles_to_css(236-242)wedocs_generate_responsive_css(251-281)
src/blocks/HelpfulModal/index.js (1)
src/blocks/HelpfulModal/edit.js (1)
Edit(54-690)
src/blocks/HelpfulFeedback/render.php (1)
src/blocks/HelpfulFeedback/edit.js (1)
attributes(22-69)
src/blocks/HelpfulFeedback/index.js (2)
src/blocks/HelpfulFeedback/edit.js (1)
Edit(19-511)src/blocks/HelpfulFeedback/save.js (1)
Save(3-5)
🪛 PHPMD (2.15.0)
src/blocks/Contributors/render.php
12-12: Avoid unused parameters such as '$content'. (undefined)
(UnusedFormalParameter)
12-12: Avoid unused parameters such as '$block'. (undefined)
(UnusedFormalParameter)
🔇 Additional comments (12)
src/blocks/Contributors/render.php (3)
11-17: LGTM: Function guard and post validation.The function existence check and early return for non-docs post types are appropriate defensive patterns.
167-344: LGTM: Avatar styling and HTML output generation.The avatar styling (lines 167-203), element style building (lines 205-230), and HTML output generation (lines 232-344) demonstrate good practices:
- Proper use of helper functions from
block-styles.php- Consistent output escaping (
esc_attr,esc_html,esc_url)- Flexible avatar rendering (user avatar or default icon)
- Configurable link behavior
- Optional schema.org markup support
346-391: LGTM: Responsive CSS generation.The responsive CSS implementation properly uses the
wedocs_generate_responsive_csshelper function and includes:
- Tablet and mobile breakpoints
- Accessibility considerations (prefers-reduced-motion)
- Hover effects with CSS custom properties
- Proper CSS variable fallbacks
src/blocks/HelpfulFeedback/view.js (1)
6-71: Well-structured AJAX voting implementation.Good use of class-based organization, proper loading state management, and comprehensive error handling with context-aware messages (403, 429 status codes). The event binding delegation pattern (
$(document).on) is appropriate for dynamically rendered content.src/blocks/HelpfulFeedback/edit.js (1)
10-16: Usage of experimental WordPress components.Multiple
__experimentalprefixed components are used (BoxControl,BorderControl,ToolsPanel,ToolsPanelItem). These APIs may change in future WordPress releases. Consider monitoring WordPress core updates for API stability.src/blocks/HelpfulModal/render.php (1)
198-199: JSON data output is properly encoded.Good use of
wp_json_encode()for the modal data script, which properly escapes special characters for safe JSON output.src/blocks/HelpfulFeedback/style.scss (1)
38-49: Excellent accessibility implementation.Good attention to accessibility: minimum touch target size (44px), visible focus indicators, and proper disabled state styling. The reduced motion and high contrast media queries are also well implemented.
src/blocks/HelpfulModal/view.js (2)
257-265: Good XSS protection withescapeHtmlhelper.Properly escapes HTML entities for user-provided content in the modal. All dynamic content (title, labels, placeholder, button text) is correctly escaped before insertion.
133-139: Good defensive check for AJAX configuration.Properly validates that
needMoreHelpAjaxis defined before attempting form submission, with a user-friendly error message.src/blocks/HelpfulModal/edit.js (2)
145-153: Good defensive coding in style computation.Proper use of ternary operators to handle potentially undefined
containerPaddingandcontainerMarginvalues, with sensible fallbacks.
585-686: Well-implemented editor modal preview.Good UX with a toggle-able modal preview in the editor. The form properly prevents default submission (line 679), and the overlay click closes the modal. This allows content editors to preview their changes without leaving the editor.
wedocs.php (1)
336-343: LGTM! Good performance optimization.The function correctly dequeues pro frontend CSS on non-docs pages to prevent unnecessary asset loading. The logic covers all relevant docs-related contexts (singular, archive, taxonomies), and the priority of 20 ensures it runs after the styles are enqueued.
| if (empty($contributors)) { | ||
| // For demo purposes, add mock contributors if none found | ||
| $contributors = [ | ||
| (object) [ | ||
| 'ID' => 1, | ||
| 'display_name' => 'Demo Author', | ||
| 'user_email' => 'demo@example.com' | ||
| ] | ||
| ]; | ||
| } |
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.
Remove or guard mock contributor data.
The mock/demo contributor data on lines 158-164 should not appear in production code. If no contributors are found, consider:
- Returning empty output
- Displaying a message to administrators only
- Moving mock data behind a development/debug flag
Currently, this mock data could appear on live documentation pages if the contributor logic fails, which would be confusing to end users.
💡 Suggested fix to remove mock data
// Filter out invalid contributors
$contributors = array_filter($contributors);
if (empty($contributors)) {
- // For demo purposes, add mock contributors if none found
- $contributors = [
- (object) [
- 'ID' => 1,
- 'display_name' => 'Demo Author',
- 'user_email' => 'demo@example.com'
- ]
- ];
+ return ''; // No contributors to display
}Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @src/blocks/Contributors/render.php around lines 156 - 165, Remove the
hard-coded demo contributor array set to $contributors when empty; instead
either return empty output or show an admin-only message. Replace the current
block that assigns the mock (the array with 'ID' => 1, 'display_name' => 'Demo
Author', 'user_email' => 'demo@example.com') with one of: 1) leave $contributors
empty and return/continue rendering nothing, 2) wrap a debug-only fallback
behind a flag like WP_DEBUG or a custom is_dev() check, or 3) display a message
only to admins using current_user_can('manage_options') before emitting any
placeholder. Ensure no mock data is present in production by removing the
literal array assignment to $contributors.
|
|
||
| return $output; | ||
| } | ||
| echo render_wedocs_contributors_block($attributes, $content, $block); |
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.
Critical: Remove incorrect echo statement.
Line 395 attempts to call the function at file scope, which is incorrect for WordPress block render callbacks. This will cause errors because:
$attributes,$content, and$blockare undefined at this scope- WordPress automatically calls the render callback when the block is rendered
- This echo will execute on every file include, not during block rendering
The function should only be defined here, not called. WordPress will invoke it via the render callback mechanism defined in block.json.
🐛 Proposed fix
return $output;
}
-echo render_wedocs_contributors_block($attributes, $content, $block);
}Note: Ensure block.json properly registers this function as the render callback.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @src/blocks/Contributors/render.php at line 395, The file currently calls
echo render_wedocs_contributors_block($attributes, $content, $block) at file
scope; remove that call so the function render_wedocs_contributors_block is only
defined and not invoked on include. Ensure the function definition remains in
place and that block.json registers this function as the render callback (so
WordPress will call it with the proper $attributes, $content, $block when
rendering the block).
| const containerStyle = { | ||
| backgroundColor: containerBgColor, | ||
| padding: `${containerPadding.top} ${containerPadding.right} ${containerPadding.bottom} ${containerPadding.left}`, | ||
| margin: `${containerMargin.top} ${containerMargin.right} ${containerMargin.bottom} ${containerMargin.left}`, | ||
| border: containerBorderStyle !== 'none' ? `${containerBorderWidth.top} ${containerBorderStyle} ${containerBorderColor}` : 'none', | ||
| borderRadius: `${containerBorderRadius.top} ${containerBorderRadius.right} ${containerBorderRadius.bottom} ${containerBorderRadius.left}`, | ||
| boxShadow: containerBoxShadow, | ||
| textAlign: alignment, | ||
| transition: 'all 0.3s ease' | ||
| }; |
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.
Potential runtime error when accessing nested padding/margin properties.
If containerPadding or containerMargin is undefined, accessing .top, .right, etc. will throw an error. Consider using optional chaining or providing fallback objects.
🛡️ Suggested defensive coding
const containerStyle = {
backgroundColor: containerBgColor,
- padding: `${containerPadding.top} ${containerPadding.right} ${containerPadding.bottom} ${containerPadding.left}`,
- margin: `${containerMargin.top} ${containerMargin.right} ${containerMargin.bottom} ${containerMargin.left}`,
+ padding: containerPadding ? `${containerPadding.top} ${containerPadding.right} ${containerPadding.bottom} ${containerPadding.left}` : undefined,
+ margin: containerMargin ? `${containerMargin.top} ${containerMargin.right} ${containerMargin.bottom} ${containerMargin.left}` : undefined,🤖 Prompt for AI Agents
In @src/blocks/HelpfulFeedback/edit.js around lines 104 - 113, The
containerStyle object can throw if containerPadding or containerMargin is
undefined; update the code that builds containerStyle (and/or create
safePadding/safeMargin helper objects) to use optional chaining or fallbacks for
top/right/bottom/left (e.g., derive safe values from containerPadding?.top ?? 0
etc.) so padding and margin string interpolation never accesses undefined
properties; apply the same defensive fallback for containerBorderRadius and
containerBorderWidth if needed to avoid runtime errors when those props are
missing.
| // Check if this is a docs post type | ||
| if (get_post_type() !== 'docs') { | ||
| return ''; | ||
| } | ||
|
|
||
| // Start output buffering | ||
| ob_start(); |
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
🏁 Script executed:
#!/bin/bash
# First, let's see the actual structure of the file in question
echo "=== Structure of src/blocks/HelpfulFeedback/render.php ==="
head -50 src/blocks/HelpfulFeedback/render.php
echo ""
echo "=== Total lines in file ==="
wc -l src/blocks/HelpfulFeedback/render.php
echo ""
echo "=== Checking for function definitions ==="
rg 'function|fn\s+\(' src/blocks/HelpfulFeedback/render.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 1975
🏁 Script executed:
#!/bin/bash
# Compare with other render.php files
echo "=== Other render.php files in src/blocks ==="
fd -e php -p 'render\.php$' src/blocks
echo ""
echo "=== Structure of a few other render.php files (first 40 lines) ==="
for file in $(fd -e php -p 'render\.php$' src/blocks | head -3); do
echo "--- File: $file ---"
head -40 "$file"
echo ""
doneRepository: weDevsOfficial/wedocs-plugin
Length of output: 5988
Structural issue: Code not wrapped in function callback.
All other render.php files in the project (AdvanceContributors, Contributors, DocsGrid) wrap their logic in a function definition. This file contains 398 lines of render logic indented as if inside a function, but with no function wrapper. The code should be wrapped in a render callback function consistent with the project's pattern:
function render_wedocs_helpful_feedback_block($attributes, $content, $block) {
// ... existing code with indentation corrected
}🤖 Prompt for AI Agents
In @src/blocks/HelpfulFeedback/render.php around lines 13 - 19, The file
contains top-level render logic that must be wrapped in the project's standard
render callback; create a function named
render_wedocs_helpful_feedback_block($attributes, $content, $block) and move the
existing code (including the get_post_type() check and ob_start()/ob_get_clean()
flow) into that function, adjust indentation, and return the buffered output
(use return ob_get_clean() instead of echo); ensure the function signature
matches other blocks so it can be used as the render callback.
|
|
||
| // Get current user ID or IP for vote tracking | ||
| $user_id = get_current_user_id(); | ||
| $user_ip = $_SERVER['REMOTE_ADDR'] ?? ''; |
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.
Unsanitized superglobal access: $_SERVER['REMOTE_ADDR'].
Direct access to $_SERVER['REMOTE_ADDR'] without sanitization. This value can be spoofed in some server configurations and should be sanitized.
🔒 Suggested fix
- $user_ip = $_SERVER['REMOTE_ADDR'] ?? '';
+ $user_ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : '';📝 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.
| $user_ip = $_SERVER['REMOTE_ADDR'] ?? ''; | |
| $user_ip = isset($_SERVER['REMOTE_ADDR']) ? sanitize_text_field(wp_unslash($_SERVER['REMOTE_ADDR'])) : ''; |
🤖 Prompt for AI Agents
In @src/blocks/HelpfulFeedback/render.php at line 26, The code directly assigns
$_SERVER['REMOTE_ADDR'] to $user_ip without sanitization; change the assignment
so you read the value safely (e.g., $raw_ip = $_SERVER['REMOTE_ADDR'] ?? '';),
then validate it with filter_var($raw_ip, FILTER_VALIDATE_IP) and only assign
the validated value to $user_ip (or set to an empty string/null if invalid).
Update the code around the $user_ip variable in render.php to use this
validation and avoid trusting the superglobal raw value.
| import { useBlockProps } from '@wordpress/block-editor'; | ||
|
|
||
| const Save = () => { | ||
| return null; | ||
| }; |
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 | 🟠 Major
Remove unused import.
The useBlockProps import is not used since the Save component returns null for server-side rendering. This unused import adds unnecessary code to the bundle.
♻️ Proposed fix
-import { useBlockProps } from '@wordpress/block-editor';
-
const Save = () => {
return null;
};🤖 Prompt for AI Agents
In @src/blocks/HelpfulFeedback/save.js around lines 1 - 5, Remove the unused
import by deleting the "useBlockProps" import statement at the top of the file
since the Save component returns null for server-side rendering; update the
import list in src/blocks/HelpfulFeedback/save.js so only necessary imports
remain (keep the Save function as-is returning null).
| const thankYouContent = ` | ||
| <div class="wedocs-feedback-thank-you"> | ||
| <div class="wedocs-feedback-title" style="color: #28a745; margin-bottom: 16px;"> | ||
| ${thankYouMessage} | ||
| </div> | ||
| <div class="wedocs-feedback-result"> | ||
| <div class="wedocs-feedback-voted-option voted-${vote}" style="display: flex; align-items: center; gap: 8px; justify-content: ${$container.hasClass('left') ? 'flex-start' : $container.hasClass('right') ? 'flex-end' : 'center'}; margin-bottom: 10px;"> | ||
| <span class="wedocs-feedback-icon">${voteIcon}</span> | ||
| ${voteText} | ||
| </div> | ||
| ${voteSummary} | ||
| </div> | ||
| </div> | ||
| `; |
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.
Potential XSS risk with thankYouMessage in template literal.
The thankYouMessage is inserted directly into the HTML template without escaping. While it comes from a data attribute, if the server-side doesn't properly sanitize this value, it could lead to XSS.
🔒 Suggested fix: Escape the thank you message
+ // Helper function to escape HTML
+ escapeHtml(text) {
+ const div = document.createElement('div');
+ div.textContent = text;
+ return div.innerHTML;
+ }
const thankYouContent = `
<div class="wedocs-feedback-thank-you">
<div class="wedocs-feedback-title" style="color: #28a745; margin-bottom: 16px;">
- ${thankYouMessage}
+ ${this.escapeHtml(thankYouMessage)}
</div>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @src/blocks/HelpfulFeedback/view.js around lines 141 - 154, The template
injects thankYouMessage directly into thankYouContent, creating an XSS risk; fix
it by escaping or encoding the message before interpolation (e.g., create an
escapeHtml utility or use a DOM text node and textContent) and replace
thankYouMessage with escapedThankYouMessage in the thankYouContent construction;
update the code that builds thankYouContent (the template literal block) to use
the escaped value and ensure any helper is reused wherever thankYouMessage is
interpolated.
| // Get icon SVG - guarded function to prevent redeclaration | ||
| if (!function_exists('get_help_icon_svg')) { | ||
| function get_help_icon_svg($type, $styles) { | ||
| $icons = [ | ||
| 'email' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 20q-.825 0-1.413-.588T2 18V6q0-.825.588-1.413T4 4h16q.825 0 1.413.588T22 6v12q0 .825-.588 1.413T20 20H4Zm8-7L4 8v10h16V8l-8 5Zm0-2 8-5H4l8 5ZM4 8V6v12V8Z"/></svg>', | ||
| 'help' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></svg>', | ||
| 'info' => '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>' | ||
| ]; | ||
|
|
||
| return sprintf('<span style="%s">%s</span>', $styles, $icons[$type] ?? $icons['email']); | ||
| } | ||
| } |
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.
Function guard pattern may cause unexpected behavior.
Using function_exists() to guard function declaration means if get_help_icon_svg is defined elsewhere (e.g., in another block's render.php loaded first), this block will use that implementation instead. Consider namespacing or using a class method to avoid conflicts.
♻️ Suggested approach using a class or unique function name
-if (!function_exists('get_help_icon_svg')) {
- function get_help_icon_svg($type, $styles) {
+if (!function_exists('wedocs_get_help_icon_svg')) {
+ function wedocs_get_help_icon_svg($type, $styles) {Then update the call on line 182:
- <?php echo get_help_icon_svg($icon_type, $icon_styles); ?>
+ <?php echo wedocs_get_help_icon_svg($icon_type, $icon_styles); ?>Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In @src/blocks/HelpfulModal/render.php around lines 140 - 151, The declared
global function get_help_icon_svg can collide with other blocks; refactor it
into a uniquely namespaced/static class method (e.g.,
HelpfulModal::getHelpIconSvg or HelpfulModal_get_help_icon_svg) and move the SVG
map into that class, then replace all calls to get_help_icon_svg(...) with the
new static method name to avoid function_exists guards and unintended override;
ensure the method signature and return behavior remain the same.
| // Close on escape key | ||
| document.addEventListener('keydown', function(e) { | ||
| if (e.key === 'Escape' && modal.classList.contains('show')) { | ||
| closeModal(); | ||
| } | ||
| }); |
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.
Document-level keydown listener added per block instance.
Each block instance adds a new keydown listener to document. If multiple blocks exist on a page, this creates redundant listeners. Consider using event delegation or a singleton pattern.
♻️ Suggested improvement
+// Track if escape handler is already registered
+let escapeHandlerRegistered = false;
+const modalInstances = new Set();
function initializeHelpBlock(block) {
// ... existing code ...
+ modalInstances.add(modal);
+
- // Close on escape key
- document.addEventListener('keydown', function(e) {
- if (e.key === 'Escape' && modal.classList.contains('show')) {
- closeModal();
- }
- });
+ // Register escape handler once
+ if (!escapeHandlerRegistered) {
+ document.addEventListener('keydown', function(e) {
+ if (e.key === 'Escape') {
+ modalInstances.forEach(m => {
+ if (m.classList.contains('show')) {
+ m.classList.remove('show');
+ document.body.style.overflow = '';
+ }
+ });
+ }
+ });
+ escapeHandlerRegistered = true;
+ }Committable suggestion skipped: line range outside the PR's diff.
| // Enqueue admin script early to make weDocsAdminScriptVars available for blocks | ||
| wp_enqueue_script( 'wedocs-admin-script' ); |
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
🏁 Script executed:
# First, find wedocs.php and view the context around lines 179-180
find . -name "wedocs.php" -type fRepository: weDevsOfficial/wedocs-plugin
Length of output: 84
🏁 Script executed:
# View the context around lines 179-180 in wedocs.php
sed -n '170,210p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 1414
🏁 Script executed:
# Search for where wedocs-admin-script is registered
rg "wedocs-admin-script" -nRepository: weDevsOfficial/wedocs-plugin
Length of output: 330
🏁 Script executed:
# View the Assets.php file to see script registration
sed -n '1,100p' ./includes/Assets.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 3344
🏁 Script executed:
# Check the full Assets.php to see the admin_enqueue method
sed -n '150,170p' ./includes/Assets.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 817
🏁 Script executed:
# Check if there are any other registrations or if the order is guaranteed
# Look at the class structure to see how Assets is instantiated
grep -rn "new Assets" . --include="*.php"Repository: weDevsOfficial/wedocs-plugin
Length of output: 54
🏁 Script executed:
# Check how the plugin initializes - look at the main wedocs.php file
sed -n '1,50p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 1728
🏁 Script executed:
# Look for the plugin initialization and where Assets is instantiated
grep -rn "Assets" ./wedocs.php | head -20Repository: weDevsOfficial/wedocs-plugin
Length of output: 142
🏁 Script executed:
# Find where the main plugin class is instantiated and when Assets is initialized
sed -n '200,250p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 1430
🏁 Script executed:
# Check when init_classes is called - look for the main plugin initialization
sed -n '80,150p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 1824
🏁 Script executed:
# Look for the init_actions method to see the order of hook registration
grep -n "init_actions" ./wedocs.php
sed -n '160,175p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 601
🏁 Script executed:
# Let me verify the execution order by checking the hooks more carefully
# Get the full init_actions and constructor
sed -n '100,110p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 358
🏁 Script executed:
# Check the bottom of wedocs.php to see when WeDocs is instantiated
tail -20 ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 810
🏁 Script executed:
# Find where WeDocs::init() is called
grep -n "WeDocs::init()" ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 102
🏁 Script executed:
# Get the context around line 326
sed -n '320,330p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 202
🏁 Script executed:
# Let me trace the execution order more carefully
# Check if there's any conditional logic around enqueuing in register_blocks
sed -n '175,195p' ./wedocs.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 864
Enqueue wedocs-admin-script only in admin/editor context and after registration is guaranteed.
The script is enqueued on the init hook without verifying registration has completed, creating a potential race condition since both Assets::register() and register_blocks() are hooked to init with the same priority. Additionally, enqueuing on init means the script loads on the frontend unnecessarily—the comment itself indicates this is for block editor support only. Move the enqueue to admin_enqueue_scripts or wrap it with is_admin() / current_user_can( 'edit_posts' ) to ensure it only loads where needed.
🤖 Prompt for AI Agents
In @wedocs.php around lines 179 - 180, The code enqueues 'wedocs-admin-script'
on init which can race with Assets::register() / register_blocks() and also
loads on the frontend; change it so the script is enqueued only after
registration and only in admin/editor context by moving the enqueue call into an
admin_enqueue_scripts callback (or guard it with is_admin() ||
current_user_can('edit_posts')) and ensure it runs after Assets::register() /
register_blocks() so 'wedocs-admin-script' is registered before calling
wp_enqueue_script.
Replaced all instances of the 'block-responsive' text domain with 'wedocs' in ColorsControls.js for consistency with the plugin's localization. Also fixed a variable reference in ListItems.js to use attributes.containerBackgroundColor directly.
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: 1
🤖 Fix all issues with AI agents
In @src/blocks/TableOfContents/ColorsControls.js:
- Around line 1-14: Update the import/notes so TabPanel is not treated as
experimental: ensure TabPanel is imported as the stable TabPanel (no
__experimental prefix) and only DropdownContentWrapper, HStack, Text, and ZStack
use the __experimental* names; remove TabPanel from any comment or component
list that claims five experimental components and leave the four actual
experimental imports unchanged.
🧹 Nitpick comments (5)
src/blocks/TableOfContents/ColorsControls.js (5)
22-28: Consider usinguseSettingfor consistency.The codebase uses
useSetting('color.palette')in BorderAndShadowControls.js to fetch theme colors, but this component usesselect('core/block-editor').getSettings(). For consistency and to follow newer WordPress patterns, consider using:const themeColors = useSetting('color.palette'); const themeGradients = useSetting('color.gradients');Based on learnings from related code in the codebase.
♻️ Proposed refactor using useSetting
+import { useSetting } from '@wordpress/block-editor'; + const ColorsControls = ({ attributes, setAttributes, device }) => { const { colorsControls } = attributes; const currentColors = colorsControls[device] || {}; - // Fetch theme colors and gradients - const { themeColors, themeGradients } = useSelect((select) => { - const editorSettings = select('core/block-editor').getSettings(); - return { - themeColors: editorSettings.colors, - themeGradients: editorSettings.gradients, - }; - }); + const themeColors = useSetting('color.palette'); + const themeGradients = useSetting('color.gradients');
47-47: Consider explicit className handling.The pattern
className={isOpen && 'is-open'}works but is less clear than explicit alternatives. Consider using a ternary operator for better readability:className={isOpen ? 'is-open' : ''}Also applies to: 101-101, 216-216
30-319: Consider extracting common color control logic.The three color controls (Text, Background, Link) share significant structural duplication:
- Similar Dropdown wrapper structure
- Repeated ColorPalette configuration (
colorsprop)- Nearly identical
onChangehandler patternsConsider extracting a reusable helper component or function to reduce duplication and improve maintainability.
Example refactor approach
const updateColorAttribute = (colorKey, colorValue) => { setAttributes({ colorsControls: { ...colorsControls, [device]: { ...currentColors, [colorKey]: colorValue, }, }, }); }; const colorPaletteProps = { enableAlpha: true, colors: [{ colors: themeColors, name: __('Theme', 'wedocs') }], };Then reuse these in each control to eliminate repetition.
165-166: Good use of nullish coalescing for GradientPicker.The explicit conversion to
null(instead ofundefined) for the GradientPicker value is good practice. Consider adding a brief comment explaining this difference from the ColorPalette components, as it may help future maintainers understand why this picker is treated differently.
322-346: Consider clarifying "Reset All" scope.The "Reset All" button only resets colors for the current device, not all devices. The button label could be more explicit to avoid user confusion:
text={__('Reset All Colors', 'wedocs')} // or text={sprintf(__('Reset %s Colors', 'wedocs'), device)}
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
package.jsonsrc/blocks/TableOfContents/ColorsControls.jssrc/blocks/TableOfContents/controls/ListItems.js
🚧 Files skipped from review as they are similar to previous changes (2)
- package.json
- src/blocks/TableOfContents/controls/ListItems.js
🧰 Additional context used
🧬 Code graph analysis (1)
src/blocks/TableOfContents/ColorsControls.js (1)
src/blocks/commonControls/BorderAndShadowControls.js (1)
themeColors(24-24)
| /* eslint-disable @wordpress/no-unsafe-wp-apis */ | ||
| import { __ } from '@wordpress/i18n'; | ||
| import { | ||
| Button, | ||
| ColorIndicator, | ||
| ColorPalette, | ||
| Dropdown, | ||
| __experimentalDropdownContentWrapper as DropdownContentWrapper, | ||
| GradientPicker, | ||
| __experimentalHStack as HStack, | ||
| TabPanel, | ||
| __experimentalText as Text, | ||
| __experimentalZStack as ZStack, | ||
| } from '@wordpress/components'; |
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
🏁 Script executed:
# First, verify the file exists and check its imports
cat -n src/blocks/TableOfContents/ColorsControls.js | head -20Repository: weDevsOfficial/wedocs-plugin
Length of output: 788
🏁 Script executed:
# Check usage of experimental components across the entire codebase
rg -n '__experimental(DropdownContentWrapper|HStack|TabPanel|Text|ZStack)' --type=jsRepository: weDevsOfficial/wedocs-plugin
Length of output: 1400
🏁 Script executed:
# Check if there are any tests for ColorsControls.js
fd -e test.js -e spec.js -e test.ts -e spec.ts | xargs rg -l 'ColorsControls' 2>/dev/null || echo "No test files found"Repository: weDevsOfficial/wedocs-plugin
Length of output: 283
🏁 Script executed:
# Check WordPress package versions in package.json to understand component stability
cat package.json | grep -A5 '@wordpress'Repository: weDevsOfficial/wedocs-plugin
Length of output: 710
TabPanel is not an experimental API; correct the component list.
The component uses four experimental WordPress components (DropdownContentWrapper, HStack, Text, ZStack), not five—TabPanel is imported without the __experimental prefix and is stable. While reliance on experimental APIs carries a small risk of future breaking changes, this pattern is consistent across the codebase (also used in BorderAndShadowControls, DimensionsControls, AiDocWriterPreview, and others), indicating an established approach. The existing ESLint disable comment and test coverage mitigate this concern.
🤖 Prompt for AI Agents
In @src/blocks/TableOfContents/ColorsControls.js around lines 1 - 14, Update the
import/notes so TabPanel is not treated as experimental: ensure TabPanel is
imported as the stable TabPanel (no __experimental prefix) and only
DropdownContentWrapper, HStack, Text, and ZStack use the __experimental* names;
remove TabPanel from any comment or component list that claims five experimental
components and leave the four actual experimental imports unchanged.
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: 8
🤖 Fix all issues with AI agents
In @src/blocks/AdvanceContributors/render.php:
- Around line 501-503: The call to render_wedocs_advance_contributors_block(
$attributes, $content, $block ) discards the function's returned $output; either
echo the return value where it’s invoked or change the function to directly
print (echo) instead of returning; locate the function
render_wedocs_advance_contributors_block and either (a) replace the bare call
with echo render_wedocs_advance_contributors_block( $attributes, $content,
$block ); or (b) modify the function so it outputs $output (echo) before
returning or returns void, ensuring the rendered content is actually sent to the
response.
- Line 458: The fallback uses PHP date() which ignores WP timezone; change the
assignment for $last_modified so the fallback uses wp_date() with a
timezone-aware timestamp: replace the date($date_format_string) call with
wp_date($date_format_string, current_time('timestamp')) while keeping the
existing use of get_the_modified_date($date_format_string, $post) for the post
case (refer to the $last_modified variable and functions wp_date(),
current_time(), and get_the_modified_date()).
- Around line 116-289: The nested definition of generate_responsive_css inside
render_wedocs_advance_contributors_block causes a "Cannot redeclare" fatal error
when the outer function runs multiple times; fix by moving
generate_responsive_css out of render_wedocs_advance_contributors_block (define
it at file scope) or, as a quick patch, wrap its declaration with a
function_exists('generate_responsive_css') check so it’s only defined once and
then update any calls inside render_wedocs_advance_contributors_block to use
that single global function.
In @src/blocks/Contributors/render.php:
- Line 336: The $last_modified assignment uses PHP's date() which ignores WP
timezone settings; update the fallback to use wp_date($date_format_string) so
that $last_modified = $post ? get_the_modified_date($date_format_string, $post)
: wp_date($date_format_string); ensuring timezone-aware formatting; keep
get_the_modified_date(...) unchanged.
- Around line 104-155: The 'all' branch misuses get_post_field and allows
duplicates: treat the main author and wedocs_contributors consistently by
retrieving the main author with get_post_field('post_author', $post->ID) and
normalizing wedocs_contributors into an array before iterating; build a unique
contributor_ids array (or use array_unique) to prevent duplicate additions, push
each contributor only if not already seen, and use get_userdata() for each id;
update variables $author_id/$authors to reflect these types and remove the
redundant push of $author_id that causes duplicates.
In @src/blocks/DocsGrid/render.php:
- Around line 176-182: The code sets $args['posts_per_page'] to the string '-1'
when $docs_per_page === 'all'; change that to the integer -1 so WP_Query
receives an integer (update the assignment in the render logic where
$args['posts_per_page'] is set for the 'all' branch); ensure $args['paged']
remains 1 in that branch.
- Around line 325-328: The file defines render_wedocs_docs_grid() but never
invokes it; add a top-level call to render_wedocs_docs_grid($attributes,
$content, $block) at the end of render.php (matching the Contributors/render.php
pattern) so the file-level render entrypoint executes when WordPress includes
the file, or alternatively update the block registration to supply
'render_callback' => 'render_wedocs_docs_grid' so WordPress will call that
function; ensure you pass the expected parameters ($attributes, $content,
$block) when invoking.
In @src/blocks/HelpfulModal/render.php:
- Line 107: The $modal_styles variable is declared but never populated—mirror
the pattern used for $modal_content_styles and $heading_styles by building
$modal_styles with sprintf() (e.g., include modal container CSS properties you
need: width, max-width, position, background, padding, etc.) before it is passed
into the JS payload so view.js:215-216 can use it; alternatively, if no
container-level styles are required, remove $modal_styles from the payload or
add a brief comment explaining it is intentionally empty and optional. Ensure
you reference and update the $modal_styles variable in
src/blocks/HelpfulModal/render.php where the other style vars are constructed so
the JS consumer receives meaningful data.
🧹 Nitpick comments (8)
src/blocks/DocsGrid/render.php (3)
187-187: Remove unused$total_pagesvariable or implement pagination controls.The variable is assigned but never used. If pagination is intended, the pagination UI should be implemented; otherwise, remove this unused variable.
Proposed fix (if pagination is not needed)
$docs_query = new WP_Query($args); $docs = $docs_query->posts; - $total_pages = $docs_query->max_num_pages;
232-233: Remove unused$total_articlesvariable.This variable is initialized to
0but never used or incremented. As flagged by static analysis.Proposed fix
$sections = get_posts($sections_query_args); - $total_articles = 0; ?>
188-216: Inline JavaScript should usewp_add_inline_scriptor be properly escaped.Outputting raw JavaScript via
echo $toggle_scriptbypasses WordPress's script handling and could pose maintenance challenges. Consider registering this script properly or at minimum, ensure the output is late enough in the render to avoid issues.src/blocks/Contributors/render.php (2)
160-169: Mock contributor fallback may expose unexpected data in production.Displaying a "Demo Author" with a fake email and ID=1 (which is typically the admin user) could be confusing in production. Consider returning an empty state message instead.
Proposed alternative
if (empty($contributors)) { - // For demo purposes, add mock contributors if none found - $contributors = [ - (object) [ - 'ID' => 1, - 'display_name' => 'Demo Author', - 'user_email' => 'demo@example.com' - ] - ]; + // Return empty if no contributors found + return '<div class="wedocs-contributors wedocs-contributors--empty">' . + esc_html__('No contributors found.', 'wedocs') . '</div>'; }
383-395: Inline CSS is duplicated on every block render.The responsive CSS and hover styles are output inline for each block instance. For pages with multiple contributor blocks, this creates duplicate CSS. Consider enqueueing these shared styles once via
wp_add_inline_style().src/blocks/AdvanceContributors/render.php (2)
10-14: Missingfunction_existsguard - inconsistent with other render files.Both
DocsGrid/render.phpandContributors/render.phpwrap their render functions withfunction_exists()checks. This file is missing that guard, which could cause issues if the file is included multiple times.Proposed fix
if (!defined('ABSPATH')) { exit; } + +if ( ! function_exists( 'render_wedocs_advance_contributors_block' ) ) { function render_wedocs_advance_contributors_block($attributes, $content, $block) {And close the guard at the end of the file (after line 502):
return $output; } +} render_wedocs_advance_contributors_block( $attributes, $content, $block );
104-113: Mock contributor fallback - same concern as Contributors block.Displaying mock data with ID=1 in production could be confusing or misleading. Consider a more graceful empty state.
src/blocks/HelpfulModal/render.php (1)
66-142: Consider extracting a style-building helper function.The style-building code follows a consistent pattern with multiple
sprintfcalls. While the current implementation is correct and safe (proper use ofesc_attr()), extracting this into a reusable helper function would reduce code duplication and improve maintainability.♻️ Example refactor using a helper function
function build_css_properties($properties) { $css = []; foreach ($properties as $property => $value) { if (is_array($value)) { foreach ($value as $key => $val) { $css[] = sprintf('%s-%s: %s', $property, $key, esc_attr($val)); } } else { $css[] = sprintf('%s: %s', $property, esc_attr($value)); } } return implode('; ', $css) . ';'; } // Usage example: $container_styles = build_css_properties([ 'background-color' => $container_background_color, 'padding' => $container_padding, 'margin' => $container_margin, // ... more properties ]);Note: This is an optional optimization and the current implementation is functionally correct.
📜 Review details
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/blocks/AdvanceContributors/render.phpsrc/blocks/Contributors/render.phpsrc/blocks/DocsGrid/render.phpsrc/blocks/HelpfulModal/render.phpsrc/blocks/TableOfContents/Inspector.js
🚧 Files skipped from review as they are similar to previous changes (1)
- src/blocks/TableOfContents/Inspector.js
🧰 Additional context used
🧬 Code graph analysis (4)
src/blocks/DocsGrid/render.php (2)
src/blocks/DocsGrid/save.js (1)
attributes(4-16)src/blocks/DocsGrid/edit.js (1)
attributes(20-48)
src/blocks/Contributors/render.php (1)
src/blocks/helpers/block-styles.php (8)
wedocs_build_background_styles(134-152)wedocs_build_spacing_styles(58-70)wedocs_build_border_styles(81-101)wedocs_build_shadow_styles(109-123)wedocs_build_element_styles(179-228)wedocs_generate_block_id(160-162)wedocs_styles_to_css(236-242)wedocs_generate_responsive_css(251-281)
src/blocks/HelpfulModal/render.php (2)
src/blocks/TableOfContents/Inspector.js (1)
attributes(16-38)src/blocks/HelpfulModal/edit.js (1)
attributes(55-104)
src/blocks/AdvanceContributors/render.php (4)
src/blocks/TableOfContents/Inspector.js (1)
attributes(16-38)src/blocks/TableOfContents/view.js (1)
content(153-153)src/components/Documentations/ParentDocs.js (1)
contributors(54-58)src/blocks/helpers/block-helpers.js (1)
border(173-173)
🪛 PHPMD (2.15.0)
src/blocks/DocsGrid/render.php
187-187: Avoid unused local variables such as '$total_pages'. (undefined)
(UnusedLocalVariable)
232-232: Avoid unused local variables such as '$total_articles'. (undefined)
(UnusedLocalVariable)
src/blocks/Contributors/render.php
16-16: Avoid unused parameters such as '$content'. (undefined)
(UnusedFormalParameter)
16-16: Avoid unused parameters such as '$block'. (undefined)
(UnusedFormalParameter)
src/blocks/AdvanceContributors/render.php
14-14: Avoid unused parameters such as '$content'. (undefined)
(UnusedFormalParameter)
14-14: Avoid unused parameters such as '$block'. (undefined)
(UnusedFormalParameter)
🔇 Additional comments (9)
src/blocks/DocsGrid/render.php (2)
9-12: LGTM - ABSPATH guard properly implemented.The direct access prevention is correctly placed at the top of the file.
14-42: LGTM - Pagination style function with proper escaping.The
get_pagination_style_tagfunction correctly usesesc_attr()for all CSS variable values and is properly guarded against redeclaration.src/blocks/Contributors/render.php (1)
10-13: LGTM - ABSPATH guard properly implemented.src/blocks/AdvanceContributors/render.php (1)
52-99: LGTM - Contributor fetching logic is well-structured.The switch statement properly handles all display modes with appropriate null checks and deduplication for revision authors.
src/blocks/HelpfulModal/render.php (5)
1-8: LGTM!The direct access prevention check follows WordPress best practices.
10-64: LGTM!The attribute extraction pattern is consistent and provides sensible defaults for all configurable properties. The array-based attributes (padding, margin, border, typography) are properly structured with fallbacks.
157-175: LGTM!The modal data array is well-structured for JavaScript consumption. All values are properly sourced from the block attributes. (Note: The empty
$modal_stylesissue is addressed in a separate comment.)
177-204: LGTM!The HTML output follows WordPress security best practices:
- User-controlled text is escaped with
esc_html()- Attributes are escaped with
esc_attr()- Translation functions are used correctly with proper placeholders
- JSON data is safely encoded with
wp_json_encode()- Conditional rendering for the last updated timestamp is implemented correctly
144-155: Current approach is acceptable for single-block usage.The
get_help_icon_svgfunction is only used within this HelpfulModal block and not shared across other blocks, making the inline definition withfunction_existsguard appropriate. No relocation is necessary.
| function generate_responsive_css($block_id, $controls, $device_suffix = '') { | ||
| $css = ''; | ||
|
|
||
| if (empty($controls)) { | ||
| return $css; | ||
| } | ||
|
|
||
| $selector = '.' . $block_id . $device_suffix; | ||
| $rules = []; | ||
|
|
||
| // Typography | ||
| if (isset($controls['fontFamily']) && $controls['fontFamily']) { | ||
| $rules[] = 'font-family: ' . esc_attr($controls['fontFamily']); | ||
| } | ||
| if (isset($controls['fontSize']) && $controls['fontSize']) { | ||
| $rules[] = 'font-size: ' . esc_attr($controls['fontSize']); | ||
| } | ||
| if (isset($controls['fontAppearance']['fontWeight']) && $controls['fontAppearance']['fontWeight']) { | ||
| $rules[] = 'font-weight: ' . esc_attr($controls['fontAppearance']['fontWeight']); | ||
| } | ||
| if (isset($controls['fontAppearance']['fontStyle']) && $controls['fontAppearance']['fontStyle']) { | ||
| $rules[] = 'font-style: ' . esc_attr($controls['fontAppearance']['fontStyle']); | ||
| } | ||
| if (isset($controls['lineHeight']) && $controls['lineHeight']) { | ||
| $rules[] = 'line-height: ' . esc_attr($controls['lineHeight']); | ||
| } | ||
| if (isset($controls['letterSpacing']) && $controls['letterSpacing']) { | ||
| $rules[] = 'letter-spacing: ' . esc_attr($controls['letterSpacing']); | ||
| } | ||
| if (isset($controls['textDecoration']) && $controls['textDecoration']) { | ||
| $rules[] = 'text-decoration: ' . esc_attr($controls['textDecoration']); | ||
| } | ||
| if (isset($controls['textTransform']) && $controls['textTransform']) { | ||
| $rules[] = 'text-transform: ' . esc_attr($controls['textTransform']); | ||
| } | ||
|
|
||
| // Colors | ||
| if (isset($controls['textColor']) && $controls['textColor']) { | ||
| $rules[] = 'color: ' . esc_attr($controls['textColor']); | ||
| } | ||
| if (isset($controls['backgroundColor']) && $controls['backgroundColor']) { | ||
| $rules[] = 'background-color: ' . esc_attr($controls['backgroundColor']); | ||
| } | ||
|
|
||
| // Dimensions | ||
| if (isset($controls['width']) && $controls['width']) { | ||
| $rules[] = 'width: ' . esc_attr($controls['width']); | ||
| } | ||
| if (isset($controls['minWidth']) && $controls['minWidth']) { | ||
| $rules[] = 'min-width: ' . esc_attr($controls['minWidth']); | ||
| } | ||
| if (isset($controls['maxWidth']) && $controls['maxWidth']) { | ||
| $rules[] = 'max-width: ' . esc_attr($controls['maxWidth']); | ||
| } | ||
| if (isset($controls['height']) && $controls['height']) { | ||
| $rules[] = 'height: ' . esc_attr($controls['height']); | ||
| } | ||
| if (isset($controls['minHeight']) && $controls['minHeight']) { | ||
| $rules[] = 'min-height: ' . esc_attr($controls['minHeight']); | ||
| } | ||
| if (isset($controls['maxHeight']) && $controls['maxHeight']) { | ||
| $rules[] = 'max-height: ' . esc_attr($controls['maxHeight']); | ||
| } | ||
|
|
||
| // Padding | ||
| if (isset($controls['padding']) && is_array($controls['padding'])) { | ||
| $padding_values = []; | ||
| $padding_values[] = $controls['padding']['top'] ?? '0'; | ||
| $padding_values[] = $controls['padding']['right'] ?? '0'; | ||
| $padding_values[] = $controls['padding']['bottom'] ?? '0'; | ||
| $padding_values[] = $controls['padding']['left'] ?? '0'; | ||
| $rules[] = 'padding: ' . implode(' ', $padding_values); | ||
| } | ||
|
|
||
| // Margin | ||
| if (isset($controls['margin']) && is_array($controls['margin'])) { | ||
| $margin_values = []; | ||
| $margin_values[] = $controls['margin']['top'] ?? '0'; | ||
| $margin_values[] = $controls['margin']['right'] ?? '0'; | ||
| $margin_values[] = $controls['margin']['bottom'] ?? '0'; | ||
| $margin_values[] = $controls['margin']['left'] ?? '0'; | ||
| $rules[] = 'margin: ' . implode(' ', $margin_values); | ||
| } | ||
|
|
||
| // Alignment | ||
| if (isset($controls['textAlign']) && $controls['textAlign']) { | ||
| $rules[] = 'text-align: ' . esc_attr($controls['textAlign']); | ||
| } | ||
| if (isset($controls['alignItems']) && $controls['alignItems']) { | ||
| $rules[] = 'align-items: ' . esc_attr($controls['alignItems']); | ||
| } | ||
| if (isset($controls['justifyContent']) && $controls['justifyContent']) { | ||
| $rules[] = 'justify-content: ' . esc_attr($controls['justifyContent']); | ||
| } | ||
| if (isset($controls['direction']) && $controls['direction']) { | ||
| $rules[] = 'flex-direction: ' . esc_attr($controls['direction']); | ||
| } | ||
|
|
||
| // Border | ||
| if (isset($controls['border']) && is_array($controls['border'])) { | ||
| $border = $controls['border']; | ||
| if (isset($border['width']) && isset($border['style']) && isset($border['color'])) { | ||
| $rules[] = 'border: ' . esc_attr($border['width']) . ' ' . esc_attr($border['style']) . ' ' . esc_attr($border['color']); | ||
| } | ||
| } | ||
|
|
||
| // Border Radius | ||
| if (isset($controls['borderRadius']) && is_array($controls['borderRadius'])) { | ||
| $radius = $controls['borderRadius']; | ||
| $radius_values = []; | ||
| $radius_values[] = $radius['topLeft'] ?? '0'; | ||
| $radius_values[] = $radius['topRight'] ?? '0'; | ||
| $radius_values[] = $radius['bottomRight'] ?? '0'; | ||
| $radius_values[] = $radius['bottomLeft'] ?? '0'; | ||
| $rules[] = 'border-radius: ' . implode(' ', $radius_values); | ||
| } | ||
|
|
||
| // Box Shadow | ||
| if (isset($controls['boxShadow']) && is_array($controls['boxShadow']) && isset($controls['boxShadow']['x'])) { | ||
| $shadow = $controls['boxShadow']; | ||
| $shadow_value = ''; | ||
| if (isset($shadow['inset']) && $shadow['inset']) { | ||
| $shadow_value .= 'inset '; | ||
| } | ||
| $shadow_value .= esc_attr($shadow['x']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['y']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['blur']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['spread']) . ' '; | ||
| $shadow_value .= esc_attr($shadow['color']); | ||
| $rules[] = 'box-shadow: ' . $shadow_value; | ||
| } | ||
|
|
||
| // Background Image | ||
| if (isset($controls['bgUrl']) && $controls['bgUrl']) { | ||
| $rules[] = 'background-image: url(' . esc_url($controls['bgUrl']) . ')'; | ||
|
|
||
| if (isset($controls['bgSize']) && $controls['bgSize']) { | ||
| $rules[] = 'background-size: ' . esc_attr($controls['bgSize']); | ||
| } | ||
|
|
||
| if (isset($controls['bgFocalPoint']) && is_array($controls['bgFocalPoint'])) { | ||
| $focal = $controls['bgFocalPoint']; | ||
| $rules[] = 'background-position: ' . ($focal['x'] * 100) . '% ' . ($focal['y'] * 100) . '%'; | ||
| } | ||
|
|
||
| if (isset($controls['bgRepeat'])) { | ||
| $rules[] = 'background-repeat: ' . ($controls['bgRepeat'] ? 'repeat' : 'no-repeat'); | ||
| } | ||
|
|
||
| if (isset($controls['bgFixed']) && $controls['bgFixed']) { | ||
| $rules[] = 'background-attachment: fixed'; | ||
| } | ||
| } | ||
|
|
||
| // Display | ||
| if (isset($controls['display']) && $controls['display']) { | ||
| $rules[] = 'display: ' . esc_attr($controls['display']); | ||
| } | ||
| if (isset($controls['visibility']) && $controls['visibility']) { | ||
| $rules[] = 'visibility: ' . esc_attr($controls['visibility']); | ||
| } | ||
| if (isset($controls['overflow']) && $controls['overflow']) { | ||
| $rules[] = 'overflow: ' . esc_attr($controls['overflow']); | ||
| } | ||
| if (isset($controls['zIndex']) && $controls['zIndex']) { | ||
| $rules[] = 'z-index: ' . esc_attr($controls['zIndex']); | ||
| } | ||
|
|
||
| if (!empty($rules)) { | ||
| $css .= $selector . ' { ' . implode('; ', $rules) . '; }'; | ||
| } | ||
|
|
||
| return $css; | ||
| } |
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.
Critical: Nested function causes fatal error on multiple block renders.
The generate_responsive_css function is defined inside render_wedocs_advance_contributors_block. PHP will attempt to redefine this function each time the outer function is called, causing a "Cannot redeclare" fatal error when multiple AdvanceContributors blocks are on the same page.
Move this function outside the render function or wrap it with a function_exists guard.
Option 1: Move function outside (recommended)
+// Helper function to generate responsive CSS - defined outside render function
+if ( ! function_exists( 'generate_responsive_css' ) ) {
+ function generate_responsive_css($block_id, $controls, $device_suffix = '') {
+ // ... function body ...
+ }
+}
+
function render_wedocs_advance_contributors_block($attributes, $content, $block) {
// ... existing code ...
- // Helper function to generate responsive CSS
- function generate_responsive_css($block_id, $controls, $device_suffix = '') {
- // ... function body ...
- }Option 2: Wrap with function_exists guard (quick fix)
// Helper function to generate responsive CSS
+ if ( ! function_exists( 'generate_responsive_css' ) ) {
function generate_responsive_css($block_id, $controls, $device_suffix = '') {
// ... existing function body ...
}
+ }🤖 Prompt for AI Agents
In @src/blocks/AdvanceContributors/render.php around lines 116 - 289, The nested
definition of generate_responsive_css inside
render_wedocs_advance_contributors_block causes a "Cannot redeclare" fatal error
when the outer function runs multiple times; fix by moving
generate_responsive_css out of render_wedocs_advance_contributors_block (define
it at file scope) or, as a quick patch, wrap its declaration with a
function_exists('generate_responsive_css') check so it’s only defined once and
then update any calls inside render_wedocs_advance_contributors_block to use
that single global function.
| // Last updated date | ||
| if ($show_last_updated) { | ||
| $date_format_string = $date_format === 'custom' ? $custom_date_format : get_option('date_format'); | ||
| $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); |
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 wp_date() instead of date() for timezone-aware formatting.
Same issue as in Contributors/render.php - native date() ignores WordPress timezone settings.
Proposed fix
- $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string);
+ $last_modified = $post ? get_the_modified_date($date_format_string, $post) : wp_date($date_format_string);📝 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.
| $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); | |
| $last_modified = $post ? get_the_modified_date($date_format_string, $post) : wp_date($date_format_string); |
🤖 Prompt for AI Agents
In @src/blocks/AdvanceContributors/render.php at line 458, The fallback uses PHP
date() which ignores WP timezone; change the assignment for $last_modified so
the fallback uses wp_date() with a timezone-aware timestamp: replace the
date($date_format_string) call with wp_date($date_format_string,
current_time('timestamp')) while keeping the existing use of
get_the_modified_date($date_format_string, $post) for the post case (refer to
the $last_modified variable and functions wp_date(), current_time(), and
get_the_modified_date()).
| return $output; | ||
| } | ||
| render_wedocs_advance_contributors_block( $attributes, $content, $block ); |
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.
Function return value is discarded.
The function returns $output but line 503 calls it without capturing or echoing the result. The rendered content will be lost.
Proposed fix
return $output;
}
-render_wedocs_advance_contributors_block( $attributes, $content, $block );
+echo render_wedocs_advance_contributors_block( $attributes, $content, $block );📝 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.
| return $output; | |
| } | |
| render_wedocs_advance_contributors_block( $attributes, $content, $block ); | |
| return $output; | |
| } | |
| echo render_wedocs_advance_contributors_block( $attributes, $content, $block ); |
🤖 Prompt for AI Agents
In @src/blocks/AdvanceContributors/render.php around lines 501 - 503, The call
to render_wedocs_advance_contributors_block( $attributes, $content, $block )
discards the function's returned $output; either echo the return value where
it’s invoked or change the function to directly print (echo) instead of
returning; locate the function render_wedocs_advance_contributors_block and
either (a) replace the bare call with echo
render_wedocs_advance_contributors_block( $attributes, $content, $block ); or
(b) modify the function so it outputs $output (echo) before returning or returns
void, ensuring the rendered content is actually sent to the response.
| switch ($contributor_display_mode) { | ||
| case 'main_author': | ||
| $author_id = get_post_field('wedocs_contributors', $post->ID); | ||
| if ($author_id) { | ||
| $contributors[] = get_userdata($author_id); | ||
| } | ||
|
|
||
| break; | ||
|
|
||
| case 'manual': | ||
| if (!empty($selected_contributors)) { | ||
| foreach ($selected_contributors as $user_id) { | ||
| $user = get_userdata($user_id); | ||
| if ($user) { | ||
| $contributors[] = $user; | ||
| } | ||
| } | ||
| } | ||
| break; | ||
|
|
||
| case 'all': | ||
| default: | ||
| // Get all contributors who have edited the post | ||
| $author_id = get_post_field('wedocs_contributors', $post->ID); | ||
| $authors = array_values($author_id); // return auhtors id. | ||
| foreach($authors as $author){ | ||
| $contributors[]= get_userdata($author); | ||
| } | ||
|
|
||
|
|
||
| if ($author_id && ($author_user = get_userdata($author_id))) { | ||
| $contributors[] = $author_user; | ||
| } | ||
|
|
||
| // Get additional contributors from post meta or revisions | ||
| if ($post) { | ||
| $revisions = wp_get_post_revisions($post->ID); | ||
| $contributor_ids = [$author_id]; | ||
|
|
||
| foreach ($revisions as $revision) { | ||
| $revision_author = get_post_field('post_author', $revision->ID); | ||
| if (!in_array($revision_author, $contributor_ids)) { | ||
| $contributor_ids[] = $revision_author; | ||
| $user = get_userdata($revision_author); | ||
| if ($user) { | ||
| $contributors[] = $user; | ||
| } | ||
| } | ||
| } | ||
| } | ||
| break; | ||
| } |
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.
Logic error in 'all' display mode - duplicate contributors and type mismatch.
The 'all' case has several issues:
- Line 127-128:
get_post_field('wedocs_contributors', ...)returns a post field value, thenarray_values($author_id)is called assuming it's an array - this will likely fail or produce unexpected results. - Lines 134-136 add the
$author_idagain after already iterating through$authors, causing potential duplicates. - The logic between 'main_author' (line 106) and 'all' (line 127) is inconsistent - both use 'wedocs_contributors' but handle the result differently.
Compare with AdvanceContributors/render.php lines 74-98 which uses get_post_field('post_author', ...) consistently.
Suggested fix aligning with AdvanceContributors pattern
case 'all':
default:
- // Get all contributors who have edited the post
- $author_id = get_post_field('wedocs_contributors', $post->ID);
- $authors = array_values($author_id); // return auhtors id.
- foreach($authors as $author){
- $contributors[]= get_userdata($author);
- }
-
-
- if ($author_id && ($author_user = get_userdata($author_id))) {
- $contributors[] = $author_user;
+ // Get post author
+ $author_id = get_post_field('post_author', $post->ID);
+ if ($author_id && ($author_user = get_userdata($author_id))) {
+ $contributors[] = $author_user;
}
// Get additional contributors from post meta or revisions
if ($post) {
$revisions = wp_get_post_revisions($post->ID);
$contributor_ids = [$author_id];
foreach ($revisions as $revision) {
$revision_author = get_post_field('post_author', $revision->ID);
if (!in_array($revision_author, $contributor_ids)) {
$contributor_ids[] = $revision_author;
$user = get_userdata($revision_author);
if ($user) {
$contributors[] = $user;
}
}
}
}
break;🤖 Prompt for AI Agents
In @src/blocks/Contributors/render.php around lines 104 - 155, The 'all' branch
misuses get_post_field and allows duplicates: treat the main author and
wedocs_contributors consistently by retrieving the main author with
get_post_field('post_author', $post->ID) and normalizing wedocs_contributors
into an array before iterating; build a unique contributor_ids array (or use
array_unique) to prevent duplicate additions, push each contributor only if not
already seen, and use get_userdata() for each id; update variables
$author_id/$authors to reflect these types and remove the redundant push of
$author_id that causes duplicates.
| // Last updated date | ||
| if ($show_last_updated) { | ||
| $date_format_string = $date_format === 'custom' ? $custom_date_format : get_option('date_format'); | ||
| $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); |
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 wp_date() instead of date() for timezone-aware formatting.
The native date() function doesn't respect WordPress timezone settings. Use wp_date() for consistent date formatting.
Proposed fix
- $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string);
+ $last_modified = $post ? get_the_modified_date($date_format_string, $post) : wp_date($date_format_string);📝 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.
| $last_modified = $post ? get_the_modified_date($date_format_string, $post) : date($date_format_string); | |
| $last_modified = $post ? get_the_modified_date($date_format_string, $post) : wp_date($date_format_string); |
🤖 Prompt for AI Agents
In @src/blocks/Contributors/render.php at line 336, The $last_modified
assignment uses PHP's date() which ignores WP timezone settings; update the
fallback to use wp_date($date_format_string) so that $last_modified = $post ?
get_the_modified_date($date_format_string, $post) :
wp_date($date_format_string); ensuring timezone-aware formatting; keep
get_the_modified_date(...) unchanged.
| if ($docs_per_page !== 'all') { | ||
| $args['posts_per_page'] = intval($docs_per_page); | ||
| $args['paged'] = $current_page; | ||
| } else { | ||
| $args['posts_per_page'] = '-1'; | ||
| $args['paged'] = 1; | ||
| } |
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 integer -1 instead of string '-1' for posts_per_page.
WordPress's WP_Query expects an integer for posts_per_page. Using a string may cause unexpected behavior.
Proposed fix
if ($docs_per_page !== 'all') {
$args['posts_per_page'] = intval($docs_per_page);
$args['paged'] = $current_page;
} else {
- $args['posts_per_page'] = '-1';
+ $args['posts_per_page'] = -1;
$args['paged'] = 1;
}🤖 Prompt for AI Agents
In @src/blocks/DocsGrid/render.php around lines 176 - 182, The code sets
$args['posts_per_page'] to the string '-1' when $docs_per_page === 'all'; change
that to the integer -1 so WP_Query receives an integer (update the assignment in
the render logic where $args['posts_per_page'] is set for the 'all' branch);
ensure $args['paged'] remains 1 in that branch.
| <?php | ||
| return ob_get_clean(); | ||
| } | ||
| } |
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
🏁 Script executed:
#!/bin/bash
# Search for how render_wedocs_docs_grid is being called
rg -n "render_wedocs_docs_grid" --type phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 247
🏁 Script executed:
#!/bin/bash
# Find block registration files
fd -e json -e php "block|register" src/blocks/DocsGrid/ || true
cat src/blocks/DocsGrid/*.json 2>/dev/null || true
# Check Contributors/render.php to see the pattern
if [ -f src/blocks/Contributors/render.php ]; then
tail -20 src/blocks/Contributors/render.php
fi
# Look for block registration patterns
rg -n "render_callback|register_block_type" --type php src/blocks/ -A 3 | head -50Repository: weDevsOfficial/wedocs-plugin
Length of output: 4187
🏁 Script executed:
#!/bin/bash
# Get the full render.php file
wc -l src/blocks/DocsGrid/render.php
cat -n src/blocks/DocsGrid/render.phpRepository: weDevsOfficial/wedocs-plugin
Length of output: 18192
Add invocation of render_wedocs_docs_grid() at the file level or reconfigure block registration.
The render_wedocs_docs_grid() function is declared (lines 44–328) but never invoked. With block.json specifying "render": "file:./render.php", WordPress includes this file but does not automatically call named functions. The block will fail to render without a top-level invocation. Either call the function with block attributes at the end of render.php (following the Contributors/render.php pattern), or configure a render_callback in block registration.
🤖 Prompt for AI Agents
In @src/blocks/DocsGrid/render.php around lines 325 - 328, The file defines
render_wedocs_docs_grid() but never invokes it; add a top-level call to
render_wedocs_docs_grid($attributes, $content, $block) at the end of render.php
(matching the Contributors/render.php pattern) so the file-level render
entrypoint executes when WordPress includes the file, or alternatively update
the block registration to supply 'render_callback' => 'render_wedocs_docs_grid'
so WordPress will call that function; ensure you pass the expected parameters
($attributes, $content, $block) when invoking.
| esc_attr($icon_size) | ||
| ); | ||
|
|
||
| $modal_styles = ''; |
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
🏁 Script executed:
# First, let's examine the render.php file to understand the context
cat -n src/blocks/HelpfulModal/render.php | sed -n '100,180p'Repository: weDevsOfficial/wedocs-plugin
Length of output: 3849
🏁 Script executed:
# Search for any modalStyles usage in JS files
rg -n "modalStyles" --type=js -g "**/HelpfulModal/**"Repository: weDevsOfficial/wedocs-plugin
Length of output: 420
🏁 Script executed:
# Also check if $modal_styles is used anywhere else in PHP
rg -n "\$modal_styles" src/blocks/HelpfulModal/Repository: weDevsOfficial/wedocs-plugin
Length of output: 54
Unused CSS initialization for modal element.
The $modal_styles variable is initialized as an empty string on line 107 but never populated, unlike other style variables ($modal_content_styles, $heading_styles, etc.) which are built via sprintf() calls. While modalStyles is passed to JavaScript and checked in view.js:215-216, it remains empty. Either populate this variable with appropriate modal styles (following the pattern of other style variables) or document why it's intentionally left empty as an optional property.
🤖 Prompt for AI Agents
In @src/blocks/HelpfulModal/render.php at line 107, The $modal_styles variable
is declared but never populated—mirror the pattern used for
$modal_content_styles and $heading_styles by building $modal_styles with
sprintf() (e.g., include modal container CSS properties you need: width,
max-width, position, background, padding, etc.) before it is passed into the JS
payload so view.js:215-216 can use it; alternatively, if no container-level
styles are required, remove $modal_styles from the payload or add a brief
comment explaining it is intentionally empty and optional. Ensure you reference
and update the $modal_styles variable in src/blocks/HelpfulModal/render.php
where the other style vars are constructed so the JS consumer receives
meaningful data.
Summary by CodeRabbit
New Features
Bug Fix / Refactor
Chores
Documentation
✏️ Tip: You can customize this high-level summary in your review settings.