How to pass variable to add_settings_section() callback?

I am attempting to automate, as much as possible, the Settings API function calls for each setting in a Plugin. Looping through the options array, and outputting add_settings_section() and add_settings_field() is simple enough:

add_settings_section():

Read More
$oenology_hooks_tabs = oenology_hooks_get_settings_page_tabs();
foreach ( $oenology_hooks_tabs as $tab ) {
    $tabname = $tab['name'];
    $tabtitle = $tab['title'];
    $tabsections = $tab['sections'];
    foreach ( $tabsections as $section ) {
        $sectionname = $section['name'];
        $sectiontitle = $section['title'];
        $sectiondescription = $section['description'];
        // Add settings section
        add_settings_section(
            'oenology_hooks_' . $sectionname . '_section',
            $sectiontitle,
            'oenology_hooks_' . $sectionname . '_text',
            'oenology_hooks_' . $tabname . '_tab'
        );
    }
}

And `add_settings_field():

global $oenology_hooks;
$oenology_hooks = oenology_hooks_get_hooks();

foreach ( $oenology_hooks as $hook ) {
    $hookname = $hook['name'];
    $hooktitle = $hook['title'];
    $hooktab = $hook['tab'];
    $hooksection = $hook['section'];
    add_settings_field(
        'oenology_hooks_' . $hookname,
        $hooktitle,
        'oenology_hooks_setting_callback',
        'oenology_hooks_' . $hooktab . '_tab',
        'oenology_hooks_' . $hooksection . '_section',
        $hook
    );
}

With add_settings_field(), I can easily write a generic callback, by passing the $hook variable to the callback, as the fifth parameter in the function call:

function oenology_hooks_setting_callback( $hook ) {
    $oenology_hooks_options = get_option( 'plugin_oenology_hooks_settings' ); 
    $hookname = $hook['name'];
    $hooktitle = $hook['title'];
    $hookdescription = $hook['description'];
    $hooktype = $hook['type'];
    $hooktab = $hook['tab'];
    $hooksection = $hook['section'];
    $inputvalue = $hookname . '_hide';
    $inputname = 'plugin_oenology_hooks_settings[' . $inputvalue . ']';
    $textareaname = 'plugin_oenology_hooks_settings[' . $hookname . ']';
    $textareavalue = $oenology_hooks_options[$hookname];
    if ( 'Filter' == $hooktype ) {
        ?>
        <input type="checkbox" name="<?php echo $inputname; ?>" value="<?php echo $inputvalue;?>" <?php checked( true == $oenology_hooks_options[$inputvalue]  ); ?> />
        <span>Hide <?php echo $hooktitle; ?> content?</span><br />
        <?php
    }
    ?>
    <span class="description"><?php echo $hooktype; ?> Hook: <?php echo $hookdescription; ?></span><br />
    <textarea name="<?php echo $textareaname; ?>" cols="80" rows="3" ><?php 
        echo esc_textarea( $textareavalue ); 
    ?></textarea>
    <?php 
}

However, it appears that add_settings_section() does not have an analogous $args parameter; thus, I cannot use the same method to pass the $section variable to the callback.

Thus, my question: is there any way to pass a variable to the add_settings_section() callback, or some other way to create a callback analogous to what I’m doing for add_settings_field()?

EDIT:

@Bainternet nailed it! Here’s my working code:

/**
 * Callback for add_settings_section()
 * 
 * Generic callback to output the section text
 * for each Plugin settings section. 
 * 
 * @param   array   $section_passed Array passed from add_settings_section()
 */
function oenology_hooks_sections_callback( $section_passed ) {
    global $oenology_hooks_tabs;
    $oenology_hooks_tabs = oenology_hooks_get_settings_page_tabs();
    foreach ( $oenology_hooks_tabs as $tab ) {
        $tabname = $tab['name'];
        $tabsections = $tab['sections'];
        foreach ( $tabsections as $section ) {
            $sectionname = $section['name'];
            $sectiondescription = $section['description'];
            $section_callback_id = 'oenology_hooks_' . $sectionname . '_section';
            if ( $section_callback_id == $section_passed['id'] ) {
                ?>
                <p><?php echo $sectiondescription; ?></p>
                <?php
            }
        }
    }
}

Related posts

Leave a Reply

3 comments

  1. if you look at the do_settings_sections function more specifically the line 1164 where the callback function is being executed :

    call_user_func($section['callback'], $section);
    

    you can see that the $section array is being passed to the callback function, so you can identify the callback by the $section['id']

    hope this make since.

    Update

    here is an example, if your add_settings_section callback for all sections was named oenology_hooks_section_callback then you can identify it like this:

    function oenology_hooks_section_callback($section_passed){
        if ($section_passed['id'] == 'whatever_section_id'){
            //do stuff
        }
        if ($section_passed['id'] == 'whatever_section_id_number2'){
            //do other stuff
        }
     }
    

    and by do stuff i mean do whatever you want to do with that section callback.

  2. I know this is an old question but I’ll throw my two cents in, just in case someone else comes along; a simpler way to do so would be do write you own modification of the add_settings_section() function, which would only add a callback args parameter at the end of it.

    This would look like this ( or something like it )

    function my_add_settings_section($id, $title, $callback, $page, $callbackargs) {
    
    global $wp_settings_sections;
    
    if ( !isset($wp_settings_sections) ) 
    {
        $wp_settings_sections = array();
    }
    
    if ( !isset($wp_settings_sections[$page]) )
    {
        $wp_settings_sections[$page] = array();
    }
    
    if ( !isset($wp_settings_sections[$page][$id]) )
    {
        $wp_settings_sections[$page][$id] = array();
    }
    
    $wp_settings_sections[$page][$id] = array( 'id' => $id, 'title' => $title, 'callback' => $callback, 'callbackargs' => $callbackargs, 'page' => 'page' );
    }
    

    Now you would simply use this instead of the native wordpress function and access your callback args through the 'callbackargs' array key in a usual fashion, like this

    function oenology_hooks_sections_callback( $section_passed ) {
       // Our callback arguments  
       $section_passed['callbackargs']
    }
    

    Which we could use to pass to some other function :

     function oenology_hooks_sections_callback( $section_passed ) {
       // Our callback arguments  
       $args = $section_passed['callbackargs'];
       some_other_function( $args );
    }
    

    Or the callback args could be an array themselves which we use :

    function oenology_hooks_sections_callback( $section_passed ) {
       // Our callback arguments  
       if ( $section_passed['callbackargs']['stuff'] !== 'things' ) 
       {
           echo 'stuff is not things!";
       }
    }
    

    This is all possible because all add_settings_section() does is add a new array member to the $wp_settings_sections global variable, that new array member could be an array itself containing any number of keys with different names, which could be used, by any function that knew they were there.
    When do_settings_sections calls the call_user_func_array it passes a $sections paramater as Bainternet noted, this means that the entire array we added to $wp_settings_sections in my_add_settings_section() is passed into our callback, meaning we have access to every new array member we add to it such as the callbackargs allowing our function to have a full fledged callback.

    Even though im sure that this might be obvious i thought that I’d just explain it in case someone who gets confused looks in.

  3. You can also always use a more general approach, not looking for the particular function implementation (meaning, without checking if add_settings_section passes anything implicitly). This general approach uses PHP closure.

    How to use it: in every place, where you pass a function name, instead of it pass an anonymous function, with use in it.

    Example:

    instead of

    foreach ( $ar as $name => value ) {
        add_settings_section(
            $section,
            'something',
            'something-else',
            'callback_name'
        );
    }
    
    function callback_name() {
        do_something();
    }
    

    you can use:

    foreach ( $ar as $name => value ) {
        add_settings_section(
            $section,
            'something',
            'something-else',
            function () use ( $name, $value ) {
                callback_name( $name, $value )
            }
        );
    }
    
    function callback_name( $name, $value ) {
        do_something( $name, $value );
    }