/

Register GraphQL Types

Learn how to register GraphQL types


Existing Types in WPGraphQL

GraphQL provides a number of Scalar types out of the box:

  • Boolean
  • Float
  • Integer
  • ID
  • String

And when you activate WPGraphQL, your WPGraphQL Schema automatically gets hundreds of new Types added to the Schema.

You can look in the TypeRegistry.php file within the plugin to see all the Types that are registered by the plugin for use within your Schema.

Additionally, since the GraphQL Schema is queryable, you can check out the Types that are available ' in your Schema by running the following Query:

GraphiQL Loading...

Registering New Types

In many cases, your data needs to be represented by something more complex than a string or number.

If an existing Type in the Schema has the shape you need, you can use that Type to return your data.

For example, if you had a field called profilePic and wanted to return an item from the media library, you might be able to use the existing MediaItem Type, which provides fields for sourceUrl, altText and caption, and more.

However, if no existing Type in the Schema provides the shape you need, you might need to register a new Type to the Schema.

The following APIs can be used to register new Types to the Schema.

Object Types

GraphQL Object types are a great fit for representing data that's more complex than a simple scalar.

There are a lot of Object Types in the GraphQL Schema. For example Post, Page, MediaItem, Tag, Category and many more. When you register a Post Type or Taxonomy to "show_in_graphql", you automatically get a new Type added to the Schema to represent that Entity, so you may not always need to register a new Type to the Schema manually, depending on your use case.

If you do need to register a new Object Type in the Schema, you can use the register_graphql_object_type() method within the graphql_register_types action.

register_graphql_object_type

The register_graphql_object_type( $type_name, $config ) method takes 2 arguments:

  • type_name (required | string): The name of the Type in the Schema. This must be unique amongst the entire Schema. There cannot be multiple Types in the Schema with the same name.
  • config (array | required): An array of config for the Type, consisting of the following:
    • description (string): Description of the Type
    • fields (array | required): The fields that should be on the Type.
      • Each field should have the name as the key, and the field config as the value. The field config should contain a description, Type and optional resolve function. (see example below)

Let's say we wanted to register an Object Type to represent a Dog. We might determine that the dog should have the following fields:

  • name: String
  • breed: String
  • age: Int

We could register a field getDog to our Schema that resolves to the Dog Type like so:

add_action( 'graphql_register_types', 'register_dog_type' );

function register_dog_type() {
    register_graphql_object_type( 'Dog', [
      'description' => __( "Man's best friend", 'your-textdomain' ),
      'fields' => [
        'name' => [
            'type' => 'String',
            'description' => __( 'The name of the dog', 'your-textdomain' ),
        ],
        'breed' => [
            'type' => 'String',
            'description' => __( 'The Breed of the dog', 'your-textdomain' ),
        ],
        'age' => [
            'type' => 'Integer',
            'description' => __( 'The age, in years, of the dog', 'your-textdomain' ),
        ],
      ],
    ] );
}

Register a field using the Type

We have now added a Type to the Type registry, but it's not used anywhere until we have a field that resolves to the Type.

We could add a field to the Schema to allow us to query for the Dog.

For example:

add_action( 'graphql_register_types', 'register_dog_field' );

function register_dog_field() {

    register_graphql_field( 'RootQuery', 'getDog', [
      'description' => __( 'Get a dog', 'your-textdomain' ),
      'type' => 'Dog',
      'resolve' => function() {

        // Here you need to return data that matches the shape of the "Dog" type. You could get
        // the data from the WP Database, an external API, or static values. For example sake,
        // we will just return a hard-coded array.
        return [
            'name' => 'Sparky',
            'breed' => 'Golden Retriever',
            'age' => 8
        ];

      }
    ] );

}

At this point, we have a field getDog on the RootQuery of our Schema, which would allow us to query like so:

{
	getDog {
		name
		breed
		age
	}
}

And in response, we would get the following:

{
	"data": {
		"getDog": {
			"name": "Sparky",
			"breed": "Golden Retriever",
			"age": 8
		}
	}
}

Enum Types

In GraphQL, Enum Types are used to provide a predefined set of values.

An example of an Enum in WPGraphQL is the AvatarRatingEnum. Avatars in GraphQL can have a rating that is one of a predefined list of values: G, PG, R, and X. Since we know all the options before hand, we can expose fields to resolve to the AvatarRatingEnum type and ensure that it's always one of those predefined values.

Let's say we wanted to be able to query for the current weather, and the responses should always be one of the following: Sunny, Cloudy, Rainy

register_graphql_enum_type

The register_graphql_enum_type( $type_name, $config ) takes to arguments:

  • type_name (string | required): The name of the Type in the Schema. This must be unique amongst the entire Schema. There cannot be multiple Types in the Schema with the same name.
  • config (array | required): An array of config for the Type, consisting of the following:
    • description (string): Description of the type and what it represents
    • values (array): The possible values of the Enum

We could define an enum like so:

add_action( 'graphql_register_types', 'register_weather_enum_type' );

function register_weather_enum_type() {
    register_graphql_enum_type( 'WeatherEnum', [
      'description' => __( 'Condition of weather', 'your-textdomain' ),
      'values' => [
        'SUNNY' => [
          'value' => 'sunny'
        ],
        'CLOUDY' => [
          'value' => 'cloudy'
        ],
        'RAINY' => [
          'value' => 'rainy'
        ],
      ],
    ] );
}

Register a field using the Type

This would add an Enum to our Type registry, but it wouldn't be in use yet. We could add a field that resolves to this Type:

add_action( 'graphql_register_types', 'register_weather_field' );

function register_weather_field() {
  register_graphql_field( 'RootQuery', 'currentWeather', [
    'type' => 'WeatherEnum',
    'description' => __( 'Get the weather', 'your-textdomain' ),
    'resolve' => function() {
      // Here you could fetch data from a database, an external API, or whatever you like.
      // In this case, we'll just return static data. It has to return one of the values
      // defined by the enum to fulfill the contract of the Schema.
      return 'rainy'; //sunny, cloudy
    },
  ] );
}

Now we could query:

{
	currentWeather
}

And get a response like:

{
	"data": {
		"currentWeather": "RAINY"
	}
}

Union Types

When a field can return one of many possible Types, Unions can be used.

An example of a Union in WPGraphQL would be the parent field on MediaItems. Media Items (attachments) can be uploaded to a Page, Post, or any other custom post type. The Type of parent isn't known until the MediaItem is queried.

If there's a case where your data can be conditionally represented by different Types, a Union could be used to represent the data.

register_graphql_union_type

The register_graphql_union_type( $type_name, $config ) accepts 2 arguments:

  • type_name (string | required ): The name of the Type in the Schema. This must be unique amongst the entire Schema. There cannot be multiple Types in the Schema with the same name.
  • config (array | required): Config for the Union Type
    • types (array | required): An array of Types that the union could return
    • resolveType (function | required): A function that takes the resolving data and determines what GraphQL Type should be returned.

Let's say we wanted to query for a Pet, but the Pet could either be a Dog or Cat, each with their own Type definition.

Let's start by registering a Dog and Cat Type:

add_action( 'graphql_register_types', 'register_pet_types' );

function register_pet_types() {
    register_graphql_object_type( 'Dog', [
      'description' => __( "Man's best friend", 'your-textdomain' ),
      'fields' => [
        'name' => [
            'type' => 'String',
            'description' => __( 'The name of the dog', 'your-textdomain' ),
        ],
        'breed' => [
            'type' => 'String',
            'description' => __( 'The Breed of the dog', 'your-textdomain' ),
        ],
        'age' => [
            'type' => 'Integer',
            'description' => __( 'The age, in years, of the dog', 'your-textdomain' ),
        ],
      ],
    ] );

    register_graphql_object_type( 'Cat', [
      'description' => __( "Not man's best friend...", 'your-textdomain' ),
      'fields' => [
        'name' => [
            'type' => 'String',
            'description' => __( 'The name of the cat', 'your-textdomain' ),
        ],
        'age' => [
            'type' => 'Integer',
            'description' => __( 'The age, in years, of the cat', 'your-textdomain' ),
        ],
        'isHighOnCatnip' => [
          'type' => 'Boolean',
          'description' => __( 'Whether the cat is high on Catnip.', 'your-textdomain' ),
        ]
      ],
    ] );
}

Now that we have a Cat and Dog Type registered to our Schema, we can register our Union. Right below the registration for those types, we can add the following:

add_action( 'graphql_register_types', 'register_pet_union', 10, 1 );

function register_pet_union( $type_registry ) {
  register_graphql_union_type( 'PetUnion', [
    'typeNames'       => [ 'Dog', 'Cat' ],
    'resolveType' => function( $pet ) use ( $type_registry ) {
      // Here we receive the object or array that's being resolved by the field
      // and we can determine what Type to return
      $type = null;
      switch( $pet['type'] ) {
        case 'dog':
	  $type = $type_registry->get_type( 'Dog' );
    	  break;
        case 'cat':
	  $type = $type_registry->get_type( 'Cat' );
	  break;
      }
      return $type;
    }
  ] );
}
You must register Unions after Types that it references have already been registered. In our case, we registered Dog and Cat before registering the union, but you may not be able to register all types of the union in the same spot. So one option would be too hook the union registration to a late priority of the "graphql_register_types" action

This registers a Union type. The types defines what Types are possible to be returned. In this case, the Dog or Cat Type.

Then the resolveType is the function that runs during execution to determine what Type should be returned. It accepts the resolving data, and you can use that data to determine what Type to return.

Let's register a field that returns the PetUnion Type to see how this works:

add_action( 'graphql_register_types', function() {

 register_graphql_field( 'RootQuery', 'myPets', [
    'description' => __( 'My pets (could be dogs or cats)', 'your-textdomain' ),
    'type' => [ 'list_of' => 'PetUnion' ],
    'resolve' => function() {
        // You would probably get data from a database or remote API here, but we're
        // just going to return hard coded data
        $pets = [
          [
            'type' => 'dog',
            'name' => 'Bender',
            'age' => 3,
            'breed' => 'Golden Retriever',
          ],
          [
            'type' => 'cat',
            'name' => 'Speckles',
            'age' => 2,
            'isHighOnCatnip' => true,
          ],
        ];

        return $pets;
    }
 ] );
});

Now we have a myPets field on our RootQuery that returns a list of Pets. The Pets could either be a Dog or Cat, and depending on which Type of animal it is, we can ask for different fields.

Now, we can query like so:

{
	myPets {
		__typename
		... on Dog {
			name
			age
		}
		... on Cat {
			name
			isHighOnCatnip
		}
	}
}

And we'll receive the following data:

{
	"data": {
		"myPets": [
			{
				"__typename": "Dog",
				"name": "Bender",
				"age": 3,
				"breed": "Golden Retriever"
			},
			{
				"__typename": "Cat",
				"name": "Speckles",
				"isHighOnCatnip": true
			}
		]
	}
}

Scalar Types

WPGraphQL doesn't have a formal mechanism (yet) for registering new Scalar Types. Coming Soon!

Interfaces

WPGraphQL doesn't have a formal mechanism (yet) for registering new Interface Types. Coming Soon!

Input Types

@todo: need to document

Edit on GitHub

Register GraphQL Types

Edit on GitHub

Discuss on Spectrum