Genesis 1.8 introduced a whole new admin system. As I was writing the previous articles in the Admin section of the Genesis Explained series I saw that this system was being updated, so I decided to wait on any further articles until Genesis 1.8 came out and settled in.
The new admin system is OOP based, which means is makes use of PHP classes to build and extend the admin menus and pages. For entry level users this is much more complicated, but it makes the code more efficient and is actually much easier for experienced users, since they don’t have to make sure they have updated repeatable code in every instance, and there is less code involved with each menu/page created in the admin system.
There are a lot of great articles out there already that explain how to work with this new system, but they still rely on code duplication, and I think we can do better than that. Since I have several plugins, most of which interact with the admin system, I didn’t feel like having to extend the admin classes for each of my plugins. Instead, I focused on building a single class that can be used to quickly extend the built in class for all of my plugins and projects I take on.
You can see this in action by looking at my Genesis Simple Comments, Genesis Simple Breadcrumbs, and Genesis Media Project plugins. You can also view/use the code I’ve uploaded to github under Genesis Admin Builder Class.
Currently the class supports a single meta box per admin page, and unlimited fields per meta box. I will be updating this to allow more than one meta box. The field types that currently work include
- text
- text_small
- text_medium
- text_money
- textarea
- textarea_small
- select
- radio
- radio_inline
- checkbox
- title
- taxonomy_select
There are some other input fields that are coded in, but which I haven’t tested or which might require some additional editing, including the calendar selector, wysiwyg editor, and file/image uploaders. There are scripts and HTML that need to be updated to correctly configure these fields. Additionally, the CMB class that this is based on has been updated to include a color picker, which I will be including in the next version. I will also be adding an HTML field for creating custom HTML output, and a pattern field type for making your own custom output with pattern based replacements.
Setting up the builder class
To use this with your theme or plugin, first download the files from the github Genesis Admin Builder Class repository. Then put theme in a folder in your theme or plugin. I typically use a “classes” folder. Then you need to check to see if the class has been loaded, and load it. This is the code I use in the Genesis Simple Breadcrumbs plugin.php file to do that
add_action( 'genesis_init', 'gsb_init', 15 ); /** Loads required files when needed */ function gsb_init() { /** Load textdomain for translation */ load_plugin_textdomain( 'gsb', false, basename( dirname( __FILE__ ) ) . '/languages/' ); if ( is_admin ( ) ) require_once(GSB_PLUGIN_DIR . '/admin.php'); else require_once(GSB_PLUGIN_DIR . '/output.php'); if( ! class_exists( 'NTG_Theme_Settings_Builder' ) && is_admin() ) require_once(GSB_PLUGIN_DIR . '/classes/admin-builder.php'); }
I check to see if the class “NTG_Theme_Settings_builder” doesn’t already exist, and that we are in the admin side of things before requiring the admin-builder.php file. You have to provide the full path to the file, which I already defined in the “GSB_PLGUIN_DIR” constant. If you are putting this in your child theme, you might use something like this
add_action( 'genesis_init', 'child_init', 15 ); /** Loads required files when needed */ function child_init() { if( ! class_exists( 'NTG_Theme_Settings_Builder' ) && is_admin() ) require_once( CHILD_DIR . '/classes/admin-builder.php'); }
It is important that both the “child_init” parts be unique on your site. Use a prefix that is unique for you. I might change that to “ntg_init” on my site, for example. By taking the time now to make sure your code in unique, you minimize the likelihood that someone will use the same function name in their plugin. Notice how I use “gsb_init” in the example code from my Genesis Simple Breadcrumbs plugin.
Comparing the new Code to the old Code
If you look at the admin.php file for my Genesis Simple Comments plugin you will see the code that actually builds the admin menu and page. The file is only slightly smaller than the previous file, that built the menu the “old” way, but there are some important differences to note. First, the code is much easier to edit now. I don’t have to go back and forth with HTML and PHP, which is more efficient. The code is consistent now, meaning all my plugins will work the same so I don’t have to try and find a piece of code in one place with this plugin or another place with another plugin, it all works exactly the same. And most importantly, my code now runs through teh new security features built into Genesis. This is something that wasn’t done int eh previous version, which would have added a good deal more code to the mix. So the file is almost 20% smaller and more secure. If someone is running multiple plugins and scripts using this method, that will really make an impact.
Builder Invocation and Settings
So let’s dig in to the actual code. This is the part that loads the menu and starts the page build
// Include & setup custom metabox and fields add_filter( 'ntg_settings_builder', 'gsc_admin_settings' ); function gsc_admin_settings( $admin_pages ) { $prefix = 'genesis_comment_form_args_'; // start with an underscore to hide fields from custom fields list $admin_pages[] = array( 'settings' => array( 'page_id' => 'gsc-settings', 'menu_ops' => array( 'submenu' => array( 'parent_slug' => 'genesis', 'page_title' => __('Simple Comments', 'gsc'), 'menu_title' => __('Simple Comments', 'gsc'), 'capability' => 'manage_options', ) ), 'page_ops' => array( ), 'settings_field' => GSC_SETTINGS_FIELD,
The opening like adds a filter to the ntg_settings_builder. This is used to build the menu and page by going through all teh rest of this code and breaking it up, then loading the builder class to make this into something that can be used on the site.
Notice that I’m using the function “gsc_admin_settings.” Again, it is important to update this for your project. For my personal site I might use ntg_admin_settings, or gsb_admin_settings for my Genesis Simple Breadcrumbs plugin. My “fluid” child theme might use fluid_admin_settings. Just make sure your function name is unique.
I set the $prefix so that my settings will be able to use a common prefix if needed, then I start building the $admin_pages[] array. The page_id needs to be unique and identifies your page, this also identifies your page hook if you want to add onto the page later. The menu_ops argument defines this as a submenu under the genesis parent menu and set the page title and menu title. It also sets the user capability as “manage_options” so users that cannot manage_options will not be able to access this. I’m not settings anything in the page_ops, but I am setting the settings_field, which is important for being able to access the settings later. This is a constant I defined in the plugin.php file, but you could use “my-settings-field” in place of GSC_SETTINGS_FIELD, just make sure you include teh quotes.
You can also load the menu on any other part of the dashboard. For example, in my Genesis Media Project plugin, I build a page that is loaded under the Video post type, so for the parent_slug I’m using
'parent_slug' => 'edit.php?post_type=video'
Default Settings
Just after the settings_field is the default settings.
'default_settings' => array( 'title_wrap' => '<h3>%s</h3>', 'genesis_title_comments' => __( 'Comments', 'genesis' ), 'genesis_no_comments_text' => '', 'genesis_comments_closed_text' => '', 'genesis_title_pings' => __( 'Trackbacks', 'genesis' ), 'genesis_no_pings_text' => '', 'genesis_comment_list_args_avatar_size' => 48, 'comment_author_says_text' => __( 'says', 'genesis' ), 'genesis_comment_awaiting_moderation' => __( 'Your comment is awaiting moderation.', 'genesis' ), $prefix. 'fields_aria_display' => TRUE, $prefix. 'fields_author_display' => TRUE, $prefix. 'fields_author_label' => __( 'Name', 'genesis' ), $prefix. 'fields_email_display' => TRUE, $prefix. 'fields_email_label' => __( 'Email', 'genesis' ), $prefix. 'fields_url_display' => TRUE, $prefix. 'fields_url_label' => __( 'Website', 'genesis' ), $prefix. 'title_reply' => __( 'Speak Your Mind', 'genesis' ), $prefix. 'comment_notes_before' => '', $prefix. 'comment_notes_after' => '', $prefix. 'label_submit' => __( 'Post Comment' ) ),
This is very simple, you put the field ID and the default.
Sanatize (aka some added security)
As I noted before this is some code that I wasn’t using previously. It was oen of the more difficult bits of code to invoke under the old admin system, but it even easier than the defaults under the new system. Directly after the defaults code you will see
'sanatize' => array( 'no_html' => array( 'genesis_title_comments', 'genesis_title_pings', 'genesis_comment_list_args_avatar_size', $prefix. 'fields_aria_display', $prefix. 'fields_author_display', $prefix. 'fields_email_display', $prefix. 'fields_url_display', $prefix. 'label_submit' ), 'safe_html' => array( 'title_wrap', 'genesis_no_comments_text', 'genesis_comments_closed_text', 'genesis_no_pings_text', 'comment_author_says_text', 'genesis_comment_awaiting_moderation', $prefix. 'fields_author_label', $prefix. 'fields_email_label', $prefix. 'fields_url_label', $prefix. 'title_reply', $prefix. 'comment_notes_before', $prefix. 'comment_notes_after' ) ),
I’m using two sanatize filters. The no_html will strip all HTML that is added. This is for anything that is just a check box, number, or for text that shouldn’t have html. The safe_html filter is being used to clean up my HTML on save, and make sure it doesn’t have code that can be exploited. The total options available here are
- one_zero: used for options that are either a 1 or 0
- no_html: used when you do not need any HTML
- safe_html: used to provide limited and secure HTML support
- requires_unfiltered_html: used when all HTML is going to be used. I recommend limiting this to only when there is no other alternative
Help, telling users how to use your page settings
I don’t use any help in the Genesis Simple Comments plugin, but will probably update that later. It is really helpful. That is why I did add it to my latest plugin, the Genesis Media Project. You can see this code
'help' => array( 'tab' => array( array( 'id' => 'add_slideshow_theme', 'title' => __( 'Add Slideshow to theme', 'gmp' ), 'content' => sprintf( __( '%1$sUse %2$s to add this to your theme.%3$sIf you do not specify the number of slides, the default from the settings will be used.%4$sIf you do not specify a slideshow by slug then the latest videos will be shown%5$s', 'gmp' ), '<p>', '<code>'. esc_html( '<?php if ( function_exists( \'gmp_slideshow\' ) ) { gmp_slideshow( array( \'slides\' => \'\', \'slideshow\' => \'\' ); } ?>' ) .'</code>', '</p><p>', '</p><p>', '</p>' ) ), array( 'id' => 'add_slideshow_content', 'title' => __( 'Add Slideshow to Page/Post', 'gmp' ), 'content' => sprintf( __( '%1$sUse %2$s to add the slideshow to page or post content.%3$sIf you do not specify the number of slides, the default from the settings will be used.%4$sIf you do not specify a slideshow by slug then the latest videos will be shown.%5$s', 'gmp' ), '<p>', '<code>[gmp_slideshow slides="" slideshow=""]</code>', '</p><p>', '</p><p>', '</p>' ) ), array( 'id' => 'add_slideshow_sidebar', 'title' => __( 'Add Slideshow to Widgeted Area', 'gmp' ), 'content' => sprintf( __( '%1$sAdd the GMP Tab Slider widget to any sidebar to display in a sidebar.%2$s', 'gmp' ), '<p>', '</p>' ) ) ), 'sidebar' => array( sprintf( '<p>%s <a href="#">%s</a></p>', __( 'For more details, please visit the module page', 'gmp' ), __( 'Genesis Media Project Tab Slider', 'gmp' ) ) ) ),
There are two kinds of “help” that are loaded by this class. The “tab” which created the main help and will make a nice tab label so your users can click to access each level of the help notes. Each tab needs a unique ID, and should have a useful name. You can output HTML, and php. I use the esc_html() function to automatically form the code into character entities so it shows the markup isntead of processing it.
The sidebar loads a sidebar that will always appear beside the tab help. You must load a tab before the sidebar will be processed.
Meta Boxes, where the magic happens
I’m going to pull from the Genesis Media Project code again, because there are a lot more options in the Genesis Simple Comments code, and is all basically the same
'meta_boxes' => array( 'id' => 'gmp-tab-slider-options', 'title' => 'General Settings', 'context' => 'main', 'priority' => 'high',/**/ 'show_names' => true, // Show field names on the left 'fields' => array( array( 'name' => __( 'Number of Videos', 'gmp' ), 'desc' => '', 'id' => $prefix . 'quantity', 'type' => 'text_small' ), array( 'name' => __("Default Slideshow:", 'gmp'), 'desc' => __( 'If no slideshow is selected, all videos will be used', 'gmp' ), 'id' => $prefix . 'slideshow', 'type' => 'taxonomy_select', 'taxonomy' => 'slideshow' ), array( 'name' => __( 'Use Ajax to load slides', 'gmp' ), 'desc' => '', 'id' => $prefix . 'ajax', 'type' => 'checkbox' ), ))
the meta_boxes array is what builds the actual page output. The ID must be unique, and the title will appear in the part that you can click. Context and priority are values that can control where the meta box appears relative to the rest of the page. If your are building a page with more than one column, you might use column1 instead of main. The show_names just enable the names field on the left, which is usually helpful. Then the fields is what builds your option fields. Each field needs a name, id, and type. The description is optional, but can be very helpful for describing what the option does. You can see here we have 3 fields with 3 options. text, text_medium, and text_small all make basic input boxes. Since I’m just looking for a number, and almost certainly one under 10, I only provide a small text field in teh first option. Then I use the taxonomy_select in the second field. Notice that it requires the taxonomy also be defined if you are using the taxonomy_select type. The last field is a simple check box. This is for “yes” or “no” type options.
And the rest of the file
All that is left is to close out the array, return the pages, and close the function
); return $admin_pages; }
That is all there is to it. Feel free to download my plugins to see how it all works and implement it into your sites and plugins. As I noted, I am planning on extending this further. If you are interested in helping, fork it on github and lets make this into something truly impressive.
David Wang says
Hi Nick, thank you for this tutorial and for putting out the Builder class for everyone to use. I’ve been messing with it and referencing your plugins to try to create a child theme settings page for a project that I’m currently working on. It’s definitely a lot easier since I don’t have to code my own metaboxes. Two questions though:
1. Is it possible to add more than 1 metabox to the settings page? For example, the Genesis Theme Settings Page has metaboxes for Info, Custom Feeds, Default Layout, etc
2. Do you have any documentation for how to define options for the dropdown select, checkbox group and radio button group fields? I’m not much of a programmer so I really don’t know how to look through the source of your Builder class to figure it out.
Thanks so much for your Genesis Explained series, your plugins and your answers in the StudioPress forums. I’d like to buy you a coffee or your Production theme at least for all that you do 🙂
nickthegeek says
At this time there isn’t a way to add additional meta boxes, that is at the top of my to do list for the next version, as I need to be able to do that, and I don’t really have any documentation just yet, but look at the way it is done in the examples for the Custom Meta Box class by Bill Ericson and Jared
Ari Wahyudi says
Thank you for the posts, Nick. Very helpful.
Question: if i want to add custom navigation in my image attachment page (Previous image/Next image), which code should I alter?
nickthegeek says
Thanks for commenting. The best place to ask that question would be the Genesis Support Forums.
Dewey says
I am really pleased to glance at this weblog posts which carries tons of valuable data, thanks
for providing such statistics.
what are the best binary options says
Somebody necessarily assist to make seriously articles I’d state. This is the very first time I frequented your website page and up to now? I amazed with the analysis you made to make this particular put up extraordinary. Wonderful activity!