Skip to content

Conversation

@iftakharul-islam
Copy link
Member

@iftakharul-islam iftakharul-islam commented Sep 25, 2025

Summary by CodeRabbit

  • New Features
    • Added Doc Contributors block (highly customizable) and a Dynamic Table of Contents and Docs Grid blocks with rich editor controls and server-rendered previews.
  • Style
    • New frontend/editor styles for contributors, TOC, docs grid, menus, device mockups, typography utilities, and improved print/RTL support.
  • Chores
    • Frontend asset/version updates and reduced stylesheet loading on non-docs pages; updated build tooling version.
  • Documentation
    • Added helpers README describing shared block styling utilities.

@coderabbitai
Copy link

coderabbitai bot commented Sep 25, 2025

Walkthrough

Adds multiple new Gutenberg blocks (Contributors, DocsGrid, TableOfContents, Dynamic TOC, AdvanceContributors), editor UI components, JS/PHP helper modules, extensive CSS assets, store/data modules, and related build asset updates; also updates plugin bootstrap to register new blocks and localize assetsUrl while commenting out a template hook.

Changes

Cohort / File(s) Summary
Built assets & manifests
assets/build/block.asset.php, assets/build/block.js, assets/build/frontend.asset.php, assets/build/print.asset.php, assets/build/store.asset.php, assets/build/frontend.js, assets/build/print.js, assets/build/frontend.css, assets/build/print.css, assets/build/style-block.css
Updated build hashes/asset manifests, webpack runtime scaffolding and minor built-JS naming; added sourceMap references and expanded compiled CSS formatting.
Built block bundles & styles
assets/build/blocks/*/index.asset.php, assets/build/blocks/*/index.js, assets/build/blocks/*/block.json, assets/build/blocks/*/style-index.css, assets/build/blocks/*/style-index-rtl.css, assets/build/blocks/*/index.css, assets/build/blocks/*/index-rtl.css, assets/build/blocks/*/view.*, assets/build/blocks/*/view.js
(Blocks: Contributors, AdvanceContributors, DocsGrid, TableOfContents, dynamic-table-of-contents, DocsGrid, TableOfContents, dynamic-table-of-contents, DocsGrid, TableOfContents)
Added built editor/front-end manifests, registration bundles and CSS for several new blocks (Contributors family, DocsGrid, TableOfContents variants, Dynamic TOC) and their RTL/editor styles; includes built view scripts for TOC behavior.
Block PHP render implementations
assets/build/blocks/Contributors/render.php, assets/build/blocks/AdvanceContributors/render.php, assets/build/blocks/DocsGrid/render.php, assets/build/blocks/TableOfContents/render.php, assets/build/blocks/dynamic-table-of-contents/build/render.php, src/blocks/Contributors/render.php, src/blocks/AdvanceContributors/render.php
Added server-side render callbacks and associated helper functions for Contributors, AdvanceContributors, DocsGrid, and Table of Contents blocks; generate HTML, inline/responsive CSS, JSON-LD schema, and safe heading extraction for TOC.
Block source code & registration
src/blocks/Contributors/*, src/blocks/AdvanceContributors/*, src/blocks/DocsGrid/*, src/blocks/TableOfContents/*, src/blocks/dynamic-table-of-contents/*, src/blocks/index.js
New block source: block.json manifests, Edit/Save components, index registration files, SCSS styles, and editor-side logic for multiple blocks (Contributors variants, DocsGrid, TOC flavors).
Editor UI components
src/blocks/components/BackgroundControl.js, BorderControl.js, DimensionControl.js, ShadowControl.js, SpacingControl.js, TabSystem.js, TypographyControl.js
New reusable React controls for background, border, dimension, shadow, spacing, tabs, and typography used across block inspector UIs.
Style helpers & documentation
src/blocks/helpers/block-helpers.js, src/blocks/helpers/block-styles.php, src/blocks/helpers/index.js, src/blocks/helpers/README.md
Added JS and PHP style/utility helpers, index re-exports and README documentation describing usage and conventions.
Store / data layer
assets/build/store.js, src/data/docs/*, src/data/settings/*
New client-side data stores (docs and settings): actions, controls, resolvers, selectors, reducers and registration wiring for WordPress data registry.
Plugin integration changes
includes/Assets.php, includes/Frontend.php, wedocs.php
Localized scripts now include assetsUrl => WEDOCS_ASSETS; commented out template_include filter in Frontend constructor; requires new helper/render files and registers Contributors block; added frontend dequeuing of pro CSS on non-docs pages.
Build tooling / config
webpack.config.js, package.json
Added @wordpress/icons import in webpack config and bumped @wordpress/scripts dev dependency version.
Global CSS additions
assets/build/index.css, assets/build/style-block.css, assets/build/block.css, assets/build/block-rtl.css, assets/build/frontend-rtl.css, assets/build/print-rtl.css, assets/build/style-block-rtl.css
New utilities and presets (horizontal menu, artboard device presets, text-transform/decoration utilities, blur, expanded frontend/print and editor CSS surfaces) and editor-scoped styles for TOC and other blocks.

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120 minutes

Possibly related PRs

Suggested labels

Needs Review

Poem

I hop and nibble at the code anew,
Contributors lined in a neat little queue.
Avatars, styles, and helpers so spry,
Tabs and controls make the editor fly.
A rabbit cheers — compile and view! 🐇

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Title Check ⚠️ Warning The title “Feat/block contributors block” redundantly repeats “block,” includes a slash, and reads like a branch name rather than a concise summary. It refers to the new Contributors block but is not clearly phrased. A title should read more cleanly, e.g. “Add Contributors block.” Rename the pull request to a concise, descriptive title such as “Add Contributors block” that clearly summarizes the primary feature without duplication or branch syntax.
Docstring Coverage ⚠️ Warning Docstring coverage is 47.50% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/Block-Contributors-Block

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

❤️ Share

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

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 17

Caution

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

⚠️ Outside diff range comments (1)
assets/build/block.js (1)

452-466: Manual contributor list silently truncates at 100 users.

The fetch at wp.apiFetch({ path: '/wp/v2/users?per_page=100&context=edit' }) only ever returns the first page of results. On any install with >100 users, the majority of contributors simply never appear in the “Select Contributors” checklist, so manual selection becomes unusable. Please either paginate through all pages (leveraging the X-WP-TotalPages header) or switch to a search-based picker that can request further pages on demand.

🧹 Nitpick comments (31)
src/blocks/Contributors/save.js (1)

1-9: Trim unused blockProps call in dynamic save.

Because this block renders exclusively on the server, useBlockProps.save() isn’t needed and just leaves an unused variable behind. Dropping it keeps the file lint-clean without changing behavior.

-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;
-};
+const Save = () => null;
 
 export default Save;
wedocs.php (1)

326-336: Namespace the new helper to prevent global collisions.

By declaring dequeue_wedocs_pro_frontend_css() in the global namespace, we risk clashing with other plugins/themes. Please wrap the function in your plugin namespace or convert it to a class method to avoid polluting the global scope.

Example:

- function dequeue_wedocs_pro_frontend_css() {
+namespace WeDevs\WeDocs;
+
+function dequeue_wedocs_pro_frontend_css() {
     …
 }
-add_action( 'wp_enqueue_scripts', 'dequeue_wedocs_pro_frontend_css', 20 );
+add_action( 'wp_enqueue_scripts', __NAMESPACE__ . '\\dequeue_wedocs_pro_frontend_css', 20 );
assets/build/style-block.css (1)

3-3: Drop the !important overrides from responsive avatar sizing.

The !important here blocks consumers from resizing avatars via inline styles. Removing it keeps responsive tweaks while allowing attribute-driven styling.

Remove the !important flags from the mobile avatar rules so inline styles still win.

src/blocks/components/TabSystem.js (1)

43-55: Handle non-array children safely.

children.map throws when only one child is passed (React gives an object, not an array). Wrap with React.Children.toArray() to keep this flexible and future-proof.

- {children.map((child, index) => {
+ {React.Children.toArray(children).map((child, index) => {
src/blocks/components/BorderControl.js (1)

1-10: Use stable components (where available) instead of experimental aliases.

If your target WordPress/Gutenberg version supports stable exports, prefer UnitControl, BoxControl, and Spacer to avoid deprecation churn.

Apply this diff (verify version compatibility first):

 import {
 	PanelBody,
-	SelectControl,
-	__experimentalUnitControl as UnitControl,
-	__experimentalBoxControl as BoxControl,
-	__experimentalSpacer as Spacer
+	SelectControl,
+	UnitControl,
+	BoxControl,
+	Spacer
 } from '@wordpress/components';
src/blocks/Contributors/edit.js (4)

272-277: Use stable React keys; avoid Math.random().

Random keys break reconciliation and hurt performance.

Apply this diff:

-				<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: attributes.contributorGap || '10px' }}>
-					{attributes.showAvatar && displayContributors.map(contributor => {
+				<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: attributes.contributorGap || '10px' }}>
+					{attributes.showAvatar && displayContributors.map((contributor, index) => {
 						// Handle both API response format and demo format
 						const contributorName = contributor.name || contributor.display_name || 'Unknown';
-						const contributorId = contributor.id || contributor.ID || Math.random();
+						const contributorId = contributor.id || contributor.ID || contributor.slug || `contributor-${index}`;

316-322: Use WP date utilities and honor custom format in editor preview.

Match frontend by using @wordpress/date (site locale/timezone) and respect attributes.dateFormat/customDateFormat.

Example change (imports required at top):

-						{attributes.datePrefix} {new Date().toLocaleDateString('en-US', {
-							year: 'numeric',
-							month: 'long',
-							day: 'numeric'
-						})}
+						{attributes.datePrefix}{' '}
+						{ ( () => {
+							const { dateI18n, __experimentalGetSettings: getSettings } = wp.date || {};
+							const fmt = attributes.dateFormat === 'custom' ? attributes.customDateFormat : (wp?.date ? getSettings().formats.date : 'F j, Y');
+							return (wp?.date && dateI18n) ? dateI18n(fmt, new Date()) : new Date().toLocaleDateString();
+						})() }

And prefer importing: import { dateI18n, __experimentalGetSettings as getSettings } from '@wordpress/date';


63-76: Confirm wp.apiFetch availability or switch to module import.

Ensure the script declares a dependency on wp-api-fetch so wp.apiFetch exists, or import from '@wordpress/api-fetch'.

If switching:

  • import apiFetch from '@wordpress/api-fetch';
  • Replace wp.apiFetch(...) with apiFetch(...).

Also applies to: 89-96, 101-111, 119-125, 130-145, 139-141


200-205: Global assets URL dependency.

Verify weDocsAdminScriptVars.assetsUrl is always localized on editor pages; add a safe fallback to avoid broken images if undefined.

Also applies to: 278-283

src/blocks/Contributors/block.json (2)

35-38: Type the array items for selectedContributors

Explicit item type avoids accidental string serialization and eases validation.

   "selectedContributors": {
     "type": "array",
-    "default": []
+    "default": [],
+    "items": { "type": "number" }
   },

30-34: Naming consistency: “Title” vs “Contributor Title”

You have both “title” (string), “contributorTitleColor/…Typography/…HoverColor” and a removed “titleColor”. Consider consistently using “title*” for the block heading (e.g., titleColor, titleTypography, titleHoverColor) to keep the public API coherent.

Also applies to: 130-134, 182-202, 220-236

assets/build/index.css (1)

3001-3030: Artboard sizes: confirm these are consumed

If these utility sizes aren’t referenced by templates/components, consider dropping them to keep the build slimmer.

src/blocks/Contributors/edit-old.js (4)

1-27: Use package API instead of global wp.apiFetch

Import apiFetch from @wordpress/api-fetch to avoid relying on a global and to benefit from middleware (nonce, preloading).

 import { useState, useEffect } from '@wordpress/element';
 import { useSelect } from '@wordpress/data';
 import { store as coreStore } from '@wordpress/core-data';
+import apiFetch from '@wordpress/api-fetch';

55-63: Switch to apiFetch import

Replace wp.apiFetch with the imported apiFetch.

-      wp.apiFetch({ path: '/wp/v2/users?per_page=100&context=edit' })
+      apiFetch({ path: '/wp/v2/users?per_page=100&context=edit' })
         .then(users => {

29-29: Remove unused clientId

clientId isn’t used.

-  const { attributes, setAttributes, clientId } = props;
+  const { attributes, setAttributes } = props;

66-72: Remove dead selector

currentPost is computed but never used.

-  const currentPost = useSelect((select) => {
-    const { getCurrentPostId, getCurrentPostType } = select('core/editor') || {};
-    if (!getCurrentPostId) return null;
-
-    return select(coreStore).getEntityRecord('postType', getCurrentPostType(), getCurrentPostId());
-  }, []);
src/blocks/helpers/block-styles.php (1)

251-281: Scoped responsive CSS is fine

Block-scoped selectors keep CSS contained. Consider aligning breakpoints with WP defaults if you adopt more blocks.

webpack.config.js (1)

5-5: Remove unused @wordpress/icons import.

The destructured image is not used and adds an unnecessary dependency load in Node.

-const { image } = require('@wordpress/icons');
src/blocks/components/TypographyControl.js (1)

3-8: Remove unused ToggleControl import.

It’s imported but not used.

 import {
 	PanelBody,
 	SelectControl,
-	ToggleControl,
 	__experimentalUnitControl as UnitControl,
 	__experimentalSpacer as Spacer
 } from '@wordpress/components';
src/blocks/components/DimensionControl.js (1)

31-37: 'auto' is not a unit; avoid listing it in UnitControl units.

UnitControl expects standard units; 'auto' is a CSS value. Use a toggle/select to set value="auto" and disable the numeric control instead of exposing it as a unit.

Would you like a patch that adds an “Auto width/height” ToggleControl and disables the UnitControl when enabled?

Also applies to: 49-54

src/blocks/components/ShadowControl.js (1)

25-109: LGTM — coherent shadow editor with sensible defaults.

Merges state safely and gates controls behind an enable toggle.

Optional: add an "Inset" toggle to support inset box-shadow.

src/blocks/helpers/block-helpers.js (2)

77-83: Default typography param to prevent crashes on undefined.

Align with other helpers that tolerate missing inputs.

-export const generateTypographyStyles = (typography) => {
+export const generateTypographyStyles = (typography = {}) => {

374-377: Guard against window being undefined (SSR/Node).

Prevents errors if called in non-browser contexts.

-export const isBreakpoint = (breakpoint) => {
+export const isBreakpoint = (breakpoint) => {
 	const breakpoints = getBreakpoints();
-	const width = window.innerWidth;
+	const width = typeof window !== 'undefined' ? window.innerWidth : Number.MAX_SAFE_INTEGER;
src/blocks/Contributors/style.scss (3)

33-38: Limit transitions to specific properties for performance

Avoid transition: all; restrict to the properties you animate.

-				transition: all 0.3s ease;
+				transition: transform 0.2s ease, box-shadow 0.2s ease;

49-55: Make default icon color theme-friendly (avoid hard-coded WP blue)

Use a CSS variable fallback so themes can override easily.

-					background-color: #0073aa;
-					color: white;
+					background-color: var(--wedocs-accent, var(--wp--preset--color--primary, #0073aa));
+					color: var(--wp--preset--color--background, #fff);

68-75: Add keyboard focus styles for links

Provide a visible focus indicator, not just hover.

 				&:hover {
 					text-decoration: underline;
 				}
 
+				&:focus-visible {
+					text-decoration: underline;
+					outline: 2px solid currentColor;
+					outline-offset: 2px;
+				}
src/blocks/components/BackgroundControl.js (5)

29-29: Provide a default panel title

Use a sensible fallback when label isn’t passed.

-		<PanelBody title={label} initialOpen={false}>
+		<PanelBody title={ label || __('Background', 'wedocs') } initialOpen={false}>

3-8: Use stable UI where possible; avoid experimental Spacer

__experimentalSpacer may change. Prefer simple CSS gaps/margins or stable layout primitives (e.g., Flex) to avoid future breakage.

Confirm your target WP/Gutenberg version guarantees __experimentalSpacer stability.


57-66: Prefer GradientPicker over free-form gradient text

Improves UX, ensures valid gradients, and aligns with core components.

-			{backgroundType === 'gradient' && showGradient && (
-				<TextControl
-					label={__('Gradient CSS', 'wedocs')}
-					value={backgroundGradient || ''}
-					onChange={onBackgroundGradientChange}
-					placeholder="linear-gradient(45deg, #ff0000, #00ff00)"
-					help={__('Enter CSS gradient value', 'wedocs')}
-				/>
-			)}
+			{ backgroundType === 'gradient' && showGradient && (
+				<GradientPicker
+					value={ backgroundGradient || '' }
+					onChange={ onBackgroundGradientChange }
+				/>
+			) }

And add the import:

 import {
 	PanelBody,
 	RadioControl,
 	TextControl,
 	Button,
-	__experimentalSpacer as Spacer
+	__experimentalSpacer as Spacer,
+	GradientPicker
 } from '@wordpress/components';

68-70: Hide image controls when gradient is selected

Avoid conflicting background inputs; show image controls only for the classic type.

-			{/* Background Image */}
-			{showImage && (
+			{/* Background Image (classic only) */}
+			{ showImage && backgroundType === 'classic' && (

15-27: Harden props with safe defaults

If any onChange callbacks are omitted, the component will throw. Consider default no-ops to improve resilience.

-const BackgroundControl = ({
+const BackgroundControl = ({
 	label,
-	backgroundType = 'classic',
-	onBackgroundTypeChange,
+	backgroundType = 'classic',
+	onBackgroundTypeChange = () => {},
 	backgroundColor,
-	onBackgroundColorChange,
+	onBackgroundColorChange = () => {},
 	backgroundGradient,
-	onBackgroundGradientChange,
-	backgroundImage = {},
-	onBackgroundImageChange,
+	onBackgroundGradientChange = () => {},
+	backgroundImage = {},
+	onBackgroundImageChange = () => {},
 	showGradient = true,
 	showImage = true
 }) => {
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c80fc84 and 39a0c77.

⛔ Files ignored due to path filters (4)
  • assets/img/demo-avatar/avatar_1.png is excluded by !**/*.png
  • assets/img/demo-avatar/avatar_2.png is excluded by !**/*.png
  • src/blocks/Contributors/demo-avtar/avatar_1.png is excluded by !**/*.png
  • src/blocks/Contributors/demo-avtar/avatar_2.png is excluded by !**/*.png
📒 Files selected for processing (30)
  • assets/build/block.asset.php (1 hunks)
  • assets/build/block.js (1 hunks)
  • assets/build/blocks/Contributors/block.json (1 hunks)
  • assets/build/blocks/Contributors/render.php (1 hunks)
  • assets/build/index.asset.php (1 hunks)
  • assets/build/index.css (9 hunks)
  • assets/build/style-block.css (1 hunks)
  • includes/Assets.php (1 hunks)
  • includes/Frontend.php (2 hunks)
  • src/blocks/Contributors/block.json (1 hunks)
  • src/blocks/Contributors/edit-old.js (1 hunks)
  • src/blocks/Contributors/edit.js (1 hunks)
  • src/blocks/Contributors/index.js (1 hunks)
  • src/blocks/Contributors/render.php (1 hunks)
  • src/blocks/Contributors/save.js (1 hunks)
  • src/blocks/Contributors/style.scss (1 hunks)
  • src/blocks/components/BackgroundControl.js (1 hunks)
  • src/blocks/components/BorderControl.js (1 hunks)
  • src/blocks/components/DimensionControl.js (1 hunks)
  • src/blocks/components/ShadowControl.js (1 hunks)
  • src/blocks/components/SpacingControl.js (1 hunks)
  • src/blocks/components/TabSystem.js (1 hunks)
  • src/blocks/components/TypographyControl.js (1 hunks)
  • src/blocks/helpers/README.md (1 hunks)
  • src/blocks/helpers/block-helpers.js (1 hunks)
  • src/blocks/helpers/block-styles.php (1 hunks)
  • src/blocks/helpers/index.js (1 hunks)
  • src/blocks/index.js (1 hunks)
  • webpack.config.js (1 hunks)
  • wedocs.php (3 hunks)
🧰 Additional context used
🧬 Code graph analysis (10)
src/blocks/components/TypographyControl.js (1)
src/blocks/CustomControls/UnitControl.js (1)
  • UnitControl (4-27)
src/blocks/Contributors/render.php (2)
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/components/Documentations/ParentDocs.js (1)
  • contributors (54-58)
assets/build/blocks/Contributors/render.php (2)
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/components/Documentations/ParentDocs.js (1)
  • contributors (54-58)
src/blocks/components/DimensionControl.js (1)
src/blocks/CustomControls/UnitControl.js (1)
  • UnitControl (4-27)
src/blocks/Contributors/edit-old.js (1)
src/blocks/Contributors/edit.js (6)
  • Edit (29-669)
  • props (30-30)
  • users (31-31)
  • isLoadingUsers (32-32)
  • blockProps (36-52)
  • renderPreview (169-326)
src/blocks/Contributors/save.js (2)
src/blocks/Contributors/edit-old.js (1)
  • blockProps (33-49)
src/blocks/Contributors/edit.js (1)
  • blockProps (36-52)
src/blocks/Contributors/edit.js (8)
src/blocks/Contributors/edit-old.js (6)
  • Edit (28-564)
  • props (29-29)
  • users (30-30)
  • isLoadingUsers (31-31)
  • currentPost (66-71)
  • renderPreview (73-164)
src/blocks/components/BackgroundControl.js (1)
  • BackgroundControl (15-110)
src/blocks/components/SpacingControl.js (1)
  • SpacingControl (9-88)
src/blocks/components/BorderControl.js (1)
  • BorderControl (11-116)
src/blocks/components/ShadowControl.js (1)
  • ShadowControl (10-111)
src/blocks/components/TypographyControl.js (1)
  • TypographyControl (11-173)
src/blocks/components/DimensionControl.js (1)
  • DimensionControl (8-60)
src/blocks/components/TabSystem.js (1)
  • TabSystem (5-59)
src/blocks/helpers/block-styles.php (1)
src/blocks/helpers/block-helpers.js (5)
  • matches (259-259)
  • matches (280-280)
  • number (283-283)
  • unit (262-262)
  • unit (284-284)
src/blocks/Contributors/index.js (1)
src/blocks/Contributors/edit.js (1)
  • Edit (29-669)
src/blocks/components/ShadowControl.js (1)
src/blocks/CustomControls/UnitControl.js (1)
  • UnitControl (4-27)
🪛 PHPMD (2.15.0)
src/blocks/Contributors/render.php

10-10: Avoid unused parameters such as '$content'. (undefined)

(UnusedFormalParameter)


10-10: Avoid unused parameters such as '$block'. (undefined)

(UnusedFormalParameter)

assets/build/blocks/Contributors/render.php

10-10: Avoid unused parameters such as '$content'. (undefined)

(UnusedFormalParameter)


10-10: Avoid unused parameters such as '$block'. (undefined)

(UnusedFormalParameter)

🪛 Biome (2.1.2)
assets/build/block.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)

🔇 Additional comments (22)
src/blocks/index.js (1)

3-3: Contributors block wire-up looks good.

Importing the new Contributors module here neatly enrolls it with the rest of the block registrations. No issues spotted.

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

1-1: Asset manifest version bump acknowledged.

The dependency list is unchanged and the new hash looks consistent with a rebuilt bundle. All good.

includes/Assets.php (1)

45-45: Admin bundle now gets the assets base URL.

Exposing assetsUrl alongside the existing AJAX data mirrors what the frontend already receives, so the admin UI can now resolve shared assets without hard-coding paths. Looks solid.

includes/Frontend.php (1)

81-82: Frontend also benefits from the assets base URL.

Mirroring the admin-side addition, weDocs_Vars.assetsUrl gives the frontend script a stable base path for shared assets. Nice improvement.

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

10-392: Same functional issues as src version; avoid duplicate function definitions.

This file duplicates render_wedocs_contributors_block. Ensure only one copy is loaded to prevent fatal redeclare. See comments on src/blocks/Contributors/render.php for logic fixes (author/meta handling, post guard).

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

55-67: Background precedence: gradient vs image

Current schema allows both gradient and image. In render you’ll end up with two background-image declarations; the last one wins (image overrides gradient). If that’s intentional, OK; otherwise consider supporting multiple layers or mutually excluding types.

Also applies to: 64-67, 141-149

assets/build/index.css (6)

1996-2010: Custom checkbox base styles look good

Solid, scoped base with CSS vars; works well with state rules below.


2501-2527: Accessible focus/checked/indeterminate states for .checkbox

Good focus-visible outline and robust ARIA/attr state handling.


2542-2546: RTL parity for checkmark

Nice RTL-specific image mirroring.


2114-2120: Duplicate .menu.horizontal rules – verify cascade

These repeat existing menu.horizontal styles. Check that duplication doesn’t inadvertently change specificity/order in your bundle.

Also applies to: 2599-2606


4796-4804: New text-transform and decoration utilities

Useful additions and consistent with existing underline utility.

Also applies to: 4947-4952


5069-5072: Blur utility

Looks fine; ensure this doesn’t defeat any backdrop/filter performance budgets on low-end devices.

src/blocks/helpers/block-styles.php (2)

134-149: Background layering: gradient + image

Both set background-image; the latter (image) overrides gradient. If layering is desired, combine with a comma-separated background-image; otherwise, keep as-is.


290-312: Good utility for CSS unit sanitization

This should be applied widely (as suggested above) to harden inline style construction.

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

1-1: Asset manifest update looks correct.

New dependencies (wp-core-data, wp-data) align with typical data usage in editor blocks. Version bump is expected from rebuild.

Ensure the PHP registration enqueues this asset file (block.asset.php) with wp_register_script so these handles are honored.

src/blocks/components/SpacingControl.js (1)

4-7: Using __experimental components—confirm target WP/Gutenberg compatibility.

__experimentalBoxControl, __experimentalUnitControl, and __experimentalSpacer can change across releases. Verify the target WP version ships compatible props.

src/blocks/helpers/README.md (1)

1-120: Docs read well and match helpers.

Clear mapping of PHP/JS helpers and usage examples.

src/blocks/components/TypographyControl.js (1)

116-126: Replace ‘normal’ fallbacks with empty string in UnitControl
UnitControl expects numeric+unit values; passing 'normal' may cause parse errors. In TypographyControl.js update the value props for line height and letter spacing to use value={value.lineHeight || ''} and value={value.letterSpacing || ''} so the default CSS applies.

src/blocks/Contributors/style.scss (1)

9-12: Verify root class matches server-rendered markup

Ensure the PHP render adds .wedocs-contributors on the root so these styles apply in both editor and frontend.

src/blocks/Contributors/index.js (2)

4-4: Confirm style enqueue strategy (editor vs frontend)

Importing ./style.scss in JS ensures editor styles via the block script. For frontend, confirm style/editorStyle handles are declared in block.json or enqueued in PHP for the dynamic block.


15-16: Dynamic block save is correct

Returning null is appropriate for server-side rendering.

src/blocks/components/BackgroundControl.js (1)

10-13: PanelColorSettings deprecation risk

PanelColorSettings has seen deprecation/migration towards Color controls/ToolsPanel in newer Gutenberg. Not blocking for your current versions, but plan to migrate to keep parity with core.

Please confirm the minimum WordPress/Gutenberg version you target so we can suggest the exact replacement API and code.

Comment on lines +26 to +29
"titleColor": {
"type": "string",
"default": "#fff"
},
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Wrong default title color undermines readability.

With titleColor defaulting to #fff while the block background defaults to a light gray, the title is effectively invisible out of the box. Please pick a contrasting default (e.g. the same dark gray used elsewhere).

Update titleColor to a darker default (e.g., #333333) so the block renders legibly without manual tweaks.

🤖 Prompt for AI Agents
In assets/build/blocks/Contributors/block.json around lines 26 to 29, the
titleColor default is set to "#fff" which yields poor contrast on the block's
light gray background; change the default value to a darker hex such as
"#333333" to ensure readable title text by updating the titleColor default to
the new darker color.


// override the theme template
add_filter( 'template_include', [ $this, 'template_loader' ], 20 );
// add_filter( 'template_include', [ $this, 'template_loader' ], 20 );
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t drop the template loader hook.

Commenting out add_filter( 'template_include', … ) stops the plugin from supplying its fallback single-doc template. In themes without a dedicated single-docs.php, this regresses the docs experience to the theme’s generic single view (or worse, a 404). Please leave the filter active unless there’s a replacement mechanism in place.

-        // add_filter( 'template_include', [ $this, 'template_loader' ], 20 );
+        add_filter( 'template_include', [ $this, 'template_loader' ], 20 );
🤖 Prompt for AI Agents
In includes/Frontend.php around line 39, the template loader hook was commented
out which prevents the plugin from providing its fallback single-doc template;
restore the add_filter( 'template_include', [ $this, 'template_loader' ], 20 );
call so the plugin can supply its single-doc template in themes that lack
single-docs.php, ensure the template_loader method still exists and returns the
correct template path, and avoid registering duplicate filters (check for
existing hook before adding if necessary).

Comment on lines +9 to +16
"description": "Display the author(s)/contributors of a doc along with the last updated date.",
"supports": {
"html": false
},
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php",
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add textdomain for block JSON i18n

Include the plugin textdomain so title/description can be localized by WordPress tooling.

   "description": "Display the author(s)/contributors of a doc along with the last updated date.",
+  "textdomain": "wedocs",
   "supports": {
📝 Committable suggestion

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

Suggested change
"description": "Display the author(s)/contributors of a doc along with the last updated date.",
"supports": {
"html": false
},
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php",
"description": "Display the author(s)/contributors of a doc along with the last updated date.",
"textdomain": "wedocs",
"supports": {
"html": false
},
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css",
"style": "file:./style-index.css",
"render": "file:./render.php",
🤖 Prompt for AI Agents
In src/blocks/Contributors/block.json around lines 9 to 16, the block.json is
missing a textdomain property so the title/description aren’t picked up by WP
i18n tools; add a "textdomain" key with your plugin's actual textdomain (e.g.,
"your-plugin-slug") at the top level of the JSON so tooling can extract/localize
strings for the block.

Comment on lines +26 to +29
"titleColor": {
"type": "string",
"default": "#fff"
},
Copy link

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/duplicated titleColor attribute

The heading color is controlled by contributorTitleColor below. titleColor isn’t referenced in the editor/render path and will be hard to remove later if shipped.

-    "titleColor": {
-			"type": "string",
-			"default": "#fff"
-		},
📝 Committable suggestion

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

Suggested change
"titleColor": {
"type": "string",
"default": "#fff"
},
🤖 Prompt for AI Agents
In src/blocks/Contributors/block.json around lines 26 to 29, remove the unused
duplicated "titleColor" attribute (type/string default "#fff") because heading
color is already controlled by contributorTitleColor; update the JSON by
deleting that property entry and any trailing comma adjustments so the object
remains valid JSON, and run a quick search to confirm no references to
"titleColor" remain in editor/render code before committing.

Comment on lines +28 to +164
const Edit = (props) => {
const { attributes, setAttributes, clientId } = props;
const [users, setUsers] = useState([]);
const [isLoadingUsers, setIsLoadingUsers] = useState(false);

const blockProps = useBlockProps({
className: `wedocs-contributors ${attributes.additionalCssClass}`,
style: {
backgroundColor: attributes.backgroundType === 'classic' ? attributes.backgroundColor : undefined,
backgroundImage: attributes.backgroundType === 'gradient' ? attributes.backgroundGradient :
(attributes.backgroundImage?.url ? `url(${attributes.backgroundImage.url})` : undefined),
padding: `${attributes.padding.top} ${attributes.padding.right} ${attributes.padding.bottom} ${attributes.padding.left}`,
margin: `${attributes.margin.top} ${attributes.margin.right} ${attributes.margin.bottom} ${attributes.margin.left}`,
borderStyle: attributes.borderStyle !== 'none' ? attributes.borderStyle : undefined,
borderWidth: attributes.borderStyle !== 'none' ?
`${attributes.borderWidth.top} ${attributes.borderWidth.right} ${attributes.borderWidth.bottom} ${attributes.borderWidth.left}` : undefined,
borderColor: attributes.borderStyle !== 'none' ? attributes.borderColor : undefined,
borderRadius: attributes.borderRadius,
boxShadow: attributes.boxShadow.enabled ?
`${attributes.boxShadow.horizontal} ${attributes.boxShadow.vertical} ${attributes.boxShadow.blur} ${attributes.boxShadow.spread} ${attributes.boxShadow.color}` : undefined
}
});

// Fetch users when component mounts or when manual selection mode is active
useEffect(() => {
if (attributes.contributorDisplayMode === 'manual') {
setIsLoadingUsers(true);
wp.apiFetch({ path: '/wp/v2/users?per_page=100&context=edit' })
.then(users => {
setUsers(users);
setIsLoadingUsers(false);
})
.catch(() => {
setIsLoadingUsers(false);
});
}
}, [attributes.contributorDisplayMode]);

const currentPost = useSelect((select) => {
const { getCurrentPostId, getCurrentPostType } = select('core/editor') || {};
if (!getCurrentPostId) return null;

return select(coreStore).getEntityRecord('postType', getCurrentPostType(), getCurrentPostId());
}, []);

const renderPreview = () => {
if (attributes.contributorDisplayMode === 'manual' && attributes.selectedContributors.length === 0) {
return (
<Placeholder
icon="groups"
label={__('Doc Contributors', 'wedocs')}
instructions={__('Select contributors from the settings panel.', 'wedocs')}
/>
);
}

// Mock data for preview
const mockContributors = attributes.contributorDisplayMode === 'main_author' ?
[{ id: 1, name: 'John Doe', avatar_urls: { 48: 'https://via.placeholder.com/48' } }] :
[
{ id: 1, name: 'John Doe', avatar_urls: { 48: 'https://via.placeholder.com/48' } },
{ id: 2, name: 'Jane Smith', avatar_urls: { 48: 'https://via.placeholder.com/48' } }
];

const avatarStyle = {
width: attributes.avatarSize,
height: attributes.avatarSize,
borderRadius: attributes.avatarShape === 'circle' ? '50%' :
(attributes.avatarShape === 'rounded' ? attributes.avatarBorderRadius : '0'),
borderStyle: attributes.avatarBorderStyle !== 'none' ? attributes.avatarBorderStyle : undefined,
borderColor: attributes.avatarBorderStyle !== 'none' ? attributes.avatarBorderColor : undefined,
borderWidth: attributes.avatarBorderStyle !== 'none' ? '2px' : undefined
};

const nameStyle = {
color: attributes.nameColor,
fontSize: attributes.nameTypography.fontSize,
fontWeight: attributes.nameTypography.fontWeight,
fontStyle: attributes.nameTypography.fontStyle
};
const contributorTitleStyle = {
color: attributes.contributorTitleColor,
fontSize: attributes.contributorTitleTypography.fontSize,
fontWeight: attributes.contributorTitleTypography.fontWeight,
fontStyle: attributes.contributorTitleTypography.fontStyle
};

const dateStyle = {
color: attributes.dateColor,
fontSize: attributes.dateTypography.fontSize,
fontWeight: attributes.dateTypography.fontWeight,
fontStyle: attributes.dateTypography.fontStyle
};

return (
<div>
{attributes.showTitle && (
<h3 style={{ marginBottom: '10px', fontSize: '16px', fontWeight: '600', ...contributorTitleStyle}}>
{attributes.title}
</h3>
)}

<div style={{ display: 'flex', alignItems: 'center', flexWrap: 'wrap', gap: '10px' }}>
{attributes.showAvatar && mockContributors.map(contributor => (
<div key={contributor.id} style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
{attributes.avatarType === 'user_avatar' ? (
<img
src={contributor.avatar_urls[48]}
alt={contributor.name}
style={avatarStyle}
/>
) : (
<div style={{...avatarStyle, backgroundColor: '#0073aa', display: 'flex', alignItems: 'center', justifyContent: 'center'}}>
<svg width="16" height="16" fill="white" viewBox="0 0 24 24">
<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"/>
</svg>
</div>
)}
<span style={nameStyle}>{contributor.name}</span>
</div>
))}
</div>

{attributes.showLastUpdated && (
<div style={{ marginTop: '10px' }}>
<span style={dateStyle}>
{attributes.datePrefix} {new Date().toLocaleDateString('en-US', {
year: 'numeric',
month: 'long',
day: 'numeric'
})}
</span>
</div>
)}
</div>
);
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Duplicate/legacy Edit – remove the old file

There’s already a primary Edit (src/blocks/Contributors/edit.js). Keeping edit-old.js invites drift and confusion. If not referenced in block.json, delete it.

Also applies to: 166-567

🤖 Prompt for AI Agents
In src/blocks/Contributors/edit-old.js lines 28-164 (and similarly lines
166-567) there is a duplicate/legacy Edit component that conflicts with
src/blocks/Contributors/edit.js; remove this file if it is not referenced by
block.json or any imports, or update block.json/imports to point to the
canonical edit.js and delete edit-old.js to avoid drift; before deleting, grep
the repo for any references to edit-old.js, ensure no active imports or
registrations depend on it, run a quick build/test to confirm nothing breaks,
then remove the file and commit the change.

Comment on lines +20 to +47
function wedocs_build_typography_styles($typography) {
$styles = [];

if (isset($typography['fontFamily']) && $typography['fontFamily'] !== 'default') {
$styles[] = 'font-family: ' . esc_attr($typography['fontFamily']);
}
if (isset($typography['fontSize'])) {
$styles[] = 'font-size: ' . esc_attr($typography['fontSize']);
}
if (isset($typography['fontWeight'])) {
$styles[] = 'font-weight: ' . esc_attr($typography['fontWeight']);
}
if (isset($typography['fontStyle'])) {
$styles[] = 'font-style: ' . esc_attr($typography['fontStyle']);
}
if (isset($typography['lineHeight']) && $typography['lineHeight'] !== 'normal') {
$styles[] = 'line-height: ' . esc_attr($typography['lineHeight']);
}
if (isset($typography['letterSpacing']) && $typography['letterSpacing'] !== 'normal') {
$styles[] = 'letter-spacing: ' . esc_attr($typography['letterSpacing']);
}
if (isset($typography['textTransform']) && $typography['textTransform'] !== 'none') {
$styles[] = 'text-transform: ' . esc_attr($typography['textTransform']);
}
if (isset($typography['textDecoration']) && $typography['textDecoration'] !== 'none') {
$styles[] = 'text-decoration: ' . esc_attr($typography['textDecoration']);
}

Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Sanitize dimension-like typography values

Use the provided wedocs_sanitize_css_value for fontSize, lineHeight, letterSpacing. Quote font-family values with spaces.

-    if (isset($typography['fontFamily']) && $typography['fontFamily'] !== 'default') {
-        $styles[] = 'font-family: ' . esc_attr($typography['fontFamily']);
-    }
-    if (isset($typography['fontSize'])) {
-        $styles[] = 'font-size: ' . esc_attr($typography['fontSize']);
-    }
+    if (isset($typography['fontFamily']) && $typography['fontFamily'] !== 'default') {
+        $font = trim($typography['fontFamily']);
+        $styles[] = 'font-family: ' . (str_contains($font, ' ') ? '"' . esc_attr($font) . '"' : esc_attr($font));
+    }
+    if (isset($typography['fontSize'])) {
+        $styles[] = 'font-size: ' . wedocs_sanitize_css_value($typography['fontSize']);
+    }
     if (isset($typography['fontWeight'])) {
         $styles[] = 'font-weight: ' . esc_attr($typography['fontWeight']);
     }
     if (isset($typography['fontStyle'])) {
         $styles[] = 'font-style: ' . esc_attr($typography['fontStyle']);
     }
-    if (isset($typography['lineHeight']) && $typography['lineHeight'] !== 'normal') {
-        $styles[] = 'line-height: ' . esc_attr($typography['lineHeight']);
-    }
-    if (isset($typography['letterSpacing']) && $typography['letterSpacing'] !== 'normal') {
-        $styles[] = 'letter-spacing: ' . esc_attr($typography['letterSpacing']);
-    }
+    if (isset($typography['lineHeight']) && $typography['lineHeight'] !== 'normal') {
+        $styles[] = 'line-height: ' . wedocs_sanitize_css_value($typography['lineHeight']);
+    }
+    if (isset($typography['letterSpacing']) && $typTypography['letterSpacing'] !== 'normal') {
+        $styles[] = 'letter-spacing: ' . wedocs_sanitize_css_value($typography['letterSpacing']);
+    }

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

🤖 Prompt for AI Agents
In src/blocks/helpers/block-styles.php around lines 20 to 47, update typography
sanitization: when building styles, use the existing wedocs_sanitize_css_value()
for fontSize, lineHeight and letterSpacing instead of raw esc_attr values; for
fontFamily, keep esc_attr but wrap the value in quotes only if it contains
whitespace (e.g., check for space and produce '"Family Name"' vs unquoted
single-word family) to ensure correct CSS; preserve existing checks for defaults
and other properties and apply esc_attr to all values passed into
wedocs_sanitize_css_value or placed into quotes.

Comment on lines +58 to +67
function wedocs_build_spacing_styles($padding, $margin) {
$styles = [];

if (!empty($padding)) {
$styles[] = 'padding: ' . esc_attr($padding['top'] ?? '0px') . ' ' . esc_attr($padding['right'] ?? '0px') . ' ' . esc_attr($padding['bottom'] ?? '0px') . ' ' . esc_attr($padding['left'] ?? '0px');
}

if (!empty($margin)) {
$styles[] = 'margin: ' . esc_attr($margin['top'] ?? '0px') . ' ' . esc_attr($margin['right'] ?? '0px') . ' ' . esc_attr($margin['bottom'] ?? '0px') . ' ' . esc_attr($margin['left'] ?? '0px');
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Sanitize spacing values

Avoid raw attribute passthrough for padding/margin.

-    if (!empty($padding)) {
-        $styles[] = 'padding: ' . esc_attr($padding['top'] ?? '0px') . ' ' . esc_attr($padding['right'] ?? '0px') . ' ' . esc_attr($padding['bottom'] ?? '0px') . ' ' . esc_attr($padding['left'] ?? '0px');
-    }
+    if (!empty($padding)) {
+        $styles[] = sprintf(
+            'padding: %s %s %s %s',
+            wedocs_sanitize_css_value($padding['top'] ?? '0px'),
+            wedocs_sanitize_css_value($padding['right'] ?? '0px'),
+            wedocs_sanitize_css_value($padding['bottom'] ?? '0px'),
+            wedocs_sanitize_css_value($padding['left'] ?? '0px')
+        );
+    }
 
-    if (!empty($margin)) {
-        $styles[] = 'margin: ' . esc_attr($margin['top'] ?? '0px') . ' ' . esc_attr($margin['right'] ?? '0px') . ' ' . esc_attr($margin['bottom'] ?? '0px') . ' ' . esc_attr($margin['left'] ?? '0px');
-    }
+    if (!empty($margin)) {
+        $styles[] = sprintf(
+            'margin: %s %s %s %s',
+            wedocs_sanitize_css_value($margin['top'] ?? '0px'),
+            wedocs_sanitize_css_value($margin['right'] ?? '0px'),
+            wedocs_sanitize_css_value($margin['bottom'] ?? '0px'),
+            wedocs_sanitize_css_value($margin['left'] ?? '0px')
+        );
+    }
📝 Committable suggestion

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

Suggested change
function wedocs_build_spacing_styles($padding, $margin) {
$styles = [];
if (!empty($padding)) {
$styles[] = 'padding: ' . esc_attr($padding['top'] ?? '0px') . ' ' . esc_attr($padding['right'] ?? '0px') . ' ' . esc_attr($padding['bottom'] ?? '0px') . ' ' . esc_attr($padding['left'] ?? '0px');
}
if (!empty($margin)) {
$styles[] = 'margin: ' . esc_attr($margin['top'] ?? '0px') . ' ' . esc_attr($margin['right'] ?? '0px') . ' ' . esc_attr($margin['bottom'] ?? '0px') . ' ' . esc_attr($margin['left'] ?? '0px');
}
function wedocs_build_spacing_styles($padding, $margin) {
$styles = [];
if (!empty($padding)) {
$styles[] = sprintf(
'padding: %s %s %s %s',
wedocs_sanitize_css_value($padding['top'] ?? '0px'),
wedocs_sanitize_css_value($padding['right'] ?? '0px'),
wedocs_sanitize_css_value($padding['bottom'] ?? '0px'),
wedocs_sanitize_css_value($padding['left'] ?? '0px')
);
}
if (!empty($margin)) {
$styles[] = sprintf(
'margin: %s %s %s %s',
wedocs_sanitize_css_value($margin['top'] ?? '0px'),
wedocs_sanitize_css_value($margin['right'] ?? '0px'),
wedocs_sanitize_css_value($margin['bottom'] ?? '0px'),
wedocs_sanitize_css_value($margin['left'] ?? '0px')
);
}
// …rest of function…
}

Comment on lines +87 to +98
if (!empty($border_width)) {
$styles[] = 'border-width: ' . esc_attr($border_width['top'] ?? '1px') . ' ' . esc_attr($border_width['right'] ?? '1px') . ' ' . esc_attr($border_width['bottom'] ?? '1px') . ' ' . esc_attr($border_width['left'] ?? '1px');
}

if ($border_color) {
$styles[] = 'border-color: ' . esc_attr($border_color);
}
}

if ($border_radius) {
$styles[] = 'border-radius: ' . esc_attr($border_radius);
}
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Sanitize border widths and radius

Prevent unsafe CSS in widths/radius.

-        if (!empty($border_width)) {
-            $styles[] = 'border-width: ' . esc_attr($border_width['top'] ?? '1px') . ' ' . esc_attr($border_width['right'] ?? '1px') . ' ' . esc_attr($border_width['bottom'] ?? '1px') . ' ' . esc_attr($border_width['left'] ?? '1px');
-        }
+        if (!empty($border_width)) {
+            $styles[] = sprintf(
+                'border-width: %s %s %s %s',
+                wedocs_sanitize_css_value($border_width['top'] ?? '1px'),
+                wedocs_sanitize_css_value($border_width['right'] ?? '1px'),
+                wedocs_sanitize_css_value($border_width['bottom'] ?? '1px'),
+                wedocs_sanitize_css_value($border_width['left'] ?? '1px')
+            );
+        }
 ...
-    if ($border_radius) {
-        $styles[] = 'border-radius: ' . esc_attr($border_radius);
-    }
+    if ($border_radius) {
+        $styles[] = 'border-radius: ' . wedocs_sanitize_css_value($border_radius, ['px','em','rem','%']);
+    }
📝 Committable suggestion

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

Suggested change
if (!empty($border_width)) {
$styles[] = 'border-width: ' . esc_attr($border_width['top'] ?? '1px') . ' ' . esc_attr($border_width['right'] ?? '1px') . ' ' . esc_attr($border_width['bottom'] ?? '1px') . ' ' . esc_attr($border_width['left'] ?? '1px');
}
if ($border_color) {
$styles[] = 'border-color: ' . esc_attr($border_color);
}
}
if ($border_radius) {
$styles[] = 'border-radius: ' . esc_attr($border_radius);
}
if (!empty($border_width)) {
$styles[] = sprintf(
'border-width: %s %s %s %s',
wedocs_sanitize_css_value($border_width['top'] ?? '1px'),
wedocs_sanitize_css_value($border_width['right'] ?? '1px'),
wedocs_sanitize_css_value($border_width['bottom']?? '1px'),
wedocs_sanitize_css_value($border_width['left'] ?? '1px')
);
}
if ($border_color) {
$styles[] = 'border-color: ' . esc_attr($border_color);
}
}
if ($border_radius) {
$styles[] = 'border-radius: ' . wedocs_sanitize_css_value(
$border_radius,
['px', 'em', 'rem', '%']
);
}

Comment on lines +10 to +23
// Export all helper functions
export {
generateBlockStyles,
generateTypographyStyles,
generateSpacingStyles,
generateElementStyles,
generateCustomProperties,
debounce,
isValidCSSValue,
convertToPx,
classNames,
getBreakpoints,
isBreakpoint
} from './block-helpers';
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Fix default export: local names are undefined (re‑export doesn’t create bindings).

export { ... } from './block-helpers' does not create local bindings, so the default export object references undefined identifiers at runtime. Replace with a barrel + namespace import.

Apply this diff:

-// Export all helper functions
-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
-};
+export * from './block-helpers';
+import * as helpers from './block-helpers';
+export default helpers;

Also applies to: 25-38

🤖 Prompt for AI Agents
In src/blocks/helpers/index.js around lines 10 to 23 (and similarly lines 25 to
38), the current re-export form doesn't create local bindings so the default
export object will reference undefined names at runtime; replace the direct
re-exports with a namespace import (e.g. import * as helpers from
'./block-helpers') and then re-export the needed named exports from that
namespace (or re-export them via export const X = helpers.X) and add a default
export of the namespace (export default helpers) so all identifiers are real
local bindings and the default export is valid.

Comment on lines 49 to 52
require_once plugin_dir_path(__FILE__) . 'src/blocks/helpers/block-styles.php';
require_once plugin_dir_path(__FILE__) . 'assets/build/blocks/DocsGrid/render.php';
require_once plugin_dir_path(__FILE__) . 'assets/build/blocks/Contributors/render.php';

Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard render_wedocs_contributors_block() availability before registration.

register_block_type() will fatally error if render_wedocs_contributors_block() isn’t loaded (e.g., load order issues or missing build artifact). Please ensure the function exists before passing it as the render callback.

Add a defensive check before registration:

+if ( function_exists( 'render_wedocs_contributors_block' ) ) {
     register_block_type(
         plugin_dir_path( __FILE__ ) . 'assets/build/blocks/Contributors',
         array(
             'render_callback' => 'render_wedocs_contributors_block'
         )
     );
+}

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

🤖 Prompt for AI Agents
In wedocs.php around lines 49 to 52, the code calls register_block_type() with
render_wedocs_contributors_block as the render callback but does not verify that
the function is defined; add a defensive check using
function_exists('render_wedocs_contributors_block') before registering the block
and only pass the callback if it exists (otherwise register without the callback
or register a safe fallback that returns an empty string and/or log an error) so
missing build/load-order issues do not cause a fatal error.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (3)
assets/build/index.css (3)

2599-2606: Make “bordered” horizontal menu styles RTL‑safe

Use logical properties (with fallback) so start side is cleared correctly in RTL.

Option A (logical prop):

-.menu.horizontal > li.bordered > a,
-        .menu.horizontal > li.bordered > button,
-        .menu.horizontal > li.bordered > span {
-  border-left-width: 0px;
+.menu.horizontal > li.bordered > a,
+        .menu.horizontal > li.bordered > button,
+        .menu.horizontal > li.bordered > span {
+  border-inline-start-width: 0;

Option B (fallback for older browsers):

[dir="rtl"] .menu.horizontal > li.bordered > a,
[dir="rtl"] .menu.horizontal > li.bordered > button,
[dir="rtl"] .menu.horizontal > li.bordered > span { border-right-width: 0; }

3001-3030: Prevent artboard overflow on small containers (optional)

Fixed widths can overflow. Consider constraining max-width.

Add a shared rule:

/* Constrain rotated phone artboards */
.artboard.phone-1.horizontal,
.artboard.phone-2.horizontal,
.artboard.phone-3.horizontal,
.artboard.phone-4.horizontal,
.artboard.phone-5.horizontal,
.artboard.phone-6.horizontal,
.artboard.phone-1.artboard-horizontal,
.artboard.phone-2.artboard-horizontal,
.artboard.phone-3.artboard-horizontal,
.artboard.phone-4.artboard-horizontal,
.artboard.phone-5.artboard-horizontal,
.artboard.phone-6.artboard-horizontal { max-width: 100%; }

5134-5137: Blur filter can be costly; use sparingly

Consider applying on small elements only, and only when needed (avoid on large containers). If toggled frequently, you may add will-change: filter on the element just before use.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 39a0c77 and 88a0274.

📒 Files selected for processing (3)
  • assets/build/index.css (6 hunks)
  • includes/Assets.php (1 hunks)
  • wedocs.php (3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • includes/Assets.php
  • wedocs.php
🔇 Additional comments (2)
assets/build/index.css (2)

4854-4862: Text transform utilities look good

Scoping uppercase/lowercase/capitalize under .wedocs-document is appropriate.


5012-5017: Decoration utilities LGTM

overline and line-through additions are fine and consistent.

Comment on lines +2114 to +2120
.menu.horizontal {
display: inline-flex;
flex-direction: row;
}
.menu.horizontal :where(li) {
flex-direction: row;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Scope horizontal menu styles to top-level items to avoid breaking submenus

Using a descendant selector will cascade into nested li. Constrain to direct children.

Apply:

-.menu.horizontal :where(li) {
-  flex-direction: row;
-}
+.menu.horizontal > :where(li) {
+  flex-direction: row;
+}
📝 Committable suggestion

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

Suggested change
.menu.horizontal {
display: inline-flex;
flex-direction: row;
}
.menu.horizontal :where(li) {
flex-direction: row;
}
.menu.horizontal {
display: inline-flex;
flex-direction: row;
}
.menu.horizontal > :where(li) {
flex-direction: row;
}
🤖 Prompt for AI Agents
In assets/build/index.css around lines 2114-2120, the selector ".menu.horizontal
:where(li)" uses a descendant combinator and incorrectly applies styles to
nested list items; change it to target only direct children by replacing the
selector with ".menu.horizontal > :where(li)" (or simply ".menu.horizontal >
li") so only top-level li get the flex-direction and prevent submenus from
inheriting the rule.

@Rubaiyat-E-Mohammad
Copy link

No changes could be noticed! @iftakharul-islam vai

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 26

Caution

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

⚠️ Outside diff range comments (1)
assets/build/frontend.css (1)

1-1224: Remove generated build artifacts from version control
Remove all files under assets/build (including frontend.css) from the repo (e.g., git rm --cached -r assets/build), add assets/build/ to .gitignore, and rely on your build/CI pipeline to regenerate these assets.

♻️ Duplicate comments (2)
assets/build/blocks/TableOfContents/index.css (1)

1-22: Duplicate of assets/build/block.css.

This file is identical to assets/build/block.css. See the review comment on that file for details.

assets/build/blocks/Contributors/style-index.css (1)

1-139: Code duplication: Identical to AdvanceContributors stylesheet.

This file is byte-for-byte identical to assets/build/blocks/AdvanceContributors/style-index.css (see earlier review comment). This duplication suggests:

  1. The Contributors and AdvanceContributors blocks may have overlapping purposes
  2. The shared styles should be extracted into a common stylesheet
  3. One of the blocks might be redundant

This issue was already flagged in the review of assets/build/blocks/AdvanceContributors/style-index.css. The verification script provided there will help identify the extent of duplication between these two blocks.

Consider:

  • Extracting common styles into a shared stylesheet (e.g., contributors-common.css)
  • Consolidating the blocks if they serve the same purpose
  • Clearly differentiating the blocks if they serve different purposes
🧹 Nitpick comments (9)
src/blocks/AdvanceContributors/save.js (1)

3-9: Remove unused blockProps variable.

The blockProps variable is assigned but never used. Since this is a dynamic block that returns null (server-side rendering), there's no need to call useBlockProps.save().

Apply this diff to simplify the component:

-const Save = () => {
-	const blockProps = useBlockProps.save();
-
+const 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;
 };

Alternatively, if block attributes need to be preserved in the HTML comment for backward compatibility, keep useBlockProps.save() but use it:

 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;
+	return <div {...blockProps} />;
 };
src/blocks/AdvanceContributors/index.js (1)

12-15: Clarify JSDoc reference to save.js.

The JSDoc comment references ./save.js, but the actual save function is defined inline as () => null. This could confuse developers looking for a separate save.js file.

Consider either:

  1. Importing and using the Save component from save.js:
 import { registerBlockType } from "@wordpress/blocks";
 import Edit from "./edit";
+import Save from "./save";
 import metadata from "./block.json";
 import "./style.scss";
 
 registerBlockType(metadata.name, {
 	/**
 	 * @see ./edit.js
 	 */
 	edit: Edit,
 
 	/**
 	 * @see ./save.js
 	 */
-	save: () => null,
+	save: Save,
 });
  1. Or updating the JSDoc to reflect the inline implementation:
 	/**
-	 * @see ./save.js
+	 * Dynamic block - server-side rendering only
 	 */
 	save: () => null,
assets/build/blocks/AdvanceContributors/style-index.css (2)

54-55: Consider using CSS custom properties for theme consistency.

Hardcoded color values (#0073aa, #4a90a4) reduce theme flexibility. Consider using CSS custom properties that can be defined at the theme level.

For example:

-.default-icon {
-  background-color: #0073aa;
+.default-icon {
+  background-color: var(--wedocs-primary-color, #0073aa);
   color: white;
 }
-@media (prefers-color-scheme: dark) {
-  .wedocs-contributors .contributor-item .contributor-avatar .default-icon {
-    background-color: #4a90a4;
+@media (prefers-color-scheme: dark) {
+  .wedocs-contributors .contributor-item .contributor-avatar .default-icon {
+    background-color: var(--wedocs-primary-color-dark, #4a90a4);
   }
 }

Also applies to: 126-127


95-97: Excessive use of !important declarations.

Multiple !important declarations (lines 95-97, 107-108, 115-119) suggest specificity issues in the CSS architecture. While some are justified for accessibility overrides (reduced-motion), others like the mobile avatar sizing could be refactored to avoid !important.

Consider increasing selector specificity or restructuring the cascade instead of relying on !important for non-accessibility overrides. For accessibility-related !important (reduced-motion, high-contrast), the usage is appropriate and should remain.

Also applies to: 107-108, 115-119

assets/build/blocks/TableOfContents/style-index.css (1)

10-11: Replace hardcoded colors with CSS custom properties.

Multiple hardcoded color values (#f9f9f9, #e0e0e0, #666, #0073aa) reduce theme flexibility and maintainability.

Define these as CSS custom properties:

+:root {
+  --wedocs-toc-bg: #f9f9f9;
+  --wedocs-toc-border: #e0e0e0;
+  --wedocs-toc-text-muted: #666;
+  --wedocs-toc-accent: #0073aa;
+}
+
 .wp-block-wedocs-table-of-contents {
-  background-color: #f9f9f9;
-  border: 1px solid #e0e0e0;
+  background-color: var(--wedocs-toc-bg);
+  border: 1px solid var(--wedocs-toc-border);
   border-radius: 5px;

Also applies to: 18-20, 54-56, 68-69, 121-122

assets/build/blocks/DocsGrid/style-index-rtl.css (1)

30-45: Extensive hardcoded color values reduce theme flexibility.

Multiple hardcoded colors throughout the stylesheet (borders, backgrounds, text colors, pagination colors) should use CSS custom properties for better theme integration and maintainability.

Consider defining a consistent color system:

:root {
  --wedocs-primary: #0073aa;
  --wedocs-primary-hover: #005177;
  --wedocs-text-primary: #333;
  --wedocs-text-secondary: #757575;
  --wedocs-border: #ddd;
  --wedocs-background: #fff;
  --wedocs-background-hover: #f5f5f5;
}

Then replace hardcoded values with these custom properties throughout the stylesheet.

Also applies to: 81-82, 177-185, 196-207, 233-260

src/blocks/AdvanceContributors/style.scss (2)

105-108: Avoid !important for sizing constraints.

Using !important for mobile avatar sizing (lines 106-107) suggests a specificity issue. Consider restructuring the selector specificity instead.

Instead of:

.contributor-avatar {
  img, .default-icon {
    width: 28px !important;
    height: 28px !important;
  }
}

Increase selector specificity:

@media (max-width: 480px) {
  .wedocs-contributors .contributors-container .contributor-item .contributor-avatar img,
  .wedocs-contributors .contributors-container .contributor-item .contributor-avatar .default-icon {
    width: 28px;
    height: 28px;
  }
}

53-54: Use SCSS variables for color consistency.

Hardcoded colors (#0073aa, #4a90a4) should be defined as SCSS variables at the top of the file for easier maintenance and theme consistency.

Add at the top of the file:

$wedocs-primary-color: #0073aa;
$wedocs-primary-color-dark: #4a90a4;
$wedocs-text-white: white;

Then use throughout:

.default-icon {
  background-color: $wedocs-primary-color;
  color: $wedocs-text-white;
}

@media (prefers-color-scheme: dark) {
  .contributor-item {
    .contributor-avatar .default-icon {
      background-color: $wedocs-primary-color-dark;
    }
  }
}

Also applies to: 154-155

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

35-45: <!-- [scratchpad]
[task review_comment_verification 1/1]
[observations]

  • TableOfContents block.json defines colorsControls.default with only desktop.
  • AdvanceContributors and other blocks include desktop, tablet, and mobile.
  • Code uses colorsControls[device] || {} and handles missing device keys without errors.
    [analysis]
  • Missing tablet/mobile defaults won’t break functionality but deviates from other blocks’ attribute shapes.
  • For consistency and predictable UI, it’s advisable to include all device keys.
    [pending]
  • None
    [done]
    Verified inconsistency and code behavior.
    [/scratchpad]

Include tablet and mobile defaults for colorsControls (assets/build/blocks/TableOfContents/block.json:35-45)
Add tablet and mobile keys to the colorsControls.default object to match the responsive attribute shape of other blocks and ensure consistent UI behavior.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88a0274 and d8983b5.

⛔ Files ignored due to path filters (23)
  • assets/build/block.css.map is excluded by !**/*.map
  • assets/build/block.js.map is excluded by !**/*.map
  • assets/build/blocks/AdvanceContributors/index.js.map is excluded by !**/*.map
  • assets/build/blocks/AdvanceContributors/style-index.css.map is excluded by !**/*.map
  • assets/build/blocks/Contributors/index.js.map is excluded by !**/*.map
  • assets/build/blocks/Contributors/style-index.css.map is excluded by !**/*.map
  • assets/build/blocks/DocsGrid/index.js.map is excluded by !**/*.map
  • assets/build/blocks/DocsGrid/style-index.css.map is excluded by !**/*.map
  • assets/build/blocks/TableOfContents/index.css.map is excluded by !**/*.map
  • assets/build/blocks/TableOfContents/index.js.map is excluded by !**/*.map
  • assets/build/blocks/TableOfContents/style-index.css.map is excluded by !**/*.map
  • assets/build/blocks/TableOfContents/view.js.map is excluded by !**/*.map
  • assets/build/frontend.css.map is excluded by !**/*.map
  • assets/build/frontend.js.map is excluded by !**/*.map
  • assets/build/index.css.map is excluded by !**/*.map
  • assets/build/index.js.map is excluded by !**/*.map
  • assets/build/print.css.map is excluded by !**/*.map
  • assets/build/print.js.map is excluded by !**/*.map
  • assets/build/store.js.map is excluded by !**/*.map
  • assets/build/style-block.css.map is excluded by !**/*.map
  • package-lock.json is excluded by !**/package-lock.json
  • src/blocks/AdvanceContributors/demo-avtar/avatar_1.png is excluded by !**/*.png
  • src/blocks/AdvanceContributors/demo-avtar/avatar_2.png is excluded by !**/*.png
📒 Files selected for processing (64)
  • assets/build/block-rtl.css (1 hunks)
  • assets/build/block.asset.php (1 hunks)
  • assets/build/block.css (1 hunks)
  • assets/build/blocks/AdvanceContributors/block.json (1 hunks)
  • assets/build/blocks/AdvanceContributors/index.asset.php (1 hunks)
  • assets/build/blocks/AdvanceContributors/render.php (1 hunks)
  • assets/build/blocks/AdvanceContributors/style-index-rtl.css (1 hunks)
  • assets/build/blocks/AdvanceContributors/style-index.css (1 hunks)
  • assets/build/blocks/Contributors/index.asset.php (1 hunks)
  • assets/build/blocks/Contributors/index.js (1 hunks)
  • assets/build/blocks/Contributors/style-index-rtl.css (1 hunks)
  • assets/build/blocks/Contributors/style-index.css (1 hunks)
  • assets/build/blocks/DocsGrid/index.asset.php (1 hunks)
  • assets/build/blocks/DocsGrid/index.js (1 hunks)
  • assets/build/blocks/DocsGrid/render.php (1 hunks)
  • assets/build/blocks/DocsGrid/style-index-rtl.css (1 hunks)
  • assets/build/blocks/DocsGrid/style-index.css (1 hunks)
  • assets/build/blocks/TableOfContents/block.json (1 hunks)
  • assets/build/blocks/TableOfContents/index-rtl.css (1 hunks)
  • assets/build/blocks/TableOfContents/index.asset.php (1 hunks)
  • assets/build/blocks/TableOfContents/index.css (1 hunks)
  • assets/build/blocks/TableOfContents/index.js (1 hunks)
  • assets/build/blocks/TableOfContents/render.php (1 hunks)
  • assets/build/blocks/TableOfContents/style-index-rtl.css (1 hunks)
  • assets/build/blocks/TableOfContents/style-index.css (1 hunks)
  • assets/build/blocks/TableOfContents/view.asset.php (1 hunks)
  • assets/build/blocks/TableOfContents/view.js (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/build/block.json (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/build/index.asset.php (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/build/index.js (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/build/render.php (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/build/view.asset.php (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/build/view.js (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/block.json (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/index-rtl.css (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/index.asset.php (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/index.css (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/index.js (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/render.php (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/style-index-rtl.css (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/style-index.css (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/view.asset.php (1 hunks)
  • assets/build/blocks/dynamic-table-of-contents/src/view.js (1 hunks)
  • assets/build/frontend-rtl.css (1 hunks)
  • assets/build/frontend.asset.php (1 hunks)
  • assets/build/frontend.css (2 hunks)
  • assets/build/frontend.js (1 hunks)
  • assets/build/print-rtl.css (1 hunks)
  • assets/build/print.asset.php (1 hunks)
  • assets/build/print.css (2 hunks)
  • assets/build/print.js (1 hunks)
  • assets/build/store.asset.php (1 hunks)
  • assets/build/store.js (1 hunks)
  • assets/build/style-block-rtl.css (1 hunks)
  • assets/build/style-block.css (1 hunks)
  • includes/Assets.php (2 hunks)
  • package.json (1 hunks)
  • src/blocks/AdvanceContributors/block.json (1 hunks)
  • src/blocks/AdvanceContributors/edit-old.js (1 hunks)
  • src/blocks/AdvanceContributors/edit.js (1 hunks)
  • src/blocks/AdvanceContributors/index.js (1 hunks)
  • src/blocks/AdvanceContributors/render.php (1 hunks)
  • src/blocks/AdvanceContributors/save.js (1 hunks)
  • src/blocks/AdvanceContributors/style.scss (1 hunks)
✅ Files skipped from review due to trivial changes (15)
  • assets/build/blocks/TableOfContents/view.asset.php
  • assets/build/block-rtl.css
  • assets/build/print.asset.php
  • assets/build/blocks/dynamic-table-of-contents/src/index.css
  • assets/build/blocks/AdvanceContributors/index.asset.php
  • assets/build/print.css
  • assets/build/blocks/AdvanceContributors/style-index-rtl.css
  • assets/build/blocks/dynamic-table-of-contents/src/view.asset.php
  • assets/build/blocks/dynamic-table-of-contents/src/index-rtl.css
  • assets/build/blocks/dynamic-table-of-contents/build/view.asset.php
  • assets/build/store.asset.php
  • assets/build/frontend.asset.php
  • assets/build/blocks/dynamic-table-of-contents/src/block.json
  • assets/build/blocks/DocsGrid/style-index.css
  • assets/build/blocks/DocsGrid/index.asset.php
🚧 Files skipped from review as they are similar to previous changes (1)
  • includes/Assets.php
🧰 Additional context used
🧬 Code graph analysis (11)
src/blocks/AdvanceContributors/edit.js (6)
src/blocks/commonControls/TypographyControls.js (2)
  • currentTypography (30-30)
  • TypographyControls (28-274)
src/blocks/commonControls/DimensionsControls.js (2)
  • currentDimensions (13-13)
  • DimensionsControls (11-261)
src/blocks/commonControls/AlignmentControls.js (2)
  • currentAlignment (28-28)
  • AlignmentControls (26-222)
src/blocks/commonControls/BackgroundImageControls.js (2)
  • currentBackgroundImage (16-16)
  • BackgroundImageControls (14-244)
src/blocks/commonControls/BorderAndShadowControls.js (1)
  • BorderAndShadowControls (21-240)
src/blocks/commonControls/DisplayControls.js (1)
  • DisplayControls (5-100)
src/blocks/AdvanceContributors/render.php (1)
src/components/Documentations/ParentDocs.js (1)
  • contributors (54-58)
assets/build/blocks/dynamic-table-of-contents/build/render.php (1)
src/blocks/TableOfContents/view.js (7)
  • content (153-153)
  • level (98-98)
  • text (99-99)
  • html (89-89)
  • counters (94-94)
  • indent (116-116)
  • numbers (122-122)
assets/build/blocks/TableOfContents/render.php (1)
src/blocks/TableOfContents/view.js (7)
  • content (153-153)
  • level (98-98)
  • text (99-99)
  • html (89-89)
  • counters (94-94)
  • indent (116-116)
  • numbers (122-122)
assets/build/blocks/dynamic-table-of-contents/src/render.php (1)
src/blocks/TableOfContents/view.js (7)
  • content (153-153)
  • level (98-98)
  • text (99-99)
  • html (89-89)
  • counters (94-94)
  • indent (116-116)
  • numbers (122-122)
assets/build/blocks/AdvanceContributors/render.php (1)
src/components/Documentations/ParentDocs.js (1)
  • contributors (54-58)
src/blocks/AdvanceContributors/edit-old.js (2)
src/blocks/DocsGrid/edit.js (1)
  • wp (16-16)
src/blocks/CustomControls/UnitControl.js (1)
  • UnitControl (4-27)
assets/build/blocks/DocsGrid/render.php (1)
src/blocks/DocsGrid/edit.js (1)
  • attributes (20-48)
assets/build/blocks/TableOfContents/index.js (2)
src/blocks/commonControls/BorderAndShadowControls.js (1)
  • themeColors (24-24)
src/blocks/TableOfContents/view.js (7)
  • content (153-153)
  • supportedHeadings (42-42)
  • showHierarchy (43-43)
  • showNumbering (44-44)
  • indent (116-116)
  • numberText (119-119)
  • level (98-98)
assets/build/blocks/Contributors/index.js (1)
src/components/Documentations/ParentDocs.js (1)
  • contributors (54-58)
assets/build/store.js (9)
src/components/DocListing/index.js (3)
  • docs (27-29)
  • loading (37-40)
  • sections (103-103)
src/components/Documentations/index.js (3)
  • docs (19-22)
  • loading (29-32)
  • parentDocs (24-27)
src/components/SelectBox.js (1)
  • pages (16-16)
src/blocks/DocsGrid/edit.js (2)
  • loading (18-18)
  • wp (16-16)
src/components/DocListing/ListingHeader.js (1)
  • loading (13-16)
src/components/Documentations/ParentDocs.js (2)
  • sections (36-40)
  • articles (42-46)
src/components/AddArticleModal.js (1)
  • articles (35-39)
src/components/DocListing/QuickEditModal.js (1)
  • articles (34-38)
src/components/DocListing/DocSections.js (2)
  • articles (70-70)
  • settings (86-89)
🪛 Biome (2.1.2)
assets/build/print-rtl.css

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

white-space is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


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

font-size is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)

assets/build/blocks/dynamic-table-of-contents/build/view.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)

assets/build/blocks/dynamic-table-of-contents/build/index.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 1-1: 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: Shouldn't redeclare 'a'. Consider to delete it or rename it.

'a' 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)

assets/build/style-block.css

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

width is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)

assets/build/blocks/dynamic-table-of-contents/src/index.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 1-1: 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: Shouldn't redeclare 'a'. Consider to delete it or rename it.

'a' 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)

assets/build/frontend-rtl.css

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

display is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


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

white-space is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)


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

font-size is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)

assets/build/blocks/dynamic-table-of-contents/src/view.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)

assets/build/style-block-rtl.css

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

width is already defined here.

Remove or rename the duplicate property to ensure consistent styling.

(lint/suspicious/noDuplicateProperties)

assets/build/blocks/DocsGrid/index.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 1047-1047: Shouldn't redeclare 'i'. Consider to delete it or rename it.

'i' is defined here:

(lint/suspicious/noRedeclare)


[error] 1048-1048: Shouldn't redeclare 'chunkIds'. Consider to delete it or rename it.

'chunkIds' is defined here:

(lint/suspicious/noRedeclare)


[error] 1048-1048: Shouldn't redeclare 'fn'. Consider to delete it or rename it.

'fn' is defined here:

(lint/suspicious/noRedeclare)


[error] 1048-1048: Shouldn't redeclare 'priority'. Consider to delete it or rename it.

'priority' is defined here:

(lint/suspicious/noRedeclare)

assets/build/blocks/TableOfContents/index.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 1086-1086: Shouldn't redeclare 'i'. Consider to delete it or rename it.

'i' is defined here:

(lint/suspicious/noRedeclare)


[error] 1087-1087: Shouldn't redeclare 'chunkIds'. Consider to delete it or rename it.

'chunkIds' is defined here:

(lint/suspicious/noRedeclare)


[error] 1087-1087: Shouldn't redeclare 'fn'. Consider to delete it or rename it.

'fn' is defined here:

(lint/suspicious/noRedeclare)


[error] 1087-1087: Shouldn't redeclare 'priority'. Consider to delete it or rename it.

'priority' is defined here:

(lint/suspicious/noRedeclare)

assets/build/blocks/Contributors/index.js

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

The variable is declared here:

(lint/correctness/noInvalidUseBeforeDeclaration)


[error] 1797-1797: Shouldn't redeclare 'i'. Consider to delete it or rename it.

'i' is defined here:

(lint/suspicious/noRedeclare)


[error] 1798-1798: Shouldn't redeclare 'chunkIds'. Consider to delete it or rename it.

'chunkIds' is defined here:

(lint/suspicious/noRedeclare)


[error] 1798-1798: Shouldn't redeclare 'fn'. Consider to delete it or rename it.

'fn' is defined here:

(lint/suspicious/noRedeclare)


[error] 1798-1798: Shouldn't redeclare 'priority'. Consider to delete it or rename it.

'priority' is defined here:

(lint/suspicious/noRedeclare)

assets/build/store.js

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

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


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

The declaration is defined in this switch clause:

Safe fix: Wrap the declaration in a block.

(lint/correctness/noSwitchDeclarations)


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

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

(lint/correctness/noUnsafeOptionalChaining)


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

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

(lint/correctness/noUnsafeOptionalChaining)

🪛 PHPMD (2.15.0)
src/blocks/AdvanceContributors/render.php

10-10: Avoid unused parameters such as '$content'. (undefined)

(UnusedFormalParameter)


10-10: Avoid unused parameters such as '$block'. (undefined)

(UnusedFormalParameter)

assets/build/blocks/TableOfContents/render.php

308-308: Avoid unused parameters such as '$content'. (undefined)

(UnusedFormalParameter)


308-308: Avoid unused parameters such as '$block'. (undefined)

(UnusedFormalParameter)


328-328: Avoid unused local variables such as '$list_hover_color'. (undefined)

(UnusedLocalVariable)


330-330: Avoid unused local variables such as '$smooth_scroll'. (undefined)

(UnusedLocalVariable)

assets/build/blocks/AdvanceContributors/render.php

10-10: Avoid unused parameters such as '$content'. (undefined)

(UnusedFormalParameter)


10-10: Avoid unused parameters such as '$block'. (undefined)

(UnusedFormalParameter)

assets/build/blocks/DocsGrid/render.php

183-183: Avoid unused local variables such as '$total_pages'. (undefined)

(UnusedLocalVariable)


228-228: Avoid unused local variables such as '$total_articles'. (undefined)

(UnusedLocalVariable)

🔇 Additional comments (19)
assets/build/print-rtl.css (3)

52-52: LGTM: RTL-specific properties are correctly implemented.

The RTL adaptations are properly applied:

  • Line 52: float: right for definition term positioning
  • Line 72: Margin adjusted for RTL text flow
  • Line 84: border-right instead of border-left for callout styling
  • Line 165: text-align: right for table cells

Also applies to: 72-72, 84-84, 165-165


144-147: LGTM: Standard print stylesheet pattern for displaying URLs.

The CSS correctly displays link URLs after anchor text when printing, which is a best practice for print stylesheets. The exclusion of .anchorjs-link prevents anchor navigation links from cluttering the printed output.


1-184: Verify whether build artifacts should be committed.

This file is also a generated build artifact. As with assets/build/print.js, consider whether build artifacts should be committed to the repository.

Please verify:

  1. Are CSS build artifacts intentionally committed in this repository?
  2. Is there a .gitignore rule that should exclude assets/build/?

The same verification script from the print.js review can help check the repository's build artifact strategy.

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

1-1: Dependency updates align with modern WordPress/React patterns.

The replacement of 'react' with 'react-jsx-runtime' reflects the modern JSX transform introduced in React 17+. The additions of 'wp-core-data' and 'wp-data' indicate integration with WordPress data stores, which is appropriate for dynamic block functionality.

However, this file is a generated build artifact. Verify whether build artifacts should be committed to the repository.

assets/build/blocks/dynamic-table-of-contents/src/index.asset.php (1)

1-1: Build artifact - dependencies are appropriate for a Gutenberg block.

This PHP asset manifest contains standard WordPress Gutenberg block dependencies. However, as a generated build artifact, verify whether it should be committed to version control.

assets/build/style-block.css (2)

53-54: Vendor prefix fallback is correct, not a duplicate.

The static analysis tool flagged lines 53-54 as duplicate properties, but this is a vendor prefix fallback pattern:

  • Line 53: width: -moz-fit-content; (Firefox-specific)
  • Line 54: width: fit-content; (standard property)

This is the correct way to handle vendor prefixes - older browsers use the prefixed version, modern browsers use the standard property. This is intentional and not an error.


1-139: Build artifact should be verified for version control inclusion.

This is a generated CSS bundle. Verify whether build artifacts should be committed to the repository.

assets/build/frontend.js (1)

1-28: Standard webpack build artifact.

This is generated webpack runtime/bootstrap code. Verify whether build artifacts should be committed to version control.

assets/build/blocks/TableOfContents/index-rtl.css (1)

1-20: RTL styles are appropriate, but verify build artifact inclusion.

The RTL-specific styles for the Table of Contents block look correct:

  • Mobile notice with proper RTL border positioning (border-right instead of border-left)
  • Appropriate hover states for links

However, this is a generated build artifact. Verify whether it should be committed to version control.

assets/build/style-block-rtl.css (3)

53-54: Vendor prefix fallback is correct, not a duplicate.

Similar to the LTR version, the static analysis tool flagged lines 53-54 as duplicate properties, but this is an intentional vendor prefix fallback pattern for browser compatibility.


47-62: RTL layout adjustments are correct.

The RTL-specific changes properly flip the layout:

  • Line 47: left: 0 (instead of right: 0 in LTR) for search submit button
  • Line 62: margin-right: auto (instead of margin-left: auto in LTR)

These are appropriate RTL adaptations.


1-137: Build artifact should be verified for version control inclusion.

This is a generated RTL CSS bundle. Verify whether build artifacts should be committed to the repository.

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

1-1: LGTM!

The asset manifest correctly declares WordPress dependencies (wp-blocks, wp-element, wp-block-editor, etc.) needed for a Gutenberg block, along with a version hash for cache busting.

assets/build/blocks/Contributors/style-index-rtl.css (1)

1-137: LGTM! Well-structured RTL styles with excellent accessibility support.

The RTL stylesheet correctly handles directionality for flex layouts and includes comprehensive accessibility features:

  • High contrast mode support (lines 105-112)
  • Reduced motion preferences (lines 113-123)
  • Dark mode support (lines 124-128)
  • Print optimizations (lines 129-137)
  • Responsive breakpoints for mobile/tablet
assets/build/blocks/TableOfContents/block.json (1)

1-159: LGTM! Well-structured block manifest.

The block configuration is comprehensive and well-organized:

  • Clear attribute definitions with appropriate types and defaults
  • Good use of server-side rendering via render.php
  • Proper asset declarations for editor and frontend
  • Supports essential block features (anchor, color controls)
assets/build/blocks/DocsGrid/style-index-rtl.css (1)

213-215: Good RTL support for directional indicators.

The RTL-specific arrow direction (content: "←") for the details link is a good practice for RTL layouts, ensuring visual indicators remain intuitive for right-to-left readers.

src/blocks/AdvanceContributors/style.scss (1)

122-148: Excellent accessibility support!

The implementation of accessibility features is commendable:

  • High contrast mode support (lines 123-133)
  • Reduced motion support (lines 136-148)
  • Dark mode support (lines 151-157)
  • Print styles (lines 160-171)

The use of !important in reduced-motion contexts (lines 138, 141, 146) is appropriate as these are accessibility overrides that should take precedence.

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

1-1: Standard WordPress asset manifest format.

This file follows the standard WordPress asset manifest format used by @wordpress/dependency-extraction-webpack-plugin. The dependencies and version hash are automatically generated during the build process.

Note: As a build artifact, this file would typically be gitignored and generated during deployment (see earlier comment about build artifacts).

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

17-331: Well-structured and comprehensive attribute definitions.

The block manifest demonstrates excellent organization:

  • Consistent per-device attribute structure (desktop/tablet/mobile)
  • Appropriate use of enums for validation (contributorDisplayMode, avatarType, avatarShape, linkBehavior)
  • Sensible default values
  • Clear attribute types

Comment on lines +1 to +22
/*!***************************************************************************************************************************************************************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/TableOfContents/editor.scss ***!
\***************************************************************************************************************************************************************************************************************************************************************/
/**
* The following styles get applied inside the editor only.
*/
.wp-block-wedocs-table-of-contents .toc-mobile-notice {
background-color: rgba(0, 115, 170, 0.1);
padding: 5px 10px;
border-radius: 3px;
border-left: 3px solid #0073aa;
color: #0073aa;
font-size: 12px;
}
.wp-block-wedocs-table-of-contents .toc-content .toc-list li a {
cursor: default;
}
.wp-block-wedocs-table-of-contents .toc-content .toc-list li a:hover {
color: #0073aa;
}

/*# sourceMappingURL=block.css.map*/ No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Remove duplicate CSS file.

This file appears to be a duplicate of assets/build/blocks/TableOfContents/index.css. Both files contain identical editor-only styles for the Table of Contents block. Having duplicate stylesheets increases bundle size and maintenance overhead.

Consider removing one of these files and updating the build configuration to reference a single source of truth for the Table of Contents editor styles.

🤖 Prompt for AI Agents
In assets/build/block.css around lines 1 to 22, this file duplicates the
editor-only Table of Contents styles already present in
assets/build/blocks/TableOfContents/index.css; remove the redundant file and
update build/config references to point to the single canonical stylesheet
(prefer the blocks/TableOfContents source), remove any import or entry that
emits assets/build/block.css from the build pipeline, and ensure source maps and
any registrations (enqueue/block registration) now reference the remaining CSS
so the editor still receives the styles.

{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "wedocs/contributors",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Critical: Potential block name collision.

The block name is wedocs/contributors (line 4), which may conflict with another Contributors block mentioned in the AI summary (assets/build/blocks/Contributors/block.json). Each block must have a unique name in WordPress.

Verify whether there's a naming conflict:

If both blocks are intended to be separate, one should be renamed (e.g., wedocs/advance-contributors vs wedocs/contributors).


🏁 Script executed:

#!/bin/bash
echo "=== Searching for block registrations with 'wedocs/contributors' ==="
rg -n "wedocs/contributors" --type=json --type=js --type=php

echo -e "\n=== Listing all block.json files and their names ==="
fd -e json block.json -x sh -c 'echo "File: {}"; jq -r ".name" {}'

echo -e "\n=== Checking for duplicate block names ==="
fd -e json block.json -x jq -r ".name" {} | sort | uniq -d

Length of output: 15571


Rename AdvanceContributors block name: Change the block name in src/blocks/AdvanceContributors/block.json and assets/build/blocks/AdvanceContributors/block.json from wedocs/contributors to wedocs/advance-contributors to avoid collision with the existing Contributors block.

🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/block.json around line 4 (and
likewise update src/blocks/AdvanceContributors/block.json), the block "name" is
currently "wedocs/contributors" which collides with the existing Contributors
block; change the "name" value to "wedocs/advance-contributors" in both JSON
files, ensure the JSON remains valid (commas/quotes intact), and verify any
references/imports/registration code use the new slug so the build and block
registration remain consistent.

Comment on lines +497 to +499
return $output;
}
render_wedocs_advance_contributors_block( $attributes, $content, $block );
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Return the rendered markup (built asset)

The compiled render file needs the same return render_wedocs_advance_contributors_block(...) change as the source; otherwise the block still outputs 1. Please regenerate the build after fixing the source.

🤖 Prompt for AI Agents
In assets/build/blocks/AdvanceContributors/render.php around lines 497-499 the
compiled file calls render_wedocs_advance_contributors_block($attributes,
$content, $block); without returning it, so the block outputs `1`; change that
call to return render_wedocs_advance_contributors_block($attributes, $content,
$block); to return the rendered markup and then regenerate the build from source
so the compiled asset matches the source change.

Comment on lines +1 to +139
/*!******************************************************************************************************************************************************************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[4].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[4].use[2]!./node_modules/sass-loader/dist/cjs.js??ruleSet[1].rules[4].use[3]!./src/blocks/AdvanceContributors/style.scss ***!
\******************************************************************************************************************************************************************************************************************************************************************/
/**
* Frontend styles for the Contributors block
*/
.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 0.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, 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: white;
}
.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 0.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: 0.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: 0.9em;
}
.wedocs-contributors .last-updated {
font-size: 0.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;
}
}

/*# sourceMappingURL=style-index.css.map*/ No newline at end of file
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify if build artifacts should be committed to the repository.

This file appears to be a compiled build artifact (based on the webpack loader comment at lines 1-3 and the source map reference at line 139). Build artifacts are typically excluded from version control via .gitignore and generated during deployment.

Additionally, this file is identical to assets/build/blocks/Contributors/style-index.css, suggesting code duplication between the Contributors and AdvanceContributors blocks.

Run the following script to verify:

  1. Whether build directories are gitignored
  2. The extent of duplication between these two blocks

🏁 Script executed:

#!/bin/bash
# Check if build directories are gitignored
echo "=== Checking .gitignore for build artifacts ==="
if [ -f .gitignore ]; then
    grep -E "(assets/build|/build/|\.map)" .gitignore || echo "No build artifact patterns found in .gitignore"
else
    echo ".gitignore not found"
fi

echo -e "\n=== Comparing AdvanceContributors and Contributors CSS files ==="
if [ -f "assets/build/blocks/Contributors/style-index.css" ] && [ -f "assets/build/blocks/AdvanceContributors/style-index.css" ]; then
    diff assets/build/blocks/Contributors/style-index.css assets/build/blocks/AdvanceContributors/style-index.css
    if [ $? -eq 0 ]; then
        echo "Files are identical - duplication confirmed"
    else
        echo "Files differ"
    fi
else
    echo "One or both files not found"
fi

echo -e "\n=== Checking for other duplicate style files ==="
fd -e css -e scss style-index assets/build/blocks/ -x md5sum {} \; | sort | uniq -w32 -D

Length of output: 1808


Exclude compiled CSS and consolidate duplicated styles

  • Add assets/build/blocks/**/style-index.css and .css.map to .gitignore, remove these committed build artifacts
  • Extract common SCSS into a shared partial and import it in both AdvanceContributors and Contributors blocks instead of duplicating the output
🤖 Prompt for AI Agents
assets/build/blocks/AdvanceContributors/style-index.css lines 1-139: The review
requests removing committed compiled CSS artifacts and eliminating duplicated
styles; to fix, add assets/build/blocks/**/style-index.css and their .css.map
files to .gitignore, remove the tracked compiled files from the repo (git rm
--cached or delete and commit), and regenerate the build so they’re not
re-added; next, refactor the duplicated output by extracting the shared rules
into a new SCSS partial (e.g., _contributors-common.scss), import that partial
into the AdvanceContributors and Contributors block SCSS entry files, remove
duplicated SCSS from each block, rebuild to verify the compiled output still
contains necessary styles, and commit only the source SCSS and updated
.gitignore.

Comment on lines +414 to +889
const Edit = ({
attributes,
setAttributes
}) => {
const blockProps = (0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.useBlockProps)();
const {
useSelect
} = wp.data;
const [currentPage, setCurrentPage] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_2__.useState)(1);
const [loading, setLoading] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_2__.useState)(false);
const {
hideDocGrid,
docStyle,
docsPerPage,
excludeDocs,
order,
orderBy,
sectionsPerDoc,
articlesPerSection,
showDocArticle,
keepArticlesCollapsed,
showViewDetails,
gridPadding,
gridMargin,
docTitleColor,
docChildrenActiveColor,
borderType,
borderRadius,
borderWidth,
borderColor,
buttonBorderRadius,
buttonPadding,
buttonMargin,
buttonColor,
buttonHoverColor,
buttonTextColor,
buttonText,
buttonHoverTextColor
} = attributes;
const applyStyles = () => {
const paddings = gridPadding ? `${gridPadding.top} ${gridPadding.right} ${gridPadding.bottom} ${gridPadding.left}` : '';
const margins = gridMargin ? `${gridMargin.top} ${gridMargin.right} ${gridMargin.bottom} ${gridMargin.left}` : '';
const btnPaddings = buttonPadding ? `${buttonPadding.top} ${buttonPadding.right} ${buttonPadding.bottom} ${buttonPadding.left}` : '';
const btnradius = buttonBorderRadius || '8px';
const btnMargins = buttonMargin ? `${buttonMargin.top} ${buttonMargin.right} ${buttonMargin.bottom} ${buttonMargin.left}` : '';
return {
item: {
padding: paddings,
margin: margins,
borderStyle: borderType || 'solid',
borderWidth: borderWidth || '1px',
borderColor: borderColor || 'rgba(0, 0, 0, 0.1)',
borderRadius: borderRadius || '8px',
backgroundColor: '#fff'
},
title: {
color: docTitleColor || '#1e1e1e'
},
children: {
color: docChildrenActiveColor || '#0073aa'
},
button: {
padding: btnPaddings,
margin: btnMargins,
backgroundColor: buttonColor || '#0073aa',
color: buttonTextColor || '#ffffff',
text: buttonText || (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('View Details', 'wedocs'),
borderRadius: btnradius || '8px',
'--hover-bg': buttonHoverColor || '#005177',
'--hover-color': buttonHoverTextColor || '#ffffff'
}
};
};
const renderGridItem = (doc, styles) => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: "wedocs-docs-grid__item",
style: styles.item,
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("h3", {
className: "wedocs-docs-grid__title",
style: styles.title,
children: doc.title.rendered
}), renderSections(doc, styles), showViewDetails && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: "wedocs-docs-grid__details",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("span", {
className: "wedocs-docs-grid__details-link",
style: styles.button,
children: styles.button.text
})
})]
}, doc.id);
const renderSections = (doc, styles) => {
if (!doc.sections) return null;
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: `wedocs-docs-grid__sections ${keepArticlesCollapsed ? 'is-collapsed' : ''}`,
children: [doc.sections.map(section => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: "wedocs-docs-grid__section",
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("h4", {
className: "wedocs-docs-grid__section-title",
style: {
...styles.title,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("span", {
children: section.title.rendered
}), showDocArticle && section.articles && section.articles.length > 0 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("svg", {
fill: "none",
viewBox: "0 0 24 24",
width: "16",
strokeWidth: "2",
stroke: "#acb8c4",
className: keepArticlesCollapsed ? '' : 'active',
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19.5 8.25l-7.5 7.5-7.5-7.5"
})
})]
}), showDocArticle && !keepArticlesCollapsed && section.articles && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("ul", {
className: "wedocs-docs-grid__articles",
children: section.articles.map(article => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("li", {
className: "wedocs-docs-grid__article",
style: styles.children,
children: article.title.rendered
}, article.id))
})]
}, section.id)), doc.sections.length === 0 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("span", {
className: "inside",
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("svg", {
fill: "none",
viewBox: "0 0 24 24",
"stroke-width": "1.5",
stroke: "currentColor",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.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,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('This document has no sections yet. Check back later or wait for the author to add content.', 'wedocs')]
})]
});
};

// Control options
const docStyles = [{
label: '1x1',
value: '1x1'
}, {
label: '1x2',
value: '1x2'
}];
const docsPerPageOptions = [{
label: 'All',
value: 'all'
}, ...Array.from({
length: 10
}, (_, i) => ({
label: String(i + 1),
value: String(i + 1)
}))];
const orderByOptions = [{
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('weDocs Order', 'wedocs'),
value: 'menu_order'
}, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('ID', 'wedocs'),
value: 'id'
}, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Name', 'wedocs'),
value: 'title'
}];
const orderOptions = [{
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Ascending', 'wedocs'),
value: 'asc'
}, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Descending', 'wedocs'),
value: 'desc'
}];
const countOptions = [{
label: 'All',
value: 'all'
}, ...Array.from({
length: 10
}, (_, i) => ({
label: String(i + 1),
value: String(i + 1)
}))];
// Get published docs
const {
pages,
sections,
articles
} = useSelect(select => {
const {
getEntityRecords
} = select('core');
const docs = getEntityRecords('postType', 'docs', {
status: 'publish',
per_page: -1,
parent: 0,
orderby: orderBy,
order: order
});

// Get all sections (docs children)
const allSections = docs ? getEntityRecords('postType', 'docs', {
status: 'publish',
parent_in: docs.map(doc => doc.id),
per_page: -1
}) : null;

// Get all articles (sections children)
const allArticles = allSections ? getEntityRecords('postType', 'docs', {
status: 'publish',
parent_in: allSections.map(section => section.id),
per_page: -1
}) : null;
return {
pages: docs,
sections: allSections,
articles: allArticles
};
}, [orderBy, order]);
const processDocsData = () => {
if (!pages || !sections || !articles) return [];

// Filter and sort docs based on settings
let processedDocs = [...pages];

// Apply exclude filter
if (excludeDocs && excludeDocs.length > 0) {
processedDocs = processedDocs.filter(doc => !excludeDocs.includes(doc.id.toString()));
}

// Process each doc with its sections and articles
processedDocs = processedDocs.map(doc => {
// Get sections for this doc
let docSections = sections.filter(section => section.parent === doc.id);

// Limit sections if specified
if (sectionsPerDoc !== 'all') {
docSections = docSections.slice(0, parseInt(sectionsPerDoc));
}

// Process sections with their articles
docSections = docSections.map(section => {
let sectionArticles = articles.filter(article => article.parent === section.id);

// Limit articles if specified
if (articlesPerSection !== 'all') {
sectionArticles = sectionArticles.slice(0, parseInt(articlesPerSection));
}
return {
...section,
articles: sectionArticles
};
});

// Calculate total articles for the doc
const totalArticles = docSections.reduce((total, section) => total + section.articles.length, 0);
return {
...doc,
sections: docSections,
articleCount: totalArticles
};
});
return processedDocs;
};
// Handle pagination
const getPagedDocs = docs => {
if (docsPerPage === 'all') return docs;
const perPage = parseInt(docsPerPage);
const start = (currentPage - 1) * perPage;
const end = start + perPage;
return docs.slice(start, end);
};

// Get final display docs
const getDisplayDocs = () => {
const processedDocs = processDocsData();
return getPagedDocs(processedDocs);
};

// Pagination controls
const renderPagination = totalDocs => {
if (docsPerPage === 'all') return null;
const totalPages = Math.ceil(totalDocs.length / parseInt(docsPerPage));

// Create style objects for pagination buttons
const paginationBaseStyle = {
padding: '8px 12px',
margin: '0 4px',
backgroundColor: attributes.paginationBackgroundColor || '#fff',
color: attributes.paginationTextColor || '#333',
border: `1px solid ${attributes.paginationBorderColor || '#ddd'}`,
borderRadius: attributes.borderRadius || '4px',
cursor: 'pointer',
transition: 'all 0.2s ease',
textDecoration: 'none',
display: 'inline-block',
minWidth: '32px',
textAlign: 'center',
fontFamily: 'inherit',
fontSize: '14px',
lineHeight: '1.4'
};

// Active button style
const activeStyle = {
...paginationBaseStyle,
backgroundColor: attributes.paginationHoverColor || '#f5f5f5',
borderColor: attributes.paginationHoverColor || '#ccc',
color: attributes.paginationTextHoverColor || '#0073aa'
};

// Hover styles will be handled by CSS custom properties
const customProperties = {
'--pagination-hover-bg': attributes.paginationHoverColor || '#f5f5f5',
'--pagination-hover-color': attributes.paginationTextHoverColor || '#0073aa',
'--pagination-hover-border': attributes.paginationHoverColor || '#ccc'
};
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: "wedocs-docs-pagination",
style: {
margin: '30px 0',
textAlign: 'center',
...customProperties
},
children: [currentPage > 1 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("button", {
style: paginationBaseStyle,
onClick: () => setCurrentPage(currentPage - 1),
className: "wedocs-docs-pagination__button",
children: "\u2190"
}), Array.from({
length: totalPages
}, (_, i) => {
const pageNum = i + 1;
const isCurrentPage = currentPage === pageNum;
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("button", {
style: isCurrentPage ? activeStyle : paginationBaseStyle,
className: `wedocs-docs-pagination__button ${isCurrentPage ? 'is-active' : ''}`,
onClick: () => setCurrentPage(pageNum),
children: pageNum
}, pageNum);
}), currentPage < totalPages && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("button", {
style: paginationBaseStyle,
onClick: () => setCurrentPage(currentPage + 1),
className: "wedocs-docs-pagination__button",
children: "\u2192"
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("style", {
children: `
.wedocs-docs-pagination__button:hover:not(.is-active) {
background-color: var(--pagination-hover-bg) !important;
color: var(--pagination-hover-color) !important;
border-color: var(--pagination-hover-border) !important;
}
`
})]
});
};
const displayDocs = getDisplayDocs();
// Create a mapping of ID to title for suggestions
const docsMap = pages ? pages.reduce((acc, page) => {
acc[page.id] = page.title.rendered;
return acc;
}, {}) : {};

// Prepare docs options for FormTokenField
const docsOptions = pages ? pages.map(page => ({
value: page.id.toString(),
label: page.title.rendered
})) : [];

// Update handlers
const updateAttribute = attributeName => value => {
setAttributes({
[attributeName]: value
});
};

// Transform IDs to titles for FormTokenField display
const excludeDocsDisplay = excludeDocs ? excludeDocs.map(id => docsMap[id] || id) : [];

// Handle token changes
const handleExcludeDocsChange = tokens => {
// Convert titles back to IDs
const newExcludeDocs = tokens.map(token => {
// Find the ID for this title
const found = Object.entries(docsMap).find(([id, title]) => title === token);
return found ? found[0] : token;
});
setAttributes({
excludeDocs: newExcludeDocs
});
};
const getGridClass = () => {
return `wedocs-docs-grid--${docStyle}`;
};
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(_wordpress_element__WEBPACK_IMPORTED_MODULE_2__.Fragment, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.InspectorControls, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelBody, {
title: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Doc Grid Settings', 'wedocs'),
icon: _wordpress_icons__WEBPACK_IMPORTED_MODULE_1__["default"],
initialOpen: false,
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: docStyle,
options: docStyles,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('DOCS GRID COLUMN STYLE', 'wedocs'),
onChange: updateAttribute('docStyle')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: docsPerPage,
options: docsPerPageOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Docs per page', 'wedocs'),
onChange: updateAttribute('docsPerPage')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.FormTokenField, {
value: excludeDocsDisplay,
suggestions: Object.values(docsMap),
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Exclude Docs', 'wedocs'),
onChange: handleExcludeDocsChange
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: order,
options: orderOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Order', 'wedocs'),
onChange: updateAttribute('order')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: orderBy,
options: orderByOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Order by', 'wedocs'),
onChange: updateAttribute('orderBy')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: sectionsPerDoc,
options: countOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Sections per doc', 'wedocs'),
onChange: updateAttribute('sectionsPerDoc')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: articlesPerSection,
options: countOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Articles per section', 'wedocs'),
onChange: updateAttribute('articlesPerSection')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.ToggleControl, {
checked: showDocArticle,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Show Doc Article', 'wedocs'),
onChange: updateAttribute('showDocArticle')
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.ToggleControl, {
checked: keepArticlesCollapsed,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Keep Article Collapsed', 'wedocs'),
onChange: updateAttribute('keepArticlesCollapsed')
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.ToggleControl, {
checked: showViewDetails,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Show View Details Button', 'wedocs'),
onChange: updateAttribute('showViewDetails')
})
})]
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.InspectorControls, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_StyleControls__WEBPACK_IMPORTED_MODULE_5__["default"], {
attributes: attributes,
setAttributes: setAttributes
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
...blockProps,
children: hideDocGrid ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: "backdrop"
}) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: "wedocs-block-wrapper",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: `wedocs-docs-grid ${getGridClass()}`,
children: loading ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(Spinner, {}) : displayDocs.map(doc => renderGridItem(doc, applyStyles()))
})
})
})]
});
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Import Spinner before using it

renderGridItem renders <Spinner/>, but the component is never imported, so the editor throws ReferenceError: Spinner is not defined. Import it from @wordpress/components along with the other controls:

-import { PanelBody, SelectControl, FormTokenField, PanelRow, ToggleControl, TextControl } from '@wordpress/components';
+import {
+  PanelBody,
+  SelectControl,
+  FormTokenField,
+  PanelRow,
+  ToggleControl,
+  TextControl,
+  Spinner,
+} from '@wordpress/components';

(or reference wp.components.Spinner). Without this, the Docs Grid block breaks whenever it enters the loading state.

📝 Committable suggestion

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

Suggested change
const Edit = ({
attributes,
setAttributes
}) => {
const blockProps = (0,_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.useBlockProps)();
const {
useSelect
} = wp.data;
const [currentPage, setCurrentPage] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_2__.useState)(1);
const [loading, setLoading] = (0,_wordpress_element__WEBPACK_IMPORTED_MODULE_2__.useState)(false);
const {
hideDocGrid,
docStyle,
docsPerPage,
excludeDocs,
order,
orderBy,
sectionsPerDoc,
articlesPerSection,
showDocArticle,
keepArticlesCollapsed,
showViewDetails,
gridPadding,
gridMargin,
docTitleColor,
docChildrenActiveColor,
borderType,
borderRadius,
borderWidth,
borderColor,
buttonBorderRadius,
buttonPadding,
buttonMargin,
buttonColor,
buttonHoverColor,
buttonTextColor,
buttonText,
buttonHoverTextColor
} = attributes;
const applyStyles = () => {
const paddings = gridPadding ? `${gridPadding.top} ${gridPadding.right} ${gridPadding.bottom} ${gridPadding.left}` : '';
const margins = gridMargin ? `${gridMargin.top} ${gridMargin.right} ${gridMargin.bottom} ${gridMargin.left}` : '';
const btnPaddings = buttonPadding ? `${buttonPadding.top} ${buttonPadding.right} ${buttonPadding.bottom} ${buttonPadding.left}` : '';
const btnradius = buttonBorderRadius || '8px';
const btnMargins = buttonMargin ? `${buttonMargin.top} ${buttonMargin.right} ${buttonMargin.bottom} ${buttonMargin.left}` : '';
return {
item: {
padding: paddings,
margin: margins,
borderStyle: borderType || 'solid',
borderWidth: borderWidth || '1px',
borderColor: borderColor || 'rgba(0, 0, 0, 0.1)',
borderRadius: borderRadius || '8px',
backgroundColor: '#fff'
},
title: {
color: docTitleColor || '#1e1e1e'
},
children: {
color: docChildrenActiveColor || '#0073aa'
},
button: {
padding: btnPaddings,
margin: btnMargins,
backgroundColor: buttonColor || '#0073aa',
color: buttonTextColor || '#ffffff',
text: buttonText || (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('View Details', 'wedocs'),
borderRadius: btnradius || '8px',
'--hover-bg': buttonHoverColor || '#005177',
'--hover-color': buttonHoverTextColor || '#ffffff'
}
};
};
const renderGridItem = (doc, styles) => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: "wedocs-docs-grid__item",
style: styles.item,
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("h3", {
className: "wedocs-docs-grid__title",
style: styles.title,
children: doc.title.rendered
}), renderSections(doc, styles), showViewDetails && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: "wedocs-docs-grid__details",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("span", {
className: "wedocs-docs-grid__details-link",
style: styles.button,
children: styles.button.text
})
})]
}, doc.id);
const renderSections = (doc, styles) => {
if (!doc.sections) return null;
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: `wedocs-docs-grid__sections ${keepArticlesCollapsed ? 'is-collapsed' : ''}`,
children: [doc.sections.map(section => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: "wedocs-docs-grid__section",
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("h4", {
className: "wedocs-docs-grid__section-title",
style: {
...styles.title,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center'
},
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("span", {
children: section.title.rendered
}), showDocArticle && section.articles && section.articles.length > 0 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("svg", {
fill: "none",
viewBox: "0 0 24 24",
width: "16",
strokeWidth: "2",
stroke: "#acb8c4",
className: keepArticlesCollapsed ? '' : 'active',
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("path", {
strokeLinecap: "round",
strokeLinejoin: "round",
d: "M19.5 8.25l-7.5 7.5-7.5-7.5"
})
})]
}), showDocArticle && !keepArticlesCollapsed && section.articles && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("ul", {
className: "wedocs-docs-grid__articles",
children: section.articles.map(article => /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("li", {
className: "wedocs-docs-grid__article",
style: styles.children,
children: article.title.rendered
}, article.id))
})]
}, section.id)), doc.sections.length === 0 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("span", {
className: "inside",
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("svg", {
fill: "none",
viewBox: "0 0 24 24",
"stroke-width": "1.5",
stroke: "currentColor",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.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,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('This document has no sections yet. Check back later or wait for the author to add content.', 'wedocs')]
})]
});
};
// Control options
const docStyles = [{
label: '1x1',
value: '1x1'
}, {
label: '1x2',
value: '1x2'
}];
const docsPerPageOptions = [{
label: 'All',
value: 'all'
}, ...Array.from({
length: 10
}, (_, i) => ({
label: String(i + 1),
value: String(i + 1)
}))];
const orderByOptions = [{
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('weDocs Order', 'wedocs'),
value: 'menu_order'
}, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('ID', 'wedocs'),
value: 'id'
}, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Name', 'wedocs'),
value: 'title'
}];
const orderOptions = [{
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Ascending', 'wedocs'),
value: 'asc'
}, {
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Descending', 'wedocs'),
value: 'desc'
}];
const countOptions = [{
label: 'All',
value: 'all'
}, ...Array.from({
length: 10
}, (_, i) => ({
label: String(i + 1),
value: String(i + 1)
}))];
// Get published docs
const {
pages,
sections,
articles
} = useSelect(select => {
const {
getEntityRecords
} = select('core');
const docs = getEntityRecords('postType', 'docs', {
status: 'publish',
per_page: -1,
parent: 0,
orderby: orderBy,
order: order
});
// Get all sections (docs children)
const allSections = docs ? getEntityRecords('postType', 'docs', {
status: 'publish',
parent_in: docs.map(doc => doc.id),
per_page: -1
}) : null;
// Get all articles (sections children)
const allArticles = allSections ? getEntityRecords('postType', 'docs', {
status: 'publish',
parent_in: allSections.map(section => section.id),
per_page: -1
}) : null;
return {
pages: docs,
sections: allSections,
articles: allArticles
};
}, [orderBy, order]);
const processDocsData = () => {
if (!pages || !sections || !articles) return [];
// Filter and sort docs based on settings
let processedDocs = [...pages];
// Apply exclude filter
if (excludeDocs && excludeDocs.length > 0) {
processedDocs = processedDocs.filter(doc => !excludeDocs.includes(doc.id.toString()));
}
// Process each doc with its sections and articles
processedDocs = processedDocs.map(doc => {
// Get sections for this doc
let docSections = sections.filter(section => section.parent === doc.id);
// Limit sections if specified
if (sectionsPerDoc !== 'all') {
docSections = docSections.slice(0, parseInt(sectionsPerDoc));
}
// Process sections with their articles
docSections = docSections.map(section => {
let sectionArticles = articles.filter(article => article.parent === section.id);
// Limit articles if specified
if (articlesPerSection !== 'all') {
sectionArticles = sectionArticles.slice(0, parseInt(articlesPerSection));
}
return {
...section,
articles: sectionArticles
};
});
// Calculate total articles for the doc
const totalArticles = docSections.reduce((total, section) => total + section.articles.length, 0);
return {
...doc,
sections: docSections,
articleCount: totalArticles
};
});
return processedDocs;
};
// Handle pagination
const getPagedDocs = docs => {
if (docsPerPage === 'all') return docs;
const perPage = parseInt(docsPerPage);
const start = (currentPage - 1) * perPage;
const end = start + perPage;
return docs.slice(start, end);
};
// Get final display docs
const getDisplayDocs = () => {
const processedDocs = processDocsData();
return getPagedDocs(processedDocs);
};
// Pagination controls
const renderPagination = totalDocs => {
if (docsPerPage === 'all') return null;
const totalPages = Math.ceil(totalDocs.length / parseInt(docsPerPage));
// Create style objects for pagination buttons
const paginationBaseStyle = {
padding: '8px 12px',
margin: '0 4px',
backgroundColor: attributes.paginationBackgroundColor || '#fff',
color: attributes.paginationTextColor || '#333',
border: `1px solid ${attributes.paginationBorderColor || '#ddd'}`,
borderRadius: attributes.borderRadius || '4px',
cursor: 'pointer',
transition: 'all 0.2s ease',
textDecoration: 'none',
display: 'inline-block',
minWidth: '32px',
textAlign: 'center',
fontFamily: 'inherit',
fontSize: '14px',
lineHeight: '1.4'
};
// Active button style
const activeStyle = {
...paginationBaseStyle,
backgroundColor: attributes.paginationHoverColor || '#f5f5f5',
borderColor: attributes.paginationHoverColor || '#ccc',
color: attributes.paginationTextHoverColor || '#0073aa'
};
// Hover styles will be handled by CSS custom properties
const customProperties = {
'--pagination-hover-bg': attributes.paginationHoverColor || '#f5f5f5',
'--pagination-hover-color': attributes.paginationTextHoverColor || '#0073aa',
'--pagination-hover-border': attributes.paginationHoverColor || '#ccc'
};
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)("div", {
className: "wedocs-docs-pagination",
style: {
margin: '30px 0',
textAlign: 'center',
...customProperties
},
children: [currentPage > 1 && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("button", {
style: paginationBaseStyle,
onClick: () => setCurrentPage(currentPage - 1),
className: "wedocs-docs-pagination__button",
children: "\u2190"
}), Array.from({
length: totalPages
}, (_, i) => {
const pageNum = i + 1;
const isCurrentPage = currentPage === pageNum;
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("button", {
style: isCurrentPage ? activeStyle : paginationBaseStyle,
className: `wedocs-docs-pagination__button ${isCurrentPage ? 'is-active' : ''}`,
onClick: () => setCurrentPage(pageNum),
children: pageNum
}, pageNum);
}), currentPage < totalPages && /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("button", {
style: paginationBaseStyle,
onClick: () => setCurrentPage(currentPage + 1),
className: "wedocs-docs-pagination__button",
children: "\u2192"
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("style", {
children: `
.wedocs-docs-pagination__button:hover:not(.is-active) {
background-color: var(--pagination-hover-bg) !important;
color: var(--pagination-hover-color) !important;
border-color: var(--pagination-hover-border) !important;
}
`
})]
});
};
const displayDocs = getDisplayDocs();
// Create a mapping of ID to title for suggestions
const docsMap = pages ? pages.reduce((acc, page) => {
acc[page.id] = page.title.rendered;
return acc;
}, {}) : {};
// Prepare docs options for FormTokenField
const docsOptions = pages ? pages.map(page => ({
value: page.id.toString(),
label: page.title.rendered
})) : [];
// Update handlers
const updateAttribute = attributeName => value => {
setAttributes({
[attributeName]: value
});
};
// Transform IDs to titles for FormTokenField display
const excludeDocsDisplay = excludeDocs ? excludeDocs.map(id => docsMap[id] || id) : [];
// Handle token changes
const handleExcludeDocsChange = tokens => {
// Convert titles back to IDs
const newExcludeDocs = tokens.map(token => {
// Find the ID for this title
const found = Object.entries(docsMap).find(([id, title]) => title === token);
return found ? found[0] : token;
});
setAttributes({
excludeDocs: newExcludeDocs
});
};
const getGridClass = () => {
return `wedocs-docs-grid--${docStyle}`;
};
return /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(_wordpress_element__WEBPACK_IMPORTED_MODULE_2__.Fragment, {
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.InspectorControls, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsxs)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelBody, {
title: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Doc Grid Settings', 'wedocs'),
icon: _wordpress_icons__WEBPACK_IMPORTED_MODULE_1__["default"],
initialOpen: false,
children: [/*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: docStyle,
options: docStyles,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('DOCS GRID COLUMN STYLE', 'wedocs'),
onChange: updateAttribute('docStyle')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: docsPerPage,
options: docsPerPageOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Docs per page', 'wedocs'),
onChange: updateAttribute('docsPerPage')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.FormTokenField, {
value: excludeDocsDisplay,
suggestions: Object.values(docsMap),
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Exclude Docs', 'wedocs'),
onChange: handleExcludeDocsChange
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: order,
options: orderOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Order', 'wedocs'),
onChange: updateAttribute('order')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: orderBy,
options: orderByOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Order by', 'wedocs'),
onChange: updateAttribute('orderBy')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: sectionsPerDoc,
options: countOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Sections per doc', 'wedocs'),
onChange: updateAttribute('sectionsPerDoc')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.SelectControl, {
value: articlesPerSection,
options: countOptions,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Articles per section', 'wedocs'),
onChange: updateAttribute('articlesPerSection')
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.ToggleControl, {
checked: showDocArticle,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Show Doc Article', 'wedocs'),
onChange: updateAttribute('showDocArticle')
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.ToggleControl, {
checked: keepArticlesCollapsed,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Keep Article Collapsed', 'wedocs'),
onChange: updateAttribute('keepArticlesCollapsed')
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.PanelRow, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_components__WEBPACK_IMPORTED_MODULE_4__.ToggleControl, {
checked: showViewDetails,
label: (0,_wordpress_i18n__WEBPACK_IMPORTED_MODULE_0__.__)('Show View Details Button', 'wedocs'),
onChange: updateAttribute('showViewDetails')
})
})]
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_wordpress_block_editor__WEBPACK_IMPORTED_MODULE_3__.InspectorControls, {
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(_StyleControls__WEBPACK_IMPORTED_MODULE_5__["default"], {
attributes: attributes,
setAttributes: setAttributes
})
}), /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
...blockProps,
children: hideDocGrid ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: "backdrop"
}) : /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: "wedocs-block-wrapper",
children: /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)("div", {
className: `wedocs-docs-grid ${getGridClass()}`,
children: loading ? /*#__PURE__*/(0,react_jsx_runtime__WEBPACK_IMPORTED_MODULE_6__.jsx)(Spinner, {}) : displayDocs.map(doc => renderGridItem(doc, applyStyles()))
})
})
})]
});
import {
PanelBody,
SelectControl,
FormTokenField,
PanelRow,
ToggleControl,
TextControl,
Spinner,
} from '@wordpress/components';
🤖 Prompt for AI Agents
In assets/build/blocks/DocsGrid/index.js around lines 414 to 889, the code uses
<Spinner/> in the render but never imports it, causing a ReferenceError; add
Spinner to the existing imports from @wordpress/components (or use
wp.components.Spinner) at the top of the file so the component is defined where
used, then rebuild to ensure the editor no longer throws when loading.

"release": "npm run version:replace && npm run build && npm run make-pot:local && npm run zip:create"
},
"devDependencies": {
"@wordpress/scripts": "^30.15.0",
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

Verify breaking changes in @wordpress/scripts upgrade from v25 to v30.

This is a significant version jump (25.0.0 → 30.15.0) for the WordPress build tooling package. Major version increments can introduce breaking changes in build configuration, webpack settings, or babel transforms.

Verify this upgrade:

  1. Check for breaking changes in the WordPress scripts changelog:

  2. Verify the build process still works correctly:


🏁 Script executed:

#!/bin/bash
# Check if package-lock.json or yarn.lock was updated
git diff --name-only | grep -E "(package-lock.json|yarn.lock)"

# Verify build scripts are defined
echo "Build scripts defined:"
cat package.json | grep -A 1 '"scripts"'

Length of output: 70


🌐 Web query:

What are the breaking changes between @wordpress/scripts version 25.0.0 and 30.15.0?

💡 Result:

I can fetch the exact, cited breaking-change list from the @wordpress/scripts changelog — do you want me to look it up now and summarize each breaking change between 25.0.0 and 30.15.0?


Commit updated lockfile and review breaking changes for @wordpress/scripts bump

  • No package-lock.json or yarn.lock updates detected after bump to ^30.15.0; run npm install or yarn and commit the updated lockfile.
  • Review the @wordpress/scripts changelog for breaking changes between v25.0.0 → v30.15.0 and adjust build config if needed.
  • Confirm the build and CI pass successfully after upgrading.
🤖 Prompt for AI Agents
In package.json around line 30, the @wordpress/scripts dependency was bumped to
^30.15.0 but no lockfile was updated and breaking changes may exist; run your
package manager (npm install or yarn) to regenerate package-lock.json or
yarn.lock and commit that updated lockfile, review the @wordpress/scripts
changelog for breaking changes between v25.0.0 and v30.15.0 and adjust any
build/webpack/babel/scripts config accordingly (update config fields, presets,
or plugin usage as required), then run the full build and CI locally and fix any
failing tests or lint/build errors before pushing the updated lockfile and
changes.

Comment on lines +100 to +111
// Border and Shadow
border: currentBorderShadow.border ? `${currentBorderShadow.border.width || '0'} ${currentBorderShadow.border.style || 'solid'} ${currentBorderShadow.border.color || 'transparent'}` : undefined,
borderRadius: currentBorderShadow.borderRadius ? `${currentBorderShadow.borderRadius.topLeft || '0'} ${currentBorderShadow.borderRadius.topRight || '0'} ${currentBorderShadow.borderRadius.bottomRight || '0'} ${currentBorderShadow.borderRadius.bottomLeft || '0'}` : undefined,
boxShadow: currentBorderShadow.boxShadow && currentBorderShadow.boxShadow.x ? `${currentBorderShadow.boxShadow.inset ? 'inset ' : ''}${currentBorderShadow.boxShadow.x || '0px'} ${currentBorderShadow.boxShadow.y || '0px'} ${currentBorderShadow.boxShadow.blur || '0px'} ${currentBorderShadow.boxShadow.spread || '0px'} ${currentBorderShadow.boxShadow.color || 'rgba(0,0,0,0.2)'}` : undefined,

// Background Image
backgroundImage: currentBackgroundImage.bgUrl ? `url(${currentBackgroundImage.bgUrl})` : undefined,
backgroundSize: currentBackgroundImage.bgSize || undefined,
backgroundPosition: currentBackgroundImage.bgFocalPoint ? `${currentBackgroundImage.bgFocalPoint.x * 100}% ${currentBackgroundImage.bgFocalPoint.y * 100}%` : undefined,
backgroundRepeat: currentBackgroundImage.bgRepeat ? 'repeat' : 'no-repeat',
backgroundAttachment: currentBackgroundImage.bgFixed ? 'fixed' : 'scroll',
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Border & shadow preview never honor user settings

getResponsiveStyles expects border and boxShadow.x/y, but the schema (see block.json Lines 254-276) only provides borderStyle, borderWidth, borderColor, and boxShadow.horizontal/vertical/.... As shipped, any border or shadow configured in the inspector is ignored in the editor preview, so users cannot verify their styling choices. Please build the style string from the actual attribute shape before returning blockProps.

Apply this diff to fix the mapping:

-			border: currentBorderShadow.border ? `${currentBorderShadow.border.width || '0'} ${currentBorderShadow.border.style || 'solid'} ${currentBorderShadow.border.color || 'transparent'}` : undefined,
-			borderRadius: currentBorderShadow.borderRadius ? `${currentBorderShadow.borderRadius.topLeft || '0'} ${currentBorderShadow.borderRadius.topRight || '0'} ${currentBorderShadow.borderRadius.bottomRight || '0'} ${currentBorderShadow.borderRadius.bottomLeft || '0'}` : undefined,
-			boxShadow: currentBorderShadow.boxShadow && currentBorderShadow.boxShadow.x ? `${currentBorderShadow.boxShadow.inset ? 'inset ' : ''}${currentBorderShadow.boxShadow.x || '0px'} ${currentBorderShadow.boxShadow.y || '0px'} ${currentBorderShadow.boxShadow.blur || '0px'} ${currentBorderShadow.boxShadow.spread || '0px'} ${currentBorderShadow.boxShadow.color || 'rgba(0,0,0,0.2)'}` : undefined,
+			borderStyle: currentBorderShadow.borderStyle || undefined,
+			borderWidth: currentBorderShadow.borderWidth
+				? `${currentBorderShadow.borderWidth.top || '0'} ${currentBorderShadow.borderWidth.right || '0'} ${currentBorderShadow.borderWidth.bottom || '0'} ${currentBorderShadow.borderWidth.left || '0'}`
+				: undefined,
+			borderColor: currentBorderShadow.borderColor || undefined,
+			borderRadius: currentBorderShadow.borderRadius
+				? `${currentBorderShadow.borderRadius.topLeft || '0'} ${currentBorderShadow.borderRadius.topRight || '0'} ${currentBorderShadow.borderRadius.bottomRight || '0'} ${currentBorderShadow.borderRadius.bottomLeft || '0'}`
+				: undefined,
+			boxShadow: currentBorderShadow.boxShadow?.enabled
+				? `${currentBorderShadow.boxShadow.inset ? 'inset ' : ''}${currentBorderShadow.boxShadow.horizontal || '0px'} ${currentBorderShadow.boxShadow.vertical || '0px'} ${currentBorderShadow.boxShadow.blur || '0px'} ${currentBorderShadow.boxShadow.spread || '0px'} ${currentBorderShadow.boxShadow.color || 'rgba(0,0,0,0.2)'}`
+				: undefined,

Based on block.json

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

🤖 Prompt for AI Agents
In src/blocks/AdvanceContributors/edit.js around lines 100 to 111, the preview
builds CSS from fields like currentBorderShadow.border and
currentBorderShadow.boxShadow.x but the block schema actually exposes
borderStyle/borderWidth/borderColor and
boxShadow.horizontal/vertical/blur/spread/inset/color (and similarly named
radius keys), so the editor never shows user-configured borders/shadows; update
the style construction to read the real attribute names: compose border using
`${borderWidth || '0'} ${borderStyle || 'solid'} ${borderColor ||
'transparent'}`, build borderRadius from the schema radius keys
(topLeft/topRight/bottomRight/bottomLeft), and build boxShadow using
`boxShadow.horizontal`, `boxShadow.vertical`, `boxShadow.blur`,
`boxShadow.spread`, `boxShadow.inset`, and `boxShadow.color` (convert inset
boolean to 'inset ' when true); also ensure background and other fallbacks
remain unchanged, then return the updated blockProps so the preview reflects the
inspector values.

Comment on lines +48 to +95
switch ($contributor_display_mode) {
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 '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 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 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;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Guard against missing global post

When the block is rendered outside of the loop (e.g. in Site Editor, patterns), get_post() can return null, so the subsequent $post->ID access fatals (Attempt to read property "ID" on null). Bail out early if no post is available.

-    $post = get_post();
+    $post = get_post();
+    if ( ! $post ) {
+        return '';
+    }
🤖 Prompt for AI Agents
src/blocks/AdvanceContributors/render.php around lines 48 to 95: the code
assumes $post is present and accesses $post->ID which can fatal when rendering
outside the loop (get_post() may return null); fix by retrieving the current
post early (e.g. $post = $post ?? get_post()) and if $post is null bail out
immediately (return early or set $contributors empty) before any use of
$post->ID so all switch cases below are safe.

Comment on lines +111 to +285
// Helper function to generate responsive CSS
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;
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Avoid redefining generate_responsive_css

Declaring generate_responsive_css() inside the render callback registers a global function the first time it runs, and attempting to declare it again on the next render triggers Cannot redeclare generate_responsive_css(). Wrap it in a closure (or move it out with a unique name) so the callback remains reusable.

-    function generate_responsive_css($block_id, $controls, $device_suffix = '') {
+    $generate_responsive_css = static function( $block_id, $controls, $device_suffix = '' ) {
         $css = '';
         …
-        return $css;
-    }
+        return $css;
+    };-            $responsive_css .= generate_responsive_css($block_id, $device_controls);
+            $responsive_css .= $generate_responsive_css( $block_id, $device_controls );-            $responsive_css .= '@media (max-width: 1024px) { ' . generate_responsive_css($block_id, $device_controls) . ' }';
+            $responsive_css .= '@media (max-width: 1024px) { ' . $generate_responsive_css( $block_id, $device_controls ) . ' }';-            $responsive_css .= '@media (max-width: 768px) { ' . generate_responsive_css($block_id, $device_controls) . ' }';
+            $responsive_css .= '@media (max-width: 768px) { ' . $generate_responsive_css( $block_id, $device_controls ) . ' }';

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

Comment on lines +497 to +499
return $output;
}
render_wedocs_advance_contributors_block( $attributes, $content, $block );
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Return the rendered markup

This file is used as the block’s render callback in block.json. Without an explicit return, include just yields 1, so the block outputs 1 instead of the generated markup.

-}
-render_wedocs_advance_contributors_block( $attributes, $content, $block );
+}
+return render_wedocs_advance_contributors_block( $attributes, $content, $block );
🤖 Prompt for AI Agents
In src/blocks/AdvanceContributors/render.php around lines 497 to 499, the render
callback ends by calling render_wedocs_advance_contributors_block(...) without
returning its output; currently the include returns 1. Update the function so it
returns the rendered markup string instead of echoing/including it — call the
render function and return its result (or buffer the output and return the
buffer) so the block outputs the generated markup rather than "1".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants