Admin_init not working in submenu page

(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!