Dynamic blocks in WordPress offer flexibility by allowing the block’s content to be rendered dynamically, as opposed to static blocks which have a predefined structure and content. This approach is essential when working with content that needs to be updated based on external data or user interaction, such as displaying the latest posts or filtering custom post types.
In this article, we will discuss the differences between server-side rendering (SSR) and client-side rendering (CSR) for dynamic blocks, and how you can implement them using class-based singleton patterns in WordPress development.
What is a Dynamic Block?
A dynamic block is a block whose content is generated when a post or page is viewed, rather than when it is saved in the database. This allows for more flexible content that can change without requiring the post to be updated. For example, a block that displays the latest movies or a filtered list of posts based on user input.
Dynamic blocks can either be:
- Server-side rendered (SSR): The content is rendered on the server using PHP and sent as part of the HTML response.
- Client-side rendered (CSR): The block fetches data asynchronously using JavaScript and APIs (like the WordPress REST API) and renders the content on the client.
Server-Side Rendering (SSR) of Dynamic Blocks
Server-side rendering means that the block content is generated using PHP on the server before being sent to the browser. This approach ensures that the block’s content is always fresh when the page is loaded, and it’s particularly useful for cases where you want to minimize the use of JavaScript or ensure better SEO.
Example: A Movie List Block with SSR
Here’s how you can create a server-side rendered dynamic block using the class-based singleton pattern.
1. Register the Block with PHP
In this example, we will create a dynamic block to display a list of movies from a custom post type rt-movie.
<?php
class Movie_List_Block {
private static $instance = null;
private function __construct() {
add_action('init', [$this, 'register_block']);
}
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function register_block() {
// Register the block server-side
register_block_type('rt-blocks/movie-list', [
'render_callback' => [$this, 'render_movie_list_block'],
'attributes' => [
'genre' => [
'type' => 'string',
'default' => '',
],
],
]);
}
public function render_movie_list_block($attributes) {
// Fetch movies based on the genre attribute
$genre = esc_attr($attributes['genre']);
$args = [
'post_type' => 'rt-movie',
'posts_per_page' => 5,
'tax_query' => [
[
'taxonomy' => 'rt-genre',
'field' => 'slug',
'terms' => $genre,
],
],
];
$movies_query = new WP_Query($args);
$output = '<div class="movie-list">';
if ($movies_query->have_posts()) {
while ($movies_query->have_posts()) {
$movies_query->the_post();
$output .= '<div class="movie-item">';
$output .= '<h3>' . get_the_title() . '</h3>';
$output .= '<p>Release Date: ' . get_post_meta(get_the_ID(), 'release_date', true) . '</p>';
$output .= '</div>';
}
wp_reset_postdata();
} else {
$output .= '<p>No movies found.</p>';
}
$output .= '</div>';
return $output;
}
}
Movie_List_Block::get_instance();
Key Points:
- Server-side rendering: The block is rendered entirely using PHP on the server.
render_callback: This function is responsible for generating the HTML of the block.- Attributes: The
genreattribute is passed from the block editor, allowing us to filter movies based on genre.
2. Block Editor Registration with JavaScript
We also need to register the block in the block editor, so it appears in the Gutenberg interface.
wp.blocks.registerBlockType('rt-blocks/movie-list', {
title: 'Movie List',
category: 'widgets',
attributes: {
genre: {
type: 'string',
},
},
edit: function (props) {
return (
<div>
<p>Select Genre:</p>
<input
type="text"
value={props.attributes.genre}
onChange={(event) => props.setAttributes({ genre: event.target.value })}
/>
<p>Movies will be rendered on the front-end.</p>
</div>
);
},
save: function () {
return null; // Content is rendered on the server.
},
});
Benefits of SSR:
- Better SEO, as content is included directly in the HTML sent to the browser.
- Simpler implementation when using WordPress queries.
- No reliance on JavaScript for content loading.
Client-Side Rendering (CSR) of Dynamic Blocks
Client-side rendering involves fetching data asynchronously in the browser after the initial HTML page has been loaded. This can be done using the WordPress REST API or custom AJAX endpoints. CSR is useful for creating more interactive or personalized blocks without requiring a page reload.
Example: A Movie Filter Block with CSR
We will now implement a client-side rendered block that allows users to filter movies dynamically based on genre. This involves making a REST API request to fetch the filtered movies.
1. Register the Block with PHP
We’ll still use a class-based singleton structure to register the block and expose a custom REST API endpoint.
<?php
class Movie_Filter_Block {
private static $instance = null;
private function __construct() {
add_action('init', [$this, 'register_block']);
add_action('rest_api_init', [$this, 'register_rest_routes']);
}
public static function get_instance() {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function register_block() {
register_block_type('rt-blocks/movie-filter', [
'attributes' => [
'genre' => ['type' => 'string', 'default' => ''],
],
'editor_script' => 'rt-blocks-movie-filter-script',
]);
}
public function register_rest_routes() {
register_rest_route('rt/v1', '/movies/', [
'methods' => 'GET',
'callback' => [$this, 'get_movies'],
'permission_callback' => '__return_true',
]);
}
public function get_movies($request) {
$genre = sanitize_text_field($request->get_param('genre'));
$args = [
'post_type' => 'rt-movie',
'posts_per_page' => 5,
'tax_query' => [
[
'taxonomy' => 'rt-genre',
'field' => 'slug',
'terms' => $genre,
],
],
];
$movies = new WP_Query($args);
$data = [];
if ($movies->have_posts()) {
while ($movies->have_posts()) {
$movies->the_post();
$data[] = [
'title' => get_the_title(),
'release_date' => get_post_meta(get_the_ID(), 'release_date', true),
];
}
}
wp_reset_postdata();
return rest_ensure_response($data);
}
}
Movie_Filter_Block::get_instance();
2. Block Editor Registration with JavaScript
Next, we register the block in JavaScript and fetch the data using the REST API.
wp.blocks.registerBlockType('rt-blocks/movie-filter', {
title: 'Movie Filter',
category: 'widgets',
attributes: {
genre: { type: 'string' },
},
edit: function (props) {
const [movies, setMovies] = wp.element.useState([]);
const fetchMovies = () => {
wp.apiFetch({ path: `/rt/v1/movies?genre=${props.attributes.genre}` })
.then((movies) => setMovies(movies));
};
return (
<div>
<input
type="text"
value={props.attributes.genre}
onChange={(event) => props.setAttributes({ genre: event.target.value })}
/>
<button onClick={fetchMovies}>Fetch Movies</button>
<ul>
{movies.map((movie, index) => (
<li key={index}>
{movie.title} - {movie.release_date}
</li>
))}
</ul>
</div>
);
},
save: function () {
return null; // Content is rendered on the client.
},
});
Benefits of CSR:
- More interactive and dynamic content.
- Can load or filter content without refreshing the page.
- Better for large datasets, as only a subset of content is loaded at a time.
When to Use SSR vs CSR?
- Server-Side Rendering (SSR): Best for scenarios where content needs to be SEO-friendly or when the page content must be available immediately without additional JavaScript processing. It’s also easier for rendering larger amounts of data directly in the HTML.
- Client-Side Rendering (CSR): Ideal for interactive, user-driven
Thank you for reading through the post… More will be added.
by ~Leaveitblank (Mayank Tripathi)