1

I followed along with this stack overflow I got everything working except for the values saving in myTest attribute array. For some reason it's not and I've been stumped for over a week on it. Here is my complete code for reference.


import React, { useState, useEffect } from 'react';

import { __ } from '@wordpress/i18n';
import { registerBlockType } from "@wordpress/blocks"
import {
    useBlockProps,
    RichText,
    InspectorControls,
    PanelColorSettings
} from '@wordpress/block-editor';
import {
    PanelBody,
    PanelRow,
    SelectControl
} from '@wordpress/components';

import apiFetch from '@wordpress/api-fetch';

import './editor.scss';



registerBlockType('blog-post-block/blog-post-container-block', {
    // Block name. Block names must be string that contains a namespace prefix. Example: my-plugin/my-custom-block.
    title: __('SfS Post block', 'sfs-block'), // Block title.
    icon: 'shield', // Block icon from Dashicons → https://developer.wordpress.org/resource/dashicons/.
    category: 'design', // Block category — Group blocks together based on common traits E.g. common, formatting, layout widgets, embed.
    attributes: {
        myTest: {
            type: 'array',
            source: 'query',
            selector: ' div.blog-stamp > * ',
            default: [],
            query: {
                image: {
                    type: 'string',
                    source: 'attribute',
                    selector: 'img',
                    attribute: 'src'
                },
                title: {
                    type: 'string',
                    selector: 'h3',
                    source: 'html'
                },
                excerpt: {
                    type: 'string',
                    selector: 'p',
                    source: 'html'
                },
                link: {
                    type: 'string',
                    source: 'attribute',
                    selector: 'a',
                    attribute: 'href'
                },
            }
        },
        backgroundColor: {
            type: "string"
        },
        textColor: {
            type: "string"
        },
        selectedValue: {
            type: "string",
            default: "vtalk"
        },
        myNumber: {
            type: "number",
            default: "3"
        },
    },
    edit({ className, attributes, setAttributes }) {
        const blockProps = useBlockProps();
        const { backgroundColor, textColor, selectedValue, myNumber, myTest } = attributes;
        const [teams, setTeams] = useState([]);
        const catagories = [];
        const newArray = [];
        useEffect(() => {
            apiFetch({ path: '/wp/v2/posts?_embed=wp:term' }).then((teams) => {
                setTeams(teams);
            });

        }, []);

        for (var i = 0; i < teams.length; i++) {
            catagories.push({ catagory: teams[i]._embedded['wp:term']['0']['0']['name'] });
            newArray.push({ value: teams[i].id, label: teams[i].title.rendered, content: teams[i].excerpt.rendered, image: teams[i].featured_image_url, link: teams[i].link, catagory: teams[i]._embedded['wp:term']['0']['0']['name'] });
        }
        const onChangeBackgroundColor = (BackgroundColor) => {
            setAttributes({ backgroundColor: BackgroundColor })
        }
        const onChangeTextColor = (TextColor) => {
            setAttributes({ textColor: TextColor })
        }
        const onChangeNumber = (number) => {
            setAttributes({ myNumber: number })
        }
        function updateAttributes(string1, string2, string3, string4, index){
            const theAttributeUpdate = [...myTest];
            theAttributeUpdate[index] = { image: {string1}, title: {string2}, excerpt: {string3}, link: {string4} };
            setAttributes({ myTest: theAttributeUpdate })
        }
        const stringArray = catagories.map(JSON.stringify);
        const uniqueStringArray = new Set(stringArray);
        const uniqueArray = Array.from(uniqueStringArray, JSON.parse);
        const handleSelectChange = (event) => {
            setAttributes({ selectedValue: event.target.value })
            console.log(event.target.value);
        }
        return (
            <div {...blockProps}>
                <InspectorControls>
                    <PanelColorSettings
                        title={__('Button Color settings', 'sfs-block')}
                        initialOpen={false}
                        colorSettings={[
                            {
                                value: textColor,
                                onChange: onChangeTextColor,
                                label: __('Button Text color', 'sfs-block')
                            },
                            {
                                value: backgroundColor,
                                onChange: onChangeBackgroundColor,
                                label: __('Button Background color', 'sfs-block')
                            }
                        ]}
                    />
                    <PanelBody
                        title={__('catagory filter', 'sfs-block')}
                        initialOpen={true}
                    >
                        <PanelRow>
                            <fieldset>
                                <select value={selectedValue} onChange={handleSelectChange}>
                                    {uniqueArray.map((cat) => {
                                        return <option value={cat.catagory}>{cat.catagory}</option>
                                    })}
                                </select>
                            </fieldset>
                        </PanelRow>
                    </PanelBody>
                    <SelectControl
                        label="How many"
                        value={myNumber}
                        options={[
                            { label: 'Three in a row', value: '3' },
                            { label: 'Six in a row', value: '6' },
                        ]}
                        onChange={onChangeNumber}
                    />
                </InspectorControls>
                <div class="blog-stamp-parent">
                    { newArray.filter((m, idx) => m.catagory == selectedValue).map((m) => {

                        return (
                            <div class="foo blog-stamp">
                                <img class="stamp-image" src={m.image} width="200" height="200" />
                                <RichText
                                    tagName="h3"
                                    value={m.label}
                                    class="foo stamp-title"
                                    onChange={({string2}) => updateAttributes(string1, string2, string3, string4, index)}

                                />
                                <RichText
                                    tagName="p"
                                    value={m.content}
                                    class="foo stamp-excerpt"
                                    onChange={({string3}) => updateAttributes(string1, string2, string3, string4, index)}
                                />
                                <p class="button-parent">
                                    <a
                                        href={m.link}
                                        className="foo sfs-button"
                                        style={{ backgroundColor: backgroundColor, color: textColor }}
                                    >
                                        {'Read more'}
                                    </a>
                                </p>
                            </div>)
                    })};
                    {console.log(myTest)}
                </div>
            </div>
        )
    },

    save({ attributes }) {
        const blockProps = useBlockProps.save();
        const { backgroundColor, textColor, selectedValue, myNumber, menuItems, myTest, para, src, href } = attributes;
        return (
            <div{...useBlockProps.save()}>
                <div class="blog-stamp-parent" >
                            {myTest && myTest.map(({ image, title, excerpt, link }) => {

return (
                    <div class="blog-stamp">
                        <img src={image} width="200" height="200" />
                        <RichText.Content className="stamp-title" tagName="h3" value={title} />
                        <RichText.Content className="stamp-excerpt" tagName="p" value={excerpt} />
                        <p class="button-parent">
                            <a href={link} class="sfs-button" style={{ backgroundColor: backgroundColor, color: textColor }}>Read more</a>
                        </p>
                        </div>)
                    })};
                </div>
            </div>
        )
    },
});



In edit, under the return statement, I map through newArray and apply the values to the block elements. Then the onchange within the block element is suppose to trigger the updateAttributes function which saves the value into an array of attributes using the myTest attribute. But, when I do it and console.log myTest, it comes back as blank with no values. Just []. Any idea why?

9
  • There's a lot of code here, what do you mean that the attributes array is not saving? What specifically isn't working and at what stage? Commented Feb 16 at 9:29
  • the question you linked to is asking how to do something they shouldn't be doing, don't store multiple values in an attribute as a list, use child blocks instead!
    – Tom J Nowell
    Commented Feb 16 at 9:47
  • @JacobPeattie - I've edited the post that better explains
    – Dave B
    Commented Feb 16 at 9:53
  • @TomJNowell - Can you give an example? I am a newbie to the world of custom blocks so any help is greatly appricated
    – Dave B
    Commented Feb 16 at 9:54
  • 1
    Thanks @TomJNowell - I was able to create a template and use the latest post core block to achieve what I want.
    – Dave B
    Commented Feb 16 at 11:13

1 Answer 1

0

The best way to achieve what i was wanting to do was to use the core blocks for latest post. Then style as I needed to. Here is what my code looks like.

import { registerBlockType } from "@wordpress/blocks";
import { __ } from "@wordpress/i18n";
import {
    useBlockProps, 
    InnerBlocks, 
} from "@wordpress/block-editor";

registerBlockType('sfs-test-header-para-block/sfs-test-header-para-container-block', {
    title: __( 'This is my test block', 'sfs-block' ),
    category: 'design',
    edit( { className} ) {
        const blockProps = useBlockProps();
        const TEMPLATE = [ [ 'core/cover', { className: 'sfs-header-cover',}, [
            [ 'core/columns', {className: 'sfs-h2-header-cols', backgroundColor: 'transparent', verticalAlignment: 'center' }, [
               [ 'core/column', {className: 'sfs-h2-header-img-col', templateLock: 'insert' }, [
                   [ 'core/latest-posts' ],
               ] ],
           ] ] ] ]];
        return(
            <div { ...blockProps }
            className={ className }>
                <InnerBlocks
                    template={ TEMPLATE }
                    templateLock="insert"
                />
            </div>
        )
    },

    save() {
        const blockProps = useBlockProps.save();
        return(
            <div { ...blockProps }>
                <InnerBlocks.Content />
            </div>
        )
    },
});

I would avoid what I was tying to do with apiFetch and list of attributes. It's a rabbit hole you want to avoid. Big Thanks to @TomJNowell for setting me straight.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.