1

I have a settings page for my plugin in which the user can toggle a custom post type on or off. When the plugin is initialized I then check this setting to see if the custom content type should be registered or not. The registerPostType() method is called on the init action:

class CPT {
  private $enabled = false;

  public function __construct()
  {
    // Handle form submission.
    add_action('init', array($this, 'checkFormSubmission'), 8);

    // Load settings.
    $settings = get_option('cpt_settings');
    $this->enabled = $settings['enabled'];

    // Add menu.
    add_action('admin_menu', array($this, 'registerMenu'));

    // Register custom post type if enabled.
    if ($this->enabled) {
        add_action('init', array($this, 'registerPostType'));
    }
  }

  public function registerMenu()
  {
    add_submenu_page(
        'options-general.php',
        __('CPT Settings', 'cpt'),
        __('CPT Settings', 'cpt'),
        'manage_options',
        'cpt',
        array($this, 'renderSettingsPage')
    );
  }

  public function registerPostType()
  {
    $args = array(
        'labels' => array(
          'name' => 'CPT',
        ),
        'public' => true,
        'publicly_queryable' => true,
        'show_ui' => true,
        'show_in_menu' => true,
        'query_var' => true,
        'capability_type' => 'post',
        'has_archive' => true,
        'hierarchical' => false,
        'menu_position' => null,
        'supports' => array('title', 'editor', 'author', 'thumbnail', 'excerpt')
    );
    register_post_type('sample-cpt',  $args);
  }

  public function checkFormSubmission()
  {
    // Validate so user has correct privileges.
    if (!current_user_can('manage_options')) {
      die(__('You are not allowed to perform this action.', 'cpt'));
    }

    // Check if settings form is submitted.
    if (filter_input(INPUT_POST, 'cpt-settings', FILTER_SANITIZE_STRING)) {
      // Verify nonce and referer.
      check_admin_referer('cpt-settings-action', 'cpt-settings-nonce');
      $this->enabled = filter_input(
          INPUT_POST,
          'cpt-enable',
          FILTER_VALIDATE_BOOLEAN
      );
      update_option('cpt_settings', array('enabled' => $this->enabled));
    }
  }

  public function renderSettingsPage()
  {
    require_once plugin_dir_path(__FILE__ ) . '/admin/templates/settings-page.php';
  }
}

new CPT();

This works as expected, but the problem is that when I'm saving the form the menu item for the custom post type is not updated until I reload the page. Obviously this is because the menu is already created.

My first thought is that I am not using the correct hooks for taking care of the form submission and registering my custom post, or perhaps the hooks should be added with a higher priority?

I tried to use wp_redirect() after the setting is saved, but I'm not able to set any headers because the output has already started.

Can someone please explain how I can make the menu item for my custom post type update when saving the setting for my plugin?

  • 1
    Not an answer, but an observation... I did a quick using the "Toolset Types" plugin which lets you create and amend custom post types (and other things). I just created a custom post type, and clicked "Save Post Type" and the menu for the Custom Post Type appeared in the Admin menu immediately. All of which leads me to believe that there's no magic but that some "basic" issue is the root cause of the trouble. Anyway, is it correct to assume that your menu for the custom post type appears in the Admin menu in its own right, and not "within" your Plugin's Admin menu? – Tedinoz Sep 16 '18 at 5:13
  • @Tedinoz - Yes, my custom post type has its own menu item, positioned at the top level in the admin menu. – Cyclonecode Sep 16 '18 at 5:43
  • 1
    Without detracting from janh's answer, may I add that there is general agreement about not putting your hooks in the constructor? There is an excellent WP_SE answer and code example by 'gmazzap' on "Best way to initiate a class in a WP plugin?" (the second and longer answer). His example uses three classes (frontend, backend and "a third used in both cases") plus a means of instantiating them using 'proper' hooks. Maybe it will give you some other ideas about your code. – Tedinoz Sep 16 '18 at 14:29
1
+50

I initially misunderstood your question completely (too much tea, too focused on my initial idea of what your problem is instead of carefully reading ;).

I believe that the problem isn't that the menu is already created (admin_menu runs after init) but rather that registerPostType will only run in init if it is enabled (and not when it is being enabled).

Moving the if ($this->enabled) { into registerPostType and running it unconditionally on init, e.g. just putting

if (!$this->enabled) return;

at the top of registerPostType and changing

// Register custom post type if enabled.
if ($this->enabled) {
    add_action('init', array($this, 'registerPostType'));
}

to

// Register custom post type if enabled.
add_action('init', array($this, 'registerPostType'));

seems most logical to me.

  • This does not seem to solve my problem? The problem is that when i register my custom post type it will not show up in the admin menu before I reload the page once? The registerMenu() only registers a menu for the plugin and should of course always be visible as long as the plugin is activated? – Cyclonecode Sep 16 '18 at 8:41
  • @Cyclonecode Sorry, I kinda completely trailed into my own thoughts that quickly diverged from what you had written. I've updated the answer and believe this should make more sense and not sound like random gibberish. – janh Sep 16 '18 at 8:56
  • You where absolutely right. I changed my code to match the above pattern and now it is working as it should. – Cyclonecode Sep 16 '18 at 9:00

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.