• This is my first attempt to work with WordPress blocks and also my first time working with React.

    The code below adds the possibility to conditionally show blocks.

    My question is related to the “select pages” section, or the “useSelect”.

    I show a list of pages which have been selected previously. I also show a list of pages based on a search. Whenever someone selects a page I move the checkbox from the search list to the selected list.

    This works great except when I save the page/post whatever. Somehow when the “initialSelectedPages” gets rendered it uses the old attributes… I have to refresh the page, or re-select the block in order to show the the correct updated list.

    But I have no idea why. Any ideas?

    Also, as this is my first React code, any feedback is welcome!

    This is my code how I load the js:

    add_action( 'enqueue_block_editor_assets', function() {
    wp_register_script(
    'sim-block-filter',
    plugins_url('blocks/build/index.js', __DIR__),
    [ 'wp-blocks', 'wp-dom', 'wp-dom-ready', 'wp-edit-post' ],
    STYLE_VERSION
    );
    wp_enqueue_script( 'sim-block-filter' );
    });

    This is the js

    const { __ } = wp.i18n;
    const { createHigherOrderComponent } = wp.compose;
    const { Fragment } = wp.element;
    const { InspectorControls } = wp.blockEditor;
    const { PanelBody, ToggleControl, CheckboxControl } = wp.components;
    import { SearchControl, Spinner, __experimentalInputControl as InputControl } from '@wordpress/components';
    import {useState, useEffect } from "@wordpress/element";
    import { useSelect } from '@wordpress/data';
    import { store as coreDataStore } from '@wordpress/core-data';
    import { decodeEntities } from '@wordpress/html-entities';

    // Add attributes
    function addFilterAttribute(settings) {
    if (typeof settings.attributes !== 'undefined') {
    settings.attributes = Object.assign(settings.attributes, {
    hideOnMobile: {
    type: 'boolean',
    },
    onlyOnHomePage: {
    type: 'boolean',
    },
    onlyLoggedIn: {
    type: 'boolean',
    },
    onlyOn: {
    type: 'array'
    },
    phpFilters: {
    type: 'array'
    }
    });
    }
    return settings;
    }

    wp.hooks.addFilter(
        'blocks.registerBlockType',
        'sim/block-filter-attribute',
        addFilterAttribute
    );
    
    // Add controls to panel
    const blockFilterControls = createHigherOrderComponent((BlockEdit) => {
        return ( props ) => {
            const { attributes, setAttributes, isSelected } = props;
    
            // Only work on selected blocks
            if(!isSelected){
                return (
                    <Fragment>
                        <BlockEdit { ...props } />
                    </Fragment>
                );
            }
    
            //console.log(attributes.onlyOn)
            if(attributes.onlyOn == undefined){
                attributes.onlyOn = [];
            }
    
            /** FUNCTIONS */
            const [ searchTerm, setSearchTerm ]     = useState( '' );
    
            // Selected page list
            const { initialSelectedPages, selectedPagesResolved} = useSelect(
                ( select) => {
                    // Find all selected pages
                    const selectedPagesArgs = [ 'postType', 'page', {include : attributes.onlyOn} ];
    
                    //console.log(attributes.onlyOn);
    
                    return {
                        initialSelectedPages: select( coreDataStore ).getEntityRecords(
                            ...selectedPagesArgs
                        ),
                        selectedPagesResolved: select( coreDataStore ).hasFinishedResolution(
                            'getEntityRecords',
                            selectedPagesArgs
                        )
                    };
                },
                []
            );
    
            // Search page list
            const { pages, pagesResolved } = useSelect(
                ( select) => {
                    // do not show results if not searching
                    if ( !searchTerm ) {
                        return{
                            pages: true,
                            pagesResolved: []
                        }
                    }
    
                    // find all pages excluding the already selected pages
                    const query = {
                        exclude : attributes.onlyOn,
                        search  : searchTerm
                    };
    
                    const pagesArgs         = [ 'postType', 'page', query ];
    
                    return {
                        pages: select( coreDataStore ).getEntityRecords(
                            ...pagesArgs
                        ),
                        pagesResolved: select( coreDataStore ).hasFinishedResolution(
                            'getEntityRecords',
                            pagesArgs
                        )
                    };
                },
                [ searchTerm ]
            );
    
            const PageSelected = function(checked){
                let newPages    = [...attributes.onlyOn];
    
                if(checked){
                    // Add to stored page ids
                    newPages.push(this);
    
                    // Add to selected pages list
                    let newSelectedPages    = [...selectedPages];
                    newSelectedPages.push(pages.find( p => p.id == this));
                    setSelectedPages(newSelectedPages);
                }else{
                    newPages    = newPages.filter( p => {return p != this} );
                }
    
                setAttributes({onlyOn: newPages});
            }
    
            const GetSelectedPagesControls = function(){
                if(attributes.onlyOn.length > 0){
                    return (
                        <>
                            <i> {__('Currently selected pages', 'sim')}:</i>
                            <br></br>
                            
                            <BuildCheckboxControls hasResolved={ selectedPagesResolved } items={initialSelectedPages} showNoResults={false}/>
                        </>
                    );
                }else{
                    return '';
                }
            }
    
            const BuildCheckboxControls = function({ hasResolved, items, showNoResults= true }){
                if ( ! hasResolved ) {
                    return(
                        <>
                        <Spinner />
                        <br></br>
                        </>
                    );
                }
            
                if ( ! items?.length ) {
                    if(showNoResults){
                        if ( !searchTerm ) {
                            return '';
                        }
                        return <div> {__('No search results', 'sim')}</div>;
                    }
    
                    return '';
                }
                
                return items?.map( ( page ) => {
                
                    return (<CheckboxControl
                        label       = {decodeEntities( page.title.rendered )}
                        onChange    = {PageSelected.bind(page.id)}
                        checked     = {attributes.onlyOn.includes(page.id)}
                    />)
                } )
            }
    
            /** HOOKS */
            const [ selectedPages, setSelectedPages ]                   = useState( [] );
            const [ selectedPagesControls, setSelectedPagesControls ]   = useState( GetSelectedPagesControls() );
    
            // Update selectedPagesControls on page resolve
            useEffect(() => {
                setSelectedPages(initialSelectedPages);
            }, [ selectedPagesResolved ]);
    
            // Update selectedPagesControls on check/uncheck
            useEffect(() => {            
                setSelectedPages( selectedPages.filter( p => {return attributes.onlyOn.includes(p.id)} ));
            }, [ attributes.onlyOn ]);
    
            useEffect( 
                () => {
                    setSelectedPagesControls(BuildCheckboxControls({hasResolved: selectedPagesResolved, items: selectedPages, showNoResults: false}));
                }, 
                [selectedPages]
            );
    
            return (
                <Fragment>
                    <BlockEdit { ...props } />
                    <InspectorControls>
                        <PanelBody title={ __( 'Block Visibility' ) }>
    
                            <strong>{__('Select pages', 'sim')}</strong><br></br>
                            {__('Select pages you want this widget to show on', 'sim')}.<br></br>
                            {__('Leave empty for all pages', 'sim')}<br></br>
                            <br></br>
                            {selectedPagesControls}
                            <i>{__('Use searchbox below to search for more pages to include', 'sim')}</i>
                            < SearchControl onChange={ setSearchTerm } value={ searchTerm } />
                            < BuildCheckboxControls hasResolved= {pagesResolved} items= {pages} />
                        </PanelBody>
                    </InspectorControls>
                </Fragment>
            );
        };
    }, 'blockFilterControls');
     
    wp.hooks.addFilter(
        'editor.BlockEdit',
        'sim/block-filter-controls',
        blockFilterControls
    );

  • The topic ‘useEffect is to early on save?’ is closed to new replies.