Last active
June 1, 2019 17:22
-
-
Save jimratliff/a9a762a8eff66b43071e2c90ffa7bf2a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Based on AJ Clarke, "How to Create a Simple WordPress Theme Options Page," WPExplorer, | |
November 21, 2016, https://www.wpexplorer.com/wordpress-theme-options/ | |
I started with AJ's code. Like many other examples of creating a theme-options page, | |
AJ sometimes used the same string for more than one distinct purpose, creating some | |
ambiguity about what role each occurrence of a string plays in its context. | |
To address this, I've modified the code to use a unique string for each distinct role. | |
This allows one to (a) understand better what's going on and (b) modify the string for | |
a particular role with a global search/replace without affecting the strings used for | |
any other roles. | |
For example, AJ had: | |
register_setting( 'theme_options', 'theme_options', array( 'WPEX_Theme_Options', 'sanitize' ) ); | |
where the same string ('theme_options') is used for both of the first two arguments, | |
which have distinct meanings: | |
argument #1: $option_group: "A settings group name. This must match the group name used in register_setting(), | |
which is the page slug name on which the form is to appear." | |
<https://codex.wordpress.org/Settings_API> | |
argument #2: $option_name: The name of an option to sanitize and save. | |
A similar remarks applies to the first two arguments of add_menu_page(). | |
I also changed the names of some of the functions/methods defined within the class to more | |
obviously signal that these are not standard-WordPress functions. (E.g., I changed the name of | |
register_settings(), to distinguish it from the standard-WordPress function register_setting().) | |
AJ's code used "WPEX_" as a prefix, corresponding to WPExplorer. I changed the prefix to "zzyzx" | |
to be more generic and a good candidate for global search/replace. | |
* | |
*/ | |
/* Some WordPress functions have an argument for a callable function. While a PHP function | |
can be passed by its name as a string, "A method of an instantiated object is passed | |
as an array containing an object at index 0 and the method name at index 1." | |
See <https://www.php.net/manual/en/language.types.callable.php>. | |
This structure/syntax is used below. | |
*/ | |
/* | |
Jim's notes | |
<div class="wrap"> apparently matches the look and feel of existing WordPress options pages. | |
See Codex, "Creating Options Pages," <https://codex.wordpress.org/Creating_Options_Pages> | |
zzyzx_Theme_Options_Class : class | |
zzyzx-custom-admin-screen-background-section: CSS class | |
zzyzx-custom-admin-login-table : CSS class | |
zzyzx_add_admin_menu : method Add sub menu page | |
zzyzx_register_settings : method Register a setting and its sanitization callback | |
zzyzx_get_theme_option : method Returns single theme option | |
zzyzx_get_theme_option_array : method Returns all theme options | |
zzyzx_sanitize : method Sanitization callback | |
zzyzx_create_admin_page : method Settings page output | |
'zzyzx_theme_options_array' : id in database for array of theme options | |
'zzyzx_theme_options_group' : id of options group. Should match between | |
(a) first argument of register_setting and | |
(b) argument of settings_fields | |
'zzyzx-theme-settings-menu-slug' : slug name to refer to menu. Should be | |
unique for this menu page and only include | |
lowercase-alpha, dashes, and underscores | |
'text-domain' | |
zzyzx_get_this_theme_option : method Helper function to use in | |
your theme to return a | |
theme option value | |
*/ | |
// Exit if accessed directly | |
if ( ! defined( 'ABSPATH' ) ) { | |
exit; | |
} | |
// Start Class | |
if ( ! class_exists( 'zzyzx_Theme_Options_Class' ) ) { | |
class zzyzx_Theme_Options_Class { | |
/* Start things up */ | |
public function __construct() { | |
// We only need to register the admin panel on the back-end | |
if ( is_admin() ) { | |
add_action( 'admin_menu', array( 'zzyzx_Theme_Options_Class', 'zzyzx_add_admin_menu' ) ); | |
add_action( 'admin_init', array( 'zzyzx_Theme_Options_Class', 'zzyzx_register_settings' ) ); | |
} | |
} | |
/* Returns all theme options */ | |
public static function zzyzx_get_theme_option_array() { | |
return get_option( 'zzyzx_theme_options_array' ); | |
} | |
/* Returns single theme option */ | |
public static function zzyzx_get_theme_option( $name_of_particular_option ) { | |
$options = self::zzyzx_get_theme_option_array(); | |
if ( isset( $options[$name_of_particular_option] ) ) { | |
return $options[$name_of_particular_option]; | |
} | |
} | |
/* Adds a top-level menu page */ | |
public static function zzyzx_add_admin_menu() { | |
// add_menu_page() adds a top-level menu page | |
add_menu_page( | |
// Note: argument is browser-window title, not the <h1> header | |
esc_html__( 'Zzyzx Theme Page Browser Window Title', 'text-domain' ), | |
// Note: argument is label that appears in the admin sidebar, clicking on | |
// which opens the options page | |
esc_html__( 'Zzyzx Theme Menu Label', 'text-domain' ), | |
'manage_options', // Capability required in order to see this menu | |
'zzyzx-theme-settings-menu-slug', // slug for resultant options page | |
// Callable function to be called to output the content of the page. | |
// See note at top about a method being passed as an array | |
array( 'zzyzx_Theme_Options_Class', 'zzyzx_create_admin_page' ) | |
); | |
} | |
/** | |
* Register a setting and its sanitization callback. | |
* | |
* We are only registering 1 setting so we can store all options in a single option as | |
* an array. You could, however, register a new setting for each option | |
*/ | |
public static function zzyzx_register_settings() { | |
register_setting( | |
'zzyzx_theme_options_group', | |
'zzyzx_theme_options_array', | |
// Notes: | |
// (1) See note at top about a method being passed as an array | |
// (2) The third argument of register_setting() is $args, an array of "Data | |
// used to describe the setting when registered." Although I don't understand | |
// perfectly how the following jibes with the documentation, it seems | |
// to be OK to just pass a callable function in that argument. | |
array( 'zzyzx_Theme_Options_Class', 'zzyzx_sanitize' ) | |
); | |
} | |
/** | |
* Sanitization callback | |
*/ | |
public static function zzyzx_sanitize( $options ) { | |
// If we have options let's sanitize them | |
if ( $options ) { | |
// Checkbox | |
if ( ! empty( $options['checkbox_example'] ) ) { | |
$options['checkbox_example'] = 'on'; | |
} else { | |
// Remove from options if not checked | |
unset( $options['checkbox_example'] ); | |
} | |
// Input | |
if ( ! empty( $options['input_example'] ) ) { | |
$options['input_example'] = sanitize_text_field( $options['input_example'] ); | |
} else { | |
unset( $options['input_example'] ); // Remove from options if empty | |
} | |
// Select | |
if ( ! empty( $options['select_example'] ) ) { | |
$options['select_example'] = sanitize_text_field( $options['select_example'] ); | |
} | |
} | |
// Return sanitized options | |
return $options; | |
} | |
/* Outputs the settings page */ | |
public static function zzyzx_create_admin_page() { ?> | |
<div class="wrap"> <!--matches the look and feel of existing WordPress options pages--> | |
<h1><?php esc_html_e( 'Zzyzx Theme Options Page header', 'text-domain' ); ?></h1> | |
<form method="post" action="options.php"> | |
<?php | |
// settings_fields() outputs nonce, action, and option_page fields for a settings page | |
// Argument should match the group name used in register_setting() | |
settings_fields( 'zzyzx_theme_options_group' ); | |
?> | |
<table class="form-table zzyzx-custom-admin-login-table"> | |
<?php // Checkbox example ?> | |
<tr valign="top"> | |
<th scope="row"><?php esc_html_e( 'Checkbox Example Label', 'text-domain' ); ?></th> | |
<td> | |
<?php $value = self::zzyzx_get_theme_option( 'checkbox_example' ); ?> | |
<input type="checkbox" name="zzyzx_theme_options_array[checkbox_example]"<?php checked( $value, 'on' ); ?>> | |
<?php esc_html_e( 'Checkbox example description.', 'text-domain' ); ?> | |
</td> | |
</tr> | |
<?php // Text input example ?> | |
<tr valign="top"> | |
<th scope="row"><?php esc_html_e( 'Input Example Label', 'text-domain' ); ?></th> | |
<td> | |
<?php $value = self::zzyzx_get_theme_option( 'input_example' ); ?> | |
<input type="text" name="zzyzx_theme_options_array[input_example]" value="<?php echo esc_attr( $value ); ?>"> | |
</td> | |
</tr> | |
<?php // Select example ?> | |
<tr valign="top" class="zzyzx-custom-admin-screen-background-section"> | |
<th scope="row"><?php esc_html_e( 'Select Example Label', 'text-domain' ); ?></th> | |
<td> | |
<?php $value = self::zzyzx_get_theme_option( 'select_example' ); ?> | |
<select name="zzyzx_theme_options_array[select_example]"> | |
<?php | |
$options = array( | |
'1' => esc_html__( 'Option 1', 'text-domain' ), | |
'2' => esc_html__( 'Option 2', 'text-domain' ), | |
'3' => esc_html__( 'Option 3', 'text-domain' ), | |
); | |
foreach ( $options as $id => $label ) { ?> | |
<option value="<?php echo esc_attr( $id ); ?>" <?php selected( $value, $id, true ); ?>> | |
<?php echo strip_tags( $label ); ?> | |
</option> | |
<?php } ?> | |
</select> | |
</td> | |
</tr> | |
</table> | |
<?php submit_button(); ?> | |
</form> | |
</div><!-- .wrap --> | |
<?php } | |
} | |
} | |
new zzyzx_Theme_Options_Class(); | |
// Helper function to use in your theme to return a theme option value | |
function zzyzx_get_this_theme_option( $name_of_particular_option = '' ) { | |
return zzyzx_Theme_Options_Class::zzyzx_get_theme_option( $name_of_particular_option ); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment