WiFi

DFMguest | DFMvisitor

WORKSHOP TOOLS

• Local WordPress Install

• WPGraphQL plugin, activated, permalinks flushed

WPGraphiQL plugin activated (or GraphiQL Desktop App)

• Code / Text Editor

Content Syndication 

With the WP REST API and WPGraphQL

Content Syndication 

With the WP REST API and WPGraphQL


 




WordCamp for Publishers 2017

Jason Bahl | @jasonbahl

Who Am I?

  • Senior WordPress Engineer at Digital First Media
     
  • Denver Native
     
  • WordPress Developer for 9+ years
  • Creator / Maintainer of WPGraphQL

Workshop Overview

  • How Digital First Media uses the WP REST API to syndicate content at scale, and lessons learned

     
  • Intro to GraphQL

     
  • Hands on with WPGraphQL

Content Syndication

Powered by the WP REST API

  • Push Syndication
  • Pull Syndication
  • Distributed Client Syndication

Push Syndication

  • Content originates in one system and is pushed to other systems
     

  • Our "Hub" validates the data and checks the syndication rules, and sends the data to it's final destination

Push Syndication

Pull Syndication

  • Content originates in an external system and is "pulled" into the user's system.
     

  • Users browse remote articles
    • click "Import"
    • article is fetched from the external system
    • article is imported into the user's system

Pull Syndication

{
    "id": 123,
    "date": "2017-08-09T13:39:18",
    "date_gmt": "2017-08-09T18:39:18",
    "guid": {
        "rendered": "http://www.denverpost.com/?p=123"
    },
    "modified": "2017-08-10T17:16:57",
    "modified_gmt": "2017-08-10T22:16:57",
    "slug": "article-title",
    "status": "publish",
    "type": "post",
    "link": "https://poststatus.com/article-title/",
    "title": {
        "rendered": "Article Title"
    },
    "content": {
        "rendered": "Some content",
    },
    ...
}

By the Numbers

Push / Pull Syndication at DFM

540,096

Articles syndicated across 9 WordPress sites since

 

Feb 2016 - May 2017
*not including article updates, media or other connected entities

~1,280

Articles syndicated each day

 

Distributed Client Syndication

  • Content is fetched from remote system and displayed by the client
     

  • The content is only represented by the client system, not duplicated in another data store

Distributed Client Syndication

{
    "id": 123,
    "date": "2017-08-09T13:39:18",
    "date_gmt": "2017-08-09T18:39:18",
    "guid": {
        "rendered": "http://www.denverpost.com/?p=123"
    },
    "modified": "2017-08-10T17:16:57",
    "modified_gmt": "2017-08-10T22:16:57",
    "slug": "article-title",
    "status": "publish",
    "type": "post",
    "link": "https://poststatus.com/article-title/",
    "title": {
        "rendered": "Article Title"
    },
    "content": {
        "rendered": "Some content",
    },
    ...
}

What We've Learned

About Syndicating Content with REST

What We've Learned

About Syndicating Content with REST

  • Designing a REST API is hard
  • Constantly over fetching and under fetching
  • Lots and lots of HTTP requests
  • Tight client-server coupling
  • Implicit Requests Make Maintenance Difficult
  • Maintaining Documentation
  • Versioning is difficult

Designing a REST API is hard

5,207 bytes

4,725 bytes

5,823 bytes

Over / Under Fetching

{
  "data": {
    "articles": [
      {
        "author": {
          "avatar": {
            "url": "http://gravatar.com/?id=123&w=50"
          },
          "name": "Hillary",
          "link": "http://hillarys-site.com",
          "followLink": "http://example.com/?follow_author=1"
        },
        "title": "The Bookshop, by Penelope Fitzgerald",
        "link": "http://example.com/article-path",
        "excerpt": "I am very much enjoying...",
        "publication": {
          "name": "Vulpes Libris",
          "link": "http://example-publication.com"
        }
      }
    ]
  }
}
GET /posts
{
  "id": 38424,
  "date": "2017-08-09T13:39:18",
  "date_gmt": "2017-08-09T18:39:18",
  "guid": {
    "rendered": "https://example.com/?p=38424"
  },
  "modified": "2017-08-10T17:16:57",
  "modified_gmt": "2017-08-10T22:16:57",
  "slug": "publish-conference-pictures",
  "status": "publish",
  "type": "post",
  "link": "https://example.com/publish-conference-pictures/",
  "title": {
    "rendered": "The Bookshop, by Penelope Fitzgerald"
  },
  "content": {
    "rendered": "<p>I am very much enjoying...Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.</p>\n<p>Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.</p>\n<p>Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.</p>\n<p>
Podcasting operational change management inside of workflows to establish a framework. Taking seamless key performance indicators offline to maximise the long tail. Keeping your eye on the ball while performing a deep dive on the start-up mentality to derive convergence on cross-platform integration.</p>\n<p>Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI.</p>\n<p>Efficiently unleash cross-media information without cross-media value. Quickly maximize timely deliverables for real-time schemas. Dramatically maintain clicks-and-mortar solutions without functional solutions.</p>\n<p>Completely synergize resource taxing relationships via premier niche markets. Professionally cultivate one-to-one customer service with robust ideas. Dynamically innovate resource-leveling customer service for state of the art customer service.</p>\n<p>Objectively innovate empowered manufactured products whereas parallel platforms. Holisticly predominate extensible testing procedures for reliable supply chains. Dramatically engage top-line web services vis-a-vis cutting-edge deliverables.</p><p>Proactively envisioned multimedia based expertise and cross-media growth strategies. Seamlessly visualize quality intellectual capital without superior collaboration and idea-sharing. Holistically pontificate installed base portals after maintainable products.</p><p>Phosfluorescently engage worldwide methodologies with web-enabled technology. Interactively coordinate proactive e-commerce via process-centric "outside the box" thinking. Completely pursue scalable customer service through sustainable potentialities.</p>",
    "protected": false
  },
  "excerpt": {
    "rendered": "<p>I am very much enjoying...Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.</p>\n",
    "protected": false
  },
  "author": 1,
  "featured_media": 38425,
  "comment_status": "open",
  "ping_status": "closed",
  "sticky": false,
  "template": "",
  "format": "standard",
  "meta": [

  ],
  "categories": [
    6,
    196
  ],
  "tags": [
    178
  ],
  "_links": {
    "self": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts/38424"
      }
    ],
    "collection": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts"
      }
    ],
    "about": [
      {
        "href": "https://example.com/wp-json/wp/v2/types/post"
      }
    ],
    "author": [
      {
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/users/1"
      }
    ],
    "replies": [
      {
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/comments?post=38424"
      }
    ],
    "version-history": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts/38424/revisions"
      }
    ],
    "wp:featuredmedia": [
      {
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/media/38425"
      }
    ],
    "wp:attachment": [
      {
        "href": "https://example.com/wp-json/wp/v2/media?parent=38424"
      }
    ],
    "wp:term": [
      {
        "taxonomy": "category",
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/categories?post=38424"
      },
      {
        "taxonomy": "post_tag",
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/tags?post=38424"
      },
      {
        "taxonomy": "yst_prominent_words",
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/yst_prominent_words?post=38424"
      }
    ],
    "curies": [
      {
        "name": "wp",
        "href": "https://api.w.org/{rel}",
        "templated": true
      }
    ]
  }
}
GET /posts

foreach post:
 GET /post/:id/:author
 GET /author/:id/avatar
 GET /post/:id/publication

Over / Under Fetching

  • Individual REST payloads very rarely include exactly what you need
  • Extra, unnecessary data passing over the network
    • Can lead to performance issues, especially on mobile networks

Common ways to fight Over / Under Fetching

  • Make more HTTP requests to get the resources you need?
    • Waaaay more data than is needed (performance issues)
  • Build feature-specific endpoints
    • Creates tight client / server coupling (hard to maintain/version)
  • WP REST API Embeds?
    • Waaaay more data than is needed (performance issues)
    • No way to specify what you want from the embedded objects
  • Ad-hoc filters via query params ?

Maintaining Implicit Requests Over Time

  • GET /posts
  • GET /authors
  • GET /sites
  • GET /publications
  • GET /tags
  • GET /categories

Implicit Requests / Versioning / Documentation

  • Consuming code isn't explicit
    • No idea what is coming back in the payload, so you need to look at the REST documentation again and again
  • Server doesn't know what fields are being used
    • Hard to deprecate fields
    • leads to versioned endpoints
      • leads to duplicate code / technical debt
      • leads to undocumented endpoints
  • GET /posts
  • GET /posts/:id
  • GET /authors
  • GET /authors/:id
  • Constantly over fetching and under fetching
  • Lots and lots of HTTP requests
  • Tight client-server coupling
  • Implicit Requests Make Maintenance Difficult
  • Maintaining Documentation
  • Versioning is difficult
  • Fetch exactly what you need, nothing more, nothing less
  • Multiple resources in a single HTTP request
  • Decoupled client-server relationship
  • Explicit requests ease maintenance
  • Self Documenting Schema / Type System
  • Easy, pain free versioning

GraphQL

A Query Language for your API

GraphQL is a query language for APIs and a runtime for fulfilling those
queries with your existing data. GraphQL provides a complete
and understandable description of the data in your API, gives
clients the power to ask for exactly what they need
and nothing more, makes it easier to evolve APIs over time,
and enables powerful developer tools

GraphQL

Graph != Graph Databases

Graph != Graph Search

Graph = Application Data Graph

QL = Query Language

GraphQL: A Query Language for Your Application Data Graph

Post

Category

Category

Category

Post

title

"Hello World"

title

"GoodBye Mars"

Image

Image

Image

name

"news"

name

"crime"

name

"sports"

Image

GraphQL

GraphQL lets us pick trees out of the Application Data Graph

GraphQL

query {
  post(id: "...") {
    title
    link
    coauthors {
      name
    }
  }
}
{
  data: {
    post: {
      title: "Hello World!"
      link: "http://site.com/hello-world"
      coauthors: [
        {
          name: "John Doe",
        },
        {
          name: "Jane Smith",
        }
      ]
    }
  }
}

GraphQL

Post

CoAuthor

CoAuthor

CoAuthor

Post

Featured

Image

title

"Hello World"

title

"GoodBye Mars"

Avatar

Avatar

Avatar

name

"jane doe"

name

"sue smith"

name

"john doe"

GraphQL

GET /post/:id

{
  "id": 38424,
  "date": "2017-08-09T13:39:18",
  "date_gmt": "2017-08-09T18:39:18",
  "guid": {
    "rendered": "https://example.com/?p=38424"
  },
  "modified": "2017-08-10T17:16:57",
  "modified_gmt": "2017-08-10T22:16:57",
  "slug": "publish-conference-pictures",
  "status": "publish",
  "type": "post",
  "link": "https://example.com/publish-conference-pictures/",
  "title": {
    "rendered": "The Bookshop, by Penelope Fitzgerald"
  },
  "content": {
    "rendered": "<p>I am very much enjoying...Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.</p>\n<p>Bring to the table win-win survival strategies to ensure proactive domination. At the end of the day, going forward, a new normal that has evolved from generation X is on the runway heading towards a streamlined cloud solution. User generated content in real-time will have multiple touchpoints for offshoring.</p>\n<p>Capitalize on low hanging fruit to identify a ballpark value added activity to beta test. Override the digital divide with additional clickthroughs from DevOps. Nanotechnology immersion along the information highway will close the loop on focusing solely on the bottom line.</p>\n<p>
Podcasting operational change management inside of workflows to establish a framework. Taking seamless key performance indicators offline to maximise the long tail. Keeping your eye on the ball while performing a deep dive on the start-up mentality to derive convergence on cross-platform integration.</p>\n<p>Collaboratively administrate empowered markets via plug-and-play networks. Dynamically procrastinate B2C users after installed base benefits. Dramatically visualize customer directed convergence without revolutionary ROI.</p>\n<p>Efficiently unleash cross-media information without cross-media value. Quickly maximize timely deliverables for real-time schemas. Dramatically maintain clicks-and-mortar solutions without functional solutions.</p>\n<p>Completely synergize resource taxing relationships via premier niche markets. Professionally cultivate one-to-one customer service with robust ideas. Dynamically innovate resource-leveling customer service for state of the art customer service.</p>\n<p>Objectively innovate empowered manufactured products whereas parallel platforms. Holisticly predominate extensible testing procedures for reliable supply chains. Dramatically engage top-line web services vis-a-vis cutting-edge deliverables.</p><p>Proactively envisioned multimedia based expertise and cross-media growth strategies. Seamlessly visualize quality intellectual capital without superior collaboration and idea-sharing. Holistically pontificate installed base portals after maintainable products.</p><p>Phosfluorescently engage worldwide methodologies with web-enabled technology. Interactively coordinate proactive e-commerce via process-centric "outside the box" thinking. Completely pursue scalable customer service through sustainable potentialities.</p>",
    "protected": false
  },
  "excerpt": {
    "rendered": "<p>I am very much enjoying...Leverage agile frameworks to provide a robust synopsis for high level overviews. Iterative approaches to corporate strategy foster collaborative thinking to further the overall value proposition. Organically grow the holistic world view of disruptive innovation via workplace diversity and empowerment.</p>\n",
    "protected": false
  },
  "author": 1,
  "featured_media": 38425,
  "comment_status": "open",
  "ping_status": "closed",
  "sticky": false,
  "template": "",
  "format": "standard",
  "meta": [

  ],
  "categories": [
    6,
    196
  ],
  "tags": [
    178
  ],
  "_links": {
    "self": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts/38424"
      }
    ],
    "collection": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts"
      }
    ],
    "about": [
      {
        "href": "https://example.com/wp-json/wp/v2/types/post"
      }
    ],
    "author": [
      {
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/users/1"
      }
    ],
    "replies": [
      {
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/comments?post=38424"
      }
    ],
    "version-history": [
      {
        "href": "https://example.com/wp-json/wp/v2/posts/38424/revisions"
      }
    ],
    "wp:featuredmedia": [
      {
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/media/38425"
      }
    ],
    "wp:attachment": [
      {
        "href": "https://example.com/wp-json/wp/v2/media?parent=38424"
      }
    ],
    "wp:term": [
      {
        "taxonomy": "category",
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/categories?post=38424"
      },
      {
        "taxonomy": "post_tag",
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/tags?post=38424"
      },
      {
        "taxonomy": "yst_prominent_words",
        "embeddable": true,
        "href": "https://example.com/wp-json/wp/v2/yst_prominent_words?post=38424"
      }
    ],
    "curies": [
      {
        "name": "wp",
        "href": "https://api.w.org/{rel}",
        "templated": true
      }
    ]
  }
}

GET /users/1

{

  "id": 1,
  "name": "Jane Doe",
  "url": "https://example.com",
  "description": "I'm a WordPress developer from Birmingham, Alabama. I'm the creator and editor of Post Status.",
  "link": "https://poststatus.com/profiles/brian-krogsgard/",
  "slug": "jane-doe",
  "avatar_urls": {
    "24": "https://secure.gravatar.com/avatar/6b89515a9781282ae3a66d4b6173523c?s=24&d=mm&r=g",
    "48": "https://secure.gravatar.com/avatar/6b89515a9781282ae3a66d4b6173523c?s=48&d=mm&r=g",
    "96": "https://secure.gravatar.com/avatar/6b89515a9781282ae3a66d4b6173523c?s=96&d=mm&r=g"
  },
  "meta": [
    
  ],
  "_links": {
    "self": [
      {
        "href": "https://poststatus.com/wp-json/wp/v2/users/1"
      }
    ],
    "collection": [
      {
        "href": "https://poststatus.com/wp-json/wp/v2/users"
      }
    ]
  }
}

GET /users/2

{

  "id": 2,
  "name": "John Doe",
  "url": "https://example.com",
  "description": "I'm a WordPress developer from Birmingham, Alabama. I'm the creator and editor of Post Status.",
  "link": "https://poststatus.com/profiles/brian-krogsgard/",
  "slug": "john-doe",
  "avatar_urls": {
    "24": "https://secure.gravatar.com/avatar/6b89515a9781282ae3a66d4b6173523c?s=24&d=mm&r=g",
    "48": "https://secure.gravatar.com/avatar/6b89515a9781282ae3a66d4b6173523c?s=48&d=mm&r=g",
    "96": "https://secure.gravatar.com/avatar/6b89515a9781282ae3a66d4b6173523c?s=96&d=mm&r=g"
  },
  "meta": [
    
  ],
  "_links": {
    "self": [
      {
        "href": "https://poststatus.com/wp-json/wp/v2/users/1"
      }
    ],
    "collection": [
      {
        "href": "https://poststatus.com/wp-json/wp/v2/users"
      }
    ]
  }
}

5,460 bytes

819 bytes

819 bytes

(sample payloads from poststatus.com)

GraphQL

query {
  post(id: "...") {
    title
    link
    coauthors {
      name
    }
  }
}
{
  data: {
    post: {
      title: "Hello World!"
      link: "http://site.com/hello-world"
      coauthors: [
        {
          name: "John Doe",
        },
        {
          name: "Jane Smith",
        }
      ]
    }
  }
}

231 bytes

GraphQL

REST

  • 3 network requests
  • Bytes Downloaded: 7,240
  • Lots of consumer transformation needed

GraphQL

  • 1 network request
  • Bytes Downloaded: 231
  • No consumer transformation needed
            
query { 
  posts {
    edges {
      node {



        














      }
    }
  }
}
            
        
            
        author {
       name
       avatar(size: 50) {
         url
       }
     }

            
        
            
                        followLink

            
        
            
                        title

            
        
            
                        featuredImage(width: 300) {
   url
}

            
        
            
                        excerpt

            
        
            
        site {
       name
       link
     }

            
        

GraphQL

WPGraphQL

A Query Language for your WordPress API

GraphQL

A Query Language for your API

GraphQL is a query language for APIs and a runtime for fulfilling those
queries with your existing data. GraphQL provides a complete
and understandable description of the data in your API, gives
clients the power to ask for exactly what they need
and nothing more, makes it easier to evolve APIs over time,
and enables powerful developer tools

WPGraphQL is an extendable open-source WordPress plugin that brings the power of GraphQL to your WordPress install. WPGraphQL defines GraphQL Types for core WordPress entities, such as posts, terms and users, and defines core entry points into the WordPress Application Data Graph via GraphQL Queries and Mutations. WPGraphQL gives clients the power to ask for exactly what they need from WordPress and enables powerful developer tools.

  • Download the plugin from Github
  • Add to your WordPress install
    • /wp-content/plugins
  • Activate the plugin
  • Flush the permalinks

Using the Plugin

GraphiQL Desktop App

https://github.com/skevy/graphiql-app

brew cask install graphiql

Tools to Run Queries

WPGraphiQL

https://github.com/wp-graphql/wp-graphiql

Download, install & activate plugin, navigate to GraphiQL in the WordPress Dashboard

  • explore GraphQL Documentation

  • query a list of posts

  • query nested resources

  • query multiple root resources

  • using the node query

  • using query fragments with GraphQL

  • using aliases with GraphQL

  • use variables with GraphQL

  • queries with variables and pagination

  • mutation - createPost

Exploring WPGraphQL

GraphQL Tooling

Let's build a plugin!

Extending WPGraphQL

<?php
/**
 * Plugin Name: WPGraphQL WordCamp Publishers Extension
 * Description: Plugin that extends WPGraphQL
 */
  • Create a new directory
    • /plugins/wpgraphql-wordcamp-publishers
  • Create a new plugin file
    • wpgraphql-wordcamp-publishers.php

Add a Root Entry Point

Extending WPGraphQL

Add a Root Entry Point

Extending WPGraphQL

add_action( 'graphql_root_queries', function( $fields ) {
	$fields['wordCampRocks'] = [
		'type' => \WPGraphQL\Types::string(),
		'description' => __( 'An example field showing how to add 
                                to the root schema', 'wp-graphql-publishers' ),
		'resolve' => function() {
			return 'Yes, it does';
		},
	];
	return $fields;
} );

Add a Field to the Post Schema

Extending WPGraphQL

Add a Field to the Post Schema

Extending WPGraphQL

add_action( 'graphql_post_fields', function( $fields ) {
	$fields['color'] = [
		'type' => \WPGraphQL\Types::string(),
		'description' => __( 'An example showing how to add a 
                                field to the "post" schema', 'wp-graphql-publishers' ),
		'resolve' => function( \WP_Post $post ) {
			return get_post_meta( $post->ID, 'color', true );
		},
	];
	return $fields;
}, 10, 1);

Add Custom Post Type to the Schema

Extending WPGraphQL

Add Custom Post Type to the Schema

Extending WPGraphQL

add_action( 'init', function() {
	register_post_type( 'book', [
		'label' => __( 'Books', 'wp-graphql-publishers' ),
		'supports' => [ 'title', 'editor', 'custom-fields' ],
		'public' => true,
		'show_in_graphql' => true,
		'graphql_single_name' => 'book',
		'graphql_plural_name' => 'books',
	] );
} );

Add Custom Taxonomy to the Schema

Extending WPGraphQL

Add Custom Taxonomy to the Schema

Extending WPGraphQL

add_action( 'init', function() {
	register_taxonomy( 'genre', 'book', [
		'label' => __( 'Genre' ),
		'public' => true,
		'show_in_graphql' => true,
		'graphql_single_name' => 'genre',
		'graphql_plural_name' => 'genres',
		'hierarchical' => true,
	]);
} );

Add a Custom Field with Mutation Support

Extending WPGraphQL

Add a Custom Field with Mutation Support

Extending WPGraphQL

add_action( 'graphql_book_fields', function( $fields ) {
	$fields['price'] = [
		'type' => \WPGraphQL\Types::string(),
		'description' => __( 'The price of the book', 'wp-graphql-publishers' ),
		'resolve' => function( \WP_Post $book ) {
			$price = get_post_meta( $book->ID, 'price', true );
			return ! empty( $price ) ? $price : null;
		},
	];
	return $fields;
}, 10, 1);

1. Add the field to the type

Add a Custom Field with Mutation Support

Extending WPGraphQL

add_action( 'graphql_post_object_mutation_input_fields', function( $fields, \WP_Post_Type $post_type_object ) {
	if ( 'book' === $post_type_object->name ) {
		$fields['price'] = [
			'type'        => \WPGraphQL\Types::string(),
			'description' => __( 'The price of the book', 'wp-graphql-publishers' ),
		];
	}
	return $fields;
}, 10, 2 );

2. Add the input field to the mutation input

Add a Custom Field with Mutation Support

Extending WPGraphQL

add_action( 'graphql_post_object_mutation_update_additional_data', 'prefix_update_price', 10, 3 );

function prefix_update_price( $post_id, $input, \WP_Post_Type $post_type_object ) {
	if ( 'book' === $post_type_object->name && ! empty( $input['price'] ) ) {
		update_post_meta( $post_id, 'price', $input['price'] );
	}
}

3. Add the input field to the mutation input

Add a Custom Field with Mutation Support

Extending WPGraphQL

add_action( 'graphql_post_object_mutation_input_fields', function( $fields, \WP_Post_Type $post_type_object ) {
	if ( 'book' === $post_type_object->name ) {
		$fields['price'] = [
			'type'        => \WPGraphQL\Types::string(),
			'description' => __( 'The price of the book', 'wp-graphql-publishers' ),
		];
	}
	return $fields;
}, 10, 2 );

2. Add the input type

Content Syndication

By Jason Bahl

Content Syndication

  • 4,825