Admin_init not working in submenu page

I've a plugin divided into multiple pages and files based on classes.

The base file (linked from plugin main file) contains code for menu and submenu pages and provides wordpress with their respective files in a subfolder.

The problem is, that the admin_init hook isn't working in the submenu page (trying to save values from a form submitted in submenu page).

The main page looks like (the admin_init hook works fine if used in this file class itself):

class MyPlugin {

    public function __construct(){
        add_action( 'admin_menu', array( $this, 'add_menu' ) );
    }

    public function add_menu() {
        add_menu_page(
            'My Plugin',
            'My Plugin',
            'manage_options',
            MY_PLUGIN_DIR.'/inc/admin/class-my-plugin-home.php',
            '',
            'dashicons-yes',
            89
        );

        add_submenu_page(
            MY_PLUGIN_DIR.'/inc/admin/class-my-plugin-home.php',
            'Submenu page',
            'Submenu page',
            'manage_options',
            MY_PLUGIN_DIR.'/inc/admin/class-my-plugin-submenu.php',
            ''
        );
    }
}

While the submenuclass-my-plugin-submenu.php file looks like:

function checkit(){

    echo "This code is not working or showing (just for example)";
}

add_action( 'admin_init', 'checkit' );

Edit:

Previously not working and now the working version (thanks to Sally CJ) can be found here: https://github.com/nabtron/wp-admin-init-test-plugin

Topic admin-init Wordpress

Category Web


(Updated answer)

Looking at the simplified plugin source, the following works:

// In class-init-test.php
public function __construct(){
    add_action( 'admin_init', array( $this, 'page_init' ) );
    ...
}

because when that add_action() is called, the admin_init action is not yet fired. Hence Init_test::page_init() gets called.

However, the following doesn't work because admin_init has already been fired by the time you call add_action( 'admin_init', ... ):

  1. In class-init-test-home.php:

    public function __construct() {
        add_action( 'admin_init', array( $this, 'save' ) );
        ...
    }
    
  2. In class-init-test-submenu.php:

    function save(){
        ...
    }
    add_action( 'admin_init', 'save' );
    

And if you want to confirm whether admin_init has been fired or not, add this before the add_action() call:

var_dump( did_action( 'admin_init' ) );

To overcome the issue, you can create a static method/function in your menu/submenu class, and hook the method from the Init_test constructor. Example for the Init_Test_Home class:

// In class-init-test.php
/* This is a simplified example! You'd need to adjust the `Init_Test_Home` class
   e.g. do `public static function save()` instead of `public function save()`,
   and you should actually load the class prior to calling the `add_action()`; or
   perhaps in init-test.php.
*/
public function __construct(){
    add_action( 'admin_init', array( Init_Test_Home, 'save' ) );
    ...
}

Or you can try the code/approach I previously suggested. :) But here, it's slightly different and based on your existing code; and this one is, again, for the Init_Test_Home class, but you can follow the same steps for the submenu class:

  1. In class-init-test.php:

    public function add_menu() {
        // Load and instantiate the class - $init_test_home is defined in the class file.
        include INIT_TEST_DIR . '/inc/admin/class-init-test-home.php';
    
        add_menu_page(
            'Init Test',
            'Init Test',
            'manage_options',
            'init-test-home', // Use a slug other than the class file path.
            array( $init_test_home, 'admin_page' ),
            'dashicons-yes',
            89
        );
    
        ...
    }
    
  2. In class-init-test-home.php:

    public function __construct() {
        add_action( 'admin_init', array( $this, 'save' ) );
    }
    
    public function admin_page() {
        require_once('views/init-test-home.php');
    }
    
  3. Define INIT_TEST_DIR like so:

    define( 'INIT_TEST_DIR', plugin_dir_path( __FILE__ ) );
    

Hopefully this answer is more helpful!

About

Geeks Mental is a community that publishes articles and tutorials about Web, Android, Data Science, new techniques and Linux security.