I am building a very basic plug-in, the template I have created works beautifully. However I am unable to get the custom post type to be built and displayed in the admin panel on activation.

The thing that is weird to me, if I add the trigger in a construct method, the post type is created and displayed in the admin panel.

On activation I receive the echo 'Plug-in Activated!', likewise for deactivation. I just cant figure out why this wouldn't work within the activate method.

Please can someone direct me as to how I can trigger the creation of this post type on activation?

Here is my code:

 * @package WebsiteLister
Plugin Name: Website Lister
Plugin URI: https://ME.co.uk/website-lister
Description: Helper enabling the ability to log website URLs into a beautiful slider!
Version: 1.0.0
Author: ME
Author URI: https://ME.co.uk
License: GPLv2 or later
Text Domain: website-lister

Copyright (C) 2020 Jason Dupley

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

defined('ABSPATH') or die('Get out of here, sneaky human!');

if (!class_exists('WebsiteLister')) :

    class WebsiteLister

        public $plugin;

        function __construct() {
            $this->plugin = plugin_basename( __FILE__ );

        // Register Enqueued Scritps
        function register_scripts() {
            add_action('admin_enqueue_scripts', array($this, 'enqueue_admin_scripts'));
            add_action('wp_enqueue_scripts', array($this, 'enqueue_frontend_scripts'));

        // Register Admin Area
        function register() {
            add_action('admin_menu', array($this, 'add_admin_pages'));
            add_filter("plugin_action_links_$this->plugin", array( $this, 'settings_link'));

        // Activate
        function activate() {
            //echo 'Plug-in Activated!';

            // Create Custom Post Type

            // Flush rewrite rules

        // Deactivate
        function deactivate() {
            //echo 'Plug-in Deactivated!';

            // Flush rewrite rules

        public function settings_link($links) {
            $settings_link = '<a href="admin.php?page=websites_plugin">Settings</a>';
            array_push($links, $settings_link);
            return $links;

        // Create Admin Pages
        public function add_admin_pages() {
             add_menu_page( 'Websites Plug-in', 'Websites Settings', 'manage_options', 'websites_plugin', array($this, 'admin_index'), 'dashicons-admin-site-alt3', 100 );

        // Create Admin Index
        public function admin_index() {
            // Require Template
            require_once plugin_dir_path( __FILE__ ) . 'templates/admin.php'; 

        // Create Custom Post Type
        protected function create_post_type() {
            add_action('init', array($this, 'custom_post_type'));

        // Register Websites Custom Post Type
        function custom_post_type() {
            register_post_type('website', ['public' => true, 'label' => 'Websites']);

        // Enqueue Admin Scripts
        function enqueue_admin_scripts() {
            // Styles
            wp_enqueue_style('websitelisteradminstylesheet', plugins_url( '/css/wl-admin-style.css', __FILE__ ));
            wp_enqueue_script('websitelisteradminscript', plugins_url( '/js/wl-admin-script.js', __FILE__ ));

        // Enqueue Front-end Scripts
        function enqueue_frontend_scripts() {
            // Styles
            wp_enqueue_style('websitelisterstylesheet', plugins_url( '/css/wl-style.css', __FILE__ ));
            wp_enqueue_script('websitelisterscript', plugins_url( '/js/wl-script.css', __FILE__ ));


    if (class_exists('WebsiteLister')) :

        $websiteLister = new WebsiteLister();


    // activation
    register_activation_hook( __FILE__, array($websiteLister, 'activate'));

    // deactivation
    register_deactivation_hook( __FILE__, array($websiteLister, 'deactivate'));

    // uninstall
    // uninstall.php located within the plug-in root folder handles this process

  • Does this answer your question? How often do you need to register_post_type? Aug 19, 2020 at 13:52
  • No, I don't believe so. I want to know why my code is not running that line on activation but will if dealt with within the constructor which loads automatically on activation. Aug 19, 2020 at 13:54
  • 1
    Did you read the accepted answer? You're not supposed to register post types on activation. That's not how they work. You need to register them on init, on every page load. Aug 19, 2020 at 13:56
  • Ah so it is best to do it through the constructor method? Aug 19, 2020 at 13:57
  • 1
    You're already adding hooks in the register method, so just use that. Aug 19, 2020 at 13:58

1 Answer 1


That's not how register_activation_hook works.

register_activation_hook is called only once, when the plugin is activated. CPT's however need to be registered on every single request, not just when the plugin is activated.

This is because WP doesn't store a list of CPT's in the database, it's generated at runtime by PHP code.

So instead, register your CPT's on the init hook. The same for custom taxonomies.

As for the activation hook, use that to create custom database tables if needed, but the activation hook isn't super reliable to begin with. Most plugins don't use it.

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.