Wp-graphql: do_graphql_request() will mess up the rest of the WP_Query

Created on 22 Oct 2020  路  3Comments  路  Source: wp-graphql/wp-graphql

It seems that there are some issues with Request->after_execute() method and how it resets the main WP query after GraphQL request. This can cause some weird issues in the rest of the page loading process like with pagination or with "Edit Page" -link in admin-bar.

The expected behavior and the actual behavior

Expected behavior: $GLOBALS['wp_the_query'] should be the same before and after do_graphql_request()

Actual behavior: $GLOBALS['wp_the_query'] is different before and after do_graphql_request()

How to reproduce?

WP Core in version 5.5.1, wp-graphql in version 0.13.3, theme is twentytwenty. No other plugins activated

  1. Add following snippets for example to content.php in theme
<?php
$query = 'query GET_POSTS {posts {nodes {title link}}}';
error_log( "Before do_graphql_request:" );
error_log( print_r( $GLOBALS['wp_the_query'], true ) );
error_log( "=============" );
$return_values = do_graphql_request( $query, 'test-query' );
error_log( "After do_graphql_request:" );
error_log( print_r( $GLOBALS['wp_the_query'], true ) );
error_log( "=============" );
?>
  1. Refresh frontpage in browser and check error logs
  • values in $GLOBALS['wp_the_query'] before do_graphql_request() are correct. For example
$GLOBALS['wp_the_query']->query === []
  • values in $GLOBALS['wp_the_query'] after do_graphql_request() are the same as in last query result in GraphQL request. For example
$GLOBALS['wp_the_query']->query === [ 'page' => '', 'p' => 48 ]

Even though I'm on a page with ID 4. Post with ID 48 is the last item in $return_values

Possible fix (not passing test)

I tried to fix this in the same way that $GLOBALS['post'] is reset: https://github.com/saulirajala/wp-graphql/commit/6ea69d417f90dfbf804a112468d5ae2e0b827136

It seems to fix the issue in my test site, but two automatic tests (vendor/bin/codecept run wpunit --env docker) failed:

There were 2 failures:
---------
1) EnqueuedScriptsTest: Enqueued script is_singular
 Test  tests/wpunit/EnqueuedScriptsTest.php:testEnqueuedScriptIs_Singular
Failed asserting that false is true.
#1  /tmp/wordpress/wp-content/plugins/wp-graphql/tests/wpunit/EnqueuedScriptsTest.php:680

---------
2) EnqueuedStylesheetsTest: Enqueued stylesheet is_singular
 Test  tests/wpunit/EnqueuedStylesheetsTest.php:testEnqueuedStylesheetIs_Singular
Failed asserting that false is true.
#1  /tmp/wordpress/wp-content/plugins/wp-graphql/tests/wpunit/EnqueuedStylesheetsTest.php:683
Actionable Bug

Most helpful comment

@saulirajala I think I figured it out.

When I try the same manual test as above with a custom post type, things don't work. I see the enqueued script getting added to the page that WordPress renders for that post type, but I _do not_ see it in the GraphQL query.

So the failed test is indeed failing properly.

To fix it, we can add the following:

            } else {
                $wp_query->parse_query( [
                    $post_type => $post_name,
                    'post_type' => $post_type,
                    'name' => $post_name,
                ] );
            }

To the end of this statement here: https://github.com/wp-graphql/wp-graphql/blob/develop/src/Model/Post.php#L212-L226

That, in addition to your existing changes, and we have passing tests again!

All 3 comments

@saulirajala can you open your changes as a PR?

It looks like a good fix. I have a feeling there's something in the way the enqueued script resolvers work that could be adjusted to compensate for this change. I'll take a look at those tests and the underlying behaviors.

@saulirajala so the 2 broken tests might be something funky with the tests themselves.

I tested the scenarios manually and the expected behavior is working for me with your changes.

For example, I can add this code to enqueue a script to _just_ single posts:

$handle = 'test-is-singular-post';
$src    = '/test-is-singular-post.js';

add_action( 'wp_enqueue_scripts', function() use ( $handle, $src ) {
    wp_register_script( $handle, $src );
    if ( is_singular( [ 'post' ] ) ) {
        wp_enqueue_script( $handle );
    }
} );

Then I can query for both pages and posts, and we can see that I get the enqueued script, as expected, for posts, and I _do not_ get the script for pages.

This is correct behavior.

Screen Shot 2020-10-23 at 1 27 54 AM

I'm not sure yet why the tests aren't reflecting this. I'm looking into that. It might be a case of a poor test, or some sort of edge case I'm not considering.

But your changes do appear to generally solve the issue.

Can you open a PR and I'll look into getting the tests fixed.

Thanks! 馃檹

@saulirajala I think I figured it out.

When I try the same manual test as above with a custom post type, things don't work. I see the enqueued script getting added to the page that WordPress renders for that post type, but I _do not_ see it in the GraphQL query.

So the failed test is indeed failing properly.

To fix it, we can add the following:

            } else {
                $wp_query->parse_query( [
                    $post_type => $post_name,
                    'post_type' => $post_type,
                    'name' => $post_name,
                ] );
            }

To the end of this statement here: https://github.com/wp-graphql/wp-graphql/blob/develop/src/Model/Post.php#L212-L226

That, in addition to your existing changes, and we have passing tests again!

Was this page helpful?
0 / 5 - 0 ratings