Archives: Recipes

  • Making Menus and Menu Items public

    By default, Menus and Menu Items that are not assigned to a Menu Location are considered private, meaning they are not exposed in non-authenticated WPGraphQL Queries.

    If you want to expose Menus and Menu Items that are not assigned to menu locations to public GraphQL Queries, you can use the following snippet:

    add_filter( 'graphql_data_is_private', function( $is_private, $model_name, $data, $visibility, $owner, $current_user ) {
    
    	if ( 'MenuObject' === $model_name || 'MenuItemObject' === $model_name ) {
    		return false;
    	}
    	
    	return $is_private;
    
    }, 10, 6 );
  • Add Edit Link to All Post Types

    The following snippet shows how to add the “Edit” link as a GraphQL field to all post types:

    add_action( 'graphql_register_types', function() {
    
    	register_graphql_field( 'ContentNode', 'editLink', [
    		'type' => 'String',
    		'description' => __( 'Link to edit the content', 'your-textdomain' ),
    		'resolve' => function( \WPGraphQL\Model\Post $post, $args, $context, $info ) {
    		   return get_edit_post_link( $post->databaseId );
    		}
    	]);
    
    } );

    This could then be queried like so:

    Screenshot of a GraphQL Query for posts with their editLink
    Screenshot of a GraphQL Query for posts with their editLink
  • Changing the Server Debug Flag

    The following snippets show how to change the Debug Flag for the GraphQL Server execution.

    By default, the function callstack trace is not included with errors data unless users are logged in.

    If you wanted to track this data on the server, for example, even for public requests, and send the data to a logging service, for example, you could enable the call stack with the following snippet. (Just make sure you _also_ cleanup the errors after the fact so you don’t expose too much data to public users.)

    add_action( 'graphql_server_config', function( \GraphQL\Server\ServerConfig $config ) {
    	$config->setDebugFlag( 1 );
    });

    Example of the Error Trace when the debug flag is set to 1

    There is no callstack trace with the error.

    Example of the Error Trace when the debug flag is set to 2

    add_action( 'graphql_server_config', function( \GraphQL\Server\ServerConfig $config ) {
    	$config->setDebugFlag( 2 );
    });

    There is a callstack trace included with the error.

  • Add field to output URLs for Sitemap

    The following code is an example of how you can create a field called allUrls that will output site URLs that could be used to generate a sitemap.

    The resolver uses mostly hard-coded data, but shows what a potential solution could look like.

    add_action( 'graphql_register_types', function() {
    
    	register_graphql_field( 'RootQuery', 'allUrls', [
    		'type' => [ 'list_of' => 'String' ],
    		'description' => __( 'A list of all urls. Helpful for rendering sitemaps', 'your-textdomain' ),
    		'resolve' => function() {
    
    			// Start collecting all URLS
    			$meta_urls = array( get_home_url() );
    
                            // Hardcoded array. You would need to fetch the URLs for all Posts
    			$all_posts = [ 'site.com/post', 'site.com/post-2' ];
    
                            // Hardcoded array. You would need to fetch the URLs for all Terms
    			$all_terms = [ 'site.com/tag', 'site.com/category' ];
    
    			return array_merge($meta_urls, $all_posts, $all_terms);
    
    		}
    	]  );
    
    });

    You can then query this field using:

    {
      allUrls
    }
    Querying the allUrls field in GraphiQL
  • Register Connection to Attached Media

    This code shows how to register a connection to attached media in WPGraphQL

    add_action( 'graphql_register_types', function() {
    
    	register_graphql_connection([
    		'fromType' => 'ContentNode',
    		'toType' => 'MediaItem',
    		'fromFieldName' => 'attachedMedia',
    		'connectionArgs' => \WPGraphQL\Connection\PostObjects::get_connection_args(),
    		'resolve' => function( \WPGraphQL\Model\Post $source, $args, $context, $info ) {
    			$resolver = new \WPGraphQL\Data\Connection\PostObjectConnectionResolver( $source, $args, $context, $info, 'attachment' );
    			$resolver->set_query_arg( 'post_parent', $source->ID );
    			return $resolver->get_connection();
    		}
    	]);
    
    } );

    You can then query for this new connection using the attachedMedia field on a ContentNode:

    {
      contentNodes {
        nodes {
          ... on NodeWithTitle {
            title
          }
          attachedMedia {
            nodes {
              id
              title
            }
          }
        }
      }
    }
  • Register GraphQL Field with Argument

    This is an example of registering a field with an argument showing how to use the argument in a resolver.

    add_action( 'graphql_register_types', function() {
    
    	register_graphql_field( 'RootQuery', 'myNewField', [
    		'type' => 'String',
    		'args' => [
    			'myArg' => [
    				'type' => 'String',
                                    'description' => __( 'Description for how the argument will impact the field resolver', 'your-textdomain' ),
    			],
    		],
    		'resolve' => function( $source, $args, $context, $info ) {
    			if ( isset( $args['myArg'] ) ) {
    				return 'The value of myArg is: ' . $args['myArg'];
    			}
    			return 'test';
    		},
    	]);
    
    });

    This will register a new field (myNewField ) to the RootQuery, and adds an argument to the field (myArg). The resolve function checks to see if that arg is set, and if so, it returns the value, if not it returns test.

    We can query this like so:

    query {
      myNewField
    }

    And the results will be:

    {
      "data": {
        "myNewField": "test"
      }
    }

    Now, we can pass a value to the argument like so:

    query {
      myNewField( myArg: "something" )
    }

    and the results will be:

    {
      "data": {
        "myNewField": "The value of myArg is: something"
      }
    }

    Now, you can introduce variables like so:

    query MyQuery($myArg:String) {
      myNewField( myArg: $myArg )
    }

    And then you can pass variables to the request. Here’s an example of using a variable in GraphiQL:

    Custom field with an argument and variable in GraphiQL
  • Register field as a list of strings

    The below code registers a field called listOfStrings that returns a list of strings as the result:

    add_action( 'graphql_register_types', function() {
    
    	register_graphql_field( 'RootQuery', 'listOfStrings', [
    		'type' => [ 'list_of' => 'String' ],
    		'resolve' => function() {
    			return [
    				'String One',
    				'String Two'
    			];
    		}
    	] );
    
    } );

    This field can now be queried:

    {
      listOfStrings
    }
    ListOfStrings field results displayed in GraphiQL
  • Register object and field for custom list of users

    The following code creates an object type called StuntPerformer and creates a field on the RootQuery called stuntPerformers that returns a custom list of users.

    In this case, the list of users are the admins of the website, but custom logic could be added to return a curated list of users.

    add_action( 'graphql_register_types', function() {
    
    	register_graphql_object_type(
    		'StuntPerformer',
    		[
    			'description' => __( 'Stunt Performer', 'bsr' ),
    			'fields'      => [
    				'firstName' => [
    					'type'        => 'String',
    					'description' => 'first name'
    				],
    				'lastName'  => [
    					'type'        => 'String',
    					'description' => 'last name'
    				],
    				'uid'       => [
    					'type'        => 'String',
    					'description' => 'user id'
    				]
    			],
    		]
    	);
    
    	register_graphql_field(
    		'RootQuery',
    		'stuntPerformers',
    		[
    			'description' => __( 'Return stunt performers', 'bsr' ),
    			'type'        => [ 'list_of' => 'stuntPerformer' ],
    			'resolve'     => function() {
    				$stunt_performers = [];
    				$performers       = get_users( array(
    					'role__in' => 'administrator'
    				) );
    
    				foreach ( $performers as $p ) {
    					$performer = [
    						'firstName' => $p->first_name,
    						'lastName'  => $p->last_name,
    						'uid'       => $p->ID
    					];
    
    					$stunt_performers[] = $performer;
    				}
    
    				return $stunt_performers;
    			}
    		]
    	);
    
    } );

    You can now query for these stuntPerformers with the following GraphQL:

    {
      stuntPerformers {
        firstName
        lastName
        uid
      } 
    }
    Stunt Performers query in GraphiQL
  • Using GraphQL Fragments in PHP

    You can execute GraphQL queries in PHP. In this case, we even show using a GraphQL Fragment.

    add_action( 'init', function() {
    
    	$results = graphql([
    		'query' => '
    		{
    		  posts {
    		    nodes {
    		      ...PostFields
    		    }
    		  }
    		}
    		fragment PostFields on Post {
    		  id
    		  title
    		}
    		',
    	]);
    
    	var_dump( $results );
    	die();
    
    } );

    Executing this code leads to the following output:

    PHP output of executing Graphql

    Additionally, if you were to define your fragment in another file, such as the file that is rendering the data, you can define fragments as variables and concatenate them like so:

    $fragment = '
      fragment PostFields on Post {
        id
        title
    }
    ';
    
    $results = graphql([
      'query' => '
        {
          posts {
            nodes {
    	  ...PostFields
    	}
          }
        }
      ' . $fragment ,
    ]);
  • Update WPGraphQL Endpoint URL

    You can modify the WPGraphQL endpoint in code with the following:

    function my_new_graphql_endpoint() {
      return 'cutepuppies';
    };
    
    add_filter( 'graphql_endpoint', 'my_new_graphql_endpoint' );

    This will change the graphql endpoint url from /graphql to /cutepuppies

    This also updates the WPGraphQL settings page:

    WPGraphQL Settings page with updated endpoint url