Thesis Box Options and Admin Pages

The Thesis Box API makes it incredibly easy to create options for your Boxes. You simply provide Thesis with information about your options, and it does the dirty work of outputting admin pages, data-handling, saving, and retrieving these options when you need them.

Class-based vs. Instance-based Options

Boxes can have two types of options—class-based and instance-based.

Class-based options apply to all potential instances of a Box, and these options can appear in either the Site or Boxes menu in the Thesis Admin. You can think of these as “universal” options for your Box.

Instance-based options, on the other hand, apply only to a particular instance of a Box, and these options are accessible via links on the Skin → Content page.

Important! Box class data is saved relative to the Box itself, but instance data is saved relative to the active Skin.

In other words, Box class data is available no matter what Skin is currently running, but Box instance data is specific to the active Skin.

Be sure to consider these points when choosing an options structure for your Box, but also keep in mind that a Box can contain both of these options structures.

In cases where Boxes contain both types of options—and if the options have the same names—the instance-based options can be seen as “overrides” for class-based options.

Class-based Options

The simplest way to create class-based options for your Thesis Box is to include the class_options() method and return an array in Thesis Options API format. For example:

protected method class_options() {
	return array(
		'text' => array(
			'type' => 'text',
			'label' => __('Enter Some Text Here', 'my_box_namespace'),
			'tooltip' => __('Enter some sample text for our sample Box.', 'my_box_namespace')),
		'check' => array(
			'type' => 'checkbox',
			'options' => array(
				'yes' => __('Test Box options by checking this box?', 'my_box_namespace'))));
}

When Thesis detects a proper class_options() method, it creates an options page for your Box inside the Thesis Admin. By default, a link to this new page will appear in the Boxes menu, but if you want, you can change this to the Site menu by way of a simple filter (more on this later).

All class-based data is stored relative to the Box itself whenever the options page is saved. You can access this saved data in your Box class through two different reserved properties:

  • $this->class_options — This is an array of class-based data exactly as it was set by the user on your class-based options page.
  • $this->options — If your Box has instance-based options, this reference will give you all options, including class-based options that have been overridden or augmented by instance-based options. If your Box doesn’t have instance-based options, then this reference is the same as $this->class_options above.

Given the sample code from above, if you wanted to reference the values of the text and check options in your Box, you might write something like this:

if (!empty($this->class_options['text']))
	echo "We have text! It is: ", $this->class_options['text'];
if (!empty($this->class_options['check']['yes']))
	echo "Yes! We are testing our options because this box has been checked.";

Ya dig? Class-based data is completely separate from Skin data and will persist no matter which Skin is in use.

Modifying Default Class-based Options Behavior

In the section above, you learned that including a class_options() method in your Box is the easiest way to create a class-based options page for your Box. This is not, however, the only way to create an options page.

There are some situations where the standard options page may not suffice. For these cases, the Thesis Box API provides ways to override the default behavior via reserved methods, override methods, and the $filters property.

Box Admin Page

/* override method */
public function admin() { }

/* override filter */
protected $filters = array(
	'admin' => 'your_admin_method');

To illustrate, let’s assume your Box requires options that cannot be adequately described in the Thesis Options API. In this case, you would not be able to use the class_options() method to initialize your class-based admin page.

Instead, you could use the admin() override method to supply your own output page, complete with any options your Box needs. Of course, this means you’ll have to output the entire options <form> yourself, but in some cases, this may be your best option.

As an alternative, you could also use the Box $filters property and the admin parameter to declare your own admin page method, like so:

protected $filters = array(
	'admin' => 'my_admin');

The above declaration would override the default admin page functionality and look for a method called my_admin to output the options page for this Box.

Note: If you use the admin() or $filters['admin'] override, you will need to provide your own save method and configure that method to work within the WordPress environment (through the admin_post hook or the admin_ajax post request for ajax).

Box Admin Page CSS and JS

/* reserved methods */
public function admin_init() { }
protected function admin_ajax() { }

No matter which method you use to declare your Box options, Thesis will automatically serve the CSS and JS necessary for standard options page functionality.

If you need additional CSS or JS on your admin page, you should use the admin_init() method to enqueue any other styles or scripts.

If your Box contains a completely custom admin page, you may wish to perform an ajax action whenever the admin page is saved. The Thesis Box API contains a special method, admin_ajax(), that is called whenever an ajax save is performed on your Box (but only when the method is present).

Note: Default Box admin behavior is a typical page refresh on save. If you want to completely override this default behavior with an ajax save, you must supply both an admin method override (from the Box Admin Page section above) and an admin_ajax() method that handles the saving of your Box data.

Box Admin Menu Link

/* override filter */
protected $filters = array(
	'menu' => 'location', /* 'site' for Site menu */
	'text' => __('Menu Link Text', 'namespace'), /* menu link text in a translation function */
	'priority' => /* number between 1 and 100 to determine menu position */,
	'url' => 'url' /* specify your own admin page URL */ );

If your Box contains class-based options, Thesis will detect this and create a link to your options page in the Thesis Admin Boxes menu. You may wish to change certain aspects of this menu link, and the Thesis Box API provides you with a way to do this via the $filters property.

You can use four $filters parameters to modify the menu link:

  • menu — set this to ‘site’ to have your menu link appear in the Site menu instead of the Boxes menu (default)
  • text — by default, this is the title of your Box, but you can supply any text you want here
  • priority — if you want to move your options up or down in the menu, you can supply a priority parameter to indicate where it should go (relatively speaking, between 1 and 100)
  • url — Thesis automatically creates a URL for your Box admin page, but if you’d like to skip this functionality entirely (and point to a non-Thesis URL), you can supply one here

Sample Box Admin Setup with Overrides

So, putting it all together with excerpts from the above examples, you might have a Box that contains code like this:

protected $filters = array(
	'menu' => 'site',
	'priority' => 2,
	'admin' => 'my_admin');

protected function translate() {
	$this->title = __('My Sample Box', 'my_box_namespace');
	$this->filters['text'] = __('Modified Menu Text', 'my_box_namespace');
}

public function my_admin() {
	/* Custom admin page output goes here */
}

In the above snippet, the example Box does not have a class_options() method and is instead using the admin filter to initiate a custom admin page in the my_admin() method.

Also, this Box’s menu link will appear in the Site menu—in second position per the priority parameter—with the text, “Modified Menu Text.”

Finally, you might have noticed that the text filter was curiously placed inside the Box’s translate() method. This is because text should always be translatable, and translations do not work when declared outside the scope of a method (or function).

If it weren’t for this translation issue, you could declare the text parameter in the same place as the rest of the $filters parameters.

Instance-based Options

For some Boxes, it makes sense to save a set of options relative to each instance within a Skin. To extend this functionality to your Box, simply include an options() method that returns an array in Thesis Options API format, like so:

protected method options() {
	return array(
		'text' => array(
			'type' => 'text',
			'label' => __('Text for This Instance', 'my_box_namespace'),
			'tooltip' => __('Enter some sample text for this instance of our sample box.', 'my_box_namespace')),
		'another' => array(
			'type' => 'checkbox',
			'options' => array(
				'yes' => __('Check this if you like instance-based options', 'my_box_namespace'))));
}

Thesis detects the presence of an options() method and creates an admin page for each instance of the Box that appears in the current Skin. Each instance also receives its own link on the Skin → Content page, and the default link text is the $name of that instance (which is controlled by the Box developer and ultimately the user).

All Box instance data is saved relative to the current Skin. You can access this data in your Box with references to the $options property. Here’s an example:

if (!empty($this->options['text']))
	echo "This instance has its own text: ", $this->options['text'];
if (!empty($this->options['another']['yes']))
	echo "You love instance-based options. Nerd.";

Note: If a Box has class_options() and options() with the same index name, any data set for the instance will override data set for the class when you reference $this->options in your Box output.