4

I am trying to create a dynamic block and I followed the steps described in the documentation, but for some reason the content that is being returned from /wp-json/wp/v2/block-renderer/plugin-blocks/frontpage-releases?context=edit&_locale=user is Error loading block: No route was found matching the URL and request method with a JSON response that says {"code":"rest_no_route","message":"No route was found matching the URL and request method","data":{"status":404}} and not an actual block. Here is my code for your review, please let me know if I am missing something. Thanks!

Notes On The Implementation:

  • All of the blocks are compiled down through React via laravel-mix with Webpack into assets/js/blocks.js

Debugging Results So Far:

  • The showBlock() method is being called when I save the page, but not when I add it to the content of the page in the editor, nor from the page itself.
  • Currently testing if either the taxonomies or custom block groups are causing it.
  • Changed the code to not use ob_start()/ob_get_clean() and appending it to the $value variable, to see if that was causing an issue.
  • Added and later removed monolog/monolog to use in addition to xdebug helper extension with PhpStorm debugging, and see that it is calling the handle() method, but not the showBlock() method except when saving.

BlockFactory.php:

namespace LibraryPlugin\Entities\Blocks;

use LibraryPlugin\Entities\Blocks\Dynamic\FrontpageReleases;
use LibraryPlugin\Traits\Helpers\LocationHelperTrait;

/**
 * Class BlockFactory
 *
 * Loads all of the blocks into the editor, so that we can use them.
 * This is called from the plugin file, within the main plugin file,
 * if we are in the admin panel.
 *
 * @package LibraryPlugin\Entities\Blocks
 */
class BlockFactory
{
    use LocationHelperTrait;

    /**
     * BlockFactory constructor.
     *
     * This is run as soon as the plugin is being loaded and allows
     * the plugin to add all of the blocks to the `init` action, before
     * the other stages.
     *
     * @throws \Exception
     */
    public function __construct()
    {
        $blocks = [
            ..., // Other non-dynamic blocks that work
            FrontpageReleases::class,
        ];

        add_filter(
            'block_categories',
            function ($categories, $post) {
                return array_merge(
                    [
                        [
                            'slug' => 'plugin-templates',
                            'title' => 'Plugin Page Templates'
                        ],
                        [
                            'slug'  => 'plugin-blocks',
                            'title' => 'Plugin Blocks',
                        ],
                    ],
                    $categories
                );
            },
            1,
            2
        );

        add_action('init', function () {
            wp_register_script(
                'plugin-blocks',
                $this->webAsset('js/blocks.js'),
                ['wp-blocks', 'wp-i18n', 'wp-element', 'wp-editor', 'lodash', 'wp-components'],
                PLUGIN_VERSION
            );

            // Ensure we have the location of any assets in plugin
            wp_localize_script('plugin-blocks', 'PLUGIN', [
                'pluginUrl' => PLUGIN_URI,
            ]);

            wp_register_style(
                'plugin-blocks',
                $this->webAsset('css/blocks.css'),
                [],
                PLUGIN_VERSION
            );
        });

        foreach ($blocks as $block) {
            add_action('init', [$block, 'handle']);
        }
    }
}

FrontpageReleases.php:

namespace LibraryPlugin\Entities\Blocks\Dynamic;

use LibraryPlugin\Traits\Helpers\LocationHelperTrait;

/**
 * Class FrontpageReleases
 *
 * This class is called during `init` action. Uses `plugin-blocks` JS
 * and CSS declared in `BlockFactory.php`. Passes a render callback to
 * make it a dynamic block.
 *
 * @package LibraryPlugin\Entities\Blocks
 */
class FrontpageReleases
{
    use LocationHelperTrait;

    /**
     * Register the release note blocks
     *
     * @return void
     */
    public static function handle(): void
    {
        register_block_type(
            'plugin-blocks/frontpage-releases',
            [
                'render_callback' => [__CLASS__, 'showBlock']
            ]
        );
    }

    /**
     * Render the value of the releases
     *
     * @param mixed $attributes
     *
     * @return mixed
     */
    public static function showBlock($attributes = null)
    {
        $classCount = 0;
        $value = '';
        try {
            $allReleases = new \WP_Query([
                'post_type' => 'page',
                'posts_per_page' => 3,
                'tax_query' => [
                    'relation' => 'AND',
                    [
                        'taxonomy' => 'release',
                        'field' => 'term_id',
                        'terms' => get_terms('release', ['fields' => 'ids'])
                    ],
                    [
                        'taxonomy' => 'solutions',
                        'field' => 'term_id',
                        'terms' => get_terms('solutions', ['fields' => 'ids']),
                        'operator' => 'NOT IN'
                    ]
                ],
                'order'          => 'DESC',
                'orderby'        => 'release', // Sort by custom taxonomy
            ]);

            if ($allReleases->have_posts()) {
                while ($allReleases->have_posts()) {
                    $allReleases->the_post();
                    $isReleased = function_exists('types_render_field')
                        ? types_render_field('is-released')
                        : get_post_meta(get_the_ID(), 'wpcf-is-released');
                    $value .= '<div class="release-version"><a href="' . get_the_permalink() . '" title="'
                        . get_the_title() . '"><h2>' . get_the_title() . '</h2><p>';
                    if (!$isReleased && $count === 0) {
                        $value .= 'Upcoming Release';
                    }
                    if ($isReleased && $count === 0) {
                        $value .= 'Current Release';
                        $count++;
                    } elseif ($isReleased && $count > 0) {
                        $value .= 'Previous Release';
                        $count++;
                    }
                    $count++;
                    $value .= '</p></a></div>';
                }
            }

            $value .= '<div class="solution-resources">
                <a href="/resources/">
                    <h2>Helpful Information</h2>
                    <p>Recommended Browser, Product Timeline, Maintentance Changes, Cloud Report,
                        Training Videos, etc.</p>
                </a>
            </div>';
        } catch (\Exception $e) {
            // TODO: Figure out how to handle any exceptions
        }

        return $value;
    }
}

frontpage-releases.jsx gets compiled into blocks.js:

import { PluginIcon } from './plugin-icon';
const { ServerSideRender } = window.wp.components;
const { registerBlockType } = window.wp.blocks;
const { __ } = window.wp.i18n;

registerBlockType('plugin-blocks/frontpage-releases', {
  title: __('Frontpage Releases', 'library-plugin'),

  icon: PluginIcon,

  category: 'plugin-blocks',

  edit: function ({ attributes }) {
    return (
      <ServerSideRender
        block="plugin-blocks/frontpage-releases"
        attributes={attributes}
      />
    );
  },

  save() {
    return null;
  },
});
1

The handle() method is being called by an add_action('enqueue_block_editor_assets, [$block, 'handle']) method along with all the other blocks.

Here lies the problem. The register_block_type is being called too late. Try to call the function inside the init action hook.

You can see an example in the shortcode block of the core.

6
  • That was actually one of the first things I tried, and I tried it again just now to see if it might work. It's still showing up as 404. Updated code to current state. Jan 13 '19 at 19:56
  • 1
    @OpensaurusRex Could you try to replace your current render function and simply return a string; to figure out if the problem is in the function or outside.
    – Alvaro
    Jan 13 '19 at 20:02
  • Returning a string also returns a 404 from API. Thanks for the help. Jan 14 '19 at 21:09
  • I have done a bit of debugging, and added more of the code that affects the previous code. Jan 17 '19 at 11:04
  • So, apparently the Gutenberg developers broke the code and it's not working at the moment: GitHub Issue #12057 Jan 20 '19 at 4:41

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.