WP Manifestindependent plugin directory
manifest / developer / pk-graphql-kit

PK GraphQL Kit

Developer toolkit for headless WordPress — CPT, ACF, WPGraphQL integrations and schema in one place

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/petrokrupenia/pk-graphql-kit/archive/refs/heads/master.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Developer toolkit for headless WordPress — CPT, ACF, WPGraphQL schema in one place.

Requirements

Installation

  1. Clone or copy the plugin into wp-content/plugins/pk-graphql-kit/
  2. Run composer install
  3. Activate the plugin in WordPress admin

Overview

The plugin is configured by editing files inside includes/. There is no settings UI for configuration — every manager exposes protected methods you override directly.

The admin overview page is available at Settings → PK GraphQL Kit.


Post Types & Taxonomies

Edit includes/PostType/PostTypeManager.php.

Register post types

protected function post_types(): array {
    return [
        [ 'slug' => 'book', 'singular' => 'Book', 'plural' => 'Books' ],
        [ 'slug' => 'team-member', 'singular' => 'Team Member', 'plural' => 'Team Members' ],
    ];
}

All post types are registered with show_in_graphql, show_in_rest, and auto-generated graphql_single_name / graphql_plural_name by default. Pass args to override any defaults.

Register taxonomies

protected function taxonomies(): array {
    return [
        [ 'slug' => 'genre', 'singular' => 'Genre', 'plural' => 'Genres', 'post_types' => [ 'book' ] ],
    ];
}

Taxonomies default to hierarchical => true and full GraphQL support.

Unregister

protected function unregister_post_types(): array {
    return [ 'some-post-type' ];
}

protected function unregister_taxonomies(): array {
    return [ 'some-taxonomy' ];
}

Enable WPGraphQL on external post types

For post types registered by other plugins that don't have GraphQL support:

protected function graphql_post_types(): array {
    return [ 'page', 'product' ];
}

protected function graphql_taxonomies(): array {
    return [ 'category' ];
}

graphql_single_name and graphql_plural_name are auto-generated from the post type labels.

Helpers

use PkGraphQLKit\PostType\PostTypeHelper;
use PkGraphQLKit\PostType\TaxonomyHelper;

// Custom post types only (no built-ins)
PostTypeHelper::all();
PostTypeHelper::public_types();
PostTypeHelper::non_public_types();
PostTypeHelper::graphql_types();

// All post types including built-ins (useful in integrations)
PostTypeHelper::all_graphql_types();

// Enable GraphQL support manually
PostTypeHelper::enable_graphql( [ 'page', 'product' ] );

Same methods available on TaxonomyHelper.

Filters

Filter Description
pkgraphqlkit/register/post_types Modify post types array before registration
pkgraphqlkit/register/taxonomies Modify taxonomies array before registration
pkgraphqlkit/unregister/post_types Modify slugs array before unregistering
pkgraphqlkit/unregister/taxonomies Modify slugs array before unregistering
pkgraphqlkit/graphql/enable/post_types Modify slugs array before enabling GraphQL
pkgraphqlkit/graphql/enable/taxonomies Modify slugs array before enabling GraphQL

ACF

Edit includes/Acf/AcfManager.php. Only available when ACF is active.

Options pages

protected function options_pages(): array {
    return [
        'Site Settings',
        [ 'page_title' => 'SEO Settings', 'parent_slug' => 'options' ],
    ];
}

ACF JSON

Field groups created in the ACF admin are automatically saved to and loaded from acf-json/ in the plugin root. Commit this directory to version control.

Dynamic fields

To dynamically populate field choices (e.g. a select from an options page), create a class in includes/Acf/DynamicFields/ that extends AcfDynamicFields:

namespace PkGraphQLKit\Acf\DynamicFields;

use PkGraphQLKit\Acf\AcfDynamicFields;

class MyDynamicFields extends AcfDynamicFields {
    protected function register_filters(): void {
        add_filter( 'acf/load_field/name=my_select', [ $this, 'load_my_select' ] );
    }

    public function load_my_select( array $field ): array {
        $field['choices'] = [ 'foo' => 'Foo', 'bar' => 'Bar' ];
        return $field;
    }
}

The class is discovered and booted automatically — no registration required.

Code-based field groups

Create a class in includes/Acf/FieldGroups/ that implements AcfFieldGroupInterface — it is discovered and registered automatically. Use /make-acf-field-group to generate the skeleton, or register manually via AcfManager::register_field_group().

Filters

Filter Description
pkgraphqlkit/acf/options_pages Add or modify options pages before registration

WPGraphQL

Settings

Edit includes/GraphQL/GraphQLSettings.php.

protected function settings(): array {
    return [
        'graphql_endpoint'             => 'graphql',
        'public_introspection_enabled' => 'on',
    ];
}

Boolean settings use 'on' / 'off' strings as WPGraphQL expects. Settings defined here override the WPGraphQL admin UI.

Environment presets — debug_mode_enabled and tracing_enabled are automatically set to 'on' for local, development, and staging environments. Values in settings() always take precedence.

CORS

protected function allowed_origins(): array {
    return [
        get_bloginfo( 'url' ),  // always included
        'https://yoursite.com',
        'http://localhost:3000',
    ];
}

Custom types, fields, mutations

Edit includes/GraphQL/GraphQLManager.php.

protected function types(): array {
    return [
        [
            'type_name' => 'Address',
            'config'    => [
                'description' => 'A physical address.',
                'fields'      => [
                    'street' => [ 'type' => 'String' ],
                    'city'   => [ 'type' => 'String' ],
                ],
            ],
        ],
    ];
}

protected function fields(): array {
    return [
        [
            'type_name'  => 'Post',
            'field_name' => 'readingTime',
            'config'     => [
                'type'    => 'Int',
                'resolve' => fn( $post ) => (int) get_post_meta( $post->databaseId, '_reading_time', true ),
            ],
        ],
    ];
}

protected function mutations(): array {
    return [
        [
            'name'   => 'SubmitContactForm',
            'config' => [
                'inputFields'         => [
                    'name'    => [ 'type' => [ 'non_null' => 'String' ] ],
                    'email'   => [ 'type' => [ 'non_null' => 'String' ] ],
                    'message' => [ 'type' => [ 'non_null' => 'String' ] ],
                ],
                'outputFields'        => [
                    'success' => [ 'type' => 'Boolean' ],
                    'message' => [ 'type' => 'String' ],
                ],
                'mutateAndGetPayload' => function ( array $input ): array {
                    // handle the mutation
                    return [ 'success' => true, 'message' => 'Sent!' ];
                },
            ],
        ],
    ];
}

Filters

Filter Description
pkgraphqlkit/graphql/register/types Modify types array before registration
pkgraphqlkit/graphql/register/fields Modify fields array before registration
pkgraphqlkit/graphql/register/mutations Modify mutations array before registration

Integrations

Integrations add WPGraphQL support for third-party plugins. They are auto-discovered — create a file in includes/Integration/Integrations/, extend AbstractIntegration, and it will be loaded automatically when the target plugin is active.

namespace PkGraphQLKit\Integration\Integrations;

use PkGraphQLKit\Integration\AbstractIntegration;

class MyPluginIntegration extends AbstractIntegration {

    public function get_plugin_file(): string {
        return 'my-plugin/my-plugin.php';
    }

    protected function graphql_fields(): array {
        return [
            [
                'type_name'  => 'Post',
                'field_name' => 'myField',
                'config'     => [
                    'type'    => 'String',
                    'resolve' => fn( $post ) => get_post_meta( $post->databaseId, '_my_field', true ),
                ],
            ],
        ];
    }
}

Override register() and call parent::register() if additional hooks beyond GraphQL schema registration are needed.

Bundled integrations

Integration Plugin
SlimSeoIntegration Slim SEO — exposes seo { title, description, noindex, canonical, og { title, description, image }, twitter { card, image, site } } on all GraphQL-enabled post types and taxonomies

Accessing managers programmatically

pkgraphqlkit()->post_types()       // PostTypeManager
pkgraphqlkit()->acf()              // AcfManager|null
pkgraphqlkit()->integrations()     // IntegrationManager
pkgraphqlkit()->graphql()          // GraphQLManager
pkgraphqlkit()->graphql_settings() // GraphQLSettings
pkgraphqlkit()->admin()            // AdminPage

Claude Code Skills

Skills are slash commands for Claude Code that generate or modify plugin code directly. They live in .claude/commands/ inside the plugin and are available automatically when Claude Code is opened from the plugin directory.

Available skills

Skill Arguments Example
/register-cpt slug singular plural /register-cpt book Book Books
/register-taxonomy slug singular plural [post_type1,post_type2] /register-taxonomy genre Genre Genres book
/unregister cpt\|taxonomy slug /unregister cpt attachment
/add-cors url [url2 ...] /add-cors https://mysite.com http://localhost:3000
/toggle-integrations on\|off /toggle-integrations off
/add-graphql-field TypeName fieldName ReturnType [description] /add-graphql-field Post readingTime Int "Reading time"
/add-mutation MutationName [description] /add-mutation SubmitContactForm
/add-acf-options-page Title [parent:parent-slug] /add-acf-options-page "Site Settings"
/make-acf-field-group ClassName "Title" [location] /make-acf-field-group BookFields "Book Fields" post-type:book
/make-acf-dynamic-fields ClassName [field1,field2] /make-acf-dynamic-fields ProductChoices product_type

/make-acf-field-group location options: post-type:slug, options, page, user.

Working from a higher-level directory

Skills are only loaded by Claude Code from the working directory it is opened in. If you open Claude Code from a parent directory (e.g. the WordPress root at app/public), create symlinks so the skills are available there too:

# Run once from the WordPress root (app/public)
mkdir -p .claude/commands
for f in wp-content/plugins/pk-graphql-kit/.claude/commands/*.md; do
    ln -sf "../../$f" ".claude/commands/$(basename $f)"
done

The symlinks at app/public/.claude/commands/ are already committed to this repository. If you add new skills to the plugin, re-run the command above to pick them up.


Directory structure

.claude/
└── commands/                        — Claude Code skills (slash commands)
includes/
├── Admin/
│   └── AdminPage.php               — admin overview page (Settings → PK GraphQL Kit)
├── Acf/
│   ├── AcfDynamicFields.php        — base class for dynamic field population
│   ├── AcfFieldGroupInterface.php  — interface for code-based field groups
│   ├── AcfManager.php              — options pages, field groups, ACF JSON path
│   ├── DynamicFields/              — auto-discovered dynamic field classes
│   └── FieldGroups/                — auto-discovered code-based field group classes
├── GraphQL/
│   ├── GraphQLManager.php          — custom types, fields, mutations
│   └── GraphQLSettings.php         — WPGraphQL settings overrides + CORS
├── Helpers/
│   └── StringHelper.php            — to_graphql_name() utility
├── Integration/
│   ├── AbstractIntegration.php     — base class for integrations
│   ├── IntegrationManager.php      — auto-discovers and boots integrations
│   └── Integrations/               — auto-discovered integration classes
└── PostType/
    ├── PostTypeConfig.php           — value object for CPT registration
    ├── PostTypeHelper.php           — static helpers for querying post types
    ├── PostTypeManager.php          — registers/unregisters CPTs and taxonomies
    ├── TaxonomyConfig.php           — value object for taxonomy registration
    └── TaxonomyHelper.php           — static helpers for querying taxonomies
acf-json/                            — ACF field group JSON (commit to version control)