wordpress plugin boilerplate home page
JumpOff, programming, web development, wordpress plugin development

Using WordPress Plugin Boilerplate

In working on my first WordPress Plugin, I’ve come across The WordPress Plugin Boilerplate, which is an object oriented starter codebase for writing WordPress plugins. I’d recommend using this generator to get started, as it’ll go ahead and properly name the files and methods with the name of your plugin.

Converting my prototype to work within the structure of the WPPB has been a bit of a challenge. It’s required me to think a little differently, but should keep things more organized as JumpOff grows. You can see the progress on my GitHub Repo.

Here’s one of the first issues I ran into:

The styling of JumpOff’s admin page requires making an edit to the default styles of the WordPress Admin Area. I needed to change the background color of the admin area wrapper:

#wpwrap {
	background-color: #222;
}

ul#adminmenu a.wp-has-current-submenu:after, ul#adminmenu>li.current>a.current:after {
	border-right-color: #222;
}

In doing so, I noticed it was applying these color changes to the whole admin area, no matter what page I was on. Hooking a plugin’s admin CSS to the ‘admin_enqueue_scripts’ hook is a bad idea in my case, but it’s also inefficient in many other cases. If you’re styling a plugin’s options page, hooking it to ‘admin_enqueue_scripts” will load it on ANY WordPress admin page. Assuming you’re properly namespacing with your CSS, this may not be a problem, but ideally, you’d only load the CSS on the pages that need it.

With WPPB, this CSS loading happens with this line:

$this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );

So I had to use a different hook, called only on a plugin’s options page. This turns out to be a little difficult within the structure of WPPB. Ultimately what I’m doing is adding this action in the “class-{plugin-name}.php” file’s “define_admin_hooks()” function:

//Load conditional CSS just on JumpOff page
$hook_suffix = 'toplevel_page_jumpoff';
$this->loader->add_action( 'admin_print_scripts-' . $hook_suffix, $plugin_admin, 'jo_page_enqueue_styles');

Now, ideally $hook_suffix, would be dynamically generated by the action that adds the options page:

//Main Menu Item
$this->hook_suffix = add_menu_page( 'JumpOff Options', 
	'JumpOff',
	'manage_options',
	'jumpoff',
	array($this, 'jumpoff_show_page'),
	'dashicons-edit',
	'6'
);

But, in keeping with WPPB’s OOP structure, this is run inside the “{plugin-name}_Admin” class, while the action enqueueing the styles has to be run from the “{plugin-name}” class. Even though I’m setting an instance variable in the “{plugin-name}_Admin” class, this isn’t done until the “admin_menu” hook fires, so my code in the “define_admin_hooks” doesn’t have access to the “$hook_suffix”.

I tried adding another action at the end of the “admin_menu” hook to get the hook suffix after it existed, then add the action with the proper hook name, but that didn’t work either. So then I hard-coded the “$hook_suffix” to make the hook “admin_print_scripts-toplevel_page_jumpoff”, which is fired only when the JumpOff admin options page is loaded.

That worked, but wasn’t very DRY. Then I realized that when “define_admin_hooks()” instantiated the “{plugin-name}_Admin” object, it passed in the plugin name as a parameter:

$plugin_admin = new Jumpoff_Admin( $this->get_plugin_name(), $this->get_version() );

So, I went into my function declaring the admin menu, and  made the code use that plugin name as it was passed in:

//Main Menu Item
add_menu_page( 
	'JumpOff Options', 
	'JumpOff',
	'manage_options',
	$this->plugin_name,
	array($this, 'jumpoff_show_page'),
	'dashicons-edit',
	'6'
);

Then I changed the admin_print_scripts conditional loading action to this:

//Load conditional CSS just on JumpOff page
$this->loader->add_action( 'admin_print_scripts-toplevel_page_' . $this->get_plugin_name(), $plugin_admin, 'jo_page_enqueue_styles');

Now the add_menu action and the admin_print_scripts-{hook_suffix} action are both relying on the plugin name defined in the plugin’s constructor. A little more DRY.

Any ideas for how to improve this? Email me (jesse (at) jessequinnlee.com)!

Standard