The code you provided lacks a lot of sections and it outputs nothing when i use it on my localhost. I’ve written and tested a full class for you that does what you are looking for.
// Start Class
if ( ! class_exists( 'my_Theme_Options' ) ) {
class my_Theme_Options {
public function __construct() {
// We only need to register the admin panel on the back-end
if ( is_admin() ) {
add_action( 'admin_menu', array( 'my_Theme_Options', 'my_add_admin_menu' ) );
add_action( 'admin_init', array( 'my_Theme_Options', 'my_register_settings' ) );
}
}
// Returns all theme options
public static function get_my_theme_options() {
return get_option( 'my_theme_options' );
}
// Returns single theme option
public static function my_get_theme_option_value( $id ) {
$options = self::get_my_theme_options();
if ( isset( $options[$id] ) ) {
return $options[$id];
}
}
// Add sub menu page
public static function my_add_admin_menu() {
add_options_page(
esc_html__( 'my Options', 'text-domain' ),
esc_html__( 'my Options', 'text-domain' ),
'manage_options',
'my-theme-settings',
array( 'my_Theme_Options', 'my_create_admin_page' )
);
}
// Register a setting and its sanitization callback.
public static function my_register_settings() {
register_setting( 'my_theme_options', 'my_theme_options', array( 'my_Theme_Options', 'my_sanitize' ) );
}
// Sanitization callback
public static function my_sanitize( $options ) {
// If we have options lets sanitize them
if ( $options ) {
// Input
if ( ! empty( $options['sample_input'] ) ) {
$options['sample_input'] = sanitize_text_field( $options['sample_input'] );
} else {
unset( $options['sample_input'] ); // Remove from options if empty
}
}
// Return sanitized options
return $options;
}
// Now we output our form to save and view our options
public static function my_create_admin_page() { ?>
<div class="wrap">
<h1><?php esc_html_e( 'Theme Options', 'text-domain' ); // The heading for Option page ?></h1>
<?php settings_errors(); // Output any error if exists ?>
<form method="post" action="options.php">
<?php settings_fields( 'my_theme_options' ); ?>
<?php esc_html_e( 'Heading', 'text-domain' ); ?>
<table class="form-table">
<tbody>
<tr>
<th scope="row">
<?php esc_html_e( 'Sample Input', 'text-domain' ); ?>
</th>
<td>
<?php $value = self::my_get_theme_option_value( 'sample_input' ); // We retrieve and output this option in the input area ?>
<input type="text" name="my_theme_options[sample_input]" value="<?php echo esc_attr( $value ); ?>">
</td>
</tr>
</tbody>
</table>
<?php submit_button(); // Let's have a button to save the form, shall we? ?>
</form>
</div>
<?php }
}
}
new my_Theme_Options();
// Helper function to use in theme to return a theme option value
function my_get_theme_option( $id = '' ) {
return my_Theme_Options::my_get_theme_option_value( $id );
}
I used a simple text input as an example, but you can use checkbox, radio buttons, anything you want.
I’ve added explanation to everywhere i could, however if you have any questions about what does a part of the code do, make sure you let me know about it.