Allowing Custom Capability to Manage Plugin Options

If you use the Settings API, that $option_page is the value of a hidden <input> field generated by settings_fields(). For example:

<input type="hidden" name="option_page" value="{Option group name}">

So if you have settings_fields( 'my-group' ) in your code, then the $option_page would be my-group. See the (as of writing, 5th) note here.

Code sample: (tried and tested working)

// Register custom option group.
add_action( 'admin_init', function(){
    register_setting( 'my-group', 'test_option' );
} );

// Allows custom role to save options in the above group (my-group).
add_filter( 'option_page_capability_my-group', function( $capability ){
    return 'custom_capability';
} );

// Render the "Custom Plugins Addon" admin page.
function add_custom_addon_options_page() {
    ?>
        <div class="wrap">
            <h1>Custom Plugins Addon</h1>
            <?php settings_errors(); ?>
            <form method="post" action="options.php">
                <p>
                    <label>Text field:</label>
                    <input name="test_option" value="<?php echo esc_attr( get_option( 'test_option' ) ); ?>">
                </p>
                <?php settings_fields( 'my-group' ); ?>
                <?php submit_button(); ?>
            </form>
        </div>
    <?php
}

Full code here, but note that in the example, I intentionally did not use add_settings_section() and add_settings_field().

UPDATE

(Sorry, I actually didn’t really notice this part in the question)

so I have tried both the option page slug and the settings group slug,
but neither have worked

The option page slug is not supposed to work (assuming it is different from the settings group slug); however, the settings group slug (or option group name) should work just as in the example I’ve given.

So maybe you’re missing the settings_fields( 'my-group' ) in your code?..

Try the example plugin and see where/what you may have done wrong.. if any.

UPDATE #2

(Revised on Mar 18 2019 UTC)

Figured it out… I was using apply_filters() instead of
add_filter()

I’m glad you figured it out. And that’s a good thing to learn from.. 🙂

Could you elaborate on when to use apply_filters() vs.
add_filter()?

Not a complete elaboration, but I hope these help you.

  1. If you have a function or code which returns something, and you want to allow plugins or custom code to filter/change that something output, you can use apply_filters() which registers a filter hook and applies/runs callback functions hooked to that filter:

    // This function has a hook for a filter named my_filter.
    function my_function() {
        // Allow plugins or custom code to change the output.
        return apply_filters( 'my_filter', 'default output' );
    }
    
    // This function does **not** have any hooks.
    function my_function2() {
        return 'something good..';
    }
    
  2. When the output of a function or code is not what you want/prefer — and that the function/code has a filter hook, you can use add_filter() (which registers a filter callback) to customize the output like so: (the function code could be combined, but I separated them so that you know you can hook as many callbacks as you want to a filter)

    function filter_my_function_output( $output ) {
        return 'custom output';
    }
    add_filter( 'my_filter', 'filter_my_function_output' );
    
    function filter_my_function_output2( $output ) {
        return is_user_logged_in() ? 'You are logged-in...' : $output;
    }
    add_filter( 'my_filter', 'filter_my_function_output2' );
    

    So the final output could be the one returned by filter_my_function_output() or filter_my_function_output2(). Or vice-versa, depending on the callback priority:

    // no priority set explicitly; so defaults to 10
    add_filter( 'my_filter', 'filter_my_function_output' ); // priority = 10
    
    // using custom priority, which is 1; so this runs before the above
    add_filter( 'my_filter', 'filter_my_function_output', 1 ); // priority = 1
    

So in summary to the points #1 and #2 above:

  • my_filter is the name of a filter

  • my_function() contains a hook/place where the filter my_filter is being applied

  • filter_my_function_output() and filter_my_function_output2() are callback functions which run when the my_filter filter is applied

Leave a Comment