0

I'm working on a plugin that adds custom templates to WordPress for use with the active theme. The template files are located in a plugin directory and are being passed into WordPress with the theme_templates hook.

What's stumping me is one small variation in an if statement results in the REST API returning an error when firing WP_REST_Posts_Controller::check_template(). The error is only present in the block editor as the classic editor bypasses the REST API check.

This is my function.

    public function add_custom_templates($templates)
    {
        global $post_type;

        /**
         * Collect an array of templates files
         */
        $templates = $this->template_files();  

        foreach ($templates as $template) {
            /**
             * Get header info from template file to parse template name and post type(s)
             */
            $data = get_file_data( MY_TEMPLATES_PATH . $template, array(
                    'name' => 'Template Name',
                    'post_type' => 'Template Post Type'
                ));

            // remove spaces if present
            $trimmed = str_replace(' ', '', $data['post_type']);
        
            //convert template data post type string to array
            $post_types = explode(',', $trimmed);

            // THIS WORKS <---
            if (!empty($data['name']) && !empty($data['post_type'])) {
                $custom_templates[$template] = $data['name'];
            }
            
            // THIS DOES NOT WORK <---
            // if (!empty($data['name']) && !empty($data['post_type']) && in_array($post_type, $post_types)){
            //     $custom_templates[$template] = $data['name'];
            // }


        }
        // manual override
        $custom_templates['example.php'] = 'fake template';

        return $custom_templates;
    }

}

Let's assume $templates = array('one.php', two.php, three.php')

one.php has the following comment block below the opening tag

/*
 * Template Name: Template One
 * Template Post Type: post, page
 */

two.php has the following comment block below the opening tag

/*
 * Template Name: Template Two
 * Template Post Type: post, product
 */

three.php has the following comment block below the opening tag

/*
 * Template Name: Template Three
 * Template Post Type: page, product
 */

This working if statement returns all templates and allows for saving/updating inside the block editor without errors from the REST API

if (!empty($data['name']) && !empty($data['post_type'])) {
     $custom_templates[$template] = $data['name'];
}

$custom_templates returns the following array: array(4) { ["one.php"]=> string(12) "Template One" ["two.php"]=> string(12) "Template Two" ["three.php"]=> string(14) "Template Three" ["example.php"]=> string(13) "fake template" }

However, that statement results in all 3 templates being accessible no matter the post type. I'm wanting to only include a template if the $data['post_type'] matches the global $post_type for the given post.

This if statement is supposed to limit it as per my intent.


if (!empty($data['name']) && !empty($data['post_type']) && in_array($post_type, $post_types)){
     $custom_templates[$template] = $data['name'];
}

When running just the second if statement on a "page", $custom_templates returns the following array:array(3) { ["one.php"]=> string(12) "Template One" ["three.php"]=> string(14) "Template Three" ["example.php"]=> string(13) "fake template" }

*No matter which if statement is used, the manual override I added as a temporary sanity check is able to be selected and saved despite the lack of an actual file existing.

When running the if statement with in_array($post_type, $post_types) it correctly returns the templates I'm wanting to return, but any attempt to select and save that template inside the block editor results in the REST API kicking back the error "Updating failed. Invalid parameter(s): template".

Any help would be greatly appreciated as I'm stumped why the REST API is blocking the request *only when adding the extra check to my if statement.

1 Answer 1

0

It appears that the issue lies with the in_array function that is checking if the current post type matches the post types specified in the template header information. The problem seems to be that the REST API is validating the parameters, including the template parameter, before passing it to the WordPress API to update the post.

It's possible that the REST API is only allowing certain values for the template parameter and the values generated by the in_array function are not accepted. You can try to debug this by logging the values of $post_type and $post_types before and after the in_array function, as well as the $custom_templates array.

Another possible solution is to modify the REST API check_template method to accept the values generated by the in_array function. This would involve creating a custom REST API controller for the posts endpoint and including the check for the custom templates in the check_template method.

Lastly, you could also try using the WP_Query class instead of the REST API to retrieve and update the templates, as it is not as strict in terms of parameter validation.

1
  • I appreciate that insight. This gives me a few more options to validate against. I'm not intentionally using the REST API, rather the block editor uses it. My code with the in_array function works as expected using the classic editor. My issue was observed to be specific to the use of block editor which uses the REST API. This made the issue more confusing as the block editor/REST API was validating the request only when the in_array function was not present.
    – Kylen
    Commented Feb 13, 2023 at 14:53

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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