Implementing an admin GUI for your WordPress plugin, the boring part…

Image: @qimono, 2016, Pixabay

Hooking into WordPress’s actions and filters, writing callbacks to do magical stuff is a fascinating experience. Writing an admin settings GUI for a plugin has always been more boring for me, boring than writing the plugin itself. In this post, I will publish some code snippets from a plugin that I have written in the past (Toolbar Login Button),  and using as a boilerplate for some other plugins.

These are only snippets, please see the original code if you are interested. The code snippets and Toolbar Login Button is published under the terms of GPLv2.

First of all, settings GUI should be separated from our main plugin file. You can put GUI code in your plugin’s directory in a file like admin/settings.php.

In this example,  we hook into three WordPress acitons.

// Create options menu
add_action( 'admin_menu', array( __CLASS__, 'create_plugin_options_menu' ) );

// Register settings
add_action( 'admin_init', array( __CLASS__, 'register_plugin_settings' ) );

// Add admin css
add_action( 'admin_enqueue_scripts', array( __CLASS__, 'custom_admin_style' ) );

You can hook into  ‘admin_menu’ action to create options menu. This is quite simple. add_options_page() WordPress function simply adds the menu. (My plugin declares static functions. You can use static functions or dynamic functions in your plugin or even write your plugin without a class.)

* Plugin options menu
static function create_plugin_options_menu() {
    $admin_page = add_options_page( 'Toolbar Login Button', 'Toolbar Login Button', 'manage_options', self::OPTIONS_SLUG, array( __CLASS__, 'display_plugin_options' ) );

    // Add a help tab when this plugin's options page gets loaded
    add_action( 'load-' . $admin_page, array( __CLASS__, 'add_help_tab' ) );
}// function

There is also a function callback referred as ‘display_plugin_options’ above. This function called to output the content for the plugins’s settings GUI (html). In this callback you can either use functions like add_settings_field() and add_settings_section() here or just print out suitale html like me for simplicity. Please see WordPress Settings API for further information.

* Diplay plugin options page
static function display_plugin_options() {
  if ( !current_user_can( 'manage_options' ) )  {
        wp_die( __( 'You do not have sufficient permissions to access this page.' ) );


  <form method="post" action="options.php">
    <?php settings_fields( 'toolbar_login_button_settings' ); ?>
    <!--main content-->
    <div id="post-body-content">
      <div class="meta-box-sortables ui-sortable">
        <!--settings group-->
        <div class="postbox">
          <h2 class="hndle"><span><?php esc_html_e( 'Logged in users', 'toolbar-login-button' ); ?></span></h2>
          <div class="inside">
            <table class="form-table">
              <tr valign="top">
                <th scope="row"><?php esc_html_e( 'Show front end toolbar', 'toolbar-login-button' ); ?></th>
                  <select name="tlb_show_logged_in" title="">

                    <option title="" value="1"<?php $tlb_show_logged_in = tlb_settings::get_option( 'tlb_show_logged_in' ); selected( '1', $tlb_show_logged_in ); ?>><?php esc_html_e( 'Show', 'toolbar-login-button' ); ?><?php self::e_default( 'tlb_show_logged_in', '1' ); ?></option>

                    <option title="" value="0"<?php selected( '0', $tlb_show_logged_in ); ?>><?php esc_html_e( 'Hide', 'toolbar-login-button' ); ?><?php self::e_default( 'tlb_show_logged_in', '0' ); ?></option>




Please note that the same option names used in the html with the register_setting() function below. i.e: ‘tlb_show_logged_in’ used both in register_setting() and in html as select name: <select name=”tlb_show_logged_in” title=””>

Next, we hook ‘admin_init’ action. This is a pretty early stage suitable for calling register_setting() WordPress function and register plugin specific settings one by one. For the option named ‘tlb_show_logged_in’, ‘intval’ (this is PHP’s intval) is used as sanitize_callback to make sure only integer values are saved to database. The options named ‘tlb_remember_user_role’ and ‘tlb_redirect_after_login’ have no sanitization callbacks and string values can be saved to the database. The last option ‘tlb_cookie_expire’ has a anonymous function (closure / lambda function) as sanitization callback to limit minimum and maximum values saved to database.

* Register plugin settings
static function register_plugin_settings() {
    // Register plugin settings
    register_setting( 'toolbar_login_button_settings', 'tlb_show_logged_in', 'intval' );
    register_setting( 'toolbar_login_button_settings', 'tlb_show_logged_out', 'intval' );
    register_setting( 'toolbar_login_button_settings', 'tlb_remember_user_role' );
    register_setting( 'toolbar_login_button_settings', 'tlb_redirect_after_login' );
    register_setting( 'toolbar_login_button_settings', 'tlb_cookie_expire', function( $value ) {
        return ( filter_var( $value, FILTER_VALIDATE_INT, array( 'options' => array( 'min_range' => 2592000, 'max_range' => 31536000*10 ) ) ) ) ? $value : self::$default_options['tlb_cookie_expire'];
    } );
    register_setting( 'toolbar_login_button_unistall', 'tlb_uninstall_delete', 'intval' );
}// function

And the last hook is for ‘admin_enqueue_scripts’ action, is just here to include javascript and css for the plugin’s admin GUI. Actually, there is only a css file included for this plugin. With this action, you can include a custom css file with  wp_enqueue_style() and a javascript file with wp_enqueue_script() for admin GUI.

* Custom admin style
static function custom_admin_style( $hook ) {
    // Add custom css only into the plugin's options page
    if( $hook == 'settings_page_' . self::OPTIONS_SLUG ) {
        wp_enqueue_style( 'toolbar_login_button_admin_css', plugins_url( 'admin/css/admin.css', dirname( __FILE__ ) ) );
}// function



You can share this blog post only by giving appropriate credit as described at Terms & Conditions.


Leave a Reply

Your email address will not be published. Required fields are marked *