Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Refactor NodeResolver::resolve_uri() to use WP_Query #2680

Merged

Conversation

justlevine
Copy link
Collaborator

@justlevine justlevine commented Dec 17, 2022

What does this implement/fix? Explain your changes.

This pr refactors NodeResolver::resolve_uri() to use WP_Query, instead of the current approach where we try to replicate the class logic locally.

This brings the resolution process more in line with WP::main(), mitigating edge cases and reducing code complexity.

In addition, it adds the following WP filters to the method:

  • graphql_resolve_uri_query_class . Used to swap out WP_Query with a specialized class, e.g. WC_Query from woo.
  • graphql_resolve_uri . Used to short-circuit resolve_uri() after the query has been run, but before our own attempts to resolve it to a WPGraphQL node, e.g. if we want a CPT to use a special dataloader.
  • graphql_post_resolve_uri. Used to provide a WPGraphQL node if resolve_uri() is unable to do so, e.g. a plugin-specific Edge case.

Does this close any currently open issues?

fixes #2178
fixes #2190
closes #1910
(possibly others)

Part of #2366

Any relevant logs, error output, GraphiQL screenshots, etc?

(If it’s long, please paste to https://ghostbin.com/ and insert the link here.)

Any other comments?

  • This PR includes test: backfill nodeByUri query testing #2659, which should be merged first.
  • Since we're no longer routing via our own conditionals, $extra_query_vars['nodeType'] and $extra_query_vars['taxonomy'] are now set in more places to let us validate the type we're receiving is compatible with the GraphQL type we resolve to.
  • I removed nodeByUri tests for when pretty permalinks are disabled for now. The reason is that parse_request() (from before this PR) marks those as a 404, which we were able to ignore when we were using our own logic before calling WP_Query, but no longer. I believe this is a quirk with Codeception, and not an issue with the code itself, and I am looking into workarounds to reinstate those tests.
  • Before merging, we should test with popular WPGraphQL Extensions, just in case they're doing something funky to work around the existing bugs.
  • While I dont expect there to be any performance hits (if anything, maybe a small perf improvement because WP_Query results are usually cached, and we're hitting it earlier in the lifecycle), but we should do some profiling to be 100% sure. This is beyond my skillset.
  • Date archives still resolve null, since without Introduce Archive Interfaces #2491 we have nowhere to resolve them to. We could put a graphql_debug() saying theyre not currently supported, and fallback to the ContentType, but there isnt precedent for that in the codebase.

Where has this been tested?

Operating System: Ubuntu 20.04 (wsl2 + devilbox + php8.0.19)

WordPress Version: 6.1.1

This is a codeception quick we need to work around.
$page_on_front = get_option( 'page_on_front', 0 );
$post = get_post( absint( $page_on_front ) );
return ! empty( $post ) ? $this->context->get_loader( 'post' )->load_deferred( $post->ID ) : null;
return ! empty( $post_type_object->name ) ? $this->context->get_loader( 'post_type' )->load_deferred( $post_type_object->name ) : null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

$post = isset( $post->ID ) ? $this->validate_post( $post ) : null;
return isset( $post->ID ) ? $this->context->get_loader( 'post' )->load_deferred( $post->ID ) : null;
}
return ! empty( $queried_object->ID ) ? $this->context->get_loader( 'post' )->load_deferred( $queried_object->ID ) : null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

$post_type_object = get_post_type_object( $this->wp->query_vars['post_type'] );
// Resolve Terms.
if ( $queried_object instanceof \WP_Term ) {
return ! empty( $queried_object->term_id ) ? $this->context->get_loader( 'term' )->load_deferred( $queried_object->term_id ) : null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

return ! empty( $post_type_object ) ? $this->context->get_loader( 'post_type' )->load_deferred( $post_type_object->name ) : null;
// Resolve Post Types.
if ( $queried_object instanceof \WP_Post_Type ) {
return ! empty( $queried_object->name ) ? $this->context->get_loader( 'post_type' )->load_deferred( $queried_object->name ) : null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

}
// Resolve Users
if ( $queried_object instanceof \WP_User ) {
return ! empty( $queried_object->ID ) ? $this->context->get_loader( 'user' )->load_deferred( $queried_object->ID ) : null;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

@coveralls
Copy link

coveralls commented Dec 17, 2022

Coverage Status

Coverage increased (+3.4%) to 84.861% when pulling 47fe8ab on justlevine:feat/NodeResolver_resolve_uri-refactor into 6ae12df on wp-graphql:develop.

}

return $node;
return apply_filters( 'graphql_post_resolve_uri', $node, $uri, $queried_object, $query, $this->context, $this->wp, $extra_query_vars );
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

@@ -217,7 +217,12 @@ public static function register_type() {
$idType = $args['idType'] ?? 'global_id';
switch ( $idType ) {
case 'uri':
return $context->node_resolver->resolve_uri( $args['id'] );
return $context->node_resolver->resolve_uri(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

@@ -527,7 +532,12 @@

break;
case 'uri':
return $context->node_resolver->resolve_uri( $args['id'] );
return $context->node_resolver->resolve_uri(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

@@ -584,7 +594,12 @@
$id = absint( $args['id'] );
break;
case 'uri':
return $context->node_resolver->resolve_uri( $args['id'] );
return $context->node_resolver->resolve_uri(
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid too many return statements within this method.

*
* @return \WP_Term|null
*/
public function validate_term( \WP_Term $term ) {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Function validate_term has a Cognitive Complexity of 8 (exceeds 5 allowed). Consider refactoring.

@codeclimate
Copy link

codeclimate bot commented Dec 17, 2022

Code Climate has analyzed commit 47fe8ab and detected 10 issues on this pull request.

Here's the issue category breakdown:

Category Count
Complexity 10

View more on Code Climate.

@justlevine
Copy link
Collaborator Author

justlevine commented Dec 17, 2022

Verifying #1910 is resolved:

  1. Install and Activate Woocommece
  2. Add some dummy products.
  3. Query nodeByUri for "\shop". This returns null, since by default products are not exposed to the schema
{
  nodeByUri(uri: "/shop") {
    __typename
    ... on ContentType {
      name
      contentNodes {
        nodes {
          __typename
          databaseId
        }
      }
    }
  }
}

Results:
image

  1. Expose WC Products to the graphql schema:
add_filter( 'register_post_type_args',
  function( array $args, string $post_type ) {
    if ( 'product' === $post_type ) {
      $args['show_in_graphql'] = true;
      $args['graphql_single_name'] = 'product';
      $args['graphql_plural_name'] = 'products';
    }
    return $args;
  },
10, 2 );
  1. Rerun the query. This will return a ContentType, since /shop is a product archive.
    Result:
    image

  2. Attempt to fetch the query as a Page. This will return null, since /shop is a product archive.

{
  page(id: "/shop", idType: URI) {
    __typename
    databaseId
  }
}

Result:
image

@jasonbahl jasonbahl merged commit 734d544 into wp-graphql:develop Feb 15, 2023
This was referenced Mar 2, 2023
@justlevine justlevine deleted the feat/NodeResolver_resolve_uri-refactor branch February 10, 2024 19:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
3 participants