You’re absolutely right that you can pass reusable form field markup to add_settings_field()
. The trick is to define the data type for each setting, and then pass the same callback to each call to add_settings_field()
. Within that callback, you simply add a switch that includes cases for each data type.
Here’s how I do it in Oenology:
First, I dynamically output all calls to add_settings_field()
:
<?php
/**
* Call add_settings_field() for each Setting Field
*
* Loop through each Theme option, and add a new
* setting field to the Theme Settings page for each
* setting.
*
* @link http://codex.wordpress.org/Function_Reference/add_settings_field Codex Reference: add_settings_field()
*
* @param string $settingid Unique Settings API identifier; passed to the callback function
* @param string $title Title of the setting field
* @param callback $callback Name of the callback function in which setting field markup is output
* @param string $pageid Name of the Settings page to which to add the setting field; passed from add_settings_section()
* @param string $sectionid ID of the Settings page section to which to add the setting field; passed from add_settings_section()
* @param array $args Array of arguments to pass to the callback function
*/
foreach ( $option_parameters as $option ) {
$optionname = $option['name'];
$optiontitle = $option['title'];
$optiontab = $option['tab'];
$optionsection = $option['section'];
$optiontype = $option['type'];
if ( 'internal' != $optiontype && 'custom' != $optiontype ) {
add_settings_field(
// $settingid
'oenology_setting_' . $optionname,
// $title
$optiontitle,
// $callback
'oenology_setting_callback',
// $pageid
'oenology_' . $optiontab . '_tab',
// $sectionid
'oenology_' . $optionsection . '_section',
// $args
$option
);
} if ( 'custom' == $optiontype ) {
add_settings_field(
// $settingid
'oenology_setting_' . $optionname,
// $title
$optiontitle,
//$callback
'oenology_setting_' . $optionname,
// $pageid
'oenology_' . $optiontab . '_tab',
// $sectionid
'oenology_' . $optionsection . '_section'
);
}
}
?>
And here’s how I define oenology_setting_callback()
:
<?php
/**
* Callback for get_settings_field()
*/
function oenology_setting_callback( $option ) {
$oenology_options = oenology_get_options();
$option_parameters = oenology_get_option_parameters();
$optionname = $option['name'];
$optiontitle = $option['title'];
$optiondescription = $option['description'];
$fieldtype = $option['type'];
$fieldname="theme_oenology_options[" . $optionname . ']';
// Output checkbox form field markup
if ( 'checkbox' == $fieldtype ) {
?>
<input type="checkbox" name="<?php echo $fieldname; ?>" <?php checked( $oenology_options[$optionname] ); ?> />
<?php
}
// Output radio button form field markup
else if ( 'radio' == $fieldtype ) {
$valid_options = array();
$valid_options = $option['valid_options'];
foreach ( $valid_options as $valid_option ) {
?>
<input type="radio" name="<?php echo $fieldname; ?>" <?php checked( $valid_option['name'] == $oenology_options[$optionname] ); ?> value="<?php echo $valid_option['name']; ?>" />
<span>
<?php echo $valid_option['title']; ?>
<?php if ( $valid_option['description'] ) { ?>
<span style="padding-left:5px;"><em><?php echo $valid_option['description']; ?></em></span>
<?php } ?>
</span>
<br />
<?php
}
}
// Output select form field markup
else if ( 'select' == $fieldtype ) {
$valid_options = array();
$valid_options = $option['valid_options'];
?>
<select name="<?php echo $fieldname; ?>">
<?php
foreach ( $valid_options as $valid_option ) {
?>
<option <?php selected( $valid_option['name'] == $oenology_options[$optionname] ); ?> value="<?php echo $valid_option['name']; ?>"><?php echo $valid_option['title']; ?></option>
<?php
}
?>
</select>
<?php
}
// Output text input form field markup
else if ( 'text' == $fieldtype ) {
?>
<input type="text" name="<?php echo $fieldname; ?>" value="<?php echo wp_filter_nohtml_kses( $oenology_options[$optionname] ); ?>" />
<?php
}
// Output the setting description
?>
<span class="description"><?php echo $optiondescription; ?></span>
<?php
}
?>
Note that I account for a “custom” type, so that I can output one-off markup for settings that might need it. These require individual callbacks.
Also, this code accounts for a tabbed settings page, which may be more complex than you need. It should be easy to make that bit static, though.