0

I have this code in a custom plugin.

    public function create_new_cpt( WP_REST_Request $request )
    {
        $args = $request->get_param('newCptDetails');

        $cpt = register_post_type( 
            $args['name'], 
            [
                'label' => $args['label'],
                'description' => $args['desc'],
                'show_ui' => true,
                'show_in_menu' => true,
                'show_in_rest' => true
            ]
        );

        if( $cpt ){
            add_option( 'cpt_name', $args['name'] );
            add_option( 'cpt_label', $args['label'] );
            add_option( 'description', $args['desc'] );
            return $cpt;
        } else {
            return 'not registered';
        }
    }

The code is a callback function for a custom REST route that is supposed to get all the needed params to create a new CPT. I've done a test but I've noticed that the CPT is not registered and I think it's because I'm not calling the init hook. In my plugin code I'm creating four routes, one is to create new cpt, another to list all cpt and the last two will be used to enable or disable a CPT.

    public function setup_admin_page_routes()
    {

        register_rest_route( 
            $this->namespace, 
            '/list-cpt', 
            [
                'methods' => 'GET',
                'callback' => [$this, 'list_cpt'],
                'permissions_callback' => [$this, 'permissions_callback']
            ], 
        );

        register_rest_route( 
            $this->namespace, 
            '/create-cpt', 
            [
                'methods' => 'POST',
                'callback' => [$this, 'create_new_cpt'],
                'permissions_callback' => [$this, 'permissions_callback']
            ], 
        );

        register_rest_route( 
            $this->namespace, 
            '/disable-cpt', 
            [
                'methods' => 'POST',
                'callback' => [$this, 'deactivate_cpt'],
                'permissions_callback' => [$this, 'permissions_callback']
            ], 
        );

    }

How I can call the init hook insite my function and how I will enable or disable or delete CPT when from the admin page I'm creating the user will give the related command?

1
  • 1
    why do you want to register post types via a REST API route?
    – Tom J Nowell
    Nov 6, 2022 at 14:50

1 Answer 1

1

That's not how post type and taxonomy registration work, they are already dynamic. You must call register_post_type on every request, no exceptions, and never later than the init hook. If you do not do this, then the CPT doesn't exist.

register_post_type and register_taxonomy store their data in PHP variables, and do not save that data anywhere, so once the request ends that information disappears and needs to be re-registered on the next request. So it doesn't make sense to modify a CPT's definition the way you describe.

It also can't be called later than the init hook. This means it is not possible to register a custom post type in an form/AJAX/REST API handler, that is too late and also won't be passed on to the next request because of the way registration works.

Instead, you can receive new values the same way you would any other form or AJAX, save them in the database as options or another way. Then on the init hook, before you call register_post_type/register_taxonomy, grab those values you saved earlier and use them in the arguments.


Remember PHP applications aren't like Node.js sites, they don't have long-running background tasks that wait for requests. Instead they're loaded fresh from the disk, generate a response, then they end. All variables dissapear at the end of the request, and the next request starts from a blank slate.

Additionally, if you try to change the URL or anything that's used in the URL, then you need to flush and resave permalinks.

8
  • 1
    noting that the options system won't scale beyond a single CPT, so you probably want an internal CPT that just stores all this information, then on init loop through them activating them. This is exactly what the custom post types plugin does alrady. Ironically setting show_in_rest to trye on such a CPT would give you exactly what you were trying to build for free
    – Tom J Nowell
    Nov 5, 2022 at 21:13
  • ok, so i need to use add_option() for each new CPT I want to create, and grab the info later right?The main problem is, if there isn't any CPT when the plugin is installed, what I will set into the register_post_type ?
    – devdev
    Nov 5, 2022 at 23:04
  • not sure if it can be a good way to achive what I want to do, but probably I can pass an array to add_option() with all the info about the new desired CPT. Then in the init that I will place in a custom method of the plugin, call the get_option() and loop for all the CPT and register it? Can you show an example that can help me please?
    – devdev
    Nov 6, 2022 at 7:42
  • I'm not sure if I can have multiple options with the same name like add_option('registered_cpt', array(...) )
    – devdev
    Nov 6, 2022 at 7:43
  • you just need to store that information somewhere, then retrieve it when you call register_post_type on the init hook. How you do that is entirely up to you, and yes you're right you can't have multiple options with the same name. Note that it seems you're reinventing the wheel and there's already a very popular plugin for registering post types with a UI. You also don't have to use options to store your data, how you store it is entirely up to you. I also notice that you never provided any context for why, theres a very high chance there's a better way than dynamic CPT's for what you want
    – Tom J Nowell
    Nov 6, 2022 at 14:48

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.