Skip to content

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

Merged
jasonbahl merged 35 commits intowp-graphql:developfrom
justlevine:feat/NodeResolver_resolve_uri-refactor
Feb 15, 2023
Merged

feat: Refactor NodeResolver::resolve_uri() to use WP_Query#2680
jasonbahl merged 35 commits intowp-graphql:developfrom
justlevine:feat/NodeResolver_resolve_uri-refactor

Conversation

@justlevine
Copy link
Copy Markdown
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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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.

@justlevine justlevine added type: enhancement Improvements to existing functionality component: architecture Relating to fundamental architectural decisions status: in progress Currently being worked on labels Dec 17, 2022
}

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

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.

@justlevine justlevine marked this pull request as ready for review December 17, 2022 16:28
switch ( $idType ) {
case 'uri':
return $context->node_resolver->resolve_uri( $args['id'] );
return $context->node_resolver->resolve_uri(
Copy link
Copy Markdown

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.

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

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.

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

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
Copy Markdown

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.

@qlty-cloud-legacy
Copy link
Copy Markdown

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
Copy Markdown
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

Labels

component: architecture Relating to fundamental architectural decisions status: in progress Currently being worked on type: enhancement Improvements to existing functionality

Projects

None yet

3 participants