so I was trying to learn more about Gutenberg Blocks and I wanted to make a block that shows the last three blog posts - something that could be used at the bottom of each page of my Wordpress site. I looked at some tutorials and I was able to create a working version... well, it works in the editor (backend) but when I apply code to the save file (frontend) my code crashes the site and nothing is displayed.
I produced the following code for my block that queries the Wordpress database and retrieves the last three blog posts
import { useBlockProps } from '@wordpress/block-editor';
import apiFetch from '@wordpress/api-fetch';
import { useState, useEffect, useRef } from '@wordpress/element';
import { addQueryArgs } from '@wordpress/url';
import './editor.scss';
export default function Edit() {
// are we loading the posts?
const [ isLoading, setLoading ] = useState( true );
// the posts we're displaying
const [ posts, setPosts ] = useState([]);
// we don't want to update state on an unmounted component
const isStillMounted = useRef();
// fetch the posts
useEffect(() => {
isStillMounted.current = true;
apiFetch( {
path: addQueryArgs( `/wp/v2/posts?_embed&filter[posts_per_page]=3`, { } ),
} )
.then( ( data ) => {
if ( isStillMounted.current ) {
setPosts( data );
setLoading( false );
}
} )
.catch( () => {
if ( isStillMounted.current ) {
setPosts( [] );
setLoading( false );
}
} );
}, [setPosts, setLoading, isStillMounted]);
return (
<div { ...useBlockProps() }>
<div className="blog">
<div className="blog__wrapper">
<div className="blog__header">
<h2 className="blog__header__heading">Blog Posts</h2>
</div>
<div className="blog__row">
{
posts.map((post) =>
<div className="blog__card">
<div className="blog__card__details">
<div className="blog__card__details__header">
{ post.title.rendered }
</div>
<div className="blog__card__details__teaser"
dangerouslySetInnerHTML={{__html: post.excerpt.rendered }}>
</div>
<div className="blog__card__details__date">
{ new Date(post.date).toLocaleString('en-GB', { timeZone: 'UTC' }).split(',')[0] }
</div>
<div className="blog__card__details__control">
<a href={post.link} className="button-link">weiter lesen</a>
</div>
</div>
<div className="blog__card__img" style={{ 'background-image': "url(" + post._embedded['wp:featuredmedia']['0'].source_url + ")"}}>
</div>
</div>
)
}
</div>
</div>
</div>
</div>
);
}
In the editor this looks great! So I thought, as I don't actually do anything with the block (meaning the user doesn't add text, photos or anything) surely I can just apply the same code to the save.js file. However, just adding the js code from the edit file to the save file breaks everything. The console tells me that I can't use react hooks?
Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
Here is the code in the save.js, I've just copied and pasted...
export default function save() {
// are we loading the posts?
const [ isLoading, setLoading ] = useState( true );
// the posts we're displaying
const [ posts, setPosts ] = useState([]);
// we don't want to update state on an unmounted component
const isStillMounted = useRef();
// fetch the posts
useEffect(() => {
isStillMounted.current = true;
apiFetch( {
path: addQueryArgs( `/wp/v2/posts?_embed&filter[posts_per_page]=3`, { } ),
} )
.then( ( data ) => {
if ( isStillMounted.current ) {
setPosts( data );
setLoading( false );
}
} )
.catch( () => {
if ( isStillMounted.current ) {
setPosts( [] );
setLoading( false );
}
} );
}, [setPosts, setLoading, isStillMounted]);
return (
<div { ...useBlockProps.save() }>
I haven't added anything here...
</div>
);
}
So, I guess I can't really do this. Can I use react code in the Frontend? I am unsure if I am doing this correctly (is my approach wrong or just ode) or if what I want to do is achievable? I want to use a "static" block as I don't really know PHP. Any advice on how I should approach this problem or if you could share some links to produce such a block would be appreciated. I'm currently reading the article from the warning and looking at other posts here but any help you can give to educate me would be great. Thanks in advance.