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. Jason Larsen says

    Thanks for your resources, Bill. They are very helpful.

    I’m having an issue when creating an admin metabox and calling that information on a specific page in my site (the homepage). It looks like it is saving multiple instances of information in the database, and only pulling the first instance of information – so I can’t update the content at all! It’s simply only pulling the first information that I entered, and won’t update accordingly.

    Any ideas on why this is? It’s probably easy, but I’m a newbie coder, so it’s driving me nuts! Thanks again!

  2. Craig Grella says

    Bill,
    thanks for the tut, very clear.

    question:
    If i’m including a color picker in the options, this kind of thing is typically implemented in css, as opposed to inside a php file / template like I might do with a more content oriented field like phone or address.

    For example, if I created a color chooser in the child theme options with the idea of using that as a custom page background color I could alter the child theme template code to include inline styling with call to that custom options field.

    But do you have any advice in calling these options purely in custom style files?

    Is that even recommended, or would I have to always alter tempalte codes with inline styling to access these custom options?

    Thanks.

    Craig

    • Bill Erickson says

      Unfortunately you’ll have to add inline styles. Hook a function to wp_head and output your styles there. This is how custom headers and backgrounds are currently handled in WordPress core.

      • Craig Grella says

        Thanks Bill.

        I took a look at http://codex.wordpress.org/Custom_Backgrounds, which looks pretty much like what you’re referring to in terms of output html.

        Maybe this is a stupid question, but is there a benefit then to going through the settings api, as opposed to just using an admin page with meta boxes like you show here or another options page / framework – if the output is essentially going to be rendered the same way?

        What I’m trying to reconcile is performance and standards vs. ease of use for client when making some theme and post options available for custom jobs.

        • Bill Erickson says

          Genesis has basically built these helper tools on top of the Settings API since that takes a lot more work to use. For details on using the Settings API, see this 10-part tutorial ( http://www.chipbennett.net/2011/02/17/incorporating-the-settings-api-in-wordpress-themes/ ).

          So I’d say the benefit is that this is easier. But what’s even easier than Genesis’ admin pages is using the Customizer in WordPress. That even has color pickers built-in. Take a look at Otto’s tutorials on the Customizer ( http://ottopress.com/2012/how-to-leverage-the-theme-customizer-in-your-own-themes/ ).

          • Craig Grella says

            Thanks Bill. I’ve read those two tutorials, though I do need to dig in a bit more.

            I tried using Otto’s sample themes with the customizer functions built it, and they work ok. I had trouble adding new fields and getting the callbacks to work correctly.

            The only thing I don’t particularly like about itis the format in which the settings are displayed on the admin screen. It’s very constricted.

            I guess the bottom line is that I need to familiarize myself more with the settings API.

            Thanks again.

  3. Stefan says

    Hi Bill,

    Thanks for this great tutorial! Works perfect.

    Is it possible to remove the reset button from $page_ops . I don’t want my users to hit it accidentally and remove all data.

    Many thanks.

    Best regards,

    Stefan

  4. Anwer Ashif says

    Bill,

    I have created some options for a child theme. All are added to Genesis theme setting page. I wanted them to move in a subpage. I would like to use OOP style but when I put your code in ct-theme-settings.php file. I am getting this error “Class ‘Genesis_Admin_Boxes’ not found in ……. \includes\ct-theme-settings.php on line 25”

    What’s wrong with it?