Admin Pages with Genesis

One of the best new features of Genesis 1.8 (and there are many) is a tool for making admin pages. These are needed if you’re building a plugin or a complex theme with site-wide settings that need to be managed.

I recently built an Event Manager theme for promoting an event, and on our Event Theme Settings page we had fields for event date and location, so these could be used throughout the site and pulled from a single source.

This code is pretty technical, but it is 100x easier than making admin pages without Genesis. See this 10 page tutorial by Chip Bennett for instructions on making them without Genesis’ help.

You should only use this method if you’re building a Genesis theme or a Genesis-specific plugin. If you build a plugin for public distribution, make sure you put some checks in place to ensure the user is running Genesis (take a look at the AgentPress plugin code as an example).

Here’s the steps:

  1. Specify the page information. This includes the page’s name and default values for your fields.
  2. Create the sanitization filters. These keep the page secure by ensuring the right type of data are entered.
  3. Set up the help tab, a very useful feature that was improved in WordPress 3.3.
  4. Add your metaboxes to the page.
  5. Build your metaboxes.
  6. Finally, add the new admin page to the backend.

Specify the page information

First, it’s best to keep all this code in its own file so your theme is easy to browse. I like to create a “lib” folder in my child theme where I store everything. In my example, I created /lib/admin/child-theme-settings.php, then added this to my functions.php to include it:

<?php
// Setup Theme Settings
include_once( CHILD_DIR . '/lib/admin/child-theme-settings.php');
view raw gistfile1.aw hosted with ❤ by GitHub

Now inside your child-theme-settings.php file, place the following:

<?php
/**
* Child Theme Settings
* Requires Genesis 1.8 or later
*
* This file registers all of this child theme's specific Theme Settings, accessible from
* Genesis > Child Theme Settings.
*
* @package BE Genesis Child
* @author Bill Erickson <[email protected]>
* @copyright Copyright (c) 2011, Bill Erickson
* @license http://www.opensource.org/licenses/gpl-license.php GPL v2.0 (or later)
* @link https://github.com/billerickson/BE-Genesis-Child
*/
/**
* Registers a new admin page, providing content and corresponding menu item
* for the Child Theme Settings page.
*
* @package BE Genesis Child
* @subpackage Admin
*
* @since 1.0.0
*/
class Child_Theme_Settings extends Genesis_Admin_Boxes {
/**
* Create an admin menu item and settings page.
*
* @since 1.0.0
*/
function __construct() {
// Specify a unique page ID.
$page_id = 'child';
// Set it as a child to genesis, and define the menu and page titles
$menu_ops = array(
'submenu' => array(
'parent_slug' => 'genesis',
'page_title' => 'Genesis - Child Theme Settings',
'menu_title' => 'Child Theme Settings',
)
);
// Set up page options. These are optional, so only uncomment if you want to change the defaults
$page_ops = array(
// 'screen_icon' => 'options-general',
// 'save_button_text' => 'Save Settings',
// 'reset_button_text' => 'Reset Settings',
// 'save_notice_text' => 'Settings saved.',
// 'reset_notice_text' => 'Settings reset.',
);
// Give it a unique settings field.
// You'll access them from genesis_get_option( 'option_name', 'child-settings' );
$settings_field = 'child-settings';
// Set the default values
$default_settings = array(
'phone' => '',
'address' => '',
);
// Create the Admin Page
$this->create( $page_id, $menu_ops, $page_ops, $settings_field, $default_settings );
// Initialize the Sanitization Filter
add_action( 'genesis_settings_sanitizer_init', array( $this, 'sanitization_filters' ) );
}
function sanitization_filters() {
}
}
view raw gistfile1.aw hosted with ❤ by GitHub

This is a lot of code, so I’ll walk through it:

  • I start out with some page-specific documentation that describes what this page is (always a good practice).
  • Then there’s the documentation for our new class, Child_Theme_Settings
  • We create our new class by extending the existing Genesis_Admin_Boxes class
  • First thing in our new class is the __construct() method (functions inside of classes are called methods). This is what sets everything up.
  • We create an unique page ID for this page. I’m calling mine ‘child’, but you could call yours whatever you’d like. I recommend naming it the same as your child theme since it will contain your child-theme-specific settings.
  • Next we specify some information about the menu item. It’s a child of the ‘genesis’ page, we give it a page title and a menu title.
  • Then we create the $page_ops variable which lets you customize some page settings. I’ve left the defaults in there and commented them out so you can see. Uncomment a line and then modify it to change the default.
  • Then we define the settings field. All the settings on this page will be grouped together. If you create a field called address you can get to it like this: $address = genesis_get_option( 'option_name', 'child-settings' );
  • Finally, we create the admin page by adding all the variables together in the create() method.
  • I’ve also added the sanitation action (in __construct() method) and sanitization_filters() method to create the sanitization filters, which we’ll do in the next step.

Before we move on, a few quick notes about classes. Everything inside the class should use the __construct() method for hooking to appropriate actions/filters. Classes are their own namespace, so you can name the methods whatever you’d like. Unlike standard functions where you always need to prefix, you don’t have to worry about any other function having the same name. And finally, when hooking methods to actions make sure you use array( $this, 'method_name' ) instead of just 'method_name'.

Create the sanitization filters

Sanitization is about ensuring the data collected is the type of data you expect. By limiting a checkbox to a 0 or 1, a title to no html… you’re able to prevent code you didn’t expect (whether malicious or not) from altering the way your theme/plugin works.

See my previous post on Genesis options for more details on sanitization filters.

I’m planning to have two fields on this page – phone and address – so I’ll register those as no_html. Update your sanitization_filters() method like this:

<?php
/**
* Set up Sanitization Filters
*
* See /lib/classes/sanitization.php for all available filters.
*
* @since 1.0.0
*/
function sanitization_filters() {
genesis_add_option_filter( 'no_html', $this->settings_field,
array(
'phone',
'address',
) );
}
view raw gistfile1.aw hosted with ❤ by GitHub

Help Tab

While not required, it’s a good idea to put instructions and other useful information in the help tab. If you’d like to have a help tab, simply create a help() method in your class.

Here’s a screenshot of the help tab in my Event Theme. I don’t usually provide this much information, but the client plans to sell the theme so we wanted to provide as much information as possible.

To create a help tab, add this method inside your Child_Theme_Settings class ( so before the last } ).

<?php
/**
* Set up Help Tab
* Genesis automatically looks for a help() function, and if provided uses it for the help tabs
* @link http://wpdevel.wordpress.com/2011/12/06/help-and-screen-api-changes-in-3-3/
*
* @since 1.0.0
*/
function help() {
$screen = get_current_screen();
$screen->add_help_tab( array(
'id' => 'sample-help',
'title' => 'Sample Help',
'content' => '<p>Help content goes here.</p>',
) );
}
view raw gistfile1.aw hosted with ❤ by GitHub

Provide an unique ID for the tab, then give it a title (shown on the left) and HTML content (shown on the right). For multiple tabs, simply repeat the $screen->add_help_tab() method inside your help() method.

Add your metaboxes

We’ll now create a method inside our class called metaboxes(). For each metabox we’d like to add to our page, we’ll write a simple one line of code to add_meta_box().

<?php
/**
* Register metaboxes on Child Theme Settings page
*
* @since 1.0.0
*
* @see Child_Theme_Settings::contact_information() Callback for contact information
*/
function metaboxes() {
add_meta_box('contact-information', 'Contact Information', array( $this, 'contact_information' ), $this->pagehook, 'main', 'high');
}
view raw gistfile1.aw hosted with ❤ by GitHub

I’ve added a single metabox with an ID of ‘contact-information’, a title of ‘Contact Information’, a callback function (where the actual metabox code is) of contact_information(), I’m putting it on the current page, it goes in the main column (not that there’s any other columns for it) and I want it positioned at the top. For more information on this function, see add_meta_box() in the Codex.

Build your metaboxes

In the previous method we referenced a callback function called contact_information(). Now it’s time to build this.

My metabox, Contact Information, will contain two fields. Phone will be a text field, and Address is a textarea. For examples of more fields, look at the actual Genesis admin pages (/lib/admin/…). And I’ve heard there might be a tool similar to our Custom Metabox Library for making Genesis admin fields (talk with NickTheGeek).

This method also goes inside your Child_Theme_Settings class.

<?php
/**
* Callback for Contact Information metabox
*
* @since 1.0.0
*
* @see Child_Theme_Settings::metaboxes()
*/
function contact_information() {
echo '<p>Phone:<br />';
echo '<input type="text" name="' . $this->get_field_name( 'phone' ) . '" id="' . $this->get_field_id( 'phone' ) . '" value="' . esc_attr( $this->get_field_value( 'phone' ) ) . '" size="50" />';
echo '</p>';
echo '<p>Address</p>';
echo '<p><textarea name="' . $this->get_field_name( 'address' ) . '" cols="78" rows="8">' . esc_textarea( $this->get_field_value( 'address' ) ) . '</textarea></p>';
}
view raw gistfile1.aw hosted with ❤ by GitHub

The important thing to note here is the handy methods that are built into the class (examples below are for the field ‘phone’ ).

  • $this->get_field_name( 'phone' );
  • $this->get_field_id( 'phone' );
  • $this->get_field_value( 'phone' );

That’s It!

That’s all it takes to build custom admin pages in Genesis. The code definitely looks complicated, but once you get started it’s pretty easy to modify it to your needs. StudioPress has done all the hard (and repetitive) work for you, so you just have to specify the things that are unique to the page.

Here’s the completed code:

<?php
/**
* Child Theme Settings
* Requires Genesis 1.8 or later
*
* This file registers all of this child theme's specific Theme Settings, accessible from
* Genesis > Child Theme Settings.
*
* @package BE Genesis Child
* @author Bill Erickson <[email protected]>
* @copyright Copyright (c) 2011, Bill Erickson
* @license http://www.opensource.org/licenses/gpl-license.php GPL v2.0 (or later)
* @link https://github.com/billerickson/BE-Genesis-Child
*/
/**
* Registers a new admin page, providing content and corresponding menu item
* for the Child Theme Settings page.
*
* @package BE Genesis Child
* @subpackage Admin
*
* @since 1.0.0
*/
class Child_Theme_Settings extends Genesis_Admin_Boxes {
/**
* Create an admin menu item and settings page.
*
* @since 1.0.0
*/
function __construct() {
// Specify a unique page ID.
$page_id = 'child';
// Set it as a child to genesis, and define the menu and page titles
$menu_ops = array(
'submenu' => array(
'parent_slug' => 'genesis',
'page_title' => 'Genesis - Child Theme Settings',
'menu_title' => 'Child Theme Settings',
)
);
// Set up page options. These are optional, so only uncomment if you want to change the defaults
$page_ops = array(
// 'screen_icon' => 'options-general',
// 'save_button_text' => 'Save Settings',
// 'reset_button_text' => 'Reset Settings',
// 'save_notice_text' => 'Settings saved.',
// 'reset_notice_text' => 'Settings reset.',
);
// Give it a unique settings field.
// You'll access them from genesis_get_option( 'option_name', 'child-settings' );
$settings_field = 'child-settings';
// Set the default values
$default_settings = array(
'phone' => '',
'address' => '',
);
// Create the Admin Page
$this->create( $page_id, $menu_ops, $page_ops, $settings_field, $default_settings );
// Initialize the Sanitization Filter
add_action( 'genesis_settings_sanitizer_init', array( $this, 'sanitization_filters' ) );
}
/**
* Set up Sanitization Filters
*
* See /lib/classes/sanitization.php for all available filters.
*
* @since 1.0.0
*/
function sanitization_filters() {
genesis_add_option_filter( 'no_html', $this->settings_field,
array(
'phone',
'address',
) );
}
/**
* Set up Help Tab
* Genesis automatically looks for a help() function, and if provided uses it for the help tabs
* @link http://wpdevel.wordpress.com/2011/12/06/help-and-screen-api-changes-in-3-3/
*
* @since 1.0.0
*/
function help() {
$screen = get_current_screen();
$screen->add_help_tab( array(
'id' => 'sample-help',
'title' => 'Sample Help',
'content' => '<p>Help content goes here.</p>',
) );
}
/**
* Register metaboxes on Child Theme Settings page
*
* @since 1.0.0
*
* @see Child_Theme_Settings::contact_information() Callback for contact information
*/
function metaboxes() {
add_meta_box('contact-information', 'Contact Information', array( $this, 'contact_information' ), $this->pagehook, 'main', 'high');
}
/**
* Callback for Contact Information metabox
*
* @since 1.0.0
*
* @see Child_Theme_Settings::metaboxes()
*/
function contact_information() {
echo '<p>Phone:<br />';
echo '<input type="text" name="' . $this->get_field_name( 'phone' ) . '" id="' . $this->get_field_id( 'phone' ) . '" value="' . esc_attr( $this->get_field_value( 'phone' ) ) . '" size="50" />';
echo '</p>';
echo '<p>Address</p>';
echo '<p><textarea name="' . $this->get_field_name( 'address' ) . '" cols="78" rows="8">' . esc_textarea( $this->get_field_value( 'address' ) ) . '</textarea></p>';
}
}
add_action( 'genesis_admin_menu', 'be_add_child_theme_settings' );
/**
* Add the Theme Settings Page
*
* @since 1.0.0
*/
function be_add_child_theme_settings() {
global $_child_theme_settings;
$_child_theme_settings = new Child_Theme_Settings;
}
view raw gistfile1.aw hosted with ❤ by GitHub

And once you do have your custom admin page up-and-running, you’ll need to access that information. Just use genesis_get_option( [field-name], [settings-field] );.

So in the above example, to access the phone number use: $phone = genesis_get_option( 'phone', 'child-settings' );.

Bill Erickson

Bill Erickson is the co-founder and lead developer at CultivateWP, a WordPress agency focusing on high performance sites for web publishers.

About Me
Ready to upgrade your website?

I build custom WordPress websites that look great and are easy to manage.

Let's Talk

Reader Interactions

Comments are closed. Continue the conversation with me on Twitter: @billerickson

Comments

  1. Dorian Speed says

    Hi, Bill – I just wanted to thank you for these tutorials. My skills aren’t good enough yet that I can really put them into practice at this point, but I save them all to Evernote so I can come back to them when I am ready to put them into effect. The detailed explanations you provide are very helpful.

  2. Nick the Geek says

    Great tutorial, you can make it even simpler though. I took the Custom Metabox class and built my own class to extend this. Now I just need one class for my plugins, and any custom stuff from my themes. Interacting with it is much easier than building a new class every time. You can see it in work on my Genesis Simple Breadcrumbs and Genesis Simple Comments plugins right now. I’ll be getting it on git once I figure out why it is denying my access to push or commit right now.

      • Bill Erickson says

        I don’t have a file uploader in my code. Take a look at Nick’s to see if he has one, or the Options Framework.

        • Arya says

          Oh yeah sorry, I was pointing to Nick plugin and yes, I was playing around with his plugins but the file upload didn’t work. Need a bit tweak but beyond my knowledge right now 🙁
          I do use Options Framework mostly, it just I want to be consistent with the Genesis Framework settings.
          Perhaps there will be a library or classes to extend Genesis Admin Settings in future, similar as CMB 🙂

  3. Alejandro Reyes says

    Great tutorial.
    One question tho. Is it possible to modify the data entered in the settings fields before it reaches the database?
    Following your example, what if I could store several phones and addresses inside an array. And the next time the page is loaded you could insert a new phone and address but also edit the ones you have already entered.
    Is this possible with the way genesis builds options pages or that should be done in the old way?

    • Bill Erickson says

      I don’t see any reason why you couldn’t do that in this instance. You have complete control of the actual fields in the page. All this class does is allow you to easily add the page.

  4. Surbma says

    Hi Bill, thank you for this great tutorial! I have a Multisite install and I want to have a network activated plugin with this function. How can I make it working in a plugin? Right now, it is not working as a plugin, it gives an error.

    Thank you for your support!

    • Bill Erickson says

      To be honest I’ve never worked in a MultiSite environment so I can’t provide guidance on that. But you might look at how the existing StudioPress plugins add their option pages.

      Before you load your code you’ll need to check to see if Genesis is running. Look in the AgentPress Listings plugin for an example of that (I use that often in my plugins).

  5. Rolf says

    Nice tut.

    What would be the best practive to do this in a plugin. I get a error that the class not exists. Wrapping the class extend into a function and hook it into “after_setup_theme” solves this, would that be a good way to do it?

      • Rolf says

        Ah thanks for the fast reply, my guess was right, ‘genesis_admin_menu’ is a better fit then ‘after_setup_theme’.

        Looks like i have to really get to know the entire genesis admin class, for my special purposes i would have to extend it and not the metaboxes class, because i need boxes only on the right and no save and reset buttons on the top and bottom.

  6. Nicolas Jonas says

    Thanks for this helpful tut.

    There is a tiny error i found:
    ‘save_notice_text’ should be ‘saved_notice_text’

  7. Cathy Finn-Derecki says

    This has worked perfectly for me. BUT, I have a question: I’m trying to get it to load as a main menu item on the same level as Genesis, not a submenu of Genesis. I’ve tried extending the “Genesis_Admin_Settings” class, but no luck. Any tips?

  8. Cathy Finn-Derecki says

    I am using this tutorial for a plugin and am getting an error: “fatal error: class genesis admin boxes not found”. I’ve used this for a child theme and it worked fine. Any special considerations when you extend the admin class for a plugin?

  9. Nicolas Jonas says

    Thanks for this tut, helped me kickstart a plugin.

    Not sure why you not approved my last comment, or did I forget to send it or something? A few days ago I mentioned a missing d in line 51 of the full gist, just wanted to help others who might wondering why custom save messages not show up. Looks like this is based on a older genesis version or something the error text line is also missing I just found out.

    Look at this gist for explanation https://gist.github.com/nextgenthemes/5191011

    Pull requests for gists would be cool 😉