This is a required file. It acts sort of as a glue between the Schema and the View (Front-End). It reads the fields and their values and makes it possible to use those fields in the View file.

By default, without any modification, it will look like this.

$block_name = basename(__DIR__);
// $block_prefix is defined inside init.php

register_block_type("$block_prefix/$block_name", array(
  'render_callback' => function($attrs, $content) {
    global $latte;
    // START:Add or modify $attrs[] params here
    // ...
    // END:Add or modify $attrs[] params here
    $html_str = $latte->renderToString(dirname( __FILE__ ) . '/view.latte', $attrs);
    return $html_str;
  'attributes' => json_decode(file_get_contents(dirname( __FILE__ ) . "/model.json"), true)['attributes']

What this file does

If we analyze the code, we will see the register_block_type() function. This is how we register the block on the back-end.

On line 6, we see that we register the block by the dynamic name of "$block_prefix/$block_name".

$block_name is the name of the directory of the current block, and also the value of the block_meta.BLOCK_REGISTER_NAME property of the model.json file.

$block_prefix is the value of the BLOCK_NAME_PREFIX constant defined in the theme_redone_global_config.json file living in the root directory of the theme.

The value of this constant is “custom”, and it will be used to prefix all the custom blocks we create.

Example: If we create a block called “Homepage Hero”, the prefixed name that we would see inside the admin screen would be “custom/Homepage Hero”.

The $attrs variable is an associative array where the values of the fields that we define will be located. We then pass that variable to the view file on line 15 in the image above.

For simplicity, let’s assume that our current block only has one field called title.

This is what the Schema for it would look like:

"title": {
  "type": "object",
  "field_meta": {
    "type": "text",
    "label": "Title"
  "default": {
    "text": ""

If we populated this field in admin and wrote “This is the title” for example, then our $attrs array would look like this.

$attrs = [
  "title" => [
    "text" => "This is the title"

Then, in the view.latte file, we would render the value of this field such as this.


Notice how we are not accessing its value by writing {$attrs['title']['text']}, we only use the name of the key in the $attrs assoc array, which in this example is $title.

Abstracting The Logic

We can also use this file to write the logic of the block, and manipulate data.

Sure, we can do that directly in the view.latte file, but doing it in this file instead (between lines 9 and 11 in the screenshot above), and then attaching the result of that logic to the $attrs array, results in a separation of concerns.

The view.latte is much cleaner and used only as a view layer, while the controller.php file is used for the logic.

Here’s a quick example:


We are fetching posts in controller.php file, and then forwarding the results to the view.latte file $attrs['posts'] = $posts;

// START:Add or modify $attrs[] params here
$posts_args = array(
  'numberposts' => 3,
  'orderby' => 'date',
  'order' => 'DESC',
  'post_type' => array( 'post' )
$posts = get_posts( $posts_args );
$attrs['posts'] = $posts;
// END:Add or modify $attrs[] params here


Now, our view.latte file is cleaner and only serves the purpose of showing the prepared data.

<div n:foreach="$posts as $post">
Join Our Newsletter

To get updates about Theme Redone