2

I created a settings page, using the Settings API, following this tutorial.

Now I want to have a button that lets users dynamically add fields, similar to the way it is done in this other one.

I don't want to try to "merge" these two things together. There must be a right way to do this. Can someone give me a clue, how to achieve this?

I already found this in Pippin's Plugins, where he creates an array for his setting fields and displays them with a foreach-loop. But I'm not shure how this can help me.

/**
 * This function introduces the theme options into the 'Appearance' menu and into a top-level 
 * 'Sandbox Theme' menu.
 */
function sandbox_example_theme_menu() {

    add_theme_page(
        'Sandbox Theme',                    // The title to be displayed in the browser window for this page.
        'Sandbox Theme',                    // The text to be displayed for this menu item
        'administrator',                    // Which type of users can see this menu item
        'sandbox_theme_options',            // The unique ID - that is, the slug - for this menu item
        'sandbox_theme_display'             // The name of the function to call when rendering this menu's page
    );

    add_menu_page(
        'Sandbox Theme',                    // The value used to populate the browser's title bar when the menu page is active
        'Sandbox Theme',                    // The text of the menu in the administrator's sidebar
        'administrator',                    // What roles are able to access the menu
        'sandbox_theme_menu',               // The ID used to bind submenu items to this menu 
        'sandbox_theme_display'             // The callback function used to render this menu
    );

    add_submenu_page(
        'sandbox_theme_menu',               // The ID of the top-level menu page to which this submenu item belongs
        __( 'Display Options', 'sandbox' ),         // The value used to populate the browser's title bar when the menu page is active
        __( 'Display Options', 'sandbox' ),                 // The label of this submenu item displayed in the menu
        'administrator',                    // What roles are able to access this submenu item
        'sandbox_theme_display_options',    // The ID used to represent this submenu item
        'sandbox_theme_display'             // The callback function used to render the options for this submenu item
    );

    add_submenu_page(
        'sandbox_theme_menu',
        __( 'Social Options', 'sandbox' ),
        __( 'Social Options', 'sandbox' ),
        'administrator',
        'sandbox_theme_social_options',
        create_function( null, 'sandbox_theme_display( "social_options" );' )
    );

    add_submenu_page(
        'sandbox_theme_menu',
        __( 'Input Examples', 'sandbox' ),
        __( 'Input Examples', 'sandbox' ),
        'administrator',
        'sandbox_theme_input_examples',
        create_function( null, 'sandbox_theme_display( "input_examples" );' )
    );


} // end sandbox_example_theme_menu
add_action( 'admin_menu', 'sandbox_example_theme_menu' );

/**
 * Renders a simple page to display for the theme menu defined above.
 */
function sandbox_theme_display( $active_tab = '' ) {
?>
    <!-- Create a header in the default WordPress 'wrap' container -->
    <div class="wrap">

        <div id="icon-themes" class="icon32"></div>
        <h2><?php _e( 'Sandbox Theme Options', 'sandbox' ); ?></h2>
        <?php settings_errors(); ?>

        <?php if( isset( $_GET[ 'tab' ] ) ) {
            $active_tab = $_GET[ 'tab' ];
        } else if( $active_tab == 'social_options' ) {
            $active_tab = 'social_options';
        } else if( $active_tab == 'input_examples' ) {
            $active_tab = 'input_examples';
        } else {
            $active_tab = 'display_options';
        } // end if/else ?>

        <h2 class="nav-tab-wrapper">
            <a href="?page=sandbox_theme_options&tab=display_options" class="nav-tab <?php echo $active_tab == 'display_options' ? 'nav-tab-active' : ''; ?>"><?php _e( 'Display Options', 'sandbox' ); ?></a>
            <a href="?page=sandbox_theme_options&tab=social_options" class="nav-tab <?php echo $active_tab == 'social_options' ? 'nav-tab-active' : ''; ?>"><?php _e( 'Social Options', 'sandbox' ); ?></a>
            <a href="?page=sandbox_theme_options&tab=input_examples" class="nav-tab <?php echo $active_tab == 'input_examples' ? 'nav-tab-active' : ''; ?>"><?php _e( 'Input Examples', 'sandbox' ); ?></a>
        </h2>

        <form method="post" action="options.php">
            <?php

                if( $active_tab == 'display_options' ) {

                    settings_fields( 'sandbox_theme_display_options' );
                    do_settings_sections( 'sandbox_theme_display_options' );

                } elseif( $active_tab == 'social_options' ) {

                    settings_fields( 'sandbox_theme_social_options' );
                    do_settings_sections( 'sandbox_theme_social_options' );

                } else {

                    settings_fields( 'sandbox_theme_input_examples' );
                    do_settings_sections( 'sandbox_theme_input_examples' );

                } // end if/else

                submit_button();

            ?>
        </form>

    </div><!-- /.wrap -->
<?php
} // end sandbox_theme_display

/* ------------------------------------------------------------------------ *
 * Setting Registration
 * ------------------------------------------------------------------------ */ 


/**
 * Provides default values for the Social Options.
 */
function sandbox_theme_default_social_options() {

    $defaults = array(
        'twitter'       =>  '',
        'facebook'      =>  '',
        'googleplus'    =>  '',
    );

    return apply_filters( 'sandbox_theme_default_social_options', $defaults );

} // end sandbox_theme_default_social_options

/**
 * Provides default values for the Display Options.
 */
function sandbox_theme_default_display_options() {

    $defaults = array(
        'show_header'       =>  '',
        'show_content'      =>  '',
        'show_footer'       =>  '',
    );

    return apply_filters( 'sandbox_theme_default_display_options', $defaults );

} // end sandbox_theme_default_display_options

/**
 * Provides default values for the Input Options.
 */
function sandbox_theme_default_input_options() {

    $defaults = array(
        'input_example'     =>  '',
        'textarea_example'  =>  '',
        'checkbox_example'  =>  '',
        'radio_example'     =>  '',
        'time_options'      =>  'default'   
    );

    return apply_filters( 'sandbox_theme_default_input_options', $defaults );

} // end sandbox_theme_default_input_options

/**
 * Initializes the theme's display options page by registering the Sections,
 * Fields, and Settings.
 *
 * This function is registered with the 'admin_init' hook.
 */ 
function sandbox_initialize_theme_options() {

    // If the theme options don't exist, create them.
    if( false == get_option( 'sandbox_theme_display_options' ) ) {  
        add_option( 'sandbox_theme_display_options', apply_filters( 'sandbox_theme_default_display_options', sandbox_theme_default_display_options() ) );
    } // end if

    // First, we register a section. This is necessary since all future options must belong to a 
    add_settings_section(
        'general_settings_section',         // ID used to identify this section and with which to register options
        __( 'Display Options', 'sandbox' ),     // Title to be displayed on the administration page
        'sandbox_general_options_callback', // Callback used to render the description of the section
        'sandbox_theme_display_options'     // Page on which to add this section of options
    );

    // Next, we'll introduce the fields for toggling the visibility of content elements.
    add_settings_field( 
        'show_header',                      // ID used to identify the field throughout the theme
        __( 'Header', 'sandbox' ),                          // The label to the left of the option interface element
        'sandbox_toggle_header_callback',   // The name of the function responsible for rendering the option interface
        'sandbox_theme_display_options',    // The page on which this option will be displayed
        'general_settings_section',         // The name of the section to which this field belongs
        array(                              // The array of arguments to pass to the callback. In this case, just a description.
            __( 'Activate this setting to display the header.', 'sandbox' ),
        )
    );

    add_settings_field( 
        'show_content',                     
        __( 'Content', 'sandbox' ),             
        'sandbox_toggle_content_callback',  
        'sandbox_theme_display_options',                    
        'general_settings_section',         
        array(                              
            __( 'Activate this setting to display the content.', 'sandbox' ),
        )
    );

    add_settings_field( 
        'show_footer',                      
        __( 'Footer', 'sandbox' ),              
        'sandbox_toggle_footer_callback',   
        'sandbox_theme_display_options',        
        'general_settings_section',         
        array(                              
            __( 'Activate this setting to display the footer.', 'sandbox' ),
        )
    );

    // Finally, we register the fields with WordPress
    register_setting(
        'sandbox_theme_display_options',
        'sandbox_theme_display_options'
    );

} // end sandbox_initialize_theme_options
add_action( 'admin_init', 'sandbox_initialize_theme_options' );

/**
 * Initializes the theme's social options by registering the Sections,
 * Fields, and Settings.
 *
 * This function is registered with the 'admin_init' hook.
 */ 
function sandbox_theme_intialize_social_options() {

    if( false == get_option( 'sandbox_theme_social_options' ) ) {   
        add_option( 'sandbox_theme_social_options', apply_filters( 'sandbox_theme_default_social_options', sandbox_theme_default_social_options() ) );
    } // end if

    add_settings_section(
        'social_settings_section',          // ID used to identify this section and with which to register options
        __( 'Social Options', 'sandbox' ),      // Title to be displayed on the administration page
        'sandbox_social_options_callback',  // Callback used to render the description of the section
        'sandbox_theme_social_options'      // Page on which to add this section of options
    );

    add_settings_field( 
        'twitter',                      
        'Twitter',                          
        'sandbox_twitter_callback', 
        'sandbox_theme_social_options', 
        'social_settings_section'           
    );

    add_settings_field( 
        'facebook',                     
        'Facebook',                         
        'sandbox_facebook_callback',    
        'sandbox_theme_social_options', 
        'social_settings_section'           
    );

    add_settings_field( 
        'googleplus',                       
        'Google+',                          
        'sandbox_googleplus_callback',  
        'sandbox_theme_social_options', 
        'social_settings_section'           
    );

    register_setting(
        'sandbox_theme_social_options',
        'sandbox_theme_social_options',
        'sandbox_theme_sanitize_social_options'
    );

} // end sandbox_theme_intialize_social_options
add_action( 'admin_init', 'sandbox_theme_intialize_social_options' );

/**
 * Initializes the theme's input example by registering the Sections,
 * Fields, and Settings. This particular group of options is used to demonstration
 * validation and sanitization.
 *
 * This function is registered with the 'admin_init' hook.
 */ 
function sandbox_theme_initialize_input_examples() {

    if( false == get_option( 'sandbox_theme_input_examples' ) ) {   
        add_option( 'sandbox_theme_input_examples', apply_filters( 'sandbox_theme_default_input_options', sandbox_theme_default_input_options() ) );
    } // end if

    add_settings_section(
        'input_examples_section',
        __( 'Input Examples', 'sandbox' ),
        'sandbox_input_examples_callback',
        'sandbox_theme_input_examples'
    );

    add_settings_field( 
        'Input Element',                        
        __( 'Input Element', 'sandbox' ),                           
        'sandbox_input_element_callback',   
        'sandbox_theme_input_examples', 
        'input_examples_section'            
    );

    add_settings_field( 
        'Textarea Element',                     
        __( 'Textarea Element', 'sandbox' ),                            
        'sandbox_textarea_element_callback',    
        'sandbox_theme_input_examples', 
        'input_examples_section'            
    );

    add_settings_field(
        'Checkbox Element',
        __( 'Checkbox Element', 'sandbox' ),
        'sandbox_checkbox_element_callback',
        'sandbox_theme_input_examples',
        'input_examples_section'
    );

    add_settings_field(
        'Radio Button Elements',
        __( 'Radio Button Elements', 'sandbox' ),
        'sandbox_radio_element_callback',
        'sandbox_theme_input_examples',
        'input_examples_section'
    );

    add_settings_field(
        'Select Element',
        __( 'Select Element', 'sandbox' ),
        'sandbox_select_element_callback',
        'sandbox_theme_input_examples',
        'input_examples_section'
    );

    register_setting(
        'sandbox_theme_input_examples',
        'sandbox_theme_input_examples',
        'sandbox_theme_validate_input_examples'
    );

} // end sandbox_theme_initialize_input_examples
add_action( 'admin_init', 'sandbox_theme_initialize_input_examples' );

/* ------------------------------------------------------------------------ *
 * Section Callbacks
 * ------------------------------------------------------------------------ */ 

/**
 * This function provides a simple description for the General Options page. 
 *
 * It's called from the 'sandbox_initialize_theme_options' function by being passed as a parameter
 * in the add_settings_section function.
 */
function sandbox_general_options_callback() {
    echo '<p>' . __( 'Select which areas of content you wish to display.', 'sandbox' ) . '</p>';
} // end sandbox_general_options_callback

/**
 * This function provides a simple description for the Social Options page. 
 *
 * It's called from the 'sandbox_theme_intialize_social_options' function by being passed as a parameter
 * in the add_settings_section function.
 */
function sandbox_social_options_callback() {
    echo '<p>' . __( 'Provide the URL to the social networks you\'d like to display.', 'sandbox' ) . '</p>';
} // end sandbox_general_options_callback

/**
 * This function provides a simple description for the Input Examples page.
 *
 * It's called from the 'sandbox_theme_intialize_input_examples_options' function by being passed as a parameter
 * in the add_settings_section function.
 */
function sandbox_input_examples_callback() {
    echo '<p>' . __( 'Provides examples of the five basic element types.', 'sandbox' ) . '</p>';
} // end sandbox_general_options_callback

/* ------------------------------------------------------------------------ *
 * Field Callbacks
 * ------------------------------------------------------------------------ */ 

/**
 * This function renders the interface elements for toggling the visibility of the header element.
 * 
 * It accepts an array or arguments and expects the first element in the array to be the description
 * to be displayed next to the checkbox.
 */
function sandbox_toggle_header_callback($args) {

    // First, we read the options collection
    $options = get_option('sandbox_theme_display_options');

    // Next, we update the name attribute to access this element's ID in the context of the display options array
    // We also access the show_header element of the options collection in the call to the checked() helper function
    $html = '<input type="checkbox" id="show_header" name="sandbox_theme_display_options[show_header]" value="1" ' . checked( 1, isset( $options['show_header'] ) ? $options['show_header'] : 0, false ) . '/>'; 

    // Here, we'll take the first argument of the array and add it to a label next to the checkbox
    $html .= '<label for="show_header">&nbsp;'  . $args[0] . '</label>'; 

    echo $html;

} // end sandbox_toggle_header_callback

function sandbox_toggle_content_callback($args) {

    $options = get_option('sandbox_theme_display_options');

    $html = '<input type="checkbox" id="show_content" name="sandbox_theme_display_options[show_content]" value="1" ' . checked( 1, isset( $options['show_content'] ) ? $options['show_content'] : 0, false ) . '/>'; 
    $html .= '<label for="show_content">&nbsp;'  . $args[0] . '</label>'; 

    echo $html;

} // end sandbox_toggle_content_callback

function sandbox_toggle_footer_callback($args) {

    $options = get_option('sandbox_theme_display_options');

    $html = '<input type="checkbox" id="show_footer" name="sandbox_theme_display_options[show_footer]" value="1" ' . checked( 1, isset( $options['show_footer'] ) ? $options['show_footer'] : 0, false ) . '/>'; 
    $html .= '<label for="show_footer">&nbsp;'  . $args[0] . '</label>'; 

    echo $html;

} // end sandbox_toggle_footer_callback

function sandbox_twitter_callback() {

    // First, we read the social options collection
    $options = get_option( 'sandbox_theme_social_options' );

    // Next, we need to make sure the element is defined in the options. If not, we'll set an empty string.
    $url = '';
    if( isset( $options['twitter'] ) ) {
        $url = esc_url( $options['twitter'] );
    } // end if

    // Render the output
    echo '<input type="text" id="twitter" name="sandbox_theme_social_options[twitter]" value="' . $url . '" />';

} // end sandbox_twitter_callback

function sandbox_facebook_callback() {

    $options = get_option( 'sandbox_theme_social_options' );

    $url = '';
    if( isset( $options['facebook'] ) ) {
        $url = esc_url( $options['facebook'] );
    } // end if

    // Render the output
    echo '<input type="text" id="facebook" name="sandbox_theme_social_options[facebook]" value="' . $url . '" />';

} // end sandbox_facebook_callback

function sandbox_googleplus_callback() {

    $options = get_option( 'sandbox_theme_social_options' );

    $url = '';
    if( isset( $options['googleplus'] ) ) {
        $url = esc_url( $options['googleplus'] );
    } // end if

    // Render the output
    echo '<input type="text" id="googleplus" name="sandbox_theme_social_options[googleplus]" value="' . $url . '" />';

} // end sandbox_googleplus_callback

function sandbox_input_element_callback() {

    $options = get_option( 'sandbox_theme_input_examples' );

    // Render the output
    echo '<input type="text" id="input_example" name="sandbox_theme_input_examples[input_example]" value="' . $options['input_example'] . '" />';

} // end sandbox_input_element_callback

function sandbox_textarea_element_callback() {

    $options = get_option( 'sandbox_theme_input_examples' );

    // Render the output
    echo '<textarea id="textarea_example" name="sandbox_theme_input_examples[textarea_example]" rows="5" cols="50">' . $options['textarea_example'] . '</textarea>';

} // end sandbox_textarea_element_callback

function sandbox_checkbox_element_callback() {

    $options = get_option( 'sandbox_theme_input_examples' );

    $html = '<input type="checkbox" id="checkbox_example" name="sandbox_theme_input_examples[checkbox_example]" value="1"' . checked( 1, $options['checkbox_example'], false ) . '/>';
    $html .= '&nbsp;';
    $html .= '<label for="checkbox_example">This is an example of a checkbox</label>';

    echo $html;

} // end sandbox_checkbox_element_callback

function sandbox_radio_element_callback() {

    $options = get_option( 'sandbox_theme_input_examples' );

    $html = '<input type="radio" id="radio_example_one" name="sandbox_theme_input_examples[radio_example]" value="1"' . checked( 1, $options['radio_example'], false ) . '/>';
    $html .= '&nbsp;';
    $html .= '<label for="radio_example_one">Option One</label>';
    $html .= '&nbsp;';
    $html .= '<input type="radio" id="radio_example_two" name="sandbox_theme_input_examples[radio_example]" value="2"' . checked( 2, $options['radio_example'], false ) . '/>';
    $html .= '&nbsp;';
    $html .= '<label for="radio_example_two">Option Two</label>';

    echo $html;

} // end sandbox_radio_element_callback

function sandbox_select_element_callback() {

    $options = get_option( 'sandbox_theme_input_examples' );

    $html = '<select id="time_options" name="sandbox_theme_input_examples[time_options]">';
        $html .= '<option value="default">' . __( 'Select a time option...', 'sandbox' ) . '</option>';
        $html .= '<option value="never"' . selected( $options['time_options'], 'never', false) . '>' . __( 'Never', 'sandbox' ) . '</option>';
        $html .= '<option value="sometimes"' . selected( $options['time_options'], 'sometimes', false) . '>' . __( 'Sometimes', 'sandbox' ) . '</option>';
        $html .= '<option value="always"' . selected( $options['time_options'], 'always', false) . '>' . __( 'Always', 'sandbox' ) . '</option>';   $html .= '</select>';

    echo $html;

} // end sandbox_radio_element_callback

/* ------------------------------------------------------------------------ *
 * Setting Callbacks
 * ------------------------------------------------------------------------ */ 

/**
 * Sanitization callback for the social options. Since each of the social options are text inputs,
 * this function loops through the incoming option and strips all tags and slashes from the value
 * before serializing it.
 *  
 * @params  $input  The unsanitized collection of options.
 *
 * @returns         The collection of sanitized values.
 */
function sandbox_theme_sanitize_social_options( $input ) {

    // Define the array for the updated options
    $output = array();

    // Loop through each of the options sanitizing the data
    foreach( $input as $key => $val ) {

        if( isset ( $input[$key] ) ) {
            $output[$key] = esc_url_raw( strip_tags( stripslashes( $input[$key] ) ) );
        } // end if 

    } // end foreach

    // Return the new collection
    return apply_filters( 'sandbox_theme_sanitize_social_options', $output, $input );

} // end sandbox_theme_sanitize_social_options

function sandbox_theme_validate_input_examples( $input ) {

    // Create our array for storing the validated options
    $output = array();

    // Loop through each of the incoming options
    foreach( $input as $key => $value ) {

        // Check to see if the current option has a value. If so, process it.
        if( isset( $input[$key] ) ) {

            // Strip all HTML and PHP tags and properly handle quoted strings
            $output[$key] = strip_tags( stripslashes( $input[ $key ] ) );

        } // end if

    } // end foreach

    // Return the array processing any additional functions filtered by this action
    return apply_filters( 'sandbox_theme_validate_input_examples', $output, $input );

} // end sandbox_theme_validate_input_examples
?>
5
  • 2
    Would be better if you presented your code and the exact point where you're getting stuck.
    – brasofilo
    May 1, 2013 at 13:52
  • This is my code. Its exactly the code from the tutorial. Im not stuck, I'm just uncertain what to do next. May 1, 2013 at 14:00
  • Ok, but what are you uncertain about in those five hundred lines? Tip: indent your code so it's easier to understand, for you and the reader.
    – brasofilo
    May 1, 2013 at 14:04
  • It is indented, but it got lost, while copying it here. These 500 lines are fine. Im not shure how I would do a repeating field. Lets say I want a text field, like the one in tab 3. But I want the user add a duplicate of it as often as he wants. Then I want to get the values from the database and display as much paragraphs as the user created (I know this is a dumb example, its just to illustrate the problem). Now I really dont know how to implement that into what I got so far. May 1, 2013 at 14:10
  • Indented the code for you(when copying from GIT, use the RAW view, paste it into an editor and tab all the code in once more, then you can paste a copy of the code straight into a question/answer without having to do anything else).
    – t31os
    May 1, 2013 at 14:58

0

Your Answer

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

Browse other questions tagged or ask your own question.