WP 5.5 Fatal Error – get_rest_controller() in rest-api.php

Since 5.5 WP_Taxonomy objects now have a new method, get_rest_controller(), to allow for per-taxonomy controller overrides. The problem is that your plugin overwrites the taxonomy saved in the global $wp_taxonomies cache with a version that isn’t a real WP_Taxonomy object, just a stdObject property bag, and so does not have get_rest_controller() to call.

This is the relevant bit: ut_registered_taxonomy() in UserTags.php lines 83-101, which is a registered_taxonomy action handler.

public function ut_registered_taxonomy( $taxonomy, $object, $args ) {
    global $wp_taxonomies;

    // Only modify user taxonomies, everything else can stay as is
    if ( $object != 'user' ) {
        return;
    }

    // Array => Object
    $args = (object) $args;

    // Register any hooks/filters that rely on knowing the taxonomy now
    add_filter( "manage_edit-{$taxonomy}_columns", array( $this, 'set_user_column' ) );
    add_filter( "manage_{$taxonomy}_custom_column",
                 array( $this, 'set_user_column_values' ), 10, 3 );

    // Save changes
    $wp_taxonomies[ $taxonomy ]    = $args;  // <--- this line is the problem
    self::$taxonomies[ $taxonomy ] = $args;
}

Note the line I’ve marked just below the “Save changes” comment: this overwrites the existing value of $wp_taxonomies[ $taxonomy ] with a bad value, and isn’t needed anyway because there haven’t been any changes made to the taxonomy properties. So I’d suggest just deleting this line as the simplest fix.

(In fairness to this code it was written before the WP_Taxonomy class was added in 4.7. And back then the (object) cast was the correct way to make a taxonomy object from $args if you had changed the contents of $args and needed to update $wp_taxonomies.)

We could now also now ensure we have a real WP_Taxonomy object in self::$taxonomies too, e.g. rather than $args = (object) $args) fetch the real object from $wp_taxonomies $args = $wp_taxonomies[ $taxonomy ] where it was placed shortly before this call. But I don’t think that’s actually necessary here.