WordPress.org

Make WordPress Core

Opened 3 years ago

Last modified 3 years ago

#31005 new enhancement

wp_send_json(): Filtering of $response prior to passing it to wp_json_encode().

Reported by: ap.0 Owned by:
Milestone: Awaiting Review Priority: normal
Severity: normal Version: 4.1
Component: General Keywords:
Focuses: Cc:

Description

It would be nice if wp_send_json() allowed $response to be filtered prior to passing it to wp_json_encode() and echo'ing the resulting JSON.

I'm working with a theme that uses wp_send_json() while responding to AJAX requests. I'd like to modify/customize the response content, however, without modifying the theme itself (which doesn't appear to have other hooks that could be used).

wp_send_json() seems to be a convenient and reasonable place to perform such filtering, but doesn't already appear to support this as of 4.1.

Change History (4)

#1 @nacin
3 years ago

Interesting idea, but I don't think this function should have a filter. It'd be like adding a filter to exit(), header(), json_encode(), or some other low-level function. Its output should be expected based on its input, ideally without filtration. It's not the right place, and it's also easily abused (to the point of brokenness, for example).

The proper way to handle this would be for the plugin to add a specific filter on the data before it sends it to the client.

#2 follow-up: @ap.0
3 years ago

Agreed, it would be better to filter earlier, were that an option. It doesn't look like that's necessarily always the case, though.

For example, I'm currently dealing with a third-party theme. I'm avoiding changing the theme directly, to try to make future updates easier.

This particular theme is somewhat complex, and uses AJAX for part of its custom admin functionality.

Some of these AJAX handlers return some user data (wp_users.user_pass, for example...) that may be tolerable while using it on a single site with a single admin, but isn't when using it in a multi-site setup with multiple admins.

While this is a problem with the theme itself, I was hoping to use WordPress' extensibility to fix or work around it, instead of modifying the theme directly.

I can't share the code in question from the theme, but the flow is roughly:

function ajax_handler() {
    // "fields" isn't specified, so it defaults to "all".
    // This results in a query like "SELECT wp_users.* FROM wp_users ..." eventually being generated.
    $query = new WP_User_Query( ... );

    // Get and mildly process the results (but no hooks exist in this theme-provided result-processing function, unfortunately).
    $result = array();
    foreach ( $query->results as $result_item ) {
        $result[] = function_with_no_hooks( $result_item );
    }

    // Prepare the response data.
    $response = array(
        ...
        'data' => array(
            'result' => $result
        ),
        ...
    );

    // Send the response.
    wp_send_json( $response );
}

add_action( 'wp_ajax_SUFFIX', 'ajax_handler' );

The "pre_get_users" hook in WP_User_Query->prepare_query() might be an option, but I'd rather not have to list all of the fields individually (which could potentially change in the future, both in terms of which ones are available/returned, and which ones the theme's code may expect to be present) just to remove "user_pass".

The same goes for using "pre_user_query", and altering the SELECT clause directly.

WP_User_Query's constructor and WP_User_Query->query() don't seem to have any hooks that could be used to modify the results just after they're retrieved, as well.

I haven't noticed any other hooks that might be used to perform this filtering.

Given the apparent lack of useful existing hooks in this particular case, a hook for filtering in wp_send_json() starts to look like a more useful and general option. The theme's code can be left unchanged, with the small amount of unwanted data removed just prior to returning the results.

Filtering in lower-level functions doesn't seem to be without precedent, as well. wp_die() and wp_redirect() both support filtering, for example, and they seem to be at roughly the same level as wp_send_json().

As for the potential for abuse/misuse possibly causing breakage, wouldn't that apply to pretty much every hook that already exists?

#3 in reply to: ↑ 2 ; follow-up: @SergeyBiryukov
3 years ago

Replying to ap.0:

While this is a problem with the theme itself, I was hoping to use WordPress' extensibility to fix or work around it, instead of modifying the theme directly.

It should be possible to unhook the theme's AJAX handler and replace it with your own.

#4 in reply to: ↑ 3 @ap.0
3 years ago

Replying to SergeyBiryukov:

It should be possible to unhook the theme's AJAX handler and replace it with your own.

Thanks for the idea. A variant of that approach does seem to work in my particular case.

Note: See TracTickets for help on using tickets.