Skip to content

Introduce register_graphql_connection_where_arg API #3065

Open
@jasonbahl

Description

@jasonbahl

What problem does this address?

When trying to do things like add Where Args to all connections to a specific type it's cumbersome to do so.

With Object Types, we can add a field to ContentNode and all Types that implement the interface get the field.

But with Input Types there's no concept of Input Interfaces, so each unique connection cannot inherit a general set of fields like Object Types can.

If we wanted to add a custom where arg to all "post" connections, it becomes tricky.

If using register_graphql_field() I would have to know the names of all possible Post connections and do something like:

register_graphql_field( 'RootQueryToPostConnectionWhereArgs', 'myCustomInputField', [] );
register_graphql_field( 'UserToPostConnectionWhereArgs', 'myCustomInputField', [] );
register_graphql_field( 'TagToPostConnectionWhereArgs', 'myCustomInputField', [] );
register_graphql_field( 'CategoryToPostConnectionWhereArgs', 'myCustomInputField', [] );
...

...and so on

This doesn't scale!

I can't / don't want to attempt to keep up with all the possible types I would need to filter. When it comes to things like ACF that add even more Types to the Schema, etc it is essentially impossible to know all the connections that may exist in the schema.

To get around this, we could add a filter like so:

add_filter( 'graphql_input_fields', function( $fields, $type_name, $config, $type_registry ) {

	$post_connection = 'ToPostConnectionWhereArgs';

	// If the Input Type is NOT where args on a connection "To Post", don't apply any changes
	if ( substr( $type_name, -strlen( $post_connection ) ) !== $post_connection ) {
		return $fields;
	}

	$fields['offsetPagination'] = [
		'type' => 'OffsetPagination',
		'description' => __( 'Paginate content nodes with offsets', 'your-textdomain' ),
	];

    return $fields;


}, 10, 4 );

This should work and is certainly better than register_graphql_field() for unknown to add a where arg to all Post connections, but feels clunky. . .and I'd still have to map how the input argument impacts the underlying resolution.

Another (cleaner) option would be hooking into the connection Instantiation like so:

add_action( 'graphql_wp_connection_type', function( array $connection_config, \WPGraphQL\Type\WPConnectionType $wp_connection_type ) {

  if ( 'product' !== $connection_config['toType'] ) {
    return;
  }

  $wp_connection_type->where_args[ 'offsetPagination' ] = [
    'type' => 'OffsetPagination',
	'description' => __( 'Paginate content nodes with offsets', 'your-textdomain' ),
  ];

} );

This is looking much better!

But I still need to map the new arg to underlying resolution.

What is your proposed solution?

I propose we introduce a register_graphql_connection_where_arg() API that makes it easier to add an argument to connection(s) AND map the argument to the underlying execution.

Something to the tune of:

function register_graphql_connection_where_arg( $to_type, $arg_name, $arg_config ) { ... };

which could be used like so:

register_graphql_connection_where_arg( 'Product', 'offsetPagination' [
  'type' => 'OffsetPagination',
  'description' => __( 'Paginate content nodes with offsets', 'your-textdomain' ),
  'map_input_arg' => function( $input ) { // this would be where we define how the input field maps to the underlying WP_Query (or similar) that would execute },
] );

What alternatives have you considered?

(see possible alternatives above)

Additional Context

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    component: connectionsRelating to GraphQL Connectionscomponent: queryRelating to GraphQL Queriesscope: apiIssues related to access functions, actions, and filterstype: enhancementImprovements to existing functionality

    Type

    No type

    Projects

    Status

    📋 Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions