3

I'm creating a block. I want my block to be able to output posts that can be "filtered". It should be possible to choose from which category the posts should be displayed. I have gotten so far that I have a function that gives me the categories and you can also select them. Then the values ​​are written in a shortcode. But my problem is, I don't see the select field at first. If I then click somewhere within the editor and then click on my block again, I get to see the SelectControl. If I reload the page and click on my block too quickly, I also get an error that the foreach is empty. How can I make sure that my foreach is already filled before loading my block?

My edit.js

function getCategories() {
    const options = [];
    const postCategory = wp.data.select('core').getEntityRecords('taxonomy', 'category');
    postCategory.forEach((cat) => {
        options.push({ value: cat.id, label: cat.name });
    });
    return options;
}

...

<SelectControl
    multiple
    label={__('Cat')}
    options={getCategories()}
    onChange={onChangeCategoriesField}
    value={categories}
/>
1

The problem is that calling wp.data.select triggers a fetch and the data takes some time to be available. Until that happens the value returned is an empty array.

My suggestion here is to use wp.data.useSelect, which is a React hook made specifically for this, so the component re-renders when there is a change in the data:

const MyComponent = () => {

    const categories = useSelect(select =>
        select('core').getEntityRecords('taxonomy', 'category')
    );

    const [categories_selected, setCategoriesSelected] = useState([]);

    return (
        <SelectControl
            multiple
            label={__('Cat')}
            options={categories.map(({id, name}) => ({label: name, value: id}))}
            onChange={(selected) => {
                // I haven't tested this code so I'm not sure what onChange returns.
                // But assuming it returns an array of selected values:
                setCategoriesSelected(selected)
            }}
            value={categories_selected}
        />
    );
};

This will also have the "issue" that the value on the first call of select('core').getEntityRecords('taxonomy', 'category') is empty. So you might want to consider it and return something different in the component if categories.length === 0.

If you really need to prevent this from happening, I guess you could call wp.data.select('core').getEntityRecords('taxonomy', 'category') in your script, close to the top, so when it is called by the component for the first time the data is already in the store.

| improve this answer | |
  • Thank you for your answer. Unfortunately, declaring my constante does not help me if I declare it before integrating the edit function. If I write the code as described by you, how do I get it to the desired position in my sidebar? – 180690 Aug 3 at 5:49
  • @Tom, you are welcome. I am not sure I understand, which constant declaration do you refer to? What are you refering to with getting the desired position in your sidebar? – Alvaro Aug 3 at 15:39
  • Thanky you. i put wp.data.select('core').getEntityRecords('taxonomy', 'category') in my index.js on top. Now it works. Strange :) – 180690 Aug 6 at 10:41
  • The array will be filled when the selector is called for the first time. That is why if we want it ready the first time useSelector is called, we need to call the selector (wp.data.select in this case) before that. – Alvaro Aug 6 at 18:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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