Even though I have years of software development experience, I am new to WP & PHP development, so please bear with me.
After reading through the plugin manual, I started with a WP plugin boiler plate, made all the required field and name changes, added a custom capability, and, as a first real functionality, tried to add a simple admin interface for the plugin like so:
<?php
class Plugin_Name_Admin {
// some code ommitted, the actual code uses my plugin's name, slugs, and fields
public function init() {
add_action('admin_menu', array($this, 'add_plugin_admin_menu'));
}
function add_plugin_admin_menu() {
add_menu_page(
'Plugin Name',
'Plugin Menu',
PLUGIN_USER_CAPABILITY,
'plugin-name-admin',
array( $this, 'admin_page' ),
null,
1
);
}
function admin_page() {
if ( current_user_can( PLUGIN_USER_CAPABILITY ) ) {
require_once plugin_dir( __FILE__ ) . 'partials/plugin-name-admin-display.php';
}
}
}
The menu shows up for the users that have the assigned capability and the URL looks like http://wp.localhost/wp-admin/admin.php?page=plugin-name-admin
but neither an administrator nor another user with the PLUGIN_USER_CAPABILITY
can access that page. The error message is "Sorry, you are not allowed to access this page." and the error occurs in wp-admin/includes/plugin.php
in the function user_can_access_admin_page
where WP checks the following:
if ( ! isset( $_registered_pages[ $hookname ] ) ) {
return false;
}
The hookname it uses is admin_page_plugin-name-admin-admin
.
What am I missing?
Also, any pointers on how to properly debug WP code in PhpStorm would be greatly appreciated. So far, I’ve just been muddling around with added error messages.
EDIT: The Plugin_Name_Admin
class is instantiated in the boilerplate code’s main class in the define_admin_hooks
function, which also adds the hook for the init
function:
private function define_admin_hooks() {
$plugin_admin = new Plugin_Name_Admin( $this->get_plugin_name(), $this->get_version() );
$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );
$this->loader->add_action( 'admin_init', $plugin_admin, 'init' );
}
This function is called from the constructor of the main class and uses the boiler plate’s loader approach to create hooks.
As I mention in my answer below, changing the call to add_plugin_admin_menu
from a hook for admin_menu
to a direct call solved the permission error.
EDIT2: I got PhpStorm to work with XDebug using this write-up.