Description:
I have developed a custom block called 'Stylized List' for the WordPress block editor (Gutenberg) that allows users to create advanced styled lists with customizable titles, items, and icons. The block is designed to be reusable, and users can add multiple instances of it to their posts or pages.
Problem:
The main issue I am facing with the 'Stylized List' block is that the list items are not being rendered correctly, and the content is getting looped between different instances of the block. When I customize the list items for one 'Stylized List' block, the same items appear in all other 'Stylized List' blocks on the page.
Steps to Reproduce:
Add multiple instances of the 'Stylized List' block to a post or page. Customize the list items (titles and icons) for each block individually. Save the post or page.
Expected Behavior:
Each instance of the 'Stylized List' block should have its own unique list items, and the content should be displayed correctly as per the customization made to each block.
Actual Behavior:
The list items of one 'Stylized List' block are appearing in all other instances of the block, causing duplication and incorrect rendering of content.
Code Snippets:
Here is the relevant code for the 'Stylized List' block:
block.json
:
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 2,
"name": "lgb/stylized-list",
"version": "1.0.0",
"title": "Stylized List",
"category": "lgb-custom-category",
"description": "Create advanced styled list",
"supports": {
"html": false
},
"attributes": {
"listHeading": {
"type": "string"
},
"listItems": {
"type": "string",
"default": "[{\"title\":\"\",\"icon\":\"\"}]"
},
"listCaption": {
"type": "string"
}
},
"textdomain": "lendeducom",
"editorScript": "file:./index.js",
"editorStyle": "file:./index.css"
}
edit.js
:
import { __ } from "@wordpress/i18n";
import {
useBlockProps,
RichText,
BlockControls,
} from "@wordpress/block-editor";
import { useState } from "@wordpress/element";
import List from "./components/list";
import SidebarSettings from "./components/sidebarsettings";
import "./css/editor.scss";
export default function Edit(props) {
const {
attributes: { listHeading, listItems, listCaption },
setAttributes,
} = props;
const blockProps = useBlockProps();
const parseListItems = JSON.parse(listItems);
const [iconIndex, setIconIndex ]= useState();
console.log({listItems});
return (
<div {...blockProps}>
<SidebarSettings
listHeading={listHeading}
setAttributes={setAttributes}
listCaption={listCaption}
/>
<section className="stylized-list-container">
<div className="lists">
<div className="lists-title">
<p className="heading-6">
{listHeading ? listHeading : "Title placeholder"}
</p>
</div>
<ul>
{parseListItems.map((item, index) => {
return (
<List
index={index}
item={item}
key={index}
onChangeTitle={(title, index) => {
parseListItems[index].title = title;
setAttributes({
listItems: JSON.stringify(parseListItems),
});
}}
removeItem={parseListItems}
setAttributes={setAttributes}
listItems={parseListItems}
/>
);
})}
</ul>
<button
className="addNewItem"
onClick={() => {
parseListItems.push({
title: "",
});
setAttributes({ listItems: JSON.stringify(parseListItems) });
}}
>
Add New Item
</button>
</div>
<RichText
tagName="p"
className="list-caption"
value={listCaption}
onChange={(val) => setAttributes({ listCaption: val })}
placeholder="Add caption here"
allowedFormats={[
"core/bold",
"core/italic",
"core/link",
"core/superscript",
"lgb/product-update",
]}
/>
</section>
</div>
);
}
list.js
:
import { __ } from "@wordpress/i18n";
import {
RichText,
} from "@wordpress/block-editor";
import { Popover, Button } from "@wordpress/components";
import { useState } from "@wordpress/element";
import yesIcon from "./../../assets/img/icon-general-yes.svg";
import noIcon from "./../../assets/img/icon-general-no.svg";
import noGrayIcon from "./../../assets/img/icon-general-no-gray.svg";
const List = (props) => {
const {
index,
item,
onChangeTitle,
removeItem,
setAttributes,
listItems,
} = props;
function conditionalListIcon(icon) {
switch (icon) {
case "yes":
return <img src={yesIcon} />;
case "no":
return <img src={noIcon} />;
case "nogray":
return <img src={noGrayIcon} />;
default:
return <img src={yesIcon} />;
}
}
const [isVisible, setIsVisible] = useState(false);
const toggleVisible = () => {
setIsVisible((state) => !state);
};
return (
<li>
{/* <div className="list-with-icon"> */}
{conditionalListIcon(item.icon)}
<RichText
tagName="p"
className="list"
value={item.title}
allowedFormats={[
"core/bold",
"core/italic",
"core/link",
"core/superscript",
"lgb/product-update",
]}
onChange={(content) => onChangeTitle(content, index)}
placeholder={__("Add List Item")}
onReplace={() => {}}
onSplit={() => {}}
multiline={false}
/>
{/* </div> */}
<Button
variant="secondary"
className="list-icon-toggle"
onClick={toggleVisible}
>
Icons
{isVisible && (
<ul className="icons">
<li
onClick={() => {
listItems[index].icon = "yes";
setAttributes({ listItems: JSON.stringify([...listItems]) });
}}
>
<img src={yesIcon} />
</li>
<li
onClick={() => {
listItems[index].icon = "no";
setAttributes({ listItems: JSON.stringify([...listItems]) });
console.log(listItems[index]);
}}
>
<img src={noIcon} />
</li>
<li
onClick={() => {
listItems[index].icon = "nogray";
setAttributes({ listItems: JSON.stringify([...listItems]) });
console.log(listItems[index]);
}}
>
<img src={noGrayIcon} />
</li>
</ul>
)}
</Button>
<button
className="removeItem"
onClick={() => {
removeItem.splice(index, 1);
setAttributes({ listItems: JSON.stringify(removeItem) });
}}
>
x
</button>
</li>
);
};
export default List;
console.log
of attributes:
{listItems: '[{"title":"item one[1]","icon":""},{"title":"item two[1]","icon":"yes"},{"title":"Item three[1]"}]'}
{listItems: '[{"title":"item one [two]","icon":""},{"title":"Item two[two]"},{"title":"Item three[two]"}]'}
Expected Solution: I am seeking assistance from the WordPress community to help identify the root cause of this issue and provide a solution to ensure that each instance of the 'Stylized List' block maintains its own unique list items without interfering with other instances. I appreciate any insights or suggestions to resolve this problem and improve the functionality of the 'Stylized List' block. Thank you in advance for your help!
<ul>
block doesn't do this in modern WP and uses a list block with a list item block and controls on allowed child/parent blocks. That approach is a lot easier[1]
at the end, but items in list 2 have[two]
, they are not the same