😍My First WPGraphQL Extension

Testing Your First Extension

wp-content\plugins\my-first-wpgraphql-extension\my-first-wpgraphql-extension.php

<?php
/**
 * Plugin Name: My First WPGraphQL Extension
 * Plugin URI: https://github.com/wp-graphql/wp-graphql
 * GitHub Plugin URI: https://github.com/wp-graphql/wp-graphql
 * Description: A tutorial plugin demonstrating WPGraphQL extension development
 * Author: WPGraphQL
 * Author URI: http://www.wpgraphql.com
 * Version: 1.31.1
 * Text Domain: wp-graphql
 * Domain Path: /languages/
 * Requires at least: 5.9
 * Tested up to: 6.7.1
 * Requires PHP: 7.1
 * License: GPL-3
 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package  WPGraphQL
 * @category Core
 * @author   WPGraphQL
 * @version  1.31.1
 */
// Prevent direct access to this file
if (! defined('ABSPATH')) {
  die('Unauthorized access!');
}
add_action('graphql_register_types', function () {
  // Register a custom type
  register_graphql_object_type('CustomType', [
    'description' => __('An example custom type demonstrating schema extension', 'my-graphql-extension'),
    'fields' => [
      'message' => [
        'type' => 'String',
        'description' => __('A simple message field', 'my-graphql-extension'),
      ],
      'number' => [
        'type' => 'Int',
        'description' => __('A simple number field', 'my-graphql-extension'),
      ],
    ],
  ]);
  // Register a field that returns our custom type
  register_graphql_field('RootQuery', 'example', [
    'type' => 'CustomType',
    'description' => __('An example field returning our custom type', 'my-graphql-extension'),
    'resolve' => function () {
      return [
        'message' => 'Hello from your first WPGraphQL extension!',
        'number' => 42,
      ];
    }
  ]);
});

Working with WordPress Options

<?php
/**
 * Plugin Name: My First WPGraphQL Extension
 * Plugin URI: https://github.com/wp-graphql/wp-graphql
 * GitHub Plugin URI: https://github.com/wp-graphql/wp-graphql
 * Description: A tutorial plugin demonstrating WPGraphQL extension development
 * Author: WPGraphQL
 * Author URI: http://www.wpgraphql.com
 * Version: 1.31.1
 * Text Domain: wp-graphql
 * Domain Path: /languages/
 * Requires at least: 5.9
 * Tested up to: 6.7.1
 * Requires PHP: 7.1
 * License: GPL-3
 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package  WPGraphQL
 * @category Core
 * @author   WPGraphQL
 * @version  1.31.1
 */
// Prevent direct access to this file
if (! defined('ABSPATH')) {
  die('Unauthorized access!');
}
add_action('graphql_register_types', function () {
  // Register a custom type
  register_graphql_object_type('CustomType', [
    'description' => __('An example custom type demonstrating schema extension', 'my-graphql-extension'),
    'fields' => [
      'message' => [
        'type' => 'String',
        'description' => __('A simple message field', 'my-graphql-extension'),
      ],
      'number' => [
        'type' => 'Int',
        'description' => __('A simple number field', 'my-graphql-extension'),
      ],
    ],
  ]);
  // Register a field that returns our custom type
  register_graphql_field('RootQuery', 'example', [
    'type' => 'CustomType',
    'description' => __('An example field returning our custom type', 'my-graphql-extension'),
    'resolve' => function () {
      return [
        'message' => 'Hello from your first WPGraphQL extension!',
        'number' => 42,
      ];
    }
  ]);
});
add_action( 'graphql_register_types', function() {
  register_graphql_field( 'RootQuery', 'siteCustomSetting', [
    'type' => 'String',
    'description' => __( 'A custom site setting', 'my-graphql-extension' ),
    'resolve' => function() {
      // Basic capability check
      if ( ! current_user_can( 'read' ) ) {
        throw new \GraphQL\Error\UserError( 'You do not have permission to access this setting' );
      }
      return get_option( 'my_custom_setting', 'default value' );
    }
  ]);
});

Custom Settings Type

wp-content\plugins\my-first-wpgraphql-extension\my-first-wpgraphql-extension.php

<?php
/**
 * Plugin Name: My First WPGraphQL Extension
 * Plugin URI: https://github.com/wp-graphql/wp-graphql
 * GitHub Plugin URI: https://github.com/wp-graphql/wp-graphql
 * Description: A tutorial plugin demonstrating WPGraphQL extension development
 * Author: WPGraphQL
 * Author URI: http://www.wpgraphql.com
 * Version: 1.31.1
 * Text Domain: wp-graphql
 * Domain Path: /languages/
 * Requires at least: 5.9
 * Tested up to: 6.7.1
 * Requires PHP: 7.1
 * License: GPL-3
 * License URI: https://www.gnu.org/licenses/gpl-3.0.html
 *
 * @package  WPGraphQL
 * @category Core
 * @author   WPGraphQL
 * @version  1.31.1
 */
// Prevent direct access to this file
if (! defined('ABSPATH')) {
  die('Unauthorized access!');
}
add_action('graphql_register_types', function () {
  // Register a custom type
  register_graphql_object_type('CustomType', [
    'description' => __('An example custom type demonstrating schema extension', 'my-graphql-extension'),
    'fields' => [
      'message' => [
        'type' => 'String',
        'description' => __('A simple message field', 'my-graphql-extension'),
      ],
      'number' => [
        'type' => 'Int',
        'description' => __('A simple number field', 'my-graphql-extension'),
      ],
    ],
  ]);
  // Register a field that returns our custom type
  register_graphql_field('RootQuery', 'example', [
    'type' => 'CustomType',
    'description' => __('An example field returning our custom type', 'my-graphql-extension'),
    'resolve' => function () {
      return [
        'message' => 'Hello from your first WPGraphQL extension!',
        'number' => 42,
      ];
    }
  ]);
});
add_action('graphql_register_types', function () {
  register_graphql_field('RootQuery', 'siteCustomSetting', [
    'type' => 'String',
    'description' => __('A custom site setting', 'my-graphql-extension'),
    'resolve' => function () {
      // Basic capability check
      if (! current_user_can('read')) {
        throw new \GraphQL\Error\UserError('You do not have permission to access this setting');
      }
      return get_option('my_custom_setting', 'default value');
    }
  ]);
});
add_action('graphql_register_types', function () {
  // Register a custom settings type
  register_graphql_object_type('CustomSiteSettings', [
    'description' => __('Custom site settings', 'my-graphql-extension'),
    'fields' => [
      'mainColor' => [
        'type' => 'String',
        'description' => __('The main color theme setting', 'my-graphql-extension'),
      ],
      'featuredCategories' => [
        'type' => ['list_of' => 'String'],
        'description' => __('List of featured category slugs', 'my-graphql-extension'),
      ],
      'lastUpdated' => [
        'type' => 'String',
        'description' => __('When the settings were last updated', 'my-graphql-extension'),
      ],
    ],
  ]);
  // Register a field that returns our settings type
  register_graphql_field('RootQuery', 'customSiteSettings', [
    'type' => 'CustomSiteSettings',
    'description' => __('Custom site settings configuration', 'my-graphql-extension'),
    'resolve' => function () {
      // Check permissions
      if (! current_user_can('manage_options')) {
        throw new \GraphQL\Error\UserError(__('You do not have permission to access site settings', 'my-graphql-extension'));
      }
      try {
        return [
          'mainColor' => get_option('site_main_color', '#ffffff'),
          'featuredCategories' => get_option('featured_categories', [1,2,3]),
          'lastUpdated' => get_option('settings_updated_at','18-05-2025'),
        ];
      } catch (\Exception $e) {
        throw new \GraphQL\Error\UserError(__('Error fetching site settings', 'my-graphql-extension'));
      }
    }
  ]);
});

Security Considerations

register_graphql_field('RootQuery', 'sensitiveData', [
  'type' => 'String',
  'resolve' => function () {
    // Always check capabilities
    if (! current_user_can('manage_options')) {
      throw new \GraphQL\Error\UserError('Unauthorized access');
    }
    return get_option('sensitive_data');
  }
]);

Data Sanitization

  'resolve' => function( $source, array $args ) {
       // Always sanitize input
       $safe_input = sanitize_text_field( $args['input'] );
       return wp_kses_post( $safe_input );
   }

Use Try-Catch Blocks

  'resolve' => function() {
       try {
           // Your resolution logic
           return get_option( 'some_option' );
       } catch ( \Exception $e ) {
           throw new \GraphQL\Error\UserError( 
               __( 'Failed to retrieve data', 'my-textdomain' )
           );
       }
   }

Tham khảo

wp-content\plugins\wp-graphql-cpt.php

<?php
/**
 * Plugin Name: WP GraphQL Custom Post Types and Custom Taxonomies
 * Description: Exposes all registered Custom Post Types and Custom Taxonomies to the WPGraphQL EndPoint.
 * Author: Niklas Dahlqvist
 * Author URI: https://www.niklasdahlqvist.com
 * Version: 0.7
 * License: GPL2+
 */
namespace WPGraphQL\Extensions;
if (!defined('ABSPATH')) {
  exit;
}
if (!class_exists('\WPGraphQL\Extensions\CPT')) {
  class CPT
  {
    public function __construct()
    {
      // Actions
      // Filters
      add_filter('register_post_type_args', [$this, 'filterPostTypes'], 10, 2);
      add_filter('register_taxonomy_args', [$this, 'filterTaxonomies'], 10, 2);
    }
    public function filterPostTypes($args, $post_type)
    {
      $graphQLArgs = [];
      $wp_default_post_types = [
        'post',
        'page',
        'attachment',
        'revision',
        'nav_menu_item',
        'custom_css',
        'customize_changeset',
        'oembed_cache',
        'user_request',
        'wp_block',
        'wp_template',
        'wp_template_part',
        'wp_global_styles',
        'wp_navigation',
        // Exclude ACF Field Groups
        'acf-field-group',
        // Exclude WooCommerce products
        'product',
        'product_variation',
        'shop_coupon',
        'shop_order',
        'shop_order_refund',
        'shop_order_placehold'
      ];
      $wp_default_post_types = apply_filters('graphql_cpt_excluded_post_types', $wp_default_post_types);
      // Filter Out Truly Custom Post Types, we don't want to mess around with the others
      if (!in_array($post_type, $wp_default_post_types) && !$this->graphQLKeysExists($args)) {
        if (isset($args['labels']) && isset($args['public']) && $args['public'] == true) {
          $graphQLArgs = apply_filters('graphql_cpt_post_type_graphql_args', [
            'show_in_graphql' => true,
            'graphql_single_name' => $this->cleanStrings($args['labels']['singular_name']),
            'graphql_plural_name' => $this->cleanStrings($args['labels']['name'])
          ], $post_type);
          $graphQLArgs = apply_filters("graphql_cpt_{$post_type}_graphql_args", $graphQLArgs);
          // Merge args together.
          return apply_filters("graphql_cpt_{$post_type}_merged_args", array_merge($args, $graphQLArgs));
        }
      }
      return $args;
    }
    public function filterTaxonomies($args, $taxonomy)
    {
      $wp_default_taxonomies = [
        'category',
        'post_tag',
        'nav_menu',
        'link_category',
        'nav_menu_item',
        'post_format',
        'wp_theme',
        'wp_template_part_area',
        'product_type',
        'product_visibility',
        'product_cat',
        'product_tag',
        'product_shipping_class',
      ];
      $wp_default_taxonomies = apply_filters('graphql_cpt_excluded_taxonomies', $wp_default_taxonomies);
      // Filter Out Truly Custom Taxonomies, we don't want to mess around with the others
      if (!in_array($taxonomy, $wp_default_taxonomies) && !$this->graphQLKeysExists($args)) {
        if (isset($args['labels'])) {
          $graphQLArgs = apply_filters('graphql_cpt_taxonomy_graphql_args', [
            'show_in_graphql' => true,
            'graphql_single_name' => $this->cleanStrings($args['labels']['singular_name']),
            'graphql_plural_name' => $this->cleanStrings($args['labels']['name'])
          ], $taxonomy);
          $graphQLArgs = apply_filters("graphql_cpt_{$taxonomy}_graphql_args", $graphQLArgs);
          // Merge args together.
          return apply_filters("graphql_cpt_{$taxonomy}_merged_args", array_merge($args, $graphQLArgs));
        }
      }
      return $args;
    }
    public function graphQLKeysExists($args)
    {
      $graphQLKeys = apply_filters('graphql_cpt_existing_keys_to_check_against', [
        'show_in_graphql',
        'graphql_single_name',
        'graphql_plural_name'
      ]);
      return !array_diff_key(array_flip($graphQLKeys), $args);
    }
    public function cleanStrings($string)
    {
      return preg_replace('/[^a-zA-Z0-9_]+/', '', lcfirst(ucwords($string)));
    }
  }
}
// Boot Plugin
add_action('plugins_loaded', function () {
  new CPT();
});

Last updated

Was this helpful?