admin管理员组

文章数量:1199187

I've been banging my head on this for a bit now.

I'm trying to create a simple wordpress block that fetches custom post types from the rest api, then displays the fetched posts via react. It only needs to do this, and requires no other editor functionality.

However, I'm a bit of a react/wp noob and I may be fundamentally misunderstanding how wordpress react functions, as I can't seem to get anywhere.

Here is my code so far:

class oupSeriesBlock extends Component {

    constructor(props) {
        super(props);
        this.state = {data: []};
    }

    getOupSeries() {
        console.log('mounted');
        apiFetch({
            path: 'wp/v2/oup_series'
        }).then((response) => {
            this.state = {data: response}
            console.log(this.state);
        })
    }

    componentDidMount() {
        this.getOupSeries();
    }

    render() {
        return(
            <div>
                Test
                {this.state.data.length > 0 ? this.state.data.map(data => <div>{data.id}</div>) : 'empty'}
            </div>
        )
    }
}

registerBlockType('cb/oup-series', {
    title: 'OUP Book Series',
    apiVersion: 2,
    category: 'cb-layout',
    icon: 'book-alt',
    description: 'Shows list of OUP book series',
    keywords: ['book', 'series', 'oup'],
    edit: () => {
        const blockProps = useBlockProps();
        return (
            <div {...blockProps}>
                <div>OUP Series List</div>
            </div>
        )
    },
    save: oupSeriesBlock
});

The block is available and rendering without error but is not displaying any data, only 'Test' is rendered.

The rest route is definitely functioning correctly as I've tested it, but componentDidMount() is never being called.

this.state.data.map also works correctly when constructed with dummy data.

I've read through multiple examples and tutorials, but I'm having trouble applying them to my problem, if anyone could help it would be greatly appreciated.

I've been banging my head on this for a bit now.

I'm trying to create a simple wordpress block that fetches custom post types from the rest api, then displays the fetched posts via react. It only needs to do this, and requires no other editor functionality.

However, I'm a bit of a react/wp noob and I may be fundamentally misunderstanding how wordpress react functions, as I can't seem to get anywhere.

Here is my code so far:

class oupSeriesBlock extends Component {

    constructor(props) {
        super(props);
        this.state = {data: []};
    }

    getOupSeries() {
        console.log('mounted');
        apiFetch({
            path: 'wp/v2/oup_series'
        }).then((response) => {
            this.state = {data: response}
            console.log(this.state);
        })
    }

    componentDidMount() {
        this.getOupSeries();
    }

    render() {
        return(
            <div>
                Test
                {this.state.data.length > 0 ? this.state.data.map(data => <div>{data.id}</div>) : 'empty'}
            </div>
        )
    }
}

registerBlockType('cb/oup-series', {
    title: 'OUP Book Series',
    apiVersion: 2,
    category: 'cb-layout',
    icon: 'book-alt',
    description: 'Shows list of OUP book series',
    keywords: ['book', 'series', 'oup'],
    edit: () => {
        const blockProps = useBlockProps();
        return (
            <div {...blockProps}>
                <div>OUP Series List</div>
            </div>
        )
    },
    save: oupSeriesBlock
});

The block is available and rendering without error but is not displaying any data, only 'Test' is rendered.

The rest route is definitely functioning correctly as I've tested it, but componentDidMount() is never being called.

this.state.data.map also works correctly when constructed with dummy data.

I've read through multiple examples and tutorials, but I'm having trouble applying them to my problem, if anyone could help it would be greatly appreciated.

Share Improve this question asked May 11, 2022 at 11:16 elliott_lelliott_l 133 bronze badges 3
  • You can already implement this without any code by using a query block with a nested title/content/link blocks, choose the latest post block or post query block. in WP 6.0 it will even offer suggested patterns that can be modified using javascript. You can also implement it as a reusable block, a template part, or as a predefined pattern with locked blocks so that the user can't change them from your preferred design. A variant of the query block may also be a possibility. – Tom J Nowell Commented May 11, 2022 at 11:40
  • I would also strongly advise the user of function based components not class components. Lots of WordPress block APIs are only available as hooks, and your use of lifecycle methods is made redundant by the useEffect hook which can be used to fetch the posts more efficiently. Likewise it is an antipattern to talk directly to the REST API to fetch posts, there are more efficient cached APIs already built into the block editor for listing entities – Tom J Nowell Commented May 11, 2022 at 11:42
  • 1 Also, your save component is meant to generate static HTML that gets saved in the database, you can't do API requests or make interactive changes in it. If you do then your block will always fail to validate. A save component can only use block attributes to generate its output. It may be necessary for you to render this block using PHP. Any javascript intended for the frontend has to run only on the frontend when the block is used, not in the editor, and not in the save component. – Tom J Nowell Commented May 11, 2022 at 11:43
Add a comment  | 

1 Answer 1

Reset to default 1

This is because when your block was rendered for save the API call had not finished. Save components do not run on the frontend.

    render() {
        return(
            <div>
                Test
                {this.state.data.length > 0 ? this.state.data.map(data => <div>{data.id}</div>) : 'empty'}
            </div>
        )
    }

The purpose of a save component is to take your blocks attributes, and turn them into static HTML to be saved in the post content. None of the code in your save component executes on the frontend. Your save component cannot have side effects or lifecycle methods.

In order to implement fetching posts from the API endpoint when the block is viewed by frontend users, you need to enqueue a javascript file, identify all the places your block is used, and fetch the data. This is not different to when a shortcode has frontend javascript. The main difference here is that WordPress has hooks and filters to let you only enqueue the blocks frontend assets when it's actually used.

In summary:

  • Save components can't have state, side effects, or pull data from external sources such as editor state or remote APIs
  • Save components don't run on the frontend
  • Only the static serialised output of a save component is saved, not the react component itself
  • A save component must always return the same output given the same block attributes, or it is built incorrectly and will fail block validation
  • Use functional components so that you can use newer versions of the block API and hooks such as useBlockProps for better performance and features.
  • frontend javascript requires a separate frontend JS file to be enqueued

本文标签: javascriptVery simple wordpress block to display posts from an api call