To avoid adding post meta values one at a time (and reduce repeat code in my theme) I wrote a simple class to store all the options so I can iterate through. The class works fine and constructs an object that I'm able to add valid options to (in much the same format one adds controls to the Customizer screen), and output the options forms in the meta box, but the values won't save. Here's how I'm trying to save the options, with some notes after. Please let me know if you have any ideas or need more info:

add_action( 'save_post', 'save_theme_options' );
function save_theme_options( $post_id ) {
    global $theme_options;
    foreach ( $theme_options->options as $option ) {
        if ( array_key_exists( $option->id, $_POST ) ) {
            update_post_meta($post_id, $option->meta_key, $_POST[$option->id]);

$theme_options is the global variable where I instantiate my object.

The $id of each option within $options requires a program-friendly string, such as "example_option". (It's not a number, like in WP objects.)

So with a single option set up like:

$theme_options->add_theme_option( 'example_text', array(
    'title'         =>  'Substrate Text Example',
    'description'   =>  'Example Description',
    'label'         =>  'Text:',
    'type'          =>  'text',
    'default'       =>  'Some text'

I expect $id to be 'example_text' and $meta_key to be '_example_text'.

Please let me know if you need more info, and thanks. (First post here.)

  • I think your code is right and should work.
    – JBoulhous
    Mar 14, 2018 at 23:28
  • using a global is always a fail. first step here to to stop using it and instead get the options from a function like get_my_theme_options(). Most likely your global is not initialized at the time of save. Mar 15, 2018 at 5:14
  • @dudieboy71 I don't see metakey defined in your options block (the second code block)... unless you are implying it is generated from the id?
    – majick
    Mar 15, 2018 at 11:12

1 Answer 1


Doing something like this would help make sure the theme object has been instantiated properly...

global $theme_options;
if ( (!isset($theme_options) || (!is_object($theme_options)) ) {
    $theme_options = new My_Theme_Options_Class();
  • 1
    Yes, while I instantiated the object globally, I added the options to the main object from inside a function... which meant those options were only available in the object within that function only. So in my saving function, the global object was still empty. Thanks for the check!
    – dudieboy71
    Mar 16, 2018 at 22:39

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.