The WordPress Settings API, Part 6: Menu Pages

In Part 3 of this series, we surveyed the various menu functions that the WordPress API provides. If you've been following along, then you know that we've already setup a settings page for our theme by using the add_theme_page function. Although introducing menus and submenus aren't explicitly part of the Settings API, they play a role in building custom functionality, plugins, and/or themes.

In this article, we're going to introduce a new menu to the WordPress dashboard that will make our theme options available elsewhere other than just under the "Appearance" options.

Before we get started: This article assumes that you're familiar with the Settings API and theme options. If you're a beginner or even intermediate WordPress developer, I highly recommend catching up on the rest of the series before diving into this post.


A Look at the API

Because we've already looked at each of the menu functions, we don't need to rehash each of the functions that WordPress has available. Instead, we'll take a look at the ones we're going to use and then work through a practical example of how to use them in our own work.

Before we look at each function, let's detail what we're planning to accomplish in the next phase of this series:

  • Introduce a top-level menu for our theme options
  • Add a submenu item that will link to the "Display Options" tab
  • Add a submenu item that will link to the "Social Options" tab

Relatively simple, right? In order to do this, we'll be taking advantage of the following two functions:

  • add_menu_page which is used for introducing top-level menu items
  • add_submenu_page which is used to introduce sub-menu items to top-level menus.

We'll take a look at each function's parameters and usage as we implement them in our theme.

Note that the remainder of this article builds on this version of the WordPress Settings Sandbox. If you're following along with the repository, make sure you check it out.


The Top-Level Menu

The first thing that we want to do is introduce a top-level menu. This menu will appear directly below the "Settings" menu in the WordPress dashboard and will serve two purposes. The menu should:

  1. Expose the theme's options to the WordPress dashboard
  2. Display a default options page for the theme options

The function takes the following seven arguments, the first five are required, the last two are not:

  1. page_title is the text that will be rendered in the browser's title bar
  2. menu_title is the text that will be displayed for the menu item
  3. capability refers to the role that the user must have in order to access this menu
  4. menu_slug is a unique value that identifies this menu. It's also how submenus register themselves with this menu.
  5. function_name that is called when the menu is clicked for displaying the options page.
  6. icon_url is the path to the icon that you want to display next to your menu item.
  7. position is where the menu should be added in relation to the other menus in the WordPress Dashboard.

In our work, we'll be focused only on the first five parameters. I discuss menu positioning in the conclusion of this article.

To get started, we're going to need to introduce a call to the add_menu_page function. According to the WordPress Codex, administration menus can be added using the admin_menu hook. Earlier in this series, we wrote a function that adds our theme options to the "Appearance" menu. Specifically, we wrote sandbox_example_theme_menu:

Note in the code above that this function was registered with the admin_menu hook, as well. You should always strive to keep your functions logically consistent. Since we already have a function that registers a menu, that is registered with the appropriate hook, and since we're introducing similar functionality, we'll be adding our new menu functions to this function.

Add the following call to add_menu_page directly under the call above:

As you can see, we're registering a menu that will display "Sandbox Theme" in both the browser's title bar and in the menu item. We're exposing the menu only to administrators and we've given the menu the unique ID of "sandbox_theme_parent_menu". We'll be re-using this parameter in the next section.

There's one important thing that we need to clarify: Notice that we've passed 'sandbox_theme_display' as the function to be called when this menu item is clicked. Recall that in Part 3 we introduced this function (and we refined it in Part 5). Specifically, it is responsible for rendering our tabbed theme options page.

By passing this existing function name to the add_menu_page function, we're taking advantage of code that we've already written and we're rendering a default options page for the menu item.

At this point, we're ready to begin adding submenus but before moving forward, make sure that your function looks exactly like this:


Add the Submenus

Submenus are very similar to menus except that they "belong" to an existing menu. The API for registering submenus is relatively similar, too. The function accepts six arguments, the first five being required, the last one being optional:

  1. parent_slug refers to the unique ID of the parent menu item. In our case, "sandbox_theme_menu".
  2. page_title is the text to be rendered in the browser's toolbar when this submenu item is active
  3. menu_title is the text for this actual submenu item in the dashboard
  4. capability is the role that a user must have to access this menu item
  5. menu_slug is the unique ID for this particular menu item
  6. function_name that is called when the menu is clicked in order for displaying the options page

The function is straightforward. We have two menu items to introduce – one for "Display Options" and one for "Social Options."

Display Options

First, let's introduce a submenu item for display options. Add the following block of code directly under the add_menu_page call that we defined above:

Each of the above parameters should be clear with the exception of the function name that we passed as the final argument. Notice that it's the same function name that we provided in the add_menu_page call. But this makes sense, right? After all, the "Display Options" is the default tab that is displayed when the theme options are selected so it would make sense that it should be rendered when the top-level menu is selected and when the "Display Options" menu item is selected.

At this point, there's an important feature of WordPress to highlight: Note that once you've added your first submenu item, WordPress will actually render two submenu items to the top-level menu – one item that duplicates the function of the top-level menu and one item that corresponds to the submenu item that you just defined. I bring this up because, in my experience, I've seen developers get confused as to how (and why) this happens. The short of it is that WordPress is doing this – it's nothing wrong with your code.

Social Options

Adding a menu item for the social options is almost exactly like adding a menu item for the display options. Of course, we just want to change the values for the title bar, menu item, and the page that is displayed whenever the menu is selected. First, let's setup our call to the add_submenu_page function. It should look like this:

Save your code, refresh your dashboard, and you should see the "Social Options" menu item now available under the "Sandbox Theme" menu; however, notice that clicking on the new submenu item only renders the "Display Options." Since we've passed the "sandbox_theme_display" as the function name, that's what we should expect, right? So now we're faced with a little bit of a challenge: How do we select the "Social Options" tab when clicking on the submenu item?

Refactoring Our Tab Functionality

There are a couple of different options that we have for binding the new submenu item to the proper tab on the theme options' page:

  • We can define a new function that renders out the social options. This would require that we do some additional work in introducing a new function, setting up tabbing functionality so that we don't break the experience of the existing page, and duplicating a little bit of code.
  • We can refactor the existing sandbox_theme_display function to accept an optional parameter and then use an anonymous function in the add_submenu_page call to pass a parameter to it.

Ultimately, either of these options are up to you; however, I'd rather refactor my existing function than duplicate code so that's what I'll be doing throughout the remainder of this article.

First, let's begin refactoring our sandbox_theme_display function. Let's have it accept an optional argument that will be used to indicate which tab we want to select. Locate the following signature in your functions.php file:

Update the signature so that it accepts a single argument and sets it to null when it's not defined:

If you're new to PHP, you can read about default arguments on this page.

Remember from the last article that our display function is actually looking for a query string value to be set. We still want to maintain that functionality, but we need to account for the fact that the parameter may be passed into the function, as well. To perform this refactoring, first locate the following line of code in the sandbox_theme_display function:

Notice that this particular line of code is only concerned with the query string parameters. To account for the new optional parameter, we need to introduce logic that first checks if the query string parameter is checked, if not, it will check to see if the function's argument is set to display the social options, and, if not, then it will default to the display options. Replace the line of code above with the following conditional:

The final version of the function should look like this:

We're not quite done yet. Though we've done the necessary work to display the social options if the proper parameter has been passed, we haven't actually called the function using a parameter. To do this, we need to refactor the add_submenu_page function from above. Currently, the function call looks like this:

We need to update the final parameter so that it calls the display function and passes the proper value for rendering the social options. To do that, we'll create an anonymous function:

If you're new to PHP, be sure to read up on the create_function feature and anonymous functions. Though they are outside the scope of this article, they can be powerful (and useful!) when used in the proper context.

The final version of the sandbox_example_theme_menu function should be as follows:


Conclusion

At this point, our theme now has its own top-level menu item with each of the settings tabs accessible via submenu items. Though this is useful, I believe it's important to note that there are some mixed opinions on introducing menus into the WordPress Dashboard. Although they can make your work more prominent and accessible, they may also interfere with existing WordPress menus or other third-party work especially if you attempt to place your menus somewhere using the position parameter. Though there is no absolute right or absolute wrong when it comes to introducing menus, think carefully about where you expose your menus. If an existing WordPress menu makes sense, register your work as a submenu.

In the next post, we'll begin taking a look at the various input elements that we can use to introduce options into our WordPress theme as well as how to validate and sanitize the data before serializing them.


Related Sources

Tags:

Comments

Related Articles