import { __ } from "@wordpress/i18n";
import { InspectorControls, useBlockProps } from "@wordpress/block-editor";
import {
Button,
CheckboxControl,
PanelBody,
SelectControl,
TextControl,
ToggleControl,
} from "@wordpress/components";
import { useEffect, useState } from "@wordpress/element";
import apiFetch from "@wordpress/api-fetch";
export default function Edit({ attributes, setAttributes }) {
const {
heading = "",
menuItems = [],
useCategories = false,
categoryOrderBy = "name",
categoryOrder = "asc",
hideEmpty = false,
selectedCategories = [],
useSelectedCategoriesOnly = false,
} = attributes;
const [categories, setCategories] = useState([]);
const [isLoading, setIsLoading] = useState(false);
// Fetch categories
useEffect(() => {
if (!useCategories) return;
let isMounted = true;
setIsLoading(true);
const queryParams =
`?per_page=100&orderby=${categoryOrderBy}&order=${categoryOrder}` +
(hideEmpty ? "&hide_empty=true" : "");
apiFetch({ path: "/wp/v2/categories" + queryParams })
.then((fetchedCategories) => {
if (isMounted) {
setCategories(fetchedCategories);
setIsLoading(false);
}
})
.catch((error) => {
if (isMounted) {
console.error("Error fetching categories:", error);
setIsLoading(false);
}
});
return () => {
isMounted = false;
};
}, [useCategories, categoryOrderBy, categoryOrder, hideEmpty]);
function addMenuItem() {
setAttributes({ menuItems: [...menuItems, { text: "", url: "" }] });
}
function updateMenuItem(index, field, value) {
const newItems = [...menuItems];
newItems[index][field] = value;
setAttributes({ menuItems: newItems });
}
function removeMenuItem(index) {
const newItems = [...menuItems];
newItems.splice(index, 1);
setAttributes({ menuItems: newItems });
}
function toggleCategorySelection(categoryId) {
const updated = selectedCategories.includes(categoryId)
? selectedCategories.filter((id) => id !== categoryId)
: [...selectedCategories, categoryId];
setAttributes({ selectedCategories: updated });
}
let previewItems = [];
if (useCategories) {
if (isLoading) {
previewItems.push(<li key="loading">Loading categories...</li>);
} else if (categories.length === 0) {
previewItems.push(<li key="none">No categories found</li>);
} else {
let displayCategories = categories;
if (useSelectedCategoriesOnly && selectedCategories.length > 0) {
displayCategories = categories.filter((cat) =>
selectedCategories.includes(cat.id),
);
}
previewItems = displayCategories.slice(0, 5).map((cat) => (
<li key={cat.id}>
<a href="#">
{cat.name} ({cat.count})
</a>
</li>
));
if (displayCategories.length > 5) {
previewItems.push(<li key="more">...</li>);
}
}
} else {
if (menuItems.length === 0) {
previewItems.push(<li key="add">Add menu items in the sidebar</li>);
} else {
previewItems = menuItems.map((item, index) => (
<li key={`menu-item-${index}`}>
<a href={item.url || "#"}>{item.text || "Menu Item"}</a>
</li>
));
}
}
return (
<>
<InspectorControls>
<PanelBody
title={__("Menu Settings", "woracious-suite")}
initialOpen={true}
>
<TextControl
label={__("Heading", "woracious-suite")}
value={heading}
onChange={(value) => setAttributes({ heading: value })}
/>
<ToggleControl
label={__("Use Categories", "woracious-suite")}
checked={useCategories}
onChange={(value) => setAttributes({ useCategories: value })}
/>
{!useCategories && (
<div className="menu-items-controls">
<h3>{__("Menu Items", "woracious-suite")}</h3>
{menuItems.map((item, index) => (
<div className="menu-item" key={`menu-item-control-${index}`}>
<TextControl
label={__("Text", "woracious-suite")}
value={item.text}
onChange={(value) => updateMenuItem(index, "text", value)}
/>
<TextControl
label={__("URL", "woracious-suite")}
value={item.url}
onChange={(value) => updateMenuItem(index, "url", value)}
/>
<Button
isDestructive
variant="secondary"
onClick={() => removeMenuItem(index)}
>
{__("Remove", "woracious-suite")}
</Button>
</div>
))}
<Button isPrimary onClick={addMenuItem}>
{__("Add Menu Item", "woracious-suite")}
</Button>
</div>
)}
{useCategories && (
<div className="category-settings">
<SelectControl
label={__("Order By", "woracious-suite")}
value={categoryOrderBy}
options={[
{ label: __("Name", "woracious-suite"), value: "name" },
{ label: __("Count", "woracious-suite"), value: "count" },
{ label: __("ID", "woracious-suite"), value: "id" },
]}
onChange={(value) => setAttributes({ categoryOrderBy: value })}
/>
<SelectControl
label={__("Order", "woracious-suite")}
value={categoryOrder}
options={[
{ label: __("Ascending", "woracious-suite"), value: "asc" },
{ label: __("Descending", "woracious-suite"), value: "desc" },
]}
onChange={(value) => setAttributes({ categoryOrder: value })}
/>
<ToggleControl
label={__("Hide Empty Categories", "woracious-suite")}
checked={hideEmpty}
onChange={(value) => setAttributes({ hideEmpty: value })}
/>
<ToggleControl
label={__("Show Only Selected Categories", "woracious-suite")}
checked={useSelectedCategoriesOnly}
onChange={(value) =>
setAttributes({ useSelectedCategoriesOnly: value })
}
/>
{useSelectedCategoriesOnly && categories.length > 0 && (
<div className="category-selection">
<h4>{__("Select Categories", "woracious-suite")}</h4>
{categories.map((category) => (
<CheckboxControl
key={category.id}
label={`${category.name} (${category.count})`}
checked={selectedCategories.includes(category.id)}
onChange={() => toggleCategorySelection(category.id)}
/>
))}
</div>
)}
</div>
)}
</PanelBody>
</InspectorControls>
<div {...useBlockProps({ className: "menu" })}>
{heading && <h6>{heading}</h6>}
<ul>{previewItems}</ul>
</div>
</>
);
}
Issue: Attributes are not saving in the Database, and same can be verified when viewed in Code Editor Mode.